From 50795600375dc5989ee5f7679fd448ef4f993866 Mon Sep 17 00:00:00 2001 From: redkale Date: Mon, 27 May 2024 12:19:58 +0800 Subject: [PATCH] format --- src/main/java/javax/persistence/Column.java | 294 +- src/main/java/javax/persistence/Entity.java | 98 +- src/main/java/javax/persistence/Id.java | 92 +- src/main/java/javax/persistence/Index.java | 128 +- src/main/java/javax/persistence/Table.java | 176 +- .../java/javax/persistence/Transient.java | 86 +- .../javax/persistence/UniqueConstraint.java | 114 +- src/main/java/module-info.java | 108 +- .../org/redkale/annotation/ClassDepends.java | 50 +- .../org/redkale/annotation/Component.java | 44 +- .../org/redkale/annotation/NonBlocking.java | 50 +- .../java/org/redkale/annotation/Nonnull.java | 36 +- .../java/org/redkale/annotation/Nullable.java | 36 +- .../java/org/redkale/annotation/Param.java | 58 +- .../org/redkale/annotation/PostConstruct.java | 40 +- .../org/redkale/annotation/PreDestroy.java | 36 +- .../redkale/annotation/ResourceInjected.java | 130 +- .../org/redkale/asm/AnnotationVisitor.java | 340 +- .../org/redkale/asm/AnnotationWriter.java | 732 +- .../java/org/redkale/asm/AsmMethodBean.java | 280 +- .../java/org/redkale/asm/AsmMethodBoost.java | 818 +- .../java/org/redkale/asm/AsmMethodParam.java | 144 +- src/main/java/org/redkale/asm/Asms.java | 394 +- src/main/java/org/redkale/asm/Attribute.java | 624 +- src/main/java/org/redkale/asm/ByteVector.java | 662 +- .../java/org/redkale/asm/ClassReader.java | 5220 +++++----- .../java/org/redkale/asm/ClassVisitor.java | 584 +- .../java/org/redkale/asm/ClassWriter.java | 3082 +++--- src/main/java/org/redkale/asm/Context.java | 286 +- .../java/org/redkale/asm/CurrentFrame.java | 166 +- src/main/java/org/redkale/asm/Edge.java | 188 +- .../java/org/redkale/asm/FieldVisitor.java | 310 +- .../java/org/redkale/asm/FieldWriter.java | 640 +- src/main/java/org/redkale/asm/Frame.java | 2916 +++--- src/main/java/org/redkale/asm/Handle.java | 380 +- src/main/java/org/redkale/asm/Handler.java | 276 +- src/main/java/org/redkale/asm/Item.java | 578 +- src/main/java/org/redkale/asm/Label.java | 1018 +- .../java/org/redkale/asm/MethodVisitor.java | 1340 +-- .../java/org/redkale/asm/MethodWriter.java | 4480 ++++---- .../java/org/redkale/asm/ModuleVisitor.java | 404 +- .../java/org/redkale/asm/ModuleWriter.java | 576 +- src/main/java/org/redkale/asm/Opcodes.java | 804 +- src/main/java/org/redkale/asm/Type.java | 1630 +-- src/main/java/org/redkale/asm/TypePath.java | 390 +- .../java/org/redkale/asm/TypeReference.java | 804 +- src/main/java/org/redkale/boot/AppConfig.java | 988 +- .../java/org/redkale/boot/Application.java | 3310 +++--- .../java/org/redkale/boot/BootModule.java | 104 +- .../java/org/redkale/boot/LoggingModule.java | 384 +- .../java/org/redkale/boot/ModuleEngine.java | 358 +- .../java/org/redkale/boot/NodeHttpServer.java | 1324 +-- .../java/org/redkale/boot/NodeServer.java | 2256 ++-- .../java/org/redkale/cache/CacheManager.java | 1684 +-- src/main/java/org/redkale/cache/Cached.java | 170 +- .../org/redkale/cache/spi/CacheAction.java | 312 +- .../cache/spi/CacheAsmMethodBoost.java | 496 +- .../org/redkale/cache/spi/CacheEntry.java | 194 +- .../cache/spi/CacheManagerProvider.java | 34 +- .../cache/spi/CacheManagerService.java | 1896 ++-- .../redkale/cache/spi/CacheModuleEngine.java | 202 +- .../org/redkale/cache/spi/CacheValue.java | 106 +- .../org/redkale/cache/spi/DynForCache.java | 82 +- .../org/redkale/cluster/ClusterRpcClient.java | 70 +- .../cluster/spi/ClusterModuleEngine.java | 506 +- .../cluster/spi/HttpClusterRpcClient.java | 456 +- .../java/org/redkale/convert/ConvertImpl.java | 130 +- .../org/redkale/convert/StreamDecoder.java | 274 +- .../redkale/convert/ext/EnumSimpledCoder.java | 196 +- .../convert/ext/InstantSimpledCoder.java | 118 +- .../convert/ext/LocalDateSimpledCoder.java | 150 +- .../ext/LocalDateTimeSimpledCoder.java | 216 +- .../convert/ext/LocalTimeSimpledCoder.java | 146 +- .../convert/ext/LongAdderSimpledCoder.java | 70 +- .../org/redkale/convert/json/JsonArray.java | 776 +- .../org/redkale/convert/json/JsonElement.java | 78 +- .../convert/json/JsonElementDecoder.java | 80 +- .../org/redkale/convert/json/JsonObject.java | 942 +- .../org/redkale/convert/json/JsonString.java | 166 +- .../convert/proto/ProtobufArrayDecoder.java | 90 +- .../convert/proto/ProtobufArrayEncoder.java | 116 +- .../proto/ProtobufByteBufferReader.java | 396 +- .../proto/ProtobufByteBufferWriter.java | 288 +- .../proto/ProtobufCollectionDecoder.java | 90 +- .../proto/ProtobufCollectionEncoder.java | 114 +- .../convert/proto/ProtobufConvert.java | 1740 ++-- .../proto/ProtobufEnumSimpledCoder.java | 142 +- .../convert/proto/ProtobufFactory.java | 690 +- .../convert/proto/ProtobufMapDecoder.java | 104 +- .../convert/proto/ProtobufMapEncoder.java | 74 +- .../convert/proto/ProtobufObjectDecoder.java | 162 +- .../convert/proto/ProtobufObjectEncoder.java | 86 +- .../redkale/convert/proto/ProtobufReader.java | 898 +- .../convert/proto/ProtobufStreamDecoder.java | 90 +- .../convert/proto/ProtobufStreamEncoder.java | 110 +- .../convert/proto/ProtobufStreamReader.java | 100 +- .../convert/proto/ProtobufStreamWriter.java | 98 +- .../redkale/convert/proto/ProtobufWriter.java | 1290 +-- .../inject/ResourceAnnotationLoader.java | 58 +- .../java/org/redkale/lock/LockManager.java | 32 +- src/main/java/org/redkale/lock/Locked.java | 72 +- .../java/org/redkale/lock/spi/DynForLock.java | 56 +- .../redkale/lock/spi/LockAsmMethodBoost.java | 198 +- .../redkale/lock/spi/LockManagerProvider.java | 36 +- .../redkale/lock/spi/LockManagerService.java | 108 +- .../redkale/lock/spi/LockModuleEngine.java | 200 +- .../java/org/redkale/mq/MessageConext.java | 122 +- .../java/org/redkale/mq/MessageConsumer.java | 64 +- .../java/org/redkale/mq/MessageManager.java | 54 +- .../java/org/redkale/mq/MessageProducer.java | 84 +- src/main/java/org/redkale/mq/Messaged.java | 86 +- .../java/org/redkale/mq/ResourceConsumer.java | 68 +- .../java/org/redkale/mq/ResourceProducer.java | 62 +- .../org/redkale/mq/spi/DynForMessage.java | 76 +- .../redkale/mq/spi/HttpRpcMessageClient.java | 100 +- .../redkale/mq/spi/MessageAsmMethodBoost.java | 690 +- .../redkale/mq/spi/MessageModuleEngine.java | 1026 +- .../org/redkale/mq/spi/MessageProcessor.java | 20 +- .../redkale/mq/spi/MessageRespProcessor.java | 144 +- .../org/redkale/net/AsyncNioConnection.java | 1396 +-- .../java/org/redkale/net/ProtocolCodec.java | 498 +- .../org/redkale/net/client/ClientCodec.java | 428 +- .../redkale/net/client/ClientConnection.java | 946 +- .../net/client/ClientMessageListener.java | 38 +- .../redkale/net/client/ClientResponse.java | 232 +- .../org/redkale/net/client/ClientResult.java | 30 +- .../org/redkale/net/client/WeightAddress.java | 184 +- .../org/redkale/net/http/HttpException.java | 66 +- .../java/org/redkale/net/http/HttpFilter.java | 156 +- .../org/redkale/net/http/HttpHeaders.java | 738 +- .../org/redkale/net/http/HttpParameters.java | 378 +- .../org/redkale/net/http/HttpRequest.java | 5768 +++++------ .../java/org/redkale/net/http/HttpServer.java | 1278 +-- src/main/java/org/redkale/net/http/Rest.java | 9070 ++++++++-------- .../org/redkale/net/http/RestException.java | 62 +- .../java/org/redkale/net/http/WebCodec.java | 358 +- .../org/redkale/net/http/WebConnection.java | 52 +- .../java/org/redkale/net/http/WebResult.java | 66 +- .../org/redkale/net/http/WebSocketFuture.java | 118 +- .../net/http/WebSocketNodeService.java | 450 +- src/main/java/org/redkale/net/sncp/Sncp.java | 2524 ++--- .../redkale/net/sncp/SncpAsyncHandler.java | 464 +- .../java/org/redkale/net/sncp/SncpClient.java | 152 +- .../org/redkale/net/sncp/SncpClientCodec.java | 318 +- .../net/sncp/SncpClientConnection.java | 82 +- .../redkale/net/sncp/SncpClientRequest.java | 180 +- .../redkale/net/sncp/SncpClientResult.java | 170 +- .../org/redkale/net/sncp/SncpException.java | 66 +- .../java/org/redkale/net/sncp/SncpHeader.java | 608 +- .../org/redkale/net/sncp/SncpRemoteInfo.java | 1090 +- .../org/redkale/net/sncp/SncpRpcGroup.java | 300 +- .../org/redkale/net/sncp/SncpRpcGroups.java | 168 +- .../java/org/redkale/net/sncp/SncpServer.java | 270 +- .../java/org/redkale/persistence/Column.java | 272 +- .../java/org/redkale/persistence/Entity.java | 134 +- .../redkale/persistence/GeneratedValue.java | 104 +- src/main/java/org/redkale/persistence/Id.java | 90 +- .../java/org/redkale/persistence/Index.java | 160 +- .../java/org/redkale/persistence/Sql.java | 78 +- .../java/org/redkale/persistence/Table.java | 132 +- .../org/redkale/persistence/Transient.java | 84 +- .../redkale/props/spi/PropertiesModule.java | 656 +- .../org/redkale/schedule/ScheduleEvent.java | 158 +- .../org/redkale/schedule/ScheduleManager.java | 94 +- .../java/org/redkale/schedule/Scheduled.java | 200 +- .../redkale/schedule/spi/CronExpression.java | 1436 +-- .../schedule/spi/ScheduleManagerProvider.java | 34 +- .../schedule/spi/ScheduleManagerService.java | 980 +- .../schedule/spi/ScheduleModuleEngine.java | 252 +- .../org/redkale/service/AbstractService.java | 146 +- .../java/org/redkale/service/LoadMode.java | 94 +- .../java/org/redkale/service/RpcAction.java | 50 +- .../redkale/source/AbstractDataSource.java | 3070 +++--- .../redkale/source/CacheEventListener.java | 34 +- .../org/redkale/source/CacheScoredValue.java | 178 +- .../org/redkale/source/ColumnBytesNode.java | 86 +- .../org/redkale/source/ColumnNameNode.java | 82 +- .../java/org/redkale/source/ColumnNodes.java | 426 +- .../org/redkale/source/ColumnNumberNode.java | 82 +- .../org/redkale/source/ColumnStringNode.java | 82 +- .../java/org/redkale/source/ColumnValues.java | 772 +- .../java/org/redkale/source/DataBatch.java | 168 +- .../redkale/source/DataJdbcConnection.java | 50 +- .../org/redkale/source/DataMemorySource.java | 892 +- .../org/redkale/source/DataNativeSqlInfo.java | 138 +- .../redkale/source/DataNativeSqlParser.java | 90 +- .../source/DataNativeSqlStatement.java | 224 +- .../org/redkale/source/DataSqlMapper.java | 6204 +++++------ .../org/redkale/source/DataSqlSource.java | 902 +- .../org/redkale/source/DataTransaction.java | 98 +- .../org/redkale/source/EntityBuilder.java | 1204 +-- .../org/redkale/source/FilterJoinType.java | 32 +- .../java/org/redkale/source/FilterNodes.java | 1218 +-- .../org/redkale/source/SourceException.java | 66 +- .../org/redkale/source/SourceManager.java | 126 +- .../spi/DataNativeSqlParserProvider.java | 34 +- .../source/spi/DataSqlMapperBuilder.java | 920 +- .../source/spi/SourceModuleEngine.java | 1318 +-- .../redkale/util/AnonymousThreadFactory.java | 78 +- .../redkale/util/AnonymousThreadLocal.java | 96 +- .../org/redkale/util/AnonymousUnsafe.java | 886 +- .../util/AnonymousVirtualExecutor.java | 42 +- .../util/AnonymousVirtualPoolFunction.java | 54 +- .../java/org/redkale/util/AnyValueWriter.java | 1210 +-- src/main/java/org/redkale/util/BoolRef.java | 92 +- .../java/org/redkale/util/ByteBufferPool.java | 278 +- .../org/redkale/util/ByteBufferWriter.java | 460 +- src/main/java/org/redkale/util/Copier.java | 2696 ++--- src/main/java/org/redkale/util/Creator.java | 1242 +-- src/main/java/org/redkale/util/Flows.java | 644 +- src/main/java/org/redkale/util/Inners.java | 672 +- src/main/java/org/redkale/util/Invoker.java | 450 +- .../org/redkale/util/LambdaBiConsumer.java | 58 +- .../java/org/redkale/util/LambdaFunction.java | 66 +- .../java/org/redkale/util/LambdaSupplier.java | 56 +- .../redkale/util/MissingParamException.java | 86 +- .../java/org/redkale/util/MultiHashKey.java | 56 +- .../java/org/redkale/util/MultiHashKeys.java | 430 +- src/main/java/org/redkale/util/ObjectRef.java | 86 +- .../org/redkale/util/RedkaleException.java | 62 +- .../java/org/redkale/util/ResourceEvent.java | 32 +- .../java/org/redkale/util/ThrowSupplier.java | 56 +- src/main/java/org/redkale/util/Times.java | 696 +- src/main/java/org/redkale/util/Unsafe.java | 382 +- src/main/java/org/redkale/util/XmlReader.java | 862 +- .../java/org/redkale/test/asm/AsmCreator.java | 78 +- .../org/redkale/test/cache/CacheInstance.java | 238 +- .../redkale/test/cache/CacheInstanceTest.java | 124 +- .../redkale/test/cache/CacheManagerTest.java | 288 +- .../test/cache/_DynLocalCacheInstance.java | 344 +- .../test/convert/BiFunctionConvertTest.java | 146 +- .../redkale/test/convert/BsonMainTest.java | 572 +- .../redkale/test/convert/ConvertImplTest.java | 82 +- .../redkale/test/convert/ConvertRecord.java | 310 +- .../org/redkale/test/convert/Fortune.java | 102 +- .../redkale/test/convert/GenericEntity.java | 212 +- .../test/convert/InnerCoderEntity.java | 256 +- .../redkale/test/convert/JsonMainTest.java | 298 +- .../redkale/test/convert/JsonPvBeanTest.java | 420 +- .../org/redkale/test/convert/Message.java | 174 +- .../java/org/redkale/test/convert/One.java | 170 +- .../test/convert/SimpleChildEntity.java | 112 +- .../redkale/test/convert/SimpleEntity.java | 266 +- .../java/org/redkale/test/convert/Two.java | 132 +- .../java/org/redkale/test/convert/World.java | 110 +- .../test/convert/_DyncFortuneJsonEncoder.java | 92 +- .../test/convert/_DyncMessageJsonEncoder.java | 94 +- .../test/convert/_DyncWorldJsonEncoder.java | 88 +- .../org/redkale/test/convert/media/Image.java | 228 +- .../org/redkale/test/convert/media/Media.java | 420 +- .../test/convert/media/MediaContent.java | 210 +- .../redkale/test/convert/proto/ArrayBean.java | 112 +- .../convert/proto/PBCustMessage2Test.java | 476 +- .../test/convert/proto/PBCustMessageTest.java | 400 +- .../convert/proto/PSimpleBeanOuterClass.java | 4774 ++++----- .../convert/proto/PTestBeanOuterClass.java | 9128 ++++++++--------- .../test/convert/proto/SimpleBean.java | 216 +- .../redkale/test/convert/proto/TestBean.java | 488 +- .../redkale/test/http/HttpRequestDesc.java | 690 +- .../redkale/test/http/HttpResponseDesc.java | 342 +- .../test/http/HttpSimpleClientTest.java | 232 +- .../redkale/test/http/HttpSimpleServlet.java | 40 +- .../redkale/test/http/RequestCoderTest.java | 140 +- .../redkale/test/http/RestSleepService.java | 68 +- .../org/redkale/test/http/RestSleepTest.java | 144 +- .../org/redkale/test/http/SocketMain.java | 72 +- .../redkale/test/http/UploadTestServlet.java | 86 +- .../org/redkale/test/http/WebSocketDesc.java | 396 +- .../test/inject/ResourceAnnotationTest.java | 162 +- .../test/inject/ResourceInjectedTest.java | 130 +- .../org/redkale/test/inject/ResourceTest.java | 362 +- .../test/rest/CreateTimeSimpleCoder.java | 78 +- .../redkale/test/rest/HelloAsyncHandler.java | 46 +- .../java/org/redkale/test/rest/HelloBean.java | 136 +- .../org/redkale/test/rest/HelloEntity.java | 302 +- .../org/redkale/test/rest/HelloService.java | 260 +- .../org/redkale/test/rest/HelloService2.java | 118 +- .../java/org/redkale/test/rest/LoginBean.java | 86 +- .../java/org/redkale/test/rest/RetCodes.java | 314 +- .../redkale/test/rest/SimpleRestServlet.java | 74 +- .../java/org/redkale/test/rest/UserInfo.java | 88 +- .../org/redkale/test/rest/UserService.java | 60 +- .../test/rest/_DynHelloRestServlet1.java | 354 +- .../test/rest/_DynHelloRestServlet2.java | 192 +- .../test/schedule/ScheduleService.java | 56 +- .../redkale/test/schedule/SchedulingTest.java | 56 +- .../redkale/test/service/ABMainService.java | 498 +- .../org/redkale/test/service/BCService.java | 170 +- .../org/redkale/test/service/CService.java | 94 +- .../redkale/test/service/MyAsyncHandler.java | 32 +- .../test/service/MyAsyncInnerHandler.java | 28 +- .../java/org/redkale/test/service/Person.java | 62 +- .../org/redkale/test/service/TestBean.java | 18 +- .../org/redkale/test/service/TestService.java | 58 +- .../test/sncp/SncpClientCodecTest.java | 188 +- .../redkale/test/sncp/SncpHandlerTest.java | 172 +- .../test/sncp/SncpRequestParseTest.java | 166 +- .../redkale/test/sncp/SncpSleepService.java | 98 +- .../org/redkale/test/sncp/SncpSleepTest.java | 138 +- .../java/org/redkale/test/sncp/SncpTest.java | 516 +- .../org/redkale/test/sncp/SncpTestBean.java | 108 +- .../redkale/test/sncp/SncpTestIService.java | 50 +- .../test/sncp/SncpTestServiceImpl.java | 252 +- .../org/redkale/test/sncp/TestService.java | 332 +- .../test/sncp/_DynLocalSncpTestService.java | 24 +- .../org/redkale/test/source/BaseEntity.java | 36 +- .../test/source/CacheMemorySourceTest.java | 1326 +-- .../redkale/test/source/CacheTestBean.java | 202 +- .../redkale/test/source/FilterNodeTest.java | 880 +- .../org/redkale/test/source/JsonRecord.java | 250 +- .../org/redkale/test/source/LoginRecord.java | 322 +- .../redkale/test/source/LoginTestBean.java | 108 +- .../redkale/test/source/LoginTestRecord.java | 172 +- .../redkale/test/source/LoginUserRecord.java | 176 +- .../redkale/test/source/TestSourceCache.java | 268 +- .../org/redkale/test/source/UserDetail.java | 218 +- .../test/source/parser/BaseEntity.java | 40 +- .../test/source/parser/BaseMapper.java | 18 +- .../test/source/parser/DataSqlMapperTest.java | 62 +- .../source/parser/DynForumInfoMapperImpl.java | 124 +- .../redkale/test/source/parser/ForumBean.java | 80 +- .../redkale/test/source/parser/ForumInfo.java | 510 +- .../test/source/parser/ForumInfoMapper.java | 82 +- .../test/source/parser/ForumResult.java | 70 +- .../test/source/parser/ForumSection.java | 260 +- .../java/org/redkale/test/type/OneBean.java | 24 +- .../java/org/redkale/test/type/OneRound.java | 18 +- .../org/redkale/test/type/OneService.java | 40 +- .../java/org/redkale/test/type/ThreeBean.java | 24 +- .../org/redkale/test/type/ThreeRound.java | 18 +- .../org/redkale/test/type/ThreeService.java | 40 +- .../java/org/redkale/test/type/TwoBean.java | 24 +- .../java/org/redkale/test/type/TwoRound.java | 18 +- .../org/redkale/test/type/TwoService.java | 26 +- .../org/redkale/test/type/TypeTokenTest.java | 86 +- .../org/redkale/test/util/CopierBeanMap.java | 96 +- .../org/redkale/test/util/CopierMapBean.java | 62 +- .../org/redkale/test/util/CopierTest.java | 1246 +-- .../org/redkale/test/util/CreatorRecord.java | 204 +- .../redkale/test/util/EnvironmentTest.java | 74 +- .../org/redkale/test/util/InvokerTest.java | 186 +- .../redkale/test/util/MultiHashKeyTest.java | 256 +- .../java/org/redkale/test/util/TestABean.java | 22 +- .../java/org/redkale/test/util/TestBean.java | 120 +- .../org/redkale/test/util/TestInterface.java | 40 +- .../org/redkale/test/util/TestX2Bean.java | 116 +- .../java/org/redkale/test/util/TestXBean.java | 18 +- .../org/redkale/test/util/TypeTokenTest.java | 146 +- .../org/redkale/test/util/UntilTestMain.java | 260 +- .../test/websocket/ChatWebSocketServlet.java | 144 +- .../org/redkale/test/websocket/Flash843.java | 52 +- .../test/websocket/VideoWebSocketServlet.java | 254 +- .../java/org/redkale/test/ws/ChatMessage.java | 48 +- .../java/org/redkale/test/ws/ChatService.java | 102 +- .../org/redkale/test/ws/ChatWebSocket.java | 220 +- .../wsdync/_DyncChatWebSocketServlet.java | 410 +- 356 files changed, 81489 insertions(+), 81489 deletions(-) diff --git a/src/main/java/javax/persistence/Column.java b/src/main/java/javax/persistence/Column.java index 1ea7a0f58..6d508d0a6 100644 --- a/src/main/java/javax/persistence/Column.java +++ b/src/main/java/javax/persistence/Column.java @@ -1,147 +1,147 @@ -/** - * ***************************************************************************** Copyright (c) 2008 - 2013 Oracle - * Corporation. All rights reserved. - * - *

This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v. 1.0 which accompanies this distribution. The Eclipse Public License is available - * at http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - *

Contributors: Linda DeMichiel - Java Persistence 2.1 Linda DeMichiel - Java Persistence 2.0 - * - *

**************************************************************************** - */ -package javax.persistence; - -import static java.lang.annotation.ElementType.*; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.*; - -/** - * Specifies the mapped column for a persistent property or field. If no Column annotation is specified, - * the default values apply. - * - *

- * - *
- *    Example 1:
- *
- *    @Column(name="DESC", nullable=false, length=512)
- *    public String getDescription() { return description; }
- *
- *    Example 2:
- *
- *    @Column(name="DESC",
- *            columnDefinition="CLOB NOT NULL",
- *            table="EMP_DETAIL")
- *    @Lob
- *    public String getDescription() { return description; }
- *
- *    Example 3:
- *
- *    @Column(name="ORDER_COST", updatable=false, precision=12, scale=2)
- *    public BigDecimal getCost() { return cost; }
- *
- * 
- * - *
- * - * @since Java Persistence 1.0 - * @deprecated replace by {@link org.redkale.persistence.Column} - * @see org.redkale.persistence.Column - */ -@Deprecated(since = "2.8.0") -@Target({METHOD, FIELD}) -@Retention(RUNTIME) -public @interface Column { - - /** - * (Optional) The name of the column. Defaults to the property or field name. - * - * @return String - */ - String name() default ""; - - /** - * (Optional) The comment of the column. - * - * @return String - */ - String comment() default ""; - - /** - * (Optional) Whether the column is a unique key. This is a shortcut for the UniqueConstraint - * annotation at the table level and is useful for when the unique key constraint corresponds to only a single - * column. This constraint applies in addition to any constraint entailed by primary key mapping and to constraints - * specified at the table level. - * - * @return boolean - */ - boolean unique() default false; - - /** - * (Optional) Whether the database column is required. - * - * @return boolean - */ - boolean nullable() default true; - - /** - * for OpenAPI Specification 3 - * - * @return String - */ - String example() default ""; - - /** - * (Optional) Whether the column is included in SQL INSERT statements generated by the persistence provider. - * - * @return boolean - */ - boolean insertable() default true; - - /** - * (Optional) Whether the column is included in SQL UPDATE statements generated by the persistence provider. - * - * @return boolean - */ - boolean updatable() default true; - - /** - * (Optional) The name of the table that contains the column. If absent the column is assumed to be in the primary - * table. - * - * @return String - */ - @Deprecated - String table() default ""; - - /** - * (Optional) The column length. (Applies only if a string-valued column is used.) if type==String and length == - * 65535 then sqltype is TEXT
- * if type==String and length <= 16777215 then sqltype is MEDIUMTEXT
- * if type==String and length > 16777215 then sqltype is LONGTEXT
- * if type==byte[] and length <= 65535 then sqltype is BLOB
- * if type==byte[] and length <= 16777215 then sqltype is MEDIUMBLOB
- * if type==byte[] and length > 16777215 then sqltype is LONGBLOB
- * - * @return int - */ - int length() default 255; - - /** - * (Optional) The precision for a decimal (exact numeric) column. (Applies only if a decimal column is used.) Value - * must be set by developer if used when generating the DDL for the column. - * - * @return int - */ - int precision() default 0; - - /** - * (Optional) The scale for a decimal (exact numeric) column. (Applies only if a decimal column is used.) - * - * @return int - */ - int scale() default 0; -} +/** + * ***************************************************************************** Copyright (c) 2008 - 2013 Oracle + * Corporation. All rights reserved. + * + *

This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v. 1.0 which accompanies this distribution. The Eclipse Public License is available + * at http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + *

Contributors: Linda DeMichiel - Java Persistence 2.1 Linda DeMichiel - Java Persistence 2.0 + * + *

**************************************************************************** + */ +package javax.persistence; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.*; + +/** + * Specifies the mapped column for a persistent property or field. If no Column annotation is specified, + * the default values apply. + * + *

+ * + *
+ *    Example 1:
+ *
+ *    @Column(name="DESC", nullable=false, length=512)
+ *    public String getDescription() { return description; }
+ *
+ *    Example 2:
+ *
+ *    @Column(name="DESC",
+ *            columnDefinition="CLOB NOT NULL",
+ *            table="EMP_DETAIL")
+ *    @Lob
+ *    public String getDescription() { return description; }
+ *
+ *    Example 3:
+ *
+ *    @Column(name="ORDER_COST", updatable=false, precision=12, scale=2)
+ *    public BigDecimal getCost() { return cost; }
+ *
+ * 
+ * + *
+ * + * @since Java Persistence 1.0 + * @deprecated replace by {@link org.redkale.persistence.Column} + * @see org.redkale.persistence.Column + */ +@Deprecated(since = "2.8.0") +@Target({METHOD, FIELD}) +@Retention(RUNTIME) +public @interface Column { + + /** + * (Optional) The name of the column. Defaults to the property or field name. + * + * @return String + */ + String name() default ""; + + /** + * (Optional) The comment of the column. + * + * @return String + */ + String comment() default ""; + + /** + * (Optional) Whether the column is a unique key. This is a shortcut for the UniqueConstraint + * annotation at the table level and is useful for when the unique key constraint corresponds to only a single + * column. This constraint applies in addition to any constraint entailed by primary key mapping and to constraints + * specified at the table level. + * + * @return boolean + */ + boolean unique() default false; + + /** + * (Optional) Whether the database column is required. + * + * @return boolean + */ + boolean nullable() default true; + + /** + * for OpenAPI Specification 3 + * + * @return String + */ + String example() default ""; + + /** + * (Optional) Whether the column is included in SQL INSERT statements generated by the persistence provider. + * + * @return boolean + */ + boolean insertable() default true; + + /** + * (Optional) Whether the column is included in SQL UPDATE statements generated by the persistence provider. + * + * @return boolean + */ + boolean updatable() default true; + + /** + * (Optional) The name of the table that contains the column. If absent the column is assumed to be in the primary + * table. + * + * @return String + */ + @Deprecated + String table() default ""; + + /** + * (Optional) The column length. (Applies only if a string-valued column is used.) if type==String and length == + * 65535 then sqltype is TEXT
+ * if type==String and length <= 16777215 then sqltype is MEDIUMTEXT
+ * if type==String and length > 16777215 then sqltype is LONGTEXT
+ * if type==byte[] and length <= 65535 then sqltype is BLOB
+ * if type==byte[] and length <= 16777215 then sqltype is MEDIUMBLOB
+ * if type==byte[] and length > 16777215 then sqltype is LONGBLOB
+ * + * @return int + */ + int length() default 255; + + /** + * (Optional) The precision for a decimal (exact numeric) column. (Applies only if a decimal column is used.) Value + * must be set by developer if used when generating the DDL for the column. + * + * @return int + */ + int precision() default 0; + + /** + * (Optional) The scale for a decimal (exact numeric) column. (Applies only if a decimal column is used.) + * + * @return int + */ + int scale() default 0; +} diff --git a/src/main/java/javax/persistence/Entity.java b/src/main/java/javax/persistence/Entity.java index 7b17377f7..12fc3b6a4 100644 --- a/src/main/java/javax/persistence/Entity.java +++ b/src/main/java/javax/persistence/Entity.java @@ -1,49 +1,49 @@ -/** - * ***************************************************************************** Copyright (c) 2008 - 2013 Oracle - * Corporation. All rights reserved. - * - *

This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v. 1.0 which accompanies this distribution. The Eclipse Public License is available - * at http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - *

Contributors: Linda DeMichiel - Java Persistence 2.1 Linda DeMichiel - Java Persistence 2.0 - * - *

**************************************************************************** - */ -package javax.persistence; - -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.*; - -/** - * Specifies that the class is an entity. This annotation is applied to the entity class. - * - * @since Java Persistence 1.0 - * @deprecated replace by {@link org.redkale.persistence.Entity} - * @see org.redkale.persistence.Entity - */ -@Deprecated(since = "2.8.0") -@Inherited -@Documented -@Target(TYPE) -@Retention(RUNTIME) -public @interface Entity { - - /** - * (Optional) The entity name. Defaults to the unqualified name of the entity class. This name is used to refer to - * the entity in queries. The name must not be a reserved literal in the Java Persistence query language. - * - * @return String - */ - String name() default ""; - - /** - * (Optional) The comment of the entity. - * - * @return String - */ - String comment() default ""; -} +/** + * ***************************************************************************** Copyright (c) 2008 - 2013 Oracle + * Corporation. All rights reserved. + * + *

This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v. 1.0 which accompanies this distribution. The Eclipse Public License is available + * at http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + *

Contributors: Linda DeMichiel - Java Persistence 2.1 Linda DeMichiel - Java Persistence 2.0 + * + *

**************************************************************************** + */ +package javax.persistence; + +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.*; + +/** + * Specifies that the class is an entity. This annotation is applied to the entity class. + * + * @since Java Persistence 1.0 + * @deprecated replace by {@link org.redkale.persistence.Entity} + * @see org.redkale.persistence.Entity + */ +@Deprecated(since = "2.8.0") +@Inherited +@Documented +@Target(TYPE) +@Retention(RUNTIME) +public @interface Entity { + + /** + * (Optional) The entity name. Defaults to the unqualified name of the entity class. This name is used to refer to + * the entity in queries. The name must not be a reserved literal in the Java Persistence query language. + * + * @return String + */ + String name() default ""; + + /** + * (Optional) The comment of the entity. + * + * @return String + */ + String comment() default ""; +} diff --git a/src/main/java/javax/persistence/Id.java b/src/main/java/javax/persistence/Id.java index 862ddc8cc..c4712f6f7 100644 --- a/src/main/java/javax/persistence/Id.java +++ b/src/main/java/javax/persistence/Id.java @@ -1,46 +1,46 @@ -/** - * ***************************************************************************** Copyright (c) 2008 - 2013 Oracle - * Corporation. All rights reserved. - * - *

This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v. 1.0 which accompanies this distribution. The Eclipse Public License is available - * at http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - *

Contributors: Linda DeMichiel - Java Persistence 2.1 Linda DeMichiel - Java Persistence 2.0 - * - *

**************************************************************************** - */ -package javax.persistence; - -import static java.lang.annotation.ElementType.*; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.*; - -/** - * Specifies the primary key of an entity. The field or property to which the Id annotation is applied - * should be one of the following types: any Java primitive type; any primitive wrapper type; String; - * java.util.Date; java.sql.Date; java.math.BigDecimal; - * java.math.BigInteger. - * - *

The mapped column for the primary key of the entity is assumed to be the primary key of the primary table. If no - * Column annotation is specified, the primary key column name is assumed to be the name of the primary key - * property or field. - * - *

- *   Example:
- *
- *   @Id
- *   public Long getId() { return id; }
- * 
- * - * @see Column see GeneratedValue - * @since Java Persistence 1.0 - * @deprecated replace by {@link org.redkale.persistence.Id} - * @see org.redkale.persistence.Id - */ -@Deprecated(since = "2.8.0") -@Target({METHOD, FIELD}) -@Retention(RUNTIME) -public @interface Id {} +/** + * ***************************************************************************** Copyright (c) 2008 - 2013 Oracle + * Corporation. All rights reserved. + * + *

This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v. 1.0 which accompanies this distribution. The Eclipse Public License is available + * at http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + *

Contributors: Linda DeMichiel - Java Persistence 2.1 Linda DeMichiel - Java Persistence 2.0 + * + *

**************************************************************************** + */ +package javax.persistence; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.*; + +/** + * Specifies the primary key of an entity. The field or property to which the Id annotation is applied + * should be one of the following types: any Java primitive type; any primitive wrapper type; String; + * java.util.Date; java.sql.Date; java.math.BigDecimal; + * java.math.BigInteger. + * + *

The mapped column for the primary key of the entity is assumed to be the primary key of the primary table. If no + * Column annotation is specified, the primary key column name is assumed to be the name of the primary key + * property or field. + * + *

+ *   Example:
+ *
+ *   @Id
+ *   public Long getId() { return id; }
+ * 
+ * + * @see Column see GeneratedValue + * @since Java Persistence 1.0 + * @deprecated replace by {@link org.redkale.persistence.Id} + * @see org.redkale.persistence.Id + */ +@Deprecated(since = "2.8.0") +@Target({METHOD, FIELD}) +@Retention(RUNTIME) +public @interface Id {} diff --git a/src/main/java/javax/persistence/Index.java b/src/main/java/javax/persistence/Index.java index f0429ad33..70b659d6c 100644 --- a/src/main/java/javax/persistence/Index.java +++ b/src/main/java/javax/persistence/Index.java @@ -1,64 +1,64 @@ -/** - * ***************************************************************************** Copyright (c) 2011 - 2013 Oracle - * Corporation. All rights reserved. - * - *

This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v. 1.0 which accompanies this distribution. The Eclipse Public License is available - * at http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - *

Contributors: Linda DeMichiel - Java Persistence 2.1 - * - *

**************************************************************************** - */ -package javax.persistence; - -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.*; - -/** - * Used in schema generation to specify creation of an index. - * - *

Note that it is not necessary to specify an index for a primary key, as the primary key index will be created - * automatically. - * - *

The syntax of the columnList element is a column_list, as follows: - * - *

- *    column::= index_column [,index_column]*
- *    index_column::= column_name [ASC | DESC]
- * 
- * - *

If ASC or DESC is not specified, ASC (ascending order) is assumed. - * - * @since Java Persistence 2.1 - * @deprecated replace by {@link org.redkale.persistence.Index} - * @see org.redkale.persistence.Index - */ -@Deprecated(since = "2.8.0") -@Target({}) -@Retention(RUNTIME) -public @interface Index { - - /** - * (Optional) The name of the index; defaults to a provider-generated name. - * - * @return String - */ - String name() default ""; - - /** - * (Required) The names of the columns to be included in the index, in order. - * - * @return String - */ - String columnList(); - - /** - * (Optional) Whether the index is unique. - * - * @return boolean - */ - boolean unique() default false; -} +/** + * ***************************************************************************** Copyright (c) 2011 - 2013 Oracle + * Corporation. All rights reserved. + * + *

This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v. 1.0 which accompanies this distribution. The Eclipse Public License is available + * at http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + *

Contributors: Linda DeMichiel - Java Persistence 2.1 + * + *

**************************************************************************** + */ +package javax.persistence; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.*; + +/** + * Used in schema generation to specify creation of an index. + * + *

Note that it is not necessary to specify an index for a primary key, as the primary key index will be created + * automatically. + * + *

The syntax of the columnList element is a column_list, as follows: + * + *

+ *    column::= index_column [,index_column]*
+ *    index_column::= column_name [ASC | DESC]
+ * 
+ * + *

If ASC or DESC is not specified, ASC (ascending order) is assumed. + * + * @since Java Persistence 2.1 + * @deprecated replace by {@link org.redkale.persistence.Index} + * @see org.redkale.persistence.Index + */ +@Deprecated(since = "2.8.0") +@Target({}) +@Retention(RUNTIME) +public @interface Index { + + /** + * (Optional) The name of the index; defaults to a provider-generated name. + * + * @return String + */ + String name() default ""; + + /** + * (Required) The names of the columns to be included in the index, in order. + * + * @return String + */ + String columnList(); + + /** + * (Optional) Whether the index is unique. + * + * @return boolean + */ + boolean unique() default false; +} diff --git a/src/main/java/javax/persistence/Table.java b/src/main/java/javax/persistence/Table.java index 7f8a5cc13..cf66fd85e 100644 --- a/src/main/java/javax/persistence/Table.java +++ b/src/main/java/javax/persistence/Table.java @@ -1,88 +1,88 @@ -/** - * ***************************************************************************** Copyright (c) 2008 - 2013 Oracle - * Corporation. All rights reserved. - * - *

This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v. 1.0 which accompanies this distribution. The Eclipse Public License is available - * at http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - *

Contributors: Linda DeMichiel - Java Persistence 2.1 Linda DeMichiel - Java Persistence 2.0 - * - *

**************************************************************************** - */ -package javax.persistence; - -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.*; - -/** - * Specifies the primary table for the annotated entity. Additional tables may be specified using SecondaryTable or - * SecondaryTables annotation. - * - *

If no Table annotation is specified for an entity class, the default values apply. - * - *

- *    Example:
- *
- *    @Entity
- *    @Table(name="CUST", schema="RECORDS")
- *    public class Customer { ... }
- * 
- * - * @since Java Persistence 1.0 - * @deprecated replace by {@link org.redkale.persistence.Table} - * @see org.redkale.persistence.Table - */ -@Deprecated(since = "2.8.0") -@Target(TYPE) -@Retention(RUNTIME) -public @interface Table { - - /** - * (Optional) The name of the table. - * - *

Defaults to the entity name. - * - * @return String - */ - String name() default ""; - - /** - * (Optional) The catalog of the table. - * - *

Defaults to the default catalog. - * - * @return String - */ - String catalog() default ""; - - /** - * (Optional) Unique constraints that are to be placed on the table. These are only used if table generation is in - * effect. These constraints apply in addition to any constraints specified by the Column and - * JoinColumn annotations and constraints entailed by primary key mappings. - * - *

Defaults to no additional constraints. - * - * @return UniqueConstraint[] - */ - UniqueConstraint[] uniqueConstraints() default {}; - - /** - * (Optional) Indexes for the table. These are only used if table generation is in effect. Note that it is not - * necessary to specify an index for a primary key, as the primary key index will be created automatically. - * - * @return indexes - * @since Java Persistence 2.1 - */ - Index[] indexes() default {}; - - /** - * comment - * - * @return String - */ - String comment() default ""; -} +/** + * ***************************************************************************** Copyright (c) 2008 - 2013 Oracle + * Corporation. All rights reserved. + * + *

This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v. 1.0 which accompanies this distribution. The Eclipse Public License is available + * at http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + *

Contributors: Linda DeMichiel - Java Persistence 2.1 Linda DeMichiel - Java Persistence 2.0 + * + *

**************************************************************************** + */ +package javax.persistence; + +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.*; + +/** + * Specifies the primary table for the annotated entity. Additional tables may be specified using SecondaryTable or + * SecondaryTables annotation. + * + *

If no Table annotation is specified for an entity class, the default values apply. + * + *

+ *    Example:
+ *
+ *    @Entity
+ *    @Table(name="CUST", schema="RECORDS")
+ *    public class Customer { ... }
+ * 
+ * + * @since Java Persistence 1.0 + * @deprecated replace by {@link org.redkale.persistence.Table} + * @see org.redkale.persistence.Table + */ +@Deprecated(since = "2.8.0") +@Target(TYPE) +@Retention(RUNTIME) +public @interface Table { + + /** + * (Optional) The name of the table. + * + *

Defaults to the entity name. + * + * @return String + */ + String name() default ""; + + /** + * (Optional) The catalog of the table. + * + *

Defaults to the default catalog. + * + * @return String + */ + String catalog() default ""; + + /** + * (Optional) Unique constraints that are to be placed on the table. These are only used if table generation is in + * effect. These constraints apply in addition to any constraints specified by the Column and + * JoinColumn annotations and constraints entailed by primary key mappings. + * + *

Defaults to no additional constraints. + * + * @return UniqueConstraint[] + */ + UniqueConstraint[] uniqueConstraints() default {}; + + /** + * (Optional) Indexes for the table. These are only used if table generation is in effect. Note that it is not + * necessary to specify an index for a primary key, as the primary key index will be created automatically. + * + * @return indexes + * @since Java Persistence 2.1 + */ + Index[] indexes() default {}; + + /** + * comment + * + * @return String + */ + String comment() default ""; +} diff --git a/src/main/java/javax/persistence/Transient.java b/src/main/java/javax/persistence/Transient.java index 0ca77614a..171894982 100644 --- a/src/main/java/javax/persistence/Transient.java +++ b/src/main/java/javax/persistence/Transient.java @@ -1,43 +1,43 @@ -/** - * ***************************************************************************** Copyright (c) 2008 - 2013 Oracle - * Corporation. All rights reserved. - * - *

This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v. 1.0 which accompanies this distribution. The Eclipse Public License is available - * at http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - *

Contributors: Linda DeMichiel - Java Persistence 2.1 Linda DeMichiel - Java Persistence 2.0 - * - *

**************************************************************************** - */ -package javax.persistence; - -import static java.lang.annotation.ElementType.*; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.*; - -/** - * Specifies that the property or field is not persistent. It is used to annotate a property or field of an entity - * class, mapped superclass, or embeddable class. - * - *

- *    Example:
- *
- *    @Entity
- *    public class Employee {
- *        @Id int id;
- *        @Transient User currentUser;
- *        ...
- *    }
- * 
- * - * @since Java Persistence 1.0 - * @deprecated replace by {@link org.redkale.persistence.Transient} - * @see org.redkale.persistence.Transient - */ -@Deprecated(since = "2.8.0") -@Target({METHOD, FIELD}) -@Retention(RUNTIME) -public @interface Transient {} +/** + * ***************************************************************************** Copyright (c) 2008 - 2013 Oracle + * Corporation. All rights reserved. + * + *

This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v. 1.0 which accompanies this distribution. The Eclipse Public License is available + * at http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + *

Contributors: Linda DeMichiel - Java Persistence 2.1 Linda DeMichiel - Java Persistence 2.0 + * + *

**************************************************************************** + */ +package javax.persistence; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.*; + +/** + * Specifies that the property or field is not persistent. It is used to annotate a property or field of an entity + * class, mapped superclass, or embeddable class. + * + *

+ *    Example:
+ *
+ *    @Entity
+ *    public class Employee {
+ *        @Id int id;
+ *        @Transient User currentUser;
+ *        ...
+ *    }
+ * 
+ * + * @since Java Persistence 1.0 + * @deprecated replace by {@link org.redkale.persistence.Transient} + * @see org.redkale.persistence.Transient + */ +@Deprecated(since = "2.8.0") +@Target({METHOD, FIELD}) +@Retention(RUNTIME) +public @interface Transient {} diff --git a/src/main/java/javax/persistence/UniqueConstraint.java b/src/main/java/javax/persistence/UniqueConstraint.java index b01e8b1df..4c210bb4a 100644 --- a/src/main/java/javax/persistence/UniqueConstraint.java +++ b/src/main/java/javax/persistence/UniqueConstraint.java @@ -1,57 +1,57 @@ -/** - * ***************************************************************************** Copyright (c) 2008 - 2013 Oracle - * Corporation. All rights reserved. - * - *

This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v. 1.0 which accompanies this distribution. The Eclipse Public License is available - * at http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - *

Contributors: Linda DeMichiel - Java Persistence 2.1 Linda DeMichiel - Java Persistence 2.0 - * - *

**************************************************************************** - */ -package javax.persistence; - -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.*; - -/** - * Specifies that a unique constraint is to be included in the generated DDL for a primary or secondary table. - * - *

- *    Example:
- *    @Entity
- *    @Table(
- *        name="EMPLOYEE",
- *        uniqueConstraints=
- *            @UniqueConstraint(columnNames={"EMP_ID", "EMP_NAME"})
- *    )
- *    public class Employee { ... }
- * 
- * - * @since Java Persistence 1.0 - * @deprecated replace by {@link org.redkale.persistence.UniqueConstraint} - * @see org.redkale.persistence.UniqueConstraint - */ -@Deprecated(since = "2.8.0") -@Target({}) -@Retention(RUNTIME) -public @interface UniqueConstraint { - - /** - * (Optional) Constraint name. A provider-chosen name will be chosen if a name is not specified. - * - * @return String - * @since Java Persistence 2.0 - */ - String name() default ""; - - /** - * (Required) An array of the column names that make up the constraint. - * - * @return String[] - */ - String[] columnNames(); -} +/** + * ***************************************************************************** Copyright (c) 2008 - 2013 Oracle + * Corporation. All rights reserved. + * + *

This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v. 1.0 which accompanies this distribution. The Eclipse Public License is available + * at http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + *

Contributors: Linda DeMichiel - Java Persistence 2.1 Linda DeMichiel - Java Persistence 2.0 + * + *

**************************************************************************** + */ +package javax.persistence; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.*; + +/** + * Specifies that a unique constraint is to be included in the generated DDL for a primary or secondary table. + * + *

+ *    Example:
+ *    @Entity
+ *    @Table(
+ *        name="EMPLOYEE",
+ *        uniqueConstraints=
+ *            @UniqueConstraint(columnNames={"EMP_ID", "EMP_NAME"})
+ *    )
+ *    public class Employee { ... }
+ * 
+ * + * @since Java Persistence 1.0 + * @deprecated replace by {@link org.redkale.persistence.UniqueConstraint} + * @see org.redkale.persistence.UniqueConstraint + */ +@Deprecated(since = "2.8.0") +@Target({}) +@Retention(RUNTIME) +public @interface UniqueConstraint { + + /** + * (Optional) Constraint name. A provider-chosen name will be chosen if a name is not specified. + * + * @return String + * @since Java Persistence 2.0 + */ + String name() default ""; + + /** + * (Required) An array of the column names that make up the constraint. + * + * @return String[] + */ + String[] columnNames(); +} diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 230b47278..74ec1a88b 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -1,54 +1,54 @@ -/** - * see: https://redkale.org - * - * @author zhangjx - */ -module org.redkale { - requires java.base; - requires java.logging; - requires java.net.http; - requires java.sql; - requires jdk.unsupported; // sun.misc.Unsafe - - exports org.redkale.annotation; - exports org.redkale.boot; - exports org.redkale.boot.watch; - exports org.redkale.cache; - exports org.redkale.cache.spi; - exports org.redkale.cluster; - exports org.redkale.cluster.spi; - exports org.redkale.convert; - exports org.redkale.convert.bson; - exports org.redkale.convert.ext; - exports org.redkale.convert.json; - exports org.redkale.convert.proto; - exports org.redkale.convert.spi; - exports org.redkale.inject; - exports org.redkale.lock; - exports org.redkale.lock.spi; - exports org.redkale.mq; - exports org.redkale.mq.spi; - exports org.redkale.net; - exports org.redkale.net.client; - exports org.redkale.net.http; - exports org.redkale.net.sncp; - exports org.redkale.persistence; - exports org.redkale.props.spi; - exports org.redkale.schedule; - exports org.redkale.schedule.spi; - exports org.redkale.service; - exports org.redkale.source; - exports org.redkale.source.spi; - exports org.redkale.util; - exports org.redkale.watch; - - uses org.redkale.props.spi.PropertiesAgentProvider; - uses org.redkale.cache.spi.CacheManagerProvider; - uses org.redkale.cluster.spi.ClusterAgentProvider; - uses org.redkale.convert.spi.ConvertProvider; - uses org.redkale.mq.spi.MessageAgentProvider; - uses org.redkale.schedule.spi.ScheduleManagerProvider; - uses org.redkale.source.spi.CacheSourceProvider; - uses org.redkale.source.spi.DataSourceProvider; - uses org.redkale.source.spi.DataNativeSqlParserProvider; -} +/** + * see: https://redkale.org + * + * @author zhangjx + */ +module org.redkale { + requires java.base; + requires java.logging; + requires java.net.http; + requires java.sql; + requires jdk.unsupported; // sun.misc.Unsafe + + exports org.redkale.annotation; + exports org.redkale.boot; + exports org.redkale.boot.watch; + exports org.redkale.cache; + exports org.redkale.cache.spi; + exports org.redkale.cluster; + exports org.redkale.cluster.spi; + exports org.redkale.convert; + exports org.redkale.convert.bson; + exports org.redkale.convert.ext; + exports org.redkale.convert.json; + exports org.redkale.convert.proto; + exports org.redkale.convert.spi; + exports org.redkale.inject; + exports org.redkale.lock; + exports org.redkale.lock.spi; + exports org.redkale.mq; + exports org.redkale.mq.spi; + exports org.redkale.net; + exports org.redkale.net.client; + exports org.redkale.net.http; + exports org.redkale.net.sncp; + exports org.redkale.persistence; + exports org.redkale.props.spi; + exports org.redkale.schedule; + exports org.redkale.schedule.spi; + exports org.redkale.service; + exports org.redkale.source; + exports org.redkale.source.spi; + exports org.redkale.util; + exports org.redkale.watch; + + uses org.redkale.props.spi.PropertiesAgentProvider; + uses org.redkale.cache.spi.CacheManagerProvider; + uses org.redkale.cluster.spi.ClusterAgentProvider; + uses org.redkale.convert.spi.ConvertProvider; + uses org.redkale.mq.spi.MessageAgentProvider; + uses org.redkale.schedule.spi.ScheduleManagerProvider; + uses org.redkale.source.spi.CacheSourceProvider; + uses org.redkale.source.spi.DataSourceProvider; + uses org.redkale.source.spi.DataNativeSqlParserProvider; +} diff --git a/src/main/java/org/redkale/annotation/ClassDepends.java b/src/main/java/org/redkale/annotation/ClassDepends.java index 0ef4a58c7..e34828021 100644 --- a/src/main/java/org/redkale/annotation/ClassDepends.java +++ b/src/main/java/org/redkale/annotation/ClassDepends.java @@ -1,25 +1,25 @@ -/* - * - */ -package org.redkale.annotation; - -import static java.lang.annotation.ElementType.*; -import static java.lang.annotation.RetentionPolicy.*; - -import java.lang.annotation.*; - -/** - * 被标记的元素表示会被动态字节码调用 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -@Documented -@Target({TYPE, METHOD, FIELD}) -@Retention(SOURCE) -public @interface ClassDepends { - - Class[] value() default {}; -} +/* + * + */ +package org.redkale.annotation; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +import java.lang.annotation.*; + +/** + * 被标记的元素表示会被动态字节码调用 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +@Documented +@Target({TYPE, METHOD, FIELD}) +@Retention(SOURCE) +public @interface ClassDepends { + + Class[] value() default {}; +} diff --git a/src/main/java/org/redkale/annotation/Component.java b/src/main/java/org/redkale/annotation/Component.java index 4cdc230a2..a698b392d 100644 --- a/src/main/java/org/redkale/annotation/Component.java +++ b/src/main/java/org/redkale/annotation/Component.java @@ -1,22 +1,22 @@ -package org.redkale.annotation; - -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.*; - -/** - * 标记Component的Service类特点:
- * 1、直接构造, 不使用Sncp动态构建对象
- * 2、不会生成对应协议的Servlet
- * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -@Inherited -@Documented -@Target({TYPE}) -@Retention(RUNTIME) -public @interface Component {} +package org.redkale.annotation; + +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.*; + +/** + * 标记Component的Service类特点:
+ * 1、直接构造, 不使用Sncp动态构建对象
+ * 2、不会生成对应协议的Servlet
+ * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +@Inherited +@Documented +@Target({TYPE}) +@Retention(RUNTIME) +public @interface Component {} diff --git a/src/main/java/org/redkale/annotation/NonBlocking.java b/src/main/java/org/redkale/annotation/NonBlocking.java index ade4b3b16..530847bbc 100644 --- a/src/main/java/org/redkale/annotation/NonBlocking.java +++ b/src/main/java/org/redkale/annotation/NonBlocking.java @@ -1,25 +1,25 @@ -/* - * - */ -package org.redkale.annotation; - -import java.lang.annotation.*; - -/** - * 非阻塞模式标记, 标记在Service类和方法、Filter类、HttpServlet类上
- * 一般情况下,没有显注此注解的方法视为阻塞时, 以下两种情况除外:
- * 1、返回类型是CompletionStage
- * 2、返回类型是void且参数存在CompletionHandler类型
- * 阻塞模式的方法会在work线程池中运行, 非阻塞在IO线程中运行。 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -@Target({ElementType.TYPE, ElementType.METHOD}) -@Retention(RetentionPolicy.RUNTIME) -public @interface NonBlocking { // 不可使用@Inherited,防止被继承, 见HttpServlet.preExecute/authenticate/execute - - boolean value() default true; -} +/* + * + */ +package org.redkale.annotation; + +import java.lang.annotation.*; + +/** + * 非阻塞模式标记, 标记在Service类和方法、Filter类、HttpServlet类上
+ * 一般情况下,没有显注此注解的方法视为阻塞时, 以下两种情况除外:
+ * 1、返回类型是CompletionStage
+ * 2、返回类型是void且参数存在CompletionHandler类型
+ * 阻塞模式的方法会在work线程池中运行, 非阻塞在IO线程中运行。 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface NonBlocking { // 不可使用@Inherited,防止被继承, 见HttpServlet.preExecute/authenticate/execute + + boolean value() default true; +} diff --git a/src/main/java/org/redkale/annotation/Nonnull.java b/src/main/java/org/redkale/annotation/Nonnull.java index 467954d07..dca9bf6cd 100644 --- a/src/main/java/org/redkale/annotation/Nonnull.java +++ b/src/main/java/org/redkale/annotation/Nonnull.java @@ -1,18 +1,18 @@ -/* - * - */ -package org.redkale.annotation; - -import java.lang.annotation.*; - -/** - * 标记值可以为null - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -@Documented -@Retention(RetentionPolicy.RUNTIME) -public @interface Nonnull {} +/* + * + */ +package org.redkale.annotation; + +import java.lang.annotation.*; + +/** + * 标记值可以为null + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +public @interface Nonnull {} diff --git a/src/main/java/org/redkale/annotation/Nullable.java b/src/main/java/org/redkale/annotation/Nullable.java index c7722e9d9..4bae5f1f0 100644 --- a/src/main/java/org/redkale/annotation/Nullable.java +++ b/src/main/java/org/redkale/annotation/Nullable.java @@ -1,18 +1,18 @@ -/* - * - */ -package org.redkale.annotation; - -import java.lang.annotation.*; - -/** - * 标记值可以为null - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -@Documented -@Retention(RetentionPolicy.RUNTIME) -public @interface Nullable {} +/* + * + */ +package org.redkale.annotation; + +import java.lang.annotation.*; + +/** + * 标记值可以为null + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +public @interface Nullable {} diff --git a/src/main/java/org/redkale/annotation/Param.java b/src/main/java/org/redkale/annotation/Param.java index 4630d2773..b0001f21a 100644 --- a/src/main/java/org/redkale/annotation/Param.java +++ b/src/main/java/org/redkale/annotation/Param.java @@ -1,29 +1,29 @@ -/* - * - */ -package org.redkale.annotation; - -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * 参数名注解,编译时加上 -parameters 参数可以不用此注解 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -@Documented -@Target({PARAMETER}) -@Retention(RUNTIME) -public @interface Param { - - String value(); - - String comment() default ""; -} +/* + * + */ +package org.redkale.annotation; + +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +/** + * 参数名注解,编译时加上 -parameters 参数可以不用此注解 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +@Documented +@Target({PARAMETER}) +@Retention(RUNTIME) +public @interface Param { + + String value(); + + String comment() default ""; +} diff --git a/src/main/java/org/redkale/annotation/PostConstruct.java b/src/main/java/org/redkale/annotation/PostConstruct.java index 2cbbe75ad..72a8813ad 100644 --- a/src/main/java/org/redkale/annotation/PostConstruct.java +++ b/src/main/java/org/redkale/annotation/PostConstruct.java @@ -1,20 +1,20 @@ -/* - * - */ -package org.redkale.annotation; - -import static java.lang.annotation.ElementType.*; -import static java.lang.annotation.RetentionPolicy.*; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * @since Common Annotations 1.0 - * @since 2.8.0 - */ -@Documented -@Retention(RUNTIME) -@Target(METHOD) -public @interface PostConstruct {} +/* + * + */ +package org.redkale.annotation; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +/** + * @since Common Annotations 1.0 + * @since 2.8.0 + */ +@Documented +@Retention(RUNTIME) +@Target(METHOD) +public @interface PostConstruct {} diff --git a/src/main/java/org/redkale/annotation/PreDestroy.java b/src/main/java/org/redkale/annotation/PreDestroy.java index 8e490eb68..aeeb6d532 100644 --- a/src/main/java/org/redkale/annotation/PreDestroy.java +++ b/src/main/java/org/redkale/annotation/PreDestroy.java @@ -1,18 +1,18 @@ -/* - * - */ -package org.redkale.annotation; - -import static java.lang.annotation.ElementType.*; -import static java.lang.annotation.RetentionPolicy.*; - -import java.lang.annotation.*; - -/** - * @since Common Annotations 1.0 - * @since 2.8.0 - */ -@Documented -@Retention(RUNTIME) -@Target(METHOD) -public @interface PreDestroy {} +/* + * + */ +package org.redkale.annotation; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +import java.lang.annotation.*; + +/** + * @since Common Annotations 1.0 + * @since 2.8.0 + */ +@Documented +@Retention(RUNTIME) +@Target(METHOD) +public @interface PreDestroy {} diff --git a/src/main/java/org/redkale/annotation/ResourceInjected.java b/src/main/java/org/redkale/annotation/ResourceInjected.java index 9c865ad8c..1131b80ef 100644 --- a/src/main/java/org/redkale/annotation/ResourceInjected.java +++ b/src/main/java/org/redkale/annotation/ResourceInjected.java @@ -1,65 +1,65 @@ -/* - * 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.annotation; - -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.*; - -/** - * @Resource资源被依赖注入时的监听事件。
- * 本注解只能标记在空参数或者(String、Object、java.lang.reflect.Field)三个参数类型的任意组合方法上
- * 方法在资源被依赖注入后调用。 - * - *

- * - *
- * public class ResourceService implements Service {
- *
- *    @Resource(name = "res.id")
- *    private int id;
- *
- *    @Resource(name = "res.name")
- *    private String name;
- *
- *    @ResourceInjected
- *    private void onInjected(Object src, String fieldName) {
- *       System.out .println("资源被注入到对象(" + src + ")的字段(" + fieldName + ")上");
- *  }
- * }
- *
- * public class RecordService implements Service {
- *
- *    @Resource
- *    private ResourceService resService;
- *
- *    public void test() {
- *  }
- *
- *  public static void main(String[] args) throws Exception {
- *      ResourceFactory factory = ResourceFactory.create();
- *      factory.register("res.id", "2345");
- *      factory.register("res.name", "my old name");
- *      ResourceService res = new ResourceService();
- *      factory.inject(res);
- *      factory.register("", res);
- *      RecordService serice = new RecordService();
- *      factory.inject(record);
- *  }
- * }
- * 
- * - *
- * - *

详情见: https://redkale.org - * - * @author zhangjx - */ -@Documented -@Target({METHOD}) -@Retention(RUNTIME) -public @interface ResourceInjected {} +/* + * 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.annotation; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.*; + +/** + * @Resource资源被依赖注入时的监听事件。
+ * 本注解只能标记在空参数或者(String、Object、java.lang.reflect.Field)三个参数类型的任意组合方法上
+ * 方法在资源被依赖注入后调用。 + * + *

+ * + *
+ * public class ResourceService implements Service {
+ *
+ *    @Resource(name = "res.id")
+ *    private int id;
+ *
+ *    @Resource(name = "res.name")
+ *    private String name;
+ *
+ *    @ResourceInjected
+ *    private void onInjected(Object src, String fieldName) {
+ *       System.out .println("资源被注入到对象(" + src + ")的字段(" + fieldName + ")上");
+ *  }
+ * }
+ *
+ * public class RecordService implements Service {
+ *
+ *    @Resource
+ *    private ResourceService resService;
+ *
+ *    public void test() {
+ *  }
+ *
+ *  public static void main(String[] args) throws Exception {
+ *      ResourceFactory factory = ResourceFactory.create();
+ *      factory.register("res.id", "2345");
+ *      factory.register("res.name", "my old name");
+ *      ResourceService res = new ResourceService();
+ *      factory.inject(res);
+ *      factory.register("", res);
+ *      RecordService serice = new RecordService();
+ *      factory.inject(record);
+ *  }
+ * }
+ * 
+ * + *
+ * + *

详情见: https://redkale.org + * + * @author zhangjx + */ +@Documented +@Target({METHOD}) +@Retention(RUNTIME) +public @interface ResourceInjected {} diff --git a/src/main/java/org/redkale/asm/AnnotationVisitor.java b/src/main/java/org/redkale/asm/AnnotationVisitor.java index 9ace2e08f..2d944c6fa 100644 --- a/src/main/java/org/redkale/asm/AnnotationVisitor.java +++ b/src/main/java/org/redkale/asm/AnnotationVisitor.java @@ -1,170 +1,170 @@ -/* - * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */ - -/* - * - * - * - * - * - * ASM: a very small and fast Java bytecode manipulation framework - * Copyright (c) 2000-2011 INRIA, France Telecom - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.redkale.asm; - -/** - * A visitor to visit a Java annotation. The methods of this class must be called in the following order: ( - * <tt>visit</tt> | <tt>visitEnum</tt> | <tt>visitAnnotation</tt> | - * <tt>visitArray</tt> )* <tt>visitEnd</tt>. - * - * @author Eric Bruneton - * @author Eugene Kuleshov - */ -public abstract class AnnotationVisitor { - - /** - * The ASM API version implemented by this visitor. The value of this field must be one of {@link Opcodes#ASM4}, - * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. - */ - protected final int api; - - /** The annotation visitor to which this visitor must delegate method calls. May be null. */ - protected AnnotationVisitor av; - - /** - * Constructs a new {@link AnnotationVisitor}. - * - * @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4}, - * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. - */ - public AnnotationVisitor(final int api) { - this(api, null); - } - - /** - * Constructs a new {@link AnnotationVisitor}. - * - * @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4}, - * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. - * @param av the annotation visitor to which this visitor must delegate method calls. May be null. - */ - public AnnotationVisitor(final int api, final AnnotationVisitor av) { - this.api = api; - this.av = av; - } - - /** - * Visits a primitive value of the annotation. - * - * @param name the value name. - * @param value the actual value, whose type must be {@link Byte}, {@link Boolean}, {@link Character}, - * {@link Short}, {@link Integer} , {@link Long}, {@link Float}, {@link Double}, {@link String} or {@link Type} - * of OBJECT or ARRAY sort. This value can also be an array of byte, boolean, short, char, int, long, float or - * double values (this is equivalent to using {@link #visitArray visitArray} and visiting each array element in - * turn, but is more convenient). - */ - public void visit(String name, Object value) { - if (av != null) { - av.visit(name, value); - } - } - - /** - * Visits an enumeration value of the annotation. - * - * @param name the value name. - * @param desc the class descriptor of the enumeration class. - * @param value the actual enumeration value. - */ - public void visitEnum(String name, String desc, String value) { - if (av != null) { - av.visitEnum(name, desc, value); - } - } - - /** - * Visits a nested annotation value of the annotation. - * - * @param name the value name. - * @param desc the class descriptor of the nested annotation class. - * @return a visitor to visit the actual nested annotation value, or <tt>null</tt> if this visitor - * is not interested in visiting this nested annotation. The nested annotation value must be fully visited - * before calling other methods on this annotation visitor. - */ - public AnnotationVisitor visitAnnotation(String name, String desc) { - if (av != null) { - return av.visitAnnotation(name, desc); - } - return null; - } - - /** - * Visits an array value of the annotation. Note that arrays of primitive types (such as byte, boolean, short, char, - * int, long, float or double) can be passed as value to {@link #visit visit}. This is what {@link ClassReader} - * does. - * - * @param name the value name. - * @return a visitor to visit the actual array value elements, or <tt>null</tt> if this visitor is - * not interested in visiting these values. The 'name' parameters passed to the methods of this visitor are - * ignored. All the array values must be visited before calling other methods on this annotation visitor. - */ - public AnnotationVisitor visitArray(String name) { - if (av != null) { - return av.visitArray(name); - } - return null; - } - - /** Visits the end of the annotation. */ - public void visitEnd() { - if (av != null) { - av.visitEnd(); - } - } -} +/* + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ + +/* + * + * + * + * + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.redkale.asm; + +/** + * A visitor to visit a Java annotation. The methods of this class must be called in the following order: ( + * <tt>visit</tt> | <tt>visitEnum</tt> | <tt>visitAnnotation</tt> | + * <tt>visitArray</tt> )* <tt>visitEnd</tt>. + * + * @author Eric Bruneton + * @author Eugene Kuleshov + */ +public abstract class AnnotationVisitor { + + /** + * The ASM API version implemented by this visitor. The value of this field must be one of {@link Opcodes#ASM4}, + * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. + */ + protected final int api; + + /** The annotation visitor to which this visitor must delegate method calls. May be null. */ + protected AnnotationVisitor av; + + /** + * Constructs a new {@link AnnotationVisitor}. + * + * @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4}, + * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. + */ + public AnnotationVisitor(final int api) { + this(api, null); + } + + /** + * Constructs a new {@link AnnotationVisitor}. + * + * @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4}, + * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. + * @param av the annotation visitor to which this visitor must delegate method calls. May be null. + */ + public AnnotationVisitor(final int api, final AnnotationVisitor av) { + this.api = api; + this.av = av; + } + + /** + * Visits a primitive value of the annotation. + * + * @param name the value name. + * @param value the actual value, whose type must be {@link Byte}, {@link Boolean}, {@link Character}, + * {@link Short}, {@link Integer} , {@link Long}, {@link Float}, {@link Double}, {@link String} or {@link Type} + * of OBJECT or ARRAY sort. This value can also be an array of byte, boolean, short, char, int, long, float or + * double values (this is equivalent to using {@link #visitArray visitArray} and visiting each array element in + * turn, but is more convenient). + */ + public void visit(String name, Object value) { + if (av != null) { + av.visit(name, value); + } + } + + /** + * Visits an enumeration value of the annotation. + * + * @param name the value name. + * @param desc the class descriptor of the enumeration class. + * @param value the actual enumeration value. + */ + public void visitEnum(String name, String desc, String value) { + if (av != null) { + av.visitEnum(name, desc, value); + } + } + + /** + * Visits a nested annotation value of the annotation. + * + * @param name the value name. + * @param desc the class descriptor of the nested annotation class. + * @return a visitor to visit the actual nested annotation value, or <tt>null</tt> if this visitor + * is not interested in visiting this nested annotation. The nested annotation value must be fully visited + * before calling other methods on this annotation visitor. + */ + public AnnotationVisitor visitAnnotation(String name, String desc) { + if (av != null) { + return av.visitAnnotation(name, desc); + } + return null; + } + + /** + * Visits an array value of the annotation. Note that arrays of primitive types (such as byte, boolean, short, char, + * int, long, float or double) can be passed as value to {@link #visit visit}. This is what {@link ClassReader} + * does. + * + * @param name the value name. + * @return a visitor to visit the actual array value elements, or <tt>null</tt> if this visitor is + * not interested in visiting these values. The 'name' parameters passed to the methods of this visitor are + * ignored. All the array values must be visited before calling other methods on this annotation visitor. + */ + public AnnotationVisitor visitArray(String name) { + if (av != null) { + return av.visitArray(name); + } + return null; + } + + /** Visits the end of the annotation. */ + public void visitEnd() { + if (av != null) { + av.visitEnd(); + } + } +} diff --git a/src/main/java/org/redkale/asm/AnnotationWriter.java b/src/main/java/org/redkale/asm/AnnotationWriter.java index b0fb93fec..165ecf86b 100644 --- a/src/main/java/org/redkale/asm/AnnotationWriter.java +++ b/src/main/java/org/redkale/asm/AnnotationWriter.java @@ -1,366 +1,366 @@ -/* - * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */ - -/* - * - * - * - * - * - * ASM: a very small and fast Java bytecode manipulation framework - * Copyright (c) 2000-2011 INRIA, France Telecom - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.redkale.asm; - -/** - * An {@link AnnotationVisitor} that generates annotations in bytecode form. - * - * @author Eric Bruneton - * @author Eugene Kuleshov - */ -final class AnnotationWriter extends AnnotationVisitor { - - /** The class writer to which this annotation must be added. */ - private final ClassWriter cw; - - /** The number of values in this annotation. */ - private int size; - - /** - * <tt>true<tt> if values are named, <tt>false</tt> otherwise. Annotation writers - * used for annotation default and annotation arrays use unnamed values. - */ - private final boolean named; - - /** - * The annotation values in bytecode form. This byte vector only contains the values themselves, i.e. the number of - * values must be stored as a unsigned short just before these bytes. - */ - private final ByteVector bv; - - /** The byte vector to be used to store the number of values of this annotation. See {@link #bv}. */ - private final ByteVector parent; - - /** Where the number of values of this annotation must be stored in {@link #parent}. */ - private final int offset; - - /** Next annotation writer. This field is used to store annotation lists. */ - AnnotationWriter next; - - /** Previous annotation writer. This field is used to store annotation lists. */ - AnnotationWriter prev; - - // ------------------------------------------------------------------------ - // Constructor - // ------------------------------------------------------------------------ - - /** - * Constructs a new {@link AnnotationWriter}. - * - * @param cw the class writer to which this annotation must be added. - * @param named <tt>true<tt> if values are named, <tt>false</tt> otherwise. - * @param bv where the annotation values must be stored. - * @param parent where the number of annotation values must be stored. - * @param offset where in <tt>parent</tt> the number of annotation values must be stored. - */ - AnnotationWriter( - final ClassWriter cw, final boolean named, final ByteVector bv, final ByteVector parent, final int offset) { - super(Opcodes.ASM6); - this.cw = cw; - this.named = named; - this.bv = bv; - this.parent = parent; - this.offset = offset; - } - - // ------------------------------------------------------------------------ - // Implementation of the AnnotationVisitor abstract class - // ------------------------------------------------------------------------ - - @Override - public void visit(final String name, final Object value) { - ++size; - if (named) { - bv.putShort(cw.newUTF8(name)); - } - if (value instanceof String) { - bv.put12('s', cw.newUTF8((String) value)); - } else if (value instanceof Byte) { - bv.put12('B', cw.newInteger(((Byte) value).byteValue()).index); - } else if (value instanceof Boolean) { - int v = ((Boolean) value).booleanValue() ? 1 : 0; - bv.put12('Z', cw.newInteger(v).index); - } else if (value instanceof Character) { - bv.put12('C', cw.newInteger(((Character) value).charValue()).index); - } else if (value instanceof Short) { - bv.put12('S', cw.newInteger(((Short) value).shortValue()).index); - } else if (value instanceof Type) { - bv.put12('c', cw.newUTF8(((Type) value).getDescriptor())); - } else if (value instanceof byte[]) { - byte[] v = (byte[]) value; - bv.put12('[', v.length); - for (int i = 0; i < v.length; i++) { - bv.put12('B', cw.newInteger(v[i]).index); - } - } else if (value instanceof boolean[]) { - boolean[] v = (boolean[]) value; - bv.put12('[', v.length); - for (int i = 0; i < v.length; i++) { - bv.put12('Z', cw.newInteger(v[i] ? 1 : 0).index); - } - } else if (value instanceof short[]) { - short[] v = (short[]) value; - bv.put12('[', v.length); - for (int i = 0; i < v.length; i++) { - bv.put12('S', cw.newInteger(v[i]).index); - } - } else if (value instanceof char[]) { - char[] v = (char[]) value; - bv.put12('[', v.length); - for (int i = 0; i < v.length; i++) { - bv.put12('C', cw.newInteger(v[i]).index); - } - } else if (value instanceof int[]) { - int[] v = (int[]) value; - bv.put12('[', v.length); - for (int i = 0; i < v.length; i++) { - bv.put12('I', cw.newInteger(v[i]).index); - } - } else if (value instanceof long[]) { - long[] v = (long[]) value; - bv.put12('[', v.length); - for (int i = 0; i < v.length; i++) { - bv.put12('J', cw.newLong(v[i]).index); - } - } else if (value instanceof float[]) { - float[] v = (float[]) value; - bv.put12('[', v.length); - for (int i = 0; i < v.length; i++) { - bv.put12('F', cw.newFloat(v[i]).index); - } - } else if (value instanceof double[]) { - double[] v = (double[]) value; - bv.put12('[', v.length); - for (int i = 0; i < v.length; i++) { - bv.put12('D', cw.newDouble(v[i]).index); - } - } else { - Item i = cw.newConstItem(value); - bv.put12(".s.IFJDCS".charAt(i.type), i.index); - } - } - - @Override - public void visitEnum(final String name, final String desc, final String value) { - ++size; - if (named) { - bv.putShort(cw.newUTF8(name)); - } - bv.put12('e', cw.newUTF8(desc)).putShort(cw.newUTF8(value)); - } - - @Override - public AnnotationVisitor visitAnnotation(final String name, final String desc) { - ++size; - if (named) { - bv.putShort(cw.newUTF8(name)); - } - // write tag and type, and reserve space for values count - bv.put12('@', cw.newUTF8(desc)).putShort(0); - return new AnnotationWriter(cw, true, bv, bv, bv.length - 2); - } - - @Override - public AnnotationVisitor visitArray(final String name) { - ++size; - if (named) { - bv.putShort(cw.newUTF8(name)); - } - // write tag, and reserve space for array size - bv.put12('[', 0); - return new AnnotationWriter(cw, false, bv, bv, bv.length - 2); - } - - @Override - public void visitEnd() { - if (parent != null) { - byte[] data = parent.data; - data[offset] = (byte) (size >>> 8); - data[offset + 1] = (byte) size; - } - } - - // ------------------------------------------------------------------------ - // Utility methods - // ------------------------------------------------------------------------ - - /** - * Returns the size of this annotation writer list. - * - * @return the size of this annotation writer list. - */ - int getSize() { - int size = 0; - AnnotationWriter aw = this; - while (aw != null) { - size += aw.bv.length; - aw = aw.next; - } - return size; - } - - /** - * Puts the annotations of this annotation writer list into the given byte vector. - * - * @param out where the annotations must be put. - */ - void put(final ByteVector out) { - int n = 0; - int size = 2; - AnnotationWriter aw = this; - AnnotationWriter last = null; - while (aw != null) { - ++n; - size += aw.bv.length; - aw.visitEnd(); // in case user forgot to call visitEnd - aw.prev = last; - last = aw; - aw = aw.next; - } - out.putInt(size); - out.putShort(n); - aw = last; - while (aw != null) { - out.putByteArray(aw.bv.data, 0, aw.bv.length); - aw = aw.prev; - } - } - - /** - * Puts the given annotation lists into the given byte vector. - * - * @param panns an array of annotation writer lists. - * @param off index of the first annotation to be written. - * @param out where the annotations must be put. - */ - static void put(final AnnotationWriter[] panns, final int off, final ByteVector out) { - int size = 1 + 2 * (panns.length - off); - for (int i = off; i < panns.length; ++i) { - size += panns[i] == null ? 0 : panns[i].getSize(); - } - out.putInt(size).putByte(panns.length - off); - for (int i = off; i < panns.length; ++i) { - AnnotationWriter aw = panns[i]; - AnnotationWriter last = null; - int n = 0; - while (aw != null) { - ++n; - aw.visitEnd(); // in case user forgot to call visitEnd - aw.prev = last; - last = aw; - aw = aw.next; - } - out.putShort(n); - aw = last; - while (aw != null) { - out.putByteArray(aw.bv.data, 0, aw.bv.length); - aw = aw.prev; - } - } - } - - /** - * Puts the given type reference and type path into the given bytevector. LOCAL_VARIABLE and RESOURCE_VARIABLE - * target types are not supported. - * - * @param typeRef a reference to the annotated type. See {@link TypeReference}. - * @param typePath the path to the annotated type argument, wildcard bound, array element type, or static inner type - * within 'typeRef'. May be <tt>null</tt> if the annotation targets 'typeRef' as a whole. - * @param out where the type reference and type path must be put. - */ - static void putTarget(int typeRef, TypePath typePath, ByteVector out) { - switch (typeRef >>> 24) { - case 0x00: // CLASS_TYPE_PARAMETER - case 0x01: // METHOD_TYPE_PARAMETER - case 0x16: // METHOD_FORMAL_PARAMETER - out.putShort(typeRef >>> 16); - break; - case 0x13: // FIELD - case 0x14: // METHOD_RETURN - case 0x15: // METHOD_RECEIVER - out.putByte(typeRef >>> 24); - break; - case 0x47: // CAST - case 0x48: // CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT - case 0x49: // METHOD_INVOCATION_TYPE_ARGUMENT - case 0x4A: // CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT - case 0x4B: // METHOD_REFERENCE_TYPE_ARGUMENT - out.putInt(typeRef); - break; - // case 0x10: // CLASS_EXTENDS - // case 0x11: // CLASS_TYPE_PARAMETER_BOUND - // case 0x12: // METHOD_TYPE_PARAMETER_BOUND - // case 0x17: // THROWS - // case 0x42: // EXCEPTION_PARAMETER - // case 0x43: // INSTANCEOF - // case 0x44: // NEW - // case 0x45: // CONSTRUCTOR_REFERENCE - // case 0x46: // METHOD_REFERENCE - default: - out.put12(typeRef >>> 24, (typeRef & 0xFFFF00) >> 8); - break; - } - if (typePath == null) { - out.putByte(0); - } else { - int length = typePath.b[typePath.offset] * 2 + 1; - out.putByteArray(typePath.b, typePath.offset, length); - } - } -} +/* + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ + +/* + * + * + * + * + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.redkale.asm; + +/** + * An {@link AnnotationVisitor} that generates annotations in bytecode form. + * + * @author Eric Bruneton + * @author Eugene Kuleshov + */ +final class AnnotationWriter extends AnnotationVisitor { + + /** The class writer to which this annotation must be added. */ + private final ClassWriter cw; + + /** The number of values in this annotation. */ + private int size; + + /** + * <tt>true<tt> if values are named, <tt>false</tt> otherwise. Annotation writers + * used for annotation default and annotation arrays use unnamed values. + */ + private final boolean named; + + /** + * The annotation values in bytecode form. This byte vector only contains the values themselves, i.e. the number of + * values must be stored as a unsigned short just before these bytes. + */ + private final ByteVector bv; + + /** The byte vector to be used to store the number of values of this annotation. See {@link #bv}. */ + private final ByteVector parent; + + /** Where the number of values of this annotation must be stored in {@link #parent}. */ + private final int offset; + + /** Next annotation writer. This field is used to store annotation lists. */ + AnnotationWriter next; + + /** Previous annotation writer. This field is used to store annotation lists. */ + AnnotationWriter prev; + + // ------------------------------------------------------------------------ + // Constructor + // ------------------------------------------------------------------------ + + /** + * Constructs a new {@link AnnotationWriter}. + * + * @param cw the class writer to which this annotation must be added. + * @param named <tt>true<tt> if values are named, <tt>false</tt> otherwise. + * @param bv where the annotation values must be stored. + * @param parent where the number of annotation values must be stored. + * @param offset where in <tt>parent</tt> the number of annotation values must be stored. + */ + AnnotationWriter( + final ClassWriter cw, final boolean named, final ByteVector bv, final ByteVector parent, final int offset) { + super(Opcodes.ASM6); + this.cw = cw; + this.named = named; + this.bv = bv; + this.parent = parent; + this.offset = offset; + } + + // ------------------------------------------------------------------------ + // Implementation of the AnnotationVisitor abstract class + // ------------------------------------------------------------------------ + + @Override + public void visit(final String name, final Object value) { + ++size; + if (named) { + bv.putShort(cw.newUTF8(name)); + } + if (value instanceof String) { + bv.put12('s', cw.newUTF8((String) value)); + } else if (value instanceof Byte) { + bv.put12('B', cw.newInteger(((Byte) value).byteValue()).index); + } else if (value instanceof Boolean) { + int v = ((Boolean) value).booleanValue() ? 1 : 0; + bv.put12('Z', cw.newInteger(v).index); + } else if (value instanceof Character) { + bv.put12('C', cw.newInteger(((Character) value).charValue()).index); + } else if (value instanceof Short) { + bv.put12('S', cw.newInteger(((Short) value).shortValue()).index); + } else if (value instanceof Type) { + bv.put12('c', cw.newUTF8(((Type) value).getDescriptor())); + } else if (value instanceof byte[]) { + byte[] v = (byte[]) value; + bv.put12('[', v.length); + for (int i = 0; i < v.length; i++) { + bv.put12('B', cw.newInteger(v[i]).index); + } + } else if (value instanceof boolean[]) { + boolean[] v = (boolean[]) value; + bv.put12('[', v.length); + for (int i = 0; i < v.length; i++) { + bv.put12('Z', cw.newInteger(v[i] ? 1 : 0).index); + } + } else if (value instanceof short[]) { + short[] v = (short[]) value; + bv.put12('[', v.length); + for (int i = 0; i < v.length; i++) { + bv.put12('S', cw.newInteger(v[i]).index); + } + } else if (value instanceof char[]) { + char[] v = (char[]) value; + bv.put12('[', v.length); + for (int i = 0; i < v.length; i++) { + bv.put12('C', cw.newInteger(v[i]).index); + } + } else if (value instanceof int[]) { + int[] v = (int[]) value; + bv.put12('[', v.length); + for (int i = 0; i < v.length; i++) { + bv.put12('I', cw.newInteger(v[i]).index); + } + } else if (value instanceof long[]) { + long[] v = (long[]) value; + bv.put12('[', v.length); + for (int i = 0; i < v.length; i++) { + bv.put12('J', cw.newLong(v[i]).index); + } + } else if (value instanceof float[]) { + float[] v = (float[]) value; + bv.put12('[', v.length); + for (int i = 0; i < v.length; i++) { + bv.put12('F', cw.newFloat(v[i]).index); + } + } else if (value instanceof double[]) { + double[] v = (double[]) value; + bv.put12('[', v.length); + for (int i = 0; i < v.length; i++) { + bv.put12('D', cw.newDouble(v[i]).index); + } + } else { + Item i = cw.newConstItem(value); + bv.put12(".s.IFJDCS".charAt(i.type), i.index); + } + } + + @Override + public void visitEnum(final String name, final String desc, final String value) { + ++size; + if (named) { + bv.putShort(cw.newUTF8(name)); + } + bv.put12('e', cw.newUTF8(desc)).putShort(cw.newUTF8(value)); + } + + @Override + public AnnotationVisitor visitAnnotation(final String name, final String desc) { + ++size; + if (named) { + bv.putShort(cw.newUTF8(name)); + } + // write tag and type, and reserve space for values count + bv.put12('@', cw.newUTF8(desc)).putShort(0); + return new AnnotationWriter(cw, true, bv, bv, bv.length - 2); + } + + @Override + public AnnotationVisitor visitArray(final String name) { + ++size; + if (named) { + bv.putShort(cw.newUTF8(name)); + } + // write tag, and reserve space for array size + bv.put12('[', 0); + return new AnnotationWriter(cw, false, bv, bv, bv.length - 2); + } + + @Override + public void visitEnd() { + if (parent != null) { + byte[] data = parent.data; + data[offset] = (byte) (size >>> 8); + data[offset + 1] = (byte) size; + } + } + + // ------------------------------------------------------------------------ + // Utility methods + // ------------------------------------------------------------------------ + + /** + * Returns the size of this annotation writer list. + * + * @return the size of this annotation writer list. + */ + int getSize() { + int size = 0; + AnnotationWriter aw = this; + while (aw != null) { + size += aw.bv.length; + aw = aw.next; + } + return size; + } + + /** + * Puts the annotations of this annotation writer list into the given byte vector. + * + * @param out where the annotations must be put. + */ + void put(final ByteVector out) { + int n = 0; + int size = 2; + AnnotationWriter aw = this; + AnnotationWriter last = null; + while (aw != null) { + ++n; + size += aw.bv.length; + aw.visitEnd(); // in case user forgot to call visitEnd + aw.prev = last; + last = aw; + aw = aw.next; + } + out.putInt(size); + out.putShort(n); + aw = last; + while (aw != null) { + out.putByteArray(aw.bv.data, 0, aw.bv.length); + aw = aw.prev; + } + } + + /** + * Puts the given annotation lists into the given byte vector. + * + * @param panns an array of annotation writer lists. + * @param off index of the first annotation to be written. + * @param out where the annotations must be put. + */ + static void put(final AnnotationWriter[] panns, final int off, final ByteVector out) { + int size = 1 + 2 * (panns.length - off); + for (int i = off; i < panns.length; ++i) { + size += panns[i] == null ? 0 : panns[i].getSize(); + } + out.putInt(size).putByte(panns.length - off); + for (int i = off; i < panns.length; ++i) { + AnnotationWriter aw = panns[i]; + AnnotationWriter last = null; + int n = 0; + while (aw != null) { + ++n; + aw.visitEnd(); // in case user forgot to call visitEnd + aw.prev = last; + last = aw; + aw = aw.next; + } + out.putShort(n); + aw = last; + while (aw != null) { + out.putByteArray(aw.bv.data, 0, aw.bv.length); + aw = aw.prev; + } + } + } + + /** + * Puts the given type reference and type path into the given bytevector. LOCAL_VARIABLE and RESOURCE_VARIABLE + * target types are not supported. + * + * @param typeRef a reference to the annotated type. See {@link TypeReference}. + * @param typePath the path to the annotated type argument, wildcard bound, array element type, or static inner type + * within 'typeRef'. May be <tt>null</tt> if the annotation targets 'typeRef' as a whole. + * @param out where the type reference and type path must be put. + */ + static void putTarget(int typeRef, TypePath typePath, ByteVector out) { + switch (typeRef >>> 24) { + case 0x00: // CLASS_TYPE_PARAMETER + case 0x01: // METHOD_TYPE_PARAMETER + case 0x16: // METHOD_FORMAL_PARAMETER + out.putShort(typeRef >>> 16); + break; + case 0x13: // FIELD + case 0x14: // METHOD_RETURN + case 0x15: // METHOD_RECEIVER + out.putByte(typeRef >>> 24); + break; + case 0x47: // CAST + case 0x48: // CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT + case 0x49: // METHOD_INVOCATION_TYPE_ARGUMENT + case 0x4A: // CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT + case 0x4B: // METHOD_REFERENCE_TYPE_ARGUMENT + out.putInt(typeRef); + break; + // case 0x10: // CLASS_EXTENDS + // case 0x11: // CLASS_TYPE_PARAMETER_BOUND + // case 0x12: // METHOD_TYPE_PARAMETER_BOUND + // case 0x17: // THROWS + // case 0x42: // EXCEPTION_PARAMETER + // case 0x43: // INSTANCEOF + // case 0x44: // NEW + // case 0x45: // CONSTRUCTOR_REFERENCE + // case 0x46: // METHOD_REFERENCE + default: + out.put12(typeRef >>> 24, (typeRef & 0xFFFF00) >> 8); + break; + } + if (typePath == null) { + out.putByte(0); + } else { + int length = typePath.b[typePath.offset] * 2 + 1; + out.putByteArray(typePath.b, typePath.offset, length); + } + } +} diff --git a/src/main/java/org/redkale/asm/AsmMethodBean.java b/src/main/java/org/redkale/asm/AsmMethodBean.java index 77ab704bd..3fd003e59 100644 --- a/src/main/java/org/redkale/asm/AsmMethodBean.java +++ b/src/main/java/org/redkale/asm/AsmMethodBean.java @@ -1,140 +1,140 @@ -/* - * - */ -package org.redkale.asm; - -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import org.redkale.convert.json.JsonConvert; - -/** - * 存放方法的字节信息 - * - * @see org.redkale.asm.AsmMethodBoost - * @since 2.8.0 - */ -public class AsmMethodBean { - - private List params; - - private int access; - - private String name; - - private String desc; - - private String signature; - - private String[] exceptions; - - public AsmMethodBean() {} - - public AsmMethodBean(int access, String name, String desc, String signature, String[] exceptions) { - this.access = access; - this.name = name; - this.desc = desc; - this.signature = signature; - this.exceptions = exceptions; - this.params = new ArrayList<>(); - } - - public static AsmMethodBean get(Map map, Method method) { - return map == null ? null : map.get(method.getName() + ":" + Type.getMethodDescriptor(method)); - } - - void removeEmptyNames() { - if (params != null) { - List dels = null; - for (AsmMethodParam p : params) { - if (" ".equals(p.getName())) { - if (dels == null) { - dels = new ArrayList<>(); - } - dels.add(p); - } - } - if (dels != null) { - for (AsmMethodParam p : dels) { - params.remove(p); - } - } - } - } - - public List fieldNameList() { - if (params == null) { - return new ArrayList<>(); - } - List rs = new ArrayList<>(params.size()); - for (AsmMethodParam p : params) { - rs.add(p.getName()); - } - return rs; - } - - public String[] fieldNameArray() { - if (params == null) { - return null; - } - String[] rs = new String[params.size()]; - for (int i = 0; i < rs.length; i++) { - rs[i] = params.get(i).getName(); - } - return rs; - } - - public List getParams() { - return params; - } - - public void setParams(List params) { - this.params = params; - } - - public int getAccess() { - return access; - } - - public void setAccess(int access) { - this.access = access; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getDesc() { - return desc; - } - - public void setDesc(String desc) { - this.desc = desc; - } - - public String getSignature() { - return signature; - } - - public void setSignature(String signature) { - this.signature = signature; - } - - public String[] getExceptions() { - return exceptions; - } - - public void setExceptions(String[] exceptions) { - this.exceptions = exceptions; - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } -} +/* + * + */ +package org.redkale.asm; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import org.redkale.convert.json.JsonConvert; + +/** + * 存放方法的字节信息 + * + * @see org.redkale.asm.AsmMethodBoost + * @since 2.8.0 + */ +public class AsmMethodBean { + + private List params; + + private int access; + + private String name; + + private String desc; + + private String signature; + + private String[] exceptions; + + public AsmMethodBean() {} + + public AsmMethodBean(int access, String name, String desc, String signature, String[] exceptions) { + this.access = access; + this.name = name; + this.desc = desc; + this.signature = signature; + this.exceptions = exceptions; + this.params = new ArrayList<>(); + } + + public static AsmMethodBean get(Map map, Method method) { + return map == null ? null : map.get(method.getName() + ":" + Type.getMethodDescriptor(method)); + } + + void removeEmptyNames() { + if (params != null) { + List dels = null; + for (AsmMethodParam p : params) { + if (" ".equals(p.getName())) { + if (dels == null) { + dels = new ArrayList<>(); + } + dels.add(p); + } + } + if (dels != null) { + for (AsmMethodParam p : dels) { + params.remove(p); + } + } + } + } + + public List fieldNameList() { + if (params == null) { + return new ArrayList<>(); + } + List rs = new ArrayList<>(params.size()); + for (AsmMethodParam p : params) { + rs.add(p.getName()); + } + return rs; + } + + public String[] fieldNameArray() { + if (params == null) { + return null; + } + String[] rs = new String[params.size()]; + for (int i = 0; i < rs.length; i++) { + rs[i] = params.get(i).getName(); + } + return rs; + } + + public List getParams() { + return params; + } + + public void setParams(List params) { + this.params = params; + } + + public int getAccess() { + return access; + } + + public void setAccess(int access) { + this.access = access; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDesc() { + return desc; + } + + public void setDesc(String desc) { + this.desc = desc; + } + + public String getSignature() { + return signature; + } + + public void setSignature(String signature) { + this.signature = signature; + } + + public String[] getExceptions() { + return exceptions; + } + + public void setExceptions(String[] exceptions) { + this.exceptions = exceptions; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } +} diff --git a/src/main/java/org/redkale/asm/AsmMethodBoost.java b/src/main/java/org/redkale/asm/AsmMethodBoost.java index 0bc31dea9..c2a8427fa 100644 --- a/src/main/java/org/redkale/asm/AsmMethodBoost.java +++ b/src/main/java/org/redkale/asm/AsmMethodBoost.java @@ -1,409 +1,409 @@ -/* - * - */ -package org.redkale.asm; - -import static org.redkale.asm.Opcodes.ACC_PRIVATE; -import static org.redkale.asm.Opcodes.ACC_PROTECTED; -import static org.redkale.asm.Opcodes.ACC_PUBLIC; -import static org.redkale.asm.Opcodes.ALOAD; -import static org.redkale.asm.Opcodes.ARETURN; -import static org.redkale.asm.Opcodes.DLOAD; -import static org.redkale.asm.Opcodes.DRETURN; -import static org.redkale.asm.Opcodes.FLOAD; -import static org.redkale.asm.Opcodes.FRETURN; -import static org.redkale.asm.Opcodes.ILOAD; -import static org.redkale.asm.Opcodes.IRETURN; -import static org.redkale.asm.Opcodes.LLOAD; -import static org.redkale.asm.Opcodes.LRETURN; -import static org.redkale.asm.Opcodes.RETURN; - -import java.io.InputStream; -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; -import org.redkale.annotation.Nullable; -import org.redkale.inject.ResourceFactory; -import org.redkale.util.Utility; - -/** - * 生产动态字节码的方法扩展器, 可以进行方法加强动作 - * - * @param 泛型 - * @since 2.8.0 - */ -public abstract class AsmMethodBoost { - - protected final AtomicInteger fieldIndex = new AtomicInteger(); - - protected final boolean remote; - - protected final Class serviceType; - - protected AsmMethodBoost(boolean remote, Class serviceType) { - this.remote = remote; - this.serviceType = serviceType; - } - - public static AsmMethodBoost create(boolean remote, Collection list) { - return new AsmMethodBoosts(remote, list); - } - - public static AsmMethodBoost create(boolean remote, AsmMethodBoost... items) { - return new AsmMethodBoosts(remote, items); - } - - /** - * 返回一个类所有方法的字节信息, key为: method.getName+':'+Type.getMethodDescriptor(method) - * - * @param clazz Class - * @return Map - */ - public static Map getMethodBeans(Class clazz) { - Map rs = MethodParamClassVisitor.getMethodParamNames(new HashMap<>(), clazz); - // 返回的List中参数列表可能会比方法参数量多,因为方法内的临时变量也会存入list中, 所以需要list的元素集合比方法的参数多 - rs.values().forEach(AsmMethodBean::removeEmptyNames); - return rs; - } - - public static String getMethodBeanKey(Method method) { - return method.getName() + ":" + Type.getMethodDescriptor(method); - } - - /** - * 获取需屏蔽的方法上的注解 - * - * @param method 方法 - * @return 需要屏蔽的注解 - */ - public abstract List> filterMethodAnnotations(Method method); - - /** - * 对方法进行动态加强处理 - * - * @param classLoader ClassLoader - * @param cw 动态字节码Writer - * @param newDynName 动态新类名 - * @param fieldPrefix 动态字段的前缀 - * @param filterAnns 需要过滤的注解 - * @param method 操作的方法 - * @param newMethodName 新的方法名, 可能为null - * @return 下一个新的方法名,不做任何处理应返回参数newMethodName - */ - public abstract String doMethod( - ClassLoader classLoader, - ClassWriter cw, - String newDynName, - String fieldPrefix, - List> filterAnns, - Method method, - @Nullable String newMethodName); - - /** - * 处理所有动态方法后调用 - * - * @param classLoader ClassLoader - * @param cw 动态字节码Writer - * @param newDynName 动态新类名 - * @param fieldPrefix 动态字段的前缀 - */ - public void doAfterMethods(ClassLoader classLoader, ClassWriter cw, String newDynName, String fieldPrefix) {} - - /** - * 实例对象进行操作,通常用于给动态的字段赋值 - * - * @param resourceFactory ResourceFactory - * @param service 实例对象 - */ - public abstract void doInstance(ResourceFactory resourceFactory, T service); - - protected AsmMethodBean getMethodBean(Method method) { - Map methodBeans = AsmMethodBoost.getMethodBeans(serviceType); - return AsmMethodBean.get(methodBeans, method); - } - - protected MethodVisitor createMethodVisitor( - ClassWriter cw, Method method, String newMethodName, AsmMethodBean methodBean) { - return new MethodDebugVisitor(cw.visitMethod( - getAcc(method, newMethodName), - getNowMethodName(method, newMethodName), - Type.getMethodDescriptor(method), - getMethodSignature(method, methodBean), - getMethodExceptions(method, methodBean))); - } - - protected int getAcc(Method method, String newMethodName) { - if (newMethodName != null) { - return ACC_PRIVATE; - } - return Modifier.isProtected(method.getModifiers()) ? ACC_PROTECTED : ACC_PUBLIC; - } - - protected String getNowMethodName(Method method, String newMethodName) { - return newMethodName == null ? method.getName() : newMethodName; - } - - protected String getMethodSignature(Method method, AsmMethodBean methodBean) { - return methodBean != null ? methodBean.getSignature() : null; - } - - protected String[] getMethodExceptions(Method method, AsmMethodBean methodBean) { - if (methodBean == null) { - String[] exceptions = null; - Class[] expTypes = method.getExceptionTypes(); - if (expTypes.length > 0) { - exceptions = new String[expTypes.length]; - for (int i = 0; i < expTypes.length; i++) { - exceptions[i] = expTypes[i].getName().replace('.', '/'); - } - } - return exceptions; - } else { - return methodBean.getExceptions(); - } - } - - protected void visitRawAnnotation( - Method method, String newMethodName, MethodVisitor mv, Class selfAnnType, List filterAnns) { - if (newMethodName == null) { - // 给方法加上原有的Annotation - final Annotation[] anns = method.getAnnotations(); - for (Annotation ann : anns) { - if (ann.annotationType() != selfAnnType - && (filterAnns == null || !filterAnns.contains(ann.annotationType()))) { - Asms.visitAnnotation(mv.visitAnnotation(Type.getDescriptor(ann.annotationType()), true), ann); - } - } - // 给参数加上原有的Annotation - final Annotation[][] annss = method.getParameterAnnotations(); - for (int k = 0; k < annss.length; k++) { - for (Annotation ann : annss[k]) { - Asms.visitAnnotation( - mv.visitParameterAnnotation(k, Type.getDescriptor(ann.annotationType()), true), ann); - } - } - } - } - - protected List visitVarInsnParamTypes(MethodVisitor mv, Method method, int insn) { - // 传参数 - Class[] paramTypes = method.getParameterTypes(); - List insns = new ArrayList<>(); - for (Class pt : paramTypes) { - insn++; - if (pt.isPrimitive()) { - if (pt == long.class) { - mv.visitVarInsn(LLOAD, insn++); - } else if (pt == float.class) { - mv.visitVarInsn(FLOAD, insn++); - } else if (pt == double.class) { - mv.visitVarInsn(DLOAD, insn++); - } else { - mv.visitVarInsn(ILOAD, insn); - } - } else { - mv.visitVarInsn(ALOAD, insn); - } - insns.add(insn); - } - return insns; - } - - protected void visitParamTypesLocalVariable( - MethodVisitor mv, Method method, Label l0, Label l2, List insns, AsmMethodBean methodBean) { - Class[] paramTypes = method.getParameterTypes(); - if (methodBean != null && paramTypes.length > 0) { - mv.visitLabel(l2); - List params = methodBean.getParams(); - for (int i = 0; i < paramTypes.length; i++) { - AsmMethodParam param = params.get(i); - mv.visitLocalVariable( - param.getName(), - param.description(paramTypes[i]), - param.signature(paramTypes[i]), - l0, - l2, - insns.get(i)); - } - } - } - - protected void visitInsnReturn( - MethodVisitor mv, Method method, Label l0, List insns, AsmMethodBean methodBean) { - if (method.getGenericReturnType() == void.class) { - mv.visitInsn(RETURN); - } else { - Class returnclz = method.getReturnType(); - if (returnclz.isPrimitive()) { - if (returnclz == long.class) { - mv.visitInsn(LRETURN); - } else if (returnclz == float.class) { - mv.visitInsn(FRETURN); - } else if (returnclz == double.class) { - mv.visitInsn(DRETURN); - } else { - mv.visitInsn(IRETURN); - } - } else { - mv.visitInsn(ARETURN); - } - } - visitParamTypesLocalVariable(mv, method, l0, new Label(), insns, methodBean); - } - - /** - * 生产动态字节码的方法扩展器, 可以进行方法加强动作 - * - * @param 泛型 - * @since 2.8.0 - */ - static class AsmMethodBoosts extends AsmMethodBoost { - - private final AsmMethodBoost[] items; - - public AsmMethodBoosts(boolean remote, Collection list) { - super(remote, null); - this.items = list.toArray(new AsmMethodBoost[list.size()]); - } - - public AsmMethodBoosts(boolean remote, AsmMethodBoost... items) { - super(remote, null); - this.items = items; - } - - @Override - public List> filterMethodAnnotations(Method method) { - List> list = null; - for (AsmMethodBoost item : items) { - if (item != null) { - List> sub = item.filterMethodAnnotations(method); - if (sub != null) { - if (list == null) { - list = new ArrayList<>(); - } - list.addAll(sub); - } - } - } - return list; - } - - @Override - public String doMethod( - ClassLoader classLoader, - ClassWriter cw, - String newDynName, - String fieldPrefix, - List> filterAnns, - Method method, - String newMethodName) { - String newName = newMethodName; - for (AsmMethodBoost item : items) { - if (item != null) { - newName = item.doMethod(classLoader, cw, newDynName, fieldPrefix, filterAnns, method, newName); - } - } - return newName; - } - - @Override - public void doAfterMethods(ClassLoader classLoader, ClassWriter cw, String newDynName, String fieldPrefix) { - for (AsmMethodBoost item : items) { - if (item != null) { - item.doAfterMethods(classLoader, cw, newDynName, fieldPrefix); - } - } - } - - @Override - public void doInstance(ResourceFactory resourceFactory, T service) { - for (AsmMethodBoost item : items) { - if (item != null) { - item.doInstance(resourceFactory, service); - } - } - } - } - - static class MethodParamClassVisitor extends ClassVisitor { - - private Class serviceType; - - private final Map methodBeanMap; - - public MethodParamClassVisitor(int api, Class serviceType, final Map methodBeanMap) { - super(api); - this.serviceType = serviceType; - this.methodBeanMap = methodBeanMap; - } - - @Override - public MethodVisitor visitMethod( - int methodAccess, - String methodName, - String methodDesc, - String methodSignature, - String[] methodExceptions) { - super.visitMethod(api, methodName, methodDesc, methodSignature, methodExceptions); - if (java.lang.reflect.Modifier.isStatic(methodAccess)) { - return null; - } - String key = methodName + ":" + methodDesc; - if (methodBeanMap.containsKey(key)) { - return null; - } - AsmMethodBean bean = - new AsmMethodBean(methodAccess, methodName, methodDesc, methodSignature, methodExceptions); - List paramList = bean.getParams(); - methodBeanMap.put(key, bean); - return new MethodVisitor(Opcodes.ASM6) { - @Override - public void visitParameter(String paramName, int paramAccess) { - paramList.add(new AsmMethodParam(paramName)); - } - - @Override - public void visitLocalVariable( - String varName, String varDesc, String varSignature, Label start, Label end, int varIndex) { - if (varIndex < 1) { - return; - } - int size = paramList.size(); - // index并不会按顺序执行 - if (varIndex > size) { - for (int i = size; i < varIndex; i++) { - paramList.add(new AsmMethodParam(" ", varDesc, varSignature)); - } - paramList.set(varIndex - 1, new AsmMethodParam(varName, varDesc, varSignature)); - } - paramList.set(varIndex - 1, new AsmMethodParam(varName, varDesc, varSignature)); - } - }; - } - - // 返回的List中参数列表可能会比方法参数量多,因为方法内的临时变量也会存入list中, 所以需要list的元素集合比方法的参数多 - static Map getMethodParamNames(Map map, Class clazz) { - String n = clazz.getName(); - InputStream in = clazz.getResourceAsStream(n.substring(n.lastIndexOf('.') + 1) + ".class"); - if (in == null) { - return map; - } - try { - new ClassReader(Utility.readBytesThenClose(in)) - .accept(new MethodParamClassVisitor(Opcodes.ASM6, clazz, map), 0); - } catch (Exception e) { // 无需理会 - } - Class superClass = clazz.getSuperclass(); - if (superClass == null || superClass == Object.class) { // 接口的getSuperclass为null - return map; - } - return getMethodParamNames(map, superClass); - } - } -} +/* + * + */ +package org.redkale.asm; + +import static org.redkale.asm.Opcodes.ACC_PRIVATE; +import static org.redkale.asm.Opcodes.ACC_PROTECTED; +import static org.redkale.asm.Opcodes.ACC_PUBLIC; +import static org.redkale.asm.Opcodes.ALOAD; +import static org.redkale.asm.Opcodes.ARETURN; +import static org.redkale.asm.Opcodes.DLOAD; +import static org.redkale.asm.Opcodes.DRETURN; +import static org.redkale.asm.Opcodes.FLOAD; +import static org.redkale.asm.Opcodes.FRETURN; +import static org.redkale.asm.Opcodes.ILOAD; +import static org.redkale.asm.Opcodes.IRETURN; +import static org.redkale.asm.Opcodes.LLOAD; +import static org.redkale.asm.Opcodes.LRETURN; +import static org.redkale.asm.Opcodes.RETURN; + +import java.io.InputStream; +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; +import org.redkale.annotation.Nullable; +import org.redkale.inject.ResourceFactory; +import org.redkale.util.Utility; + +/** + * 生产动态字节码的方法扩展器, 可以进行方法加强动作 + * + * @param 泛型 + * @since 2.8.0 + */ +public abstract class AsmMethodBoost { + + protected final AtomicInteger fieldIndex = new AtomicInteger(); + + protected final boolean remote; + + protected final Class serviceType; + + protected AsmMethodBoost(boolean remote, Class serviceType) { + this.remote = remote; + this.serviceType = serviceType; + } + + public static AsmMethodBoost create(boolean remote, Collection list) { + return new AsmMethodBoosts(remote, list); + } + + public static AsmMethodBoost create(boolean remote, AsmMethodBoost... items) { + return new AsmMethodBoosts(remote, items); + } + + /** + * 返回一个类所有方法的字节信息, key为: method.getName+':'+Type.getMethodDescriptor(method) + * + * @param clazz Class + * @return Map + */ + public static Map getMethodBeans(Class clazz) { + Map rs = MethodParamClassVisitor.getMethodParamNames(new HashMap<>(), clazz); + // 返回的List中参数列表可能会比方法参数量多,因为方法内的临时变量也会存入list中, 所以需要list的元素集合比方法的参数多 + rs.values().forEach(AsmMethodBean::removeEmptyNames); + return rs; + } + + public static String getMethodBeanKey(Method method) { + return method.getName() + ":" + Type.getMethodDescriptor(method); + } + + /** + * 获取需屏蔽的方法上的注解 + * + * @param method 方法 + * @return 需要屏蔽的注解 + */ + public abstract List> filterMethodAnnotations(Method method); + + /** + * 对方法进行动态加强处理 + * + * @param classLoader ClassLoader + * @param cw 动态字节码Writer + * @param newDynName 动态新类名 + * @param fieldPrefix 动态字段的前缀 + * @param filterAnns 需要过滤的注解 + * @param method 操作的方法 + * @param newMethodName 新的方法名, 可能为null + * @return 下一个新的方法名,不做任何处理应返回参数newMethodName + */ + public abstract String doMethod( + ClassLoader classLoader, + ClassWriter cw, + String newDynName, + String fieldPrefix, + List> filterAnns, + Method method, + @Nullable String newMethodName); + + /** + * 处理所有动态方法后调用 + * + * @param classLoader ClassLoader + * @param cw 动态字节码Writer + * @param newDynName 动态新类名 + * @param fieldPrefix 动态字段的前缀 + */ + public void doAfterMethods(ClassLoader classLoader, ClassWriter cw, String newDynName, String fieldPrefix) {} + + /** + * 实例对象进行操作,通常用于给动态的字段赋值 + * + * @param resourceFactory ResourceFactory + * @param service 实例对象 + */ + public abstract void doInstance(ResourceFactory resourceFactory, T service); + + protected AsmMethodBean getMethodBean(Method method) { + Map methodBeans = AsmMethodBoost.getMethodBeans(serviceType); + return AsmMethodBean.get(methodBeans, method); + } + + protected MethodVisitor createMethodVisitor( + ClassWriter cw, Method method, String newMethodName, AsmMethodBean methodBean) { + return new MethodDebugVisitor(cw.visitMethod( + getAcc(method, newMethodName), + getNowMethodName(method, newMethodName), + Type.getMethodDescriptor(method), + getMethodSignature(method, methodBean), + getMethodExceptions(method, methodBean))); + } + + protected int getAcc(Method method, String newMethodName) { + if (newMethodName != null) { + return ACC_PRIVATE; + } + return Modifier.isProtected(method.getModifiers()) ? ACC_PROTECTED : ACC_PUBLIC; + } + + protected String getNowMethodName(Method method, String newMethodName) { + return newMethodName == null ? method.getName() : newMethodName; + } + + protected String getMethodSignature(Method method, AsmMethodBean methodBean) { + return methodBean != null ? methodBean.getSignature() : null; + } + + protected String[] getMethodExceptions(Method method, AsmMethodBean methodBean) { + if (methodBean == null) { + String[] exceptions = null; + Class[] expTypes = method.getExceptionTypes(); + if (expTypes.length > 0) { + exceptions = new String[expTypes.length]; + for (int i = 0; i < expTypes.length; i++) { + exceptions[i] = expTypes[i].getName().replace('.', '/'); + } + } + return exceptions; + } else { + return methodBean.getExceptions(); + } + } + + protected void visitRawAnnotation( + Method method, String newMethodName, MethodVisitor mv, Class selfAnnType, List filterAnns) { + if (newMethodName == null) { + // 给方法加上原有的Annotation + final Annotation[] anns = method.getAnnotations(); + for (Annotation ann : anns) { + if (ann.annotationType() != selfAnnType + && (filterAnns == null || !filterAnns.contains(ann.annotationType()))) { + Asms.visitAnnotation(mv.visitAnnotation(Type.getDescriptor(ann.annotationType()), true), ann); + } + } + // 给参数加上原有的Annotation + final Annotation[][] annss = method.getParameterAnnotations(); + for (int k = 0; k < annss.length; k++) { + for (Annotation ann : annss[k]) { + Asms.visitAnnotation( + mv.visitParameterAnnotation(k, Type.getDescriptor(ann.annotationType()), true), ann); + } + } + } + } + + protected List visitVarInsnParamTypes(MethodVisitor mv, Method method, int insn) { + // 传参数 + Class[] paramTypes = method.getParameterTypes(); + List insns = new ArrayList<>(); + for (Class pt : paramTypes) { + insn++; + if (pt.isPrimitive()) { + if (pt == long.class) { + mv.visitVarInsn(LLOAD, insn++); + } else if (pt == float.class) { + mv.visitVarInsn(FLOAD, insn++); + } else if (pt == double.class) { + mv.visitVarInsn(DLOAD, insn++); + } else { + mv.visitVarInsn(ILOAD, insn); + } + } else { + mv.visitVarInsn(ALOAD, insn); + } + insns.add(insn); + } + return insns; + } + + protected void visitParamTypesLocalVariable( + MethodVisitor mv, Method method, Label l0, Label l2, List insns, AsmMethodBean methodBean) { + Class[] paramTypes = method.getParameterTypes(); + if (methodBean != null && paramTypes.length > 0) { + mv.visitLabel(l2); + List params = methodBean.getParams(); + for (int i = 0; i < paramTypes.length; i++) { + AsmMethodParam param = params.get(i); + mv.visitLocalVariable( + param.getName(), + param.description(paramTypes[i]), + param.signature(paramTypes[i]), + l0, + l2, + insns.get(i)); + } + } + } + + protected void visitInsnReturn( + MethodVisitor mv, Method method, Label l0, List insns, AsmMethodBean methodBean) { + if (method.getGenericReturnType() == void.class) { + mv.visitInsn(RETURN); + } else { + Class returnclz = method.getReturnType(); + if (returnclz.isPrimitive()) { + if (returnclz == long.class) { + mv.visitInsn(LRETURN); + } else if (returnclz == float.class) { + mv.visitInsn(FRETURN); + } else if (returnclz == double.class) { + mv.visitInsn(DRETURN); + } else { + mv.visitInsn(IRETURN); + } + } else { + mv.visitInsn(ARETURN); + } + } + visitParamTypesLocalVariable(mv, method, l0, new Label(), insns, methodBean); + } + + /** + * 生产动态字节码的方法扩展器, 可以进行方法加强动作 + * + * @param 泛型 + * @since 2.8.0 + */ + static class AsmMethodBoosts extends AsmMethodBoost { + + private final AsmMethodBoost[] items; + + public AsmMethodBoosts(boolean remote, Collection list) { + super(remote, null); + this.items = list.toArray(new AsmMethodBoost[list.size()]); + } + + public AsmMethodBoosts(boolean remote, AsmMethodBoost... items) { + super(remote, null); + this.items = items; + } + + @Override + public List> filterMethodAnnotations(Method method) { + List> list = null; + for (AsmMethodBoost item : items) { + if (item != null) { + List> sub = item.filterMethodAnnotations(method); + if (sub != null) { + if (list == null) { + list = new ArrayList<>(); + } + list.addAll(sub); + } + } + } + return list; + } + + @Override + public String doMethod( + ClassLoader classLoader, + ClassWriter cw, + String newDynName, + String fieldPrefix, + List> filterAnns, + Method method, + String newMethodName) { + String newName = newMethodName; + for (AsmMethodBoost item : items) { + if (item != null) { + newName = item.doMethod(classLoader, cw, newDynName, fieldPrefix, filterAnns, method, newName); + } + } + return newName; + } + + @Override + public void doAfterMethods(ClassLoader classLoader, ClassWriter cw, String newDynName, String fieldPrefix) { + for (AsmMethodBoost item : items) { + if (item != null) { + item.doAfterMethods(classLoader, cw, newDynName, fieldPrefix); + } + } + } + + @Override + public void doInstance(ResourceFactory resourceFactory, T service) { + for (AsmMethodBoost item : items) { + if (item != null) { + item.doInstance(resourceFactory, service); + } + } + } + } + + static class MethodParamClassVisitor extends ClassVisitor { + + private Class serviceType; + + private final Map methodBeanMap; + + public MethodParamClassVisitor(int api, Class serviceType, final Map methodBeanMap) { + super(api); + this.serviceType = serviceType; + this.methodBeanMap = methodBeanMap; + } + + @Override + public MethodVisitor visitMethod( + int methodAccess, + String methodName, + String methodDesc, + String methodSignature, + String[] methodExceptions) { + super.visitMethod(api, methodName, methodDesc, methodSignature, methodExceptions); + if (java.lang.reflect.Modifier.isStatic(methodAccess)) { + return null; + } + String key = methodName + ":" + methodDesc; + if (methodBeanMap.containsKey(key)) { + return null; + } + AsmMethodBean bean = + new AsmMethodBean(methodAccess, methodName, methodDesc, methodSignature, methodExceptions); + List paramList = bean.getParams(); + methodBeanMap.put(key, bean); + return new MethodVisitor(Opcodes.ASM6) { + @Override + public void visitParameter(String paramName, int paramAccess) { + paramList.add(new AsmMethodParam(paramName)); + } + + @Override + public void visitLocalVariable( + String varName, String varDesc, String varSignature, Label start, Label end, int varIndex) { + if (varIndex < 1) { + return; + } + int size = paramList.size(); + // index并不会按顺序执行 + if (varIndex > size) { + for (int i = size; i < varIndex; i++) { + paramList.add(new AsmMethodParam(" ", varDesc, varSignature)); + } + paramList.set(varIndex - 1, new AsmMethodParam(varName, varDesc, varSignature)); + } + paramList.set(varIndex - 1, new AsmMethodParam(varName, varDesc, varSignature)); + } + }; + } + + // 返回的List中参数列表可能会比方法参数量多,因为方法内的临时变量也会存入list中, 所以需要list的元素集合比方法的参数多 + static Map getMethodParamNames(Map map, Class clazz) { + String n = clazz.getName(); + InputStream in = clazz.getResourceAsStream(n.substring(n.lastIndexOf('.') + 1) + ".class"); + if (in == null) { + return map; + } + try { + new ClassReader(Utility.readBytesThenClose(in)) + .accept(new MethodParamClassVisitor(Opcodes.ASM6, clazz, map), 0); + } catch (Exception e) { // 无需理会 + } + Class superClass = clazz.getSuperclass(); + if (superClass == null || superClass == Object.class) { // 接口的getSuperclass为null + return map; + } + return getMethodParamNames(map, superClass); + } + } +} diff --git a/src/main/java/org/redkale/asm/AsmMethodParam.java b/src/main/java/org/redkale/asm/AsmMethodParam.java index d5ab67c50..bda1ae4bc 100644 --- a/src/main/java/org/redkale/asm/AsmMethodParam.java +++ b/src/main/java/org/redkale/asm/AsmMethodParam.java @@ -1,72 +1,72 @@ -/* - * - */ -package org.redkale.asm; - -import org.redkale.convert.json.JsonConvert; -import org.redkale.util.TypeToken; - -/** - * 存放方法参数的字节信息 - * - * @see org.redkale.asm.AsmMethodBean - * @see org.redkale.asm.AsmMethodBoost - * @since 2.8.0 - */ -public class AsmMethodParam { - - private String name; - - private String description; - - private String signature; - - public AsmMethodParam() {} - - public AsmMethodParam(String name) { - this.name = name; - } - - public AsmMethodParam(String name, String description, String signature) { - this.name = name; - this.description = description; - this.signature = signature; - } - - public String description(java.lang.reflect.Type type) { - return description == null ? Type.getDescriptor(TypeToken.typeToClass(type)) : description; - } - - public String signature(java.lang.reflect.Type type) { - return signature; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public String getSignature() { - return signature; - } - - public void setSignature(String signature) { - this.signature = signature; - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } -} +/* + * + */ +package org.redkale.asm; + +import org.redkale.convert.json.JsonConvert; +import org.redkale.util.TypeToken; + +/** + * 存放方法参数的字节信息 + * + * @see org.redkale.asm.AsmMethodBean + * @see org.redkale.asm.AsmMethodBoost + * @since 2.8.0 + */ +public class AsmMethodParam { + + private String name; + + private String description; + + private String signature; + + public AsmMethodParam() {} + + public AsmMethodParam(String name) { + this.name = name; + } + + public AsmMethodParam(String name, String description, String signature) { + this.name = name; + this.description = description; + this.signature = signature; + } + + public String description(java.lang.reflect.Type type) { + return description == null ? Type.getDescriptor(TypeToken.typeToClass(type)) : description; + } + + public String signature(java.lang.reflect.Type type) { + return signature; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getSignature() { + return signature; + } + + public void setSignature(String signature) { + this.signature = signature; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } +} diff --git a/src/main/java/org/redkale/asm/Asms.java b/src/main/java/org/redkale/asm/Asms.java index cfb2b585b..42d137be8 100644 --- a/src/main/java/org/redkale/asm/Asms.java +++ b/src/main/java/org/redkale/asm/Asms.java @@ -1,197 +1,197 @@ -/* - * - */ -package org.redkale.asm; - -import static org.redkale.asm.Opcodes.BIPUSH; -import static org.redkale.asm.Opcodes.CHECKCAST; -import static org.redkale.asm.Opcodes.GETSTATIC; -import static org.redkale.asm.Opcodes.ICONST_0; -import static org.redkale.asm.Opcodes.INVOKESTATIC; -import static org.redkale.asm.Opcodes.INVOKEVIRTUAL; -import static org.redkale.asm.Opcodes.SIPUSH; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; -import org.redkale.util.RedkaleException; - -/** - * ASM简单的工具方法
- * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public final class Asms { - - private Asms() {} - - public static Handle createLambdaMetaHandle() { - return new Handle( - Opcodes.H_INVOKESTATIC, - "java/lang/invoke/LambdaMetafactory", - "metafactory", - "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;", - false); - } - - public static void visitAnnotation(final AnnotationVisitor av, final Annotation ann) { - try { - for (Method anm : ann.annotationType().getMethods()) { - final String mname = anm.getName(); - if ("equals".equals(mname) - || "hashCode".equals(mname) - || "toString".equals(mname) - || "annotationType".equals(mname)) { - continue; - } - final Object r = anm.invoke(ann); - if (r instanceof String[]) { - AnnotationVisitor av1 = av.visitArray(mname); - for (String item : (String[]) r) { - av1.visit(null, item); - } - av1.visitEnd(); - } else if (r instanceof Class[]) { - AnnotationVisitor av1 = av.visitArray(mname); - for (Class item : (Class[]) r) { - av1.visit(null, Type.getType(item)); - } - av1.visitEnd(); - } else if (r instanceof Enum[]) { - AnnotationVisitor av1 = av.visitArray(mname); - for (Enum item : (Enum[]) r) { - av1.visitEnum(null, Type.getDescriptor(item.getClass()), ((Enum) item).name()); - } - av1.visitEnd(); - } else if (r instanceof Annotation[]) { - AnnotationVisitor av1 = av.visitArray(mname); - for (Annotation item : (Annotation[]) r) { - visitAnnotation( - av1.visitAnnotation(null, Type.getDescriptor(((Annotation) item).annotationType())), - item); - } - av1.visitEnd(); - } else if (r instanceof Class) { - av.visit(mname, Type.getType((Class) r)); - } else if (r instanceof Enum) { - av.visitEnum(mname, Type.getDescriptor(r.getClass()), ((Enum) r).name()); - } else if (r instanceof Annotation) { - visitAnnotation( - av.visitAnnotation(null, Type.getDescriptor(((Annotation) r).annotationType())), - (Annotation) r); - } else { - av.visit(mname, r); - } - } - av.visitEnd(); - } catch (Exception e) { - throw new RedkaleException(e); - } - } - - public static void visitInsn(MethodVisitor mv, int num) { - if (num < 6) { - mv.visitInsn(ICONST_0 + num); - } else if (num <= Byte.MAX_VALUE) { - mv.visitIntInsn(BIPUSH, num); - } else if (num <= Short.MAX_VALUE) { - mv.visitIntInsn(SIPUSH, num); - } else { - mv.visitLdcInsn(num); - } - } - - public static void visitFieldInsn(MethodVisitor mv, Class clazz) { - if (clazz == boolean.class) { - mv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "TYPE", "Ljava/lang/Class;"); - } else if (clazz == byte.class) { - mv.visitFieldInsn(GETSTATIC, "java/lang/Byte", "TYPE", "Ljava/lang/Class;"); - } else if (clazz == char.class) { - mv.visitFieldInsn(GETSTATIC, "java/lang/Character", "TYPE", "Ljava/lang/Class;"); - } else if (clazz == short.class) { - mv.visitFieldInsn(GETSTATIC, "java/lang/Short", "TYPE", "Ljava/lang/Class;"); - } else if (clazz == int.class) { - mv.visitFieldInsn(GETSTATIC, "java/lang/Integer", "TYPE", "Ljava/lang/Class;"); - } else if (clazz == float.class) { - mv.visitFieldInsn(GETSTATIC, "java/lang/Float", "TYPE", "Ljava/lang/Class;"); - } else if (clazz == long.class) { - mv.visitFieldInsn(GETSTATIC, "java/lang/Long", "TYPE", "Ljava/lang/Class;"); - } else if (clazz == double.class) { - mv.visitFieldInsn(GETSTATIC, "java/lang/Double", "TYPE", "Ljava/lang/Class;"); - } else { - mv.visitLdcInsn(Type.getType(Type.getDescriptor(clazz))); - } - } - - public static void visitPrimitiveValueOf(MethodVisitor mv, Class clazz) { - if (clazz == boolean.class) { - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false); - } else if (clazz == byte.class) { - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;", false); - } else if (clazz == short.class) { - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;", false); - } else if (clazz == char.class) { - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;", false); - } else if (clazz == int.class) { - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false); - } else if (clazz == float.class) { - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", false); - } else if (clazz == long.class) { - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;", false); - } else if (clazz == double.class) { - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", false); - } - } - - public static void visitCheckCast(MethodVisitor mv, Class clazz) { - if (clazz == boolean.class) { - mv.visitTypeInsn(CHECKCAST, "java/lang/Boolean"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z", false); - } else if (clazz == byte.class) { - mv.visitTypeInsn(CHECKCAST, "java/lang/Byte"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B", false); - } else if (clazz == short.class) { - mv.visitTypeInsn(CHECKCAST, "java/lang/Short"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S", false); - } else if (clazz == char.class) { - mv.visitTypeInsn(CHECKCAST, "java/lang/Character"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C", false); - } else if (clazz == int.class) { - mv.visitTypeInsn(CHECKCAST, "java/lang/Integer"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false); - } else if (clazz == float.class) { - mv.visitTypeInsn(CHECKCAST, "java/lang/Float"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F", false); - } else if (clazz == long.class) { - mv.visitTypeInsn(CHECKCAST, "java/lang/Long"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J", false); - } else if (clazz == double.class) { - mv.visitTypeInsn(CHECKCAST, "java/lang/Double"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D", false); - } else { - mv.visitTypeInsn(CHECKCAST, clazz.getName().replace('.', '/')); - } - } - - public static void visitPrimitiveVirtual(MethodVisitor mv, Class clazz) { - if (clazz == boolean.class) { - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z", false); - } else if (clazz == byte.class) { - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B", false); - } else if (clazz == short.class) { - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S", false); - } else if (clazz == char.class) { - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C", false); - } else if (clazz == int.class) { - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false); - } else if (clazz == float.class) { - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F", false); - } else if (clazz == long.class) { - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J", false); - } else if (clazz == double.class) { - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D", false); - } - } -} +/* + * + */ +package org.redkale.asm; + +import static org.redkale.asm.Opcodes.BIPUSH; +import static org.redkale.asm.Opcodes.CHECKCAST; +import static org.redkale.asm.Opcodes.GETSTATIC; +import static org.redkale.asm.Opcodes.ICONST_0; +import static org.redkale.asm.Opcodes.INVOKESTATIC; +import static org.redkale.asm.Opcodes.INVOKEVIRTUAL; +import static org.redkale.asm.Opcodes.SIPUSH; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import org.redkale.util.RedkaleException; + +/** + * ASM简单的工具方法
+ * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public final class Asms { + + private Asms() {} + + public static Handle createLambdaMetaHandle() { + return new Handle( + Opcodes.H_INVOKESTATIC, + "java/lang/invoke/LambdaMetafactory", + "metafactory", + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;", + false); + } + + public static void visitAnnotation(final AnnotationVisitor av, final Annotation ann) { + try { + for (Method anm : ann.annotationType().getMethods()) { + final String mname = anm.getName(); + if ("equals".equals(mname) + || "hashCode".equals(mname) + || "toString".equals(mname) + || "annotationType".equals(mname)) { + continue; + } + final Object r = anm.invoke(ann); + if (r instanceof String[]) { + AnnotationVisitor av1 = av.visitArray(mname); + for (String item : (String[]) r) { + av1.visit(null, item); + } + av1.visitEnd(); + } else if (r instanceof Class[]) { + AnnotationVisitor av1 = av.visitArray(mname); + for (Class item : (Class[]) r) { + av1.visit(null, Type.getType(item)); + } + av1.visitEnd(); + } else if (r instanceof Enum[]) { + AnnotationVisitor av1 = av.visitArray(mname); + for (Enum item : (Enum[]) r) { + av1.visitEnum(null, Type.getDescriptor(item.getClass()), ((Enum) item).name()); + } + av1.visitEnd(); + } else if (r instanceof Annotation[]) { + AnnotationVisitor av1 = av.visitArray(mname); + for (Annotation item : (Annotation[]) r) { + visitAnnotation( + av1.visitAnnotation(null, Type.getDescriptor(((Annotation) item).annotationType())), + item); + } + av1.visitEnd(); + } else if (r instanceof Class) { + av.visit(mname, Type.getType((Class) r)); + } else if (r instanceof Enum) { + av.visitEnum(mname, Type.getDescriptor(r.getClass()), ((Enum) r).name()); + } else if (r instanceof Annotation) { + visitAnnotation( + av.visitAnnotation(null, Type.getDescriptor(((Annotation) r).annotationType())), + (Annotation) r); + } else { + av.visit(mname, r); + } + } + av.visitEnd(); + } catch (Exception e) { + throw new RedkaleException(e); + } + } + + public static void visitInsn(MethodVisitor mv, int num) { + if (num < 6) { + mv.visitInsn(ICONST_0 + num); + } else if (num <= Byte.MAX_VALUE) { + mv.visitIntInsn(BIPUSH, num); + } else if (num <= Short.MAX_VALUE) { + mv.visitIntInsn(SIPUSH, num); + } else { + mv.visitLdcInsn(num); + } + } + + public static void visitFieldInsn(MethodVisitor mv, Class clazz) { + if (clazz == boolean.class) { + mv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "TYPE", "Ljava/lang/Class;"); + } else if (clazz == byte.class) { + mv.visitFieldInsn(GETSTATIC, "java/lang/Byte", "TYPE", "Ljava/lang/Class;"); + } else if (clazz == char.class) { + mv.visitFieldInsn(GETSTATIC, "java/lang/Character", "TYPE", "Ljava/lang/Class;"); + } else if (clazz == short.class) { + mv.visitFieldInsn(GETSTATIC, "java/lang/Short", "TYPE", "Ljava/lang/Class;"); + } else if (clazz == int.class) { + mv.visitFieldInsn(GETSTATIC, "java/lang/Integer", "TYPE", "Ljava/lang/Class;"); + } else if (clazz == float.class) { + mv.visitFieldInsn(GETSTATIC, "java/lang/Float", "TYPE", "Ljava/lang/Class;"); + } else if (clazz == long.class) { + mv.visitFieldInsn(GETSTATIC, "java/lang/Long", "TYPE", "Ljava/lang/Class;"); + } else if (clazz == double.class) { + mv.visitFieldInsn(GETSTATIC, "java/lang/Double", "TYPE", "Ljava/lang/Class;"); + } else { + mv.visitLdcInsn(Type.getType(Type.getDescriptor(clazz))); + } + } + + public static void visitPrimitiveValueOf(MethodVisitor mv, Class clazz) { + if (clazz == boolean.class) { + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false); + } else if (clazz == byte.class) { + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;", false); + } else if (clazz == short.class) { + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;", false); + } else if (clazz == char.class) { + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;", false); + } else if (clazz == int.class) { + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false); + } else if (clazz == float.class) { + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", false); + } else if (clazz == long.class) { + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;", false); + } else if (clazz == double.class) { + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", false); + } + } + + public static void visitCheckCast(MethodVisitor mv, Class clazz) { + if (clazz == boolean.class) { + mv.visitTypeInsn(CHECKCAST, "java/lang/Boolean"); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z", false); + } else if (clazz == byte.class) { + mv.visitTypeInsn(CHECKCAST, "java/lang/Byte"); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B", false); + } else if (clazz == short.class) { + mv.visitTypeInsn(CHECKCAST, "java/lang/Short"); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S", false); + } else if (clazz == char.class) { + mv.visitTypeInsn(CHECKCAST, "java/lang/Character"); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C", false); + } else if (clazz == int.class) { + mv.visitTypeInsn(CHECKCAST, "java/lang/Integer"); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false); + } else if (clazz == float.class) { + mv.visitTypeInsn(CHECKCAST, "java/lang/Float"); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F", false); + } else if (clazz == long.class) { + mv.visitTypeInsn(CHECKCAST, "java/lang/Long"); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J", false); + } else if (clazz == double.class) { + mv.visitTypeInsn(CHECKCAST, "java/lang/Double"); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D", false); + } else { + mv.visitTypeInsn(CHECKCAST, clazz.getName().replace('.', '/')); + } + } + + public static void visitPrimitiveVirtual(MethodVisitor mv, Class clazz) { + if (clazz == boolean.class) { + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z", false); + } else if (clazz == byte.class) { + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B", false); + } else if (clazz == short.class) { + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S", false); + } else if (clazz == char.class) { + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C", false); + } else if (clazz == int.class) { + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false); + } else if (clazz == float.class) { + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F", false); + } else if (clazz == long.class) { + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J", false); + } else if (clazz == double.class) { + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D", false); + } + } +} diff --git a/src/main/java/org/redkale/asm/Attribute.java b/src/main/java/org/redkale/asm/Attribute.java index 20ef03d5a..0cf206b99 100644 --- a/src/main/java/org/redkale/asm/Attribute.java +++ b/src/main/java/org/redkale/asm/Attribute.java @@ -1,312 +1,312 @@ -/* - * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */ - -/* - * - * - * - * - * - * ASM: a very small and fast Java bytecode manipulation framework - * Copyright (c) 2000-2011 INRIA, France Telecom - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.redkale.asm; - -import java.util.Arrays; - -/** - * A non standard class, field, method or code attribute. - * - * @author Eric Bruneton - * @author Eugene Kuleshov - */ -public class Attribute { - - /** The type of this attribute. */ - public final String type; - - /** The raw value of this attribute, used only for unknown attributes. */ - byte[] value; - - /** The next attribute in this attribute list. May be <tt>null</tt>. */ - Attribute next; - - /** - * Constructs a new empty attribute. - * - * @param type the type of the attribute. - */ - protected Attribute(final String type) { - this.type = type; - } - - /** - * Returns <tt>true</tt> if this type of attribute is unknown. The default implementation of this - * method always returns <tt>true</tt>. - * - * @return <tt>true</tt> if this type of attribute is unknown. - */ - public boolean isUnknown() { - return true; - } - - /** - * Returns <tt>true</tt> if this type of attribute is a code attribute. - * - * @return <tt>true</tt> if this type of attribute is a code attribute. - */ - public boolean isCodeAttribute() { - return false; - } - - /** - * Returns the labels corresponding to this attribute. - * - * @return the labels corresponding to this attribute, or <tt>null</tt> if this attribute is not a - * code attribute that contains labels. - */ - protected Label[] getLabels() { - return null; - } - - /** - * Reads a {@link #type type} attribute. This method must return a new {@link Attribute} object, of type - * {@link #type type}, corresponding to the <tt>len</tt> bytes starting at the given offset, in the - * given class reader. - * - * @param cr the class that contains the attribute to be read. - * @param off index of the first byte of the attribute's content in {@link ClassReader#b cr.b}. The 6 attribute - * header bytes, containing the type and the length of the attribute, are not taken into account here. - * @param len the length of the attribute's content. - * @param buf buffer to be used to call {@link ClassReader#readUTF8 readUTF8}, - * {@link ClassReader#readClass(int,char[]) readClass} or {@link ClassReader#readConst readConst}. - * @param codeOff index of the first byte of code's attribute content in {@link ClassReader#b cr.b}, or -1 if the - * attribute to be read is not a code attribute. The 6 attribute header bytes, containing the type and the - * length of the attribute, are not taken into account here. - * @param labels the labels of the method's code, or <tt>null</tt> if the attribute to be read is - * not a code attribute. - * @return a new {@link Attribute} object corresponding to the given bytes. - */ - protected Attribute read( - final ClassReader cr, - final int off, - final int len, - final char[] buf, - final int codeOff, - final Label[] labels) { - Attribute attr = new Attribute(type); - attr.value = new byte[len]; - System.arraycopy(cr.b, off, attr.value, 0, len); - return attr; - } - - /** - * Returns the byte array form of this attribute. - * - * @param cw the class to which this attribute must be added. This parameter can be used to add to the constant pool - * of this class the items that corresponds to this attribute. - * @param code the bytecode of the method corresponding to this code attribute, or <tt>null</tt> if - * this attribute is not a code attributes. - * @param len the length of the bytecode of the method corresponding to this code attribute, or - * <tt>null</tt> if this attribute is not a code attribute. - * @param maxStack the maximum stack size of the method corresponding to this code attribute, or -1 if this - * attribute is not a code attribute. - * @param maxLocals the maximum number of local variables of the method corresponding to this code attribute, or -1 - * if this attribute is not a code attribute. - * @return the byte array form of this attribute. - */ - protected ByteVector write( - final ClassWriter cw, final byte[] code, final int len, final int maxStack, final int maxLocals) { - ByteVector v = new ByteVector(); - v.data = value; - v.length = value.length; - return v; - } - - /** - * Returns the length of the attribute list that begins with this attribute. - * - * @return the length of the attribute list that begins with this attribute. - */ - final int getCount() { - int count = 0; - Attribute attr = this; - while (attr != null) { - count += 1; - attr = attr.next; - } - return count; - } - - /** - * Returns the size of all the attributes in this attribute list. - * - * @param cw the class writer to be used to convert the attributes into byte arrays, with the {@link #write write} - * method. - * @param code the bytecode of the method corresponding to these code attributes, or <tt>null</tt> - * if these attributes are not code attributes. - * @param len the length of the bytecode of the method corresponding to these code attributes, or - * <tt>null</tt> if these attributes are not code attributes. - * @param maxStack the maximum stack size of the method corresponding to these code attributes, or -1 if these - * attributes are not code attributes. - * @param maxLocals the maximum number of local variables of the method corresponding to these code attributes, or - * -1 if these attributes are not code attributes. - * @return the size of all the attributes in this attribute list. This size includes the size of the attribute - * headers. - */ - final int getSize(final ClassWriter cw, final byte[] code, final int len, final int maxStack, final int maxLocals) { - Attribute attr = this; - int size = 0; - while (attr != null) { - cw.newUTF8(attr.type); - size += attr.write(cw, code, len, maxStack, maxLocals).length + 6; - attr = attr.next; - } - return size; - } - - /** - * Writes all the attributes of this attribute list in the given byte vector. - * - * @param cw the class writer to be used to convert the attributes into byte arrays, with the {@link #write write} - * method. - * @param code the bytecode of the method corresponding to these code attributes, or <tt>null</tt> - * if these attributes are not code attributes. - * @param len the length of the bytecode of the method corresponding to these code attributes, or - * <tt>null</tt> if these attributes are not code attributes. - * @param maxStack the maximum stack size of the method corresponding to these code attributes, or -1 if these - * attributes are not code attributes. - * @param maxLocals the maximum number of local variables of the method corresponding to these code attributes, or - * -1 if these attributes are not code attributes. - * @param out where the attributes must be written. - */ - final void put( - final ClassWriter cw, - final byte[] code, - final int len, - final int maxStack, - final int maxLocals, - final ByteVector out) { - Attribute attr = this; - while (attr != null) { - ByteVector b = attr.write(cw, code, len, maxStack, maxLocals); - out.putShort(cw.newUTF8(attr.type)).putInt(b.length); - out.putByteArray(b.data, 0, b.length); - attr = attr.next; - } - } - - // The stuff below is temporary - once proper support for nestmate attribute has been added, it can be safely - // removed. - // see also changes in ClassReader.accept. - /** */ - public static class NestMembers extends Attribute { - /** */ - public NestMembers() { - super("NestMembers"); - } - - byte[] bytes; - String[] classes; - - @Override - protected Attribute read(ClassReader cr, int off, int len, char[] buf, int codeOff, Label[] labels) { - int offset = off; - NestMembers a = new NestMembers(); - int size = cr.readShort(off); - a.classes = new String[size]; - off += 2; - for (int i = 0; i < size; i++) { - a.classes[i] = cr.readClass(off, buf); - off += 2; - } - a.bytes = Arrays.copyOfRange(cr.b, offset, offset + len); - return a; - } - - @Override - protected ByteVector write(ClassWriter cw, byte[] code, int len, int maxStack, int maxLocals) { - ByteVector v = new ByteVector(bytes.length); - v.putShort(classes.length); - for (String s : classes) { - v.putShort(cw.newClass(s)); - } - return v; - } - } - - /** */ - public static class NestHost extends Attribute { - - byte[] bytes; - String clazz; - /** */ - public NestHost() { - super("NestHost"); - } - - @Override - protected Attribute read(ClassReader cr, int off, int len, char[] buf, int codeOff, Label[] labels) { - int offset = off; - NestHost a = new NestHost(); - a.clazz = cr.readClass(off, buf); - a.bytes = Arrays.copyOfRange(cr.b, offset, offset + len); - return a; - } - - @Override - protected ByteVector write(ClassWriter cw, byte[] code, int len, int maxStack, int maxLocals) { - ByteVector v = new ByteVector(bytes.length); - v.putShort(cw.newClass(clazz)); - return v; - } - } - - static final Attribute[] DEFAULT_ATTRIBUTE_PROTOS = new Attribute[] {new NestMembers(), new NestHost()}; -} +/* + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ + +/* + * + * + * + * + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.redkale.asm; + +import java.util.Arrays; + +/** + * A non standard class, field, method or code attribute. + * + * @author Eric Bruneton + * @author Eugene Kuleshov + */ +public class Attribute { + + /** The type of this attribute. */ + public final String type; + + /** The raw value of this attribute, used only for unknown attributes. */ + byte[] value; + + /** The next attribute in this attribute list. May be <tt>null</tt>. */ + Attribute next; + + /** + * Constructs a new empty attribute. + * + * @param type the type of the attribute. + */ + protected Attribute(final String type) { + this.type = type; + } + + /** + * Returns <tt>true</tt> if this type of attribute is unknown. The default implementation of this + * method always returns <tt>true</tt>. + * + * @return <tt>true</tt> if this type of attribute is unknown. + */ + public boolean isUnknown() { + return true; + } + + /** + * Returns <tt>true</tt> if this type of attribute is a code attribute. + * + * @return <tt>true</tt> if this type of attribute is a code attribute. + */ + public boolean isCodeAttribute() { + return false; + } + + /** + * Returns the labels corresponding to this attribute. + * + * @return the labels corresponding to this attribute, or <tt>null</tt> if this attribute is not a + * code attribute that contains labels. + */ + protected Label[] getLabels() { + return null; + } + + /** + * Reads a {@link #type type} attribute. This method must return a new {@link Attribute} object, of type + * {@link #type type}, corresponding to the <tt>len</tt> bytes starting at the given offset, in the + * given class reader. + * + * @param cr the class that contains the attribute to be read. + * @param off index of the first byte of the attribute's content in {@link ClassReader#b cr.b}. The 6 attribute + * header bytes, containing the type and the length of the attribute, are not taken into account here. + * @param len the length of the attribute's content. + * @param buf buffer to be used to call {@link ClassReader#readUTF8 readUTF8}, + * {@link ClassReader#readClass(int,char[]) readClass} or {@link ClassReader#readConst readConst}. + * @param codeOff index of the first byte of code's attribute content in {@link ClassReader#b cr.b}, or -1 if the + * attribute to be read is not a code attribute. The 6 attribute header bytes, containing the type and the + * length of the attribute, are not taken into account here. + * @param labels the labels of the method's code, or <tt>null</tt> if the attribute to be read is + * not a code attribute. + * @return a new {@link Attribute} object corresponding to the given bytes. + */ + protected Attribute read( + final ClassReader cr, + final int off, + final int len, + final char[] buf, + final int codeOff, + final Label[] labels) { + Attribute attr = new Attribute(type); + attr.value = new byte[len]; + System.arraycopy(cr.b, off, attr.value, 0, len); + return attr; + } + + /** + * Returns the byte array form of this attribute. + * + * @param cw the class to which this attribute must be added. This parameter can be used to add to the constant pool + * of this class the items that corresponds to this attribute. + * @param code the bytecode of the method corresponding to this code attribute, or <tt>null</tt> if + * this attribute is not a code attributes. + * @param len the length of the bytecode of the method corresponding to this code attribute, or + * <tt>null</tt> if this attribute is not a code attribute. + * @param maxStack the maximum stack size of the method corresponding to this code attribute, or -1 if this + * attribute is not a code attribute. + * @param maxLocals the maximum number of local variables of the method corresponding to this code attribute, or -1 + * if this attribute is not a code attribute. + * @return the byte array form of this attribute. + */ + protected ByteVector write( + final ClassWriter cw, final byte[] code, final int len, final int maxStack, final int maxLocals) { + ByteVector v = new ByteVector(); + v.data = value; + v.length = value.length; + return v; + } + + /** + * Returns the length of the attribute list that begins with this attribute. + * + * @return the length of the attribute list that begins with this attribute. + */ + final int getCount() { + int count = 0; + Attribute attr = this; + while (attr != null) { + count += 1; + attr = attr.next; + } + return count; + } + + /** + * Returns the size of all the attributes in this attribute list. + * + * @param cw the class writer to be used to convert the attributes into byte arrays, with the {@link #write write} + * method. + * @param code the bytecode of the method corresponding to these code attributes, or <tt>null</tt> + * if these attributes are not code attributes. + * @param len the length of the bytecode of the method corresponding to these code attributes, or + * <tt>null</tt> if these attributes are not code attributes. + * @param maxStack the maximum stack size of the method corresponding to these code attributes, or -1 if these + * attributes are not code attributes. + * @param maxLocals the maximum number of local variables of the method corresponding to these code attributes, or + * -1 if these attributes are not code attributes. + * @return the size of all the attributes in this attribute list. This size includes the size of the attribute + * headers. + */ + final int getSize(final ClassWriter cw, final byte[] code, final int len, final int maxStack, final int maxLocals) { + Attribute attr = this; + int size = 0; + while (attr != null) { + cw.newUTF8(attr.type); + size += attr.write(cw, code, len, maxStack, maxLocals).length + 6; + attr = attr.next; + } + return size; + } + + /** + * Writes all the attributes of this attribute list in the given byte vector. + * + * @param cw the class writer to be used to convert the attributes into byte arrays, with the {@link #write write} + * method. + * @param code the bytecode of the method corresponding to these code attributes, or <tt>null</tt> + * if these attributes are not code attributes. + * @param len the length of the bytecode of the method corresponding to these code attributes, or + * <tt>null</tt> if these attributes are not code attributes. + * @param maxStack the maximum stack size of the method corresponding to these code attributes, or -1 if these + * attributes are not code attributes. + * @param maxLocals the maximum number of local variables of the method corresponding to these code attributes, or + * -1 if these attributes are not code attributes. + * @param out where the attributes must be written. + */ + final void put( + final ClassWriter cw, + final byte[] code, + final int len, + final int maxStack, + final int maxLocals, + final ByteVector out) { + Attribute attr = this; + while (attr != null) { + ByteVector b = attr.write(cw, code, len, maxStack, maxLocals); + out.putShort(cw.newUTF8(attr.type)).putInt(b.length); + out.putByteArray(b.data, 0, b.length); + attr = attr.next; + } + } + + // The stuff below is temporary - once proper support for nestmate attribute has been added, it can be safely + // removed. + // see also changes in ClassReader.accept. + /** */ + public static class NestMembers extends Attribute { + /** */ + public NestMembers() { + super("NestMembers"); + } + + byte[] bytes; + String[] classes; + + @Override + protected Attribute read(ClassReader cr, int off, int len, char[] buf, int codeOff, Label[] labels) { + int offset = off; + NestMembers a = new NestMembers(); + int size = cr.readShort(off); + a.classes = new String[size]; + off += 2; + for (int i = 0; i < size; i++) { + a.classes[i] = cr.readClass(off, buf); + off += 2; + } + a.bytes = Arrays.copyOfRange(cr.b, offset, offset + len); + return a; + } + + @Override + protected ByteVector write(ClassWriter cw, byte[] code, int len, int maxStack, int maxLocals) { + ByteVector v = new ByteVector(bytes.length); + v.putShort(classes.length); + for (String s : classes) { + v.putShort(cw.newClass(s)); + } + return v; + } + } + + /** */ + public static class NestHost extends Attribute { + + byte[] bytes; + String clazz; + /** */ + public NestHost() { + super("NestHost"); + } + + @Override + protected Attribute read(ClassReader cr, int off, int len, char[] buf, int codeOff, Label[] labels) { + int offset = off; + NestHost a = new NestHost(); + a.clazz = cr.readClass(off, buf); + a.bytes = Arrays.copyOfRange(cr.b, offset, offset + len); + return a; + } + + @Override + protected ByteVector write(ClassWriter cw, byte[] code, int len, int maxStack, int maxLocals) { + ByteVector v = new ByteVector(bytes.length); + v.putShort(cw.newClass(clazz)); + return v; + } + } + + static final Attribute[] DEFAULT_ATTRIBUTE_PROTOS = new Attribute[] {new NestMembers(), new NestHost()}; +} diff --git a/src/main/java/org/redkale/asm/ByteVector.java b/src/main/java/org/redkale/asm/ByteVector.java index 9341072c6..70840aacd 100644 --- a/src/main/java/org/redkale/asm/ByteVector.java +++ b/src/main/java/org/redkale/asm/ByteVector.java @@ -1,331 +1,331 @@ -/* - * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */ - -/* - * - * - * - * - * - * ASM: a very small and fast Java bytecode manipulation framework - * Copyright (c) 2000-2011 INRIA, France Telecom - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.redkale.asm; - -/** - * A dynamically extensible vector of bytes. This class is roughly equivalent to a DataOutputStream on top of a - * ByteArrayOutputStream, but is more efficient. - * - * @author Eric Bruneton - */ -public class ByteVector { - - /** The content of this vector. */ - byte[] data; - - /** Actual number of bytes in this vector. */ - int length; - - /** Constructs a new {@link ByteVector ByteVector} with a default initial size. */ - public ByteVector() { - data = new byte[64]; - } - - /** - * Constructs a new {@link ByteVector ByteVector} with the given initial size. - * - * @param initialSize the initial size of the byte vector to be constructed. - */ - public ByteVector(final int initialSize) { - data = new byte[initialSize]; - } - - /** - * Puts a byte into this byte vector. The byte vector is automatically enlarged if necessary. - * - * @param b a byte. - * @return this byte vector. - */ - public ByteVector putByte(final int b) { - int length = this.length; - if (length + 1 > data.length) { - enlarge(1); - } - data[length++] = (byte) b; - this.length = length; - return this; - } - - /** - * Puts two bytes into this byte vector. The byte vector is automatically enlarged if necessary. - * - * @param b1 a byte. - * @param b2 another byte. - * @return this byte vector. - */ - ByteVector put11(final int b1, final int b2) { - int length = this.length; - if (length + 2 > data.length) { - enlarge(2); - } - byte[] data = this.data; - data[length++] = (byte) b1; - data[length++] = (byte) b2; - this.length = length; - return this; - } - - /** - * Puts a short into this byte vector. The byte vector is automatically enlarged if necessary. - * - * @param s a short. - * @return this byte vector. - */ - public ByteVector putShort(final int s) { - int length = this.length; - if (length + 2 > data.length) { - enlarge(2); - } - byte[] data = this.data; - data[length++] = (byte) (s >>> 8); - data[length++] = (byte) s; - this.length = length; - return this; - } - - /** - * Puts a byte and a short into this byte vector. The byte vector is automatically enlarged if necessary. - * - * @param b a byte. - * @param s a short. - * @return this byte vector. - */ - ByteVector put12(final int b, final int s) { - int length = this.length; - if (length + 3 > data.length) { - enlarge(3); - } - byte[] data = this.data; - data[length++] = (byte) b; - data[length++] = (byte) (s >>> 8); - data[length++] = (byte) s; - this.length = length; - return this; - } - - /** - * Puts an int into this byte vector. The byte vector is automatically enlarged if necessary. - * - * @param i an int. - * @return this byte vector. - */ - public ByteVector putInt(final int i) { - int length = this.length; - if (length + 4 > data.length) { - enlarge(4); - } - byte[] data = this.data; - data[length++] = (byte) (i >>> 24); - data[length++] = (byte) (i >>> 16); - data[length++] = (byte) (i >>> 8); - data[length++] = (byte) i; - this.length = length; - return this; - } - - /** - * Puts a long into this byte vector. The byte vector is automatically enlarged if necessary. - * - * @param l a long. - * @return this byte vector. - */ - public ByteVector putLong(final long l) { - int length = this.length; - if (length + 8 > data.length) { - enlarge(8); - } - byte[] data = this.data; - int i = (int) (l >>> 32); - data[length++] = (byte) (i >>> 24); - data[length++] = (byte) (i >>> 16); - data[length++] = (byte) (i >>> 8); - data[length++] = (byte) i; - i = (int) l; - data[length++] = (byte) (i >>> 24); - data[length++] = (byte) (i >>> 16); - data[length++] = (byte) (i >>> 8); - data[length++] = (byte) i; - this.length = length; - return this; - } - - /** - * Puts an UTF8 string into this byte vector. The byte vector is automatically enlarged if necessary. - * - * @param s a String whose UTF8 encoded length must be less than 65536. - * @return this byte vector. - */ - public ByteVector putUTF8(final String s) { - int charLength = s.length(); - if (charLength > 65535) { - throw new IllegalArgumentException(); - } - int len = length; - if (len + 2 + charLength > data.length) { - enlarge(2 + charLength); - } - byte[] data = this.data; - // optimistic algorithm: instead of computing the byte length and then - // serializing the string (which requires two loops), we assume the byte - // length is equal to char length (which is the most frequent case), and - // we start serializing the string right away. During the serialization, - // if we find that this assumption is wrong, we continue with the - // general method. - data[len++] = (byte) (charLength >>> 8); - data[len++] = (byte) charLength; - for (int i = 0; i < charLength; ++i) { - char c = s.charAt(i); - if (c >= '\001' && c <= '\177') { - data[len++] = (byte) c; - } else { - length = len; - return encodeUTF8(s, i, 65535); - } - } - length = len; - return this; - } - - /** - * Puts an UTF8 string into this byte vector. The byte vector is automatically enlarged if necessary. The string - * length is encoded in two bytes before the encoded characters, if there is space for that (i.e. if this.length - i - * - 2 >= 0). - * - * @param s the String to encode. - * @param i the index of the first character to encode. The previous characters are supposed to have already been - * encoded, using only one byte per character. - * @param maxByteLength the maximum byte length of the encoded string, including the already encoded characters. - * @return this byte vector. - */ - ByteVector encodeUTF8(final String s, int i, int maxByteLength) { - int charLength = s.length(); - int byteLength = i; - char c; - for (int j = i; j < charLength; ++j) { - c = s.charAt(j); - if (c >= '\001' && c <= '\177') { - byteLength++; - } else if (c > '\u07FF') { - byteLength += 3; - } else { - byteLength += 2; - } - } - if (byteLength > maxByteLength) { - throw new IllegalArgumentException(); - } - int start = length - i - 2; - if (start >= 0) { - data[start] = (byte) (byteLength >>> 8); - data[start + 1] = (byte) byteLength; - } - if (length + byteLength - i > data.length) { - enlarge(byteLength - i); - } - int len = length; - for (int j = i; j < charLength; ++j) { - c = s.charAt(j); - if (c >= '\001' && c <= '\177') { - data[len++] = (byte) c; - } else if (c > '\u07FF') { - data[len++] = (byte) (0xE0 | c >> 12 & 0xF); - data[len++] = (byte) (0x80 | c >> 6 & 0x3F); - data[len++] = (byte) (0x80 | c & 0x3F); - } else { - data[len++] = (byte) (0xC0 | c >> 6 & 0x1F); - data[len++] = (byte) (0x80 | c & 0x3F); - } - } - length = len; - return this; - } - - /** - * Puts an array of bytes into this byte vector. The byte vector is automatically enlarged if necessary. - * - * @param b an array of bytes. May be <tt>null</tt> to put <tt>len</tt> null bytes - * into this byte vector. - * @param off index of the fist byte of b that must be copied. - * @param len number of bytes of b that must be copied. - * @return this byte vector. - */ - public ByteVector putByteArray(final byte[] b, final int off, final int len) { - if (length + len > data.length) { - enlarge(len); - } - if (b != null) { - System.arraycopy(b, off, data, length, len); - } - length += len; - return this; - } - - /** - * Enlarge this byte vector so that it can receive n more bytes. - * - * @param size number of additional bytes that this byte vector should be able to receive. - */ - private void enlarge(final int size) { - int length1 = 2 * data.length; - int length2 = length + size; - byte[] newData = new byte[length1 > length2 ? length1 : length2]; - System.arraycopy(data, 0, newData, 0, length); - data = newData; - } -} +/* + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ + +/* + * + * + * + * + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.redkale.asm; + +/** + * A dynamically extensible vector of bytes. This class is roughly equivalent to a DataOutputStream on top of a + * ByteArrayOutputStream, but is more efficient. + * + * @author Eric Bruneton + */ +public class ByteVector { + + /** The content of this vector. */ + byte[] data; + + /** Actual number of bytes in this vector. */ + int length; + + /** Constructs a new {@link ByteVector ByteVector} with a default initial size. */ + public ByteVector() { + data = new byte[64]; + } + + /** + * Constructs a new {@link ByteVector ByteVector} with the given initial size. + * + * @param initialSize the initial size of the byte vector to be constructed. + */ + public ByteVector(final int initialSize) { + data = new byte[initialSize]; + } + + /** + * Puts a byte into this byte vector. The byte vector is automatically enlarged if necessary. + * + * @param b a byte. + * @return this byte vector. + */ + public ByteVector putByte(final int b) { + int length = this.length; + if (length + 1 > data.length) { + enlarge(1); + } + data[length++] = (byte) b; + this.length = length; + return this; + } + + /** + * Puts two bytes into this byte vector. The byte vector is automatically enlarged if necessary. + * + * @param b1 a byte. + * @param b2 another byte. + * @return this byte vector. + */ + ByteVector put11(final int b1, final int b2) { + int length = this.length; + if (length + 2 > data.length) { + enlarge(2); + } + byte[] data = this.data; + data[length++] = (byte) b1; + data[length++] = (byte) b2; + this.length = length; + return this; + } + + /** + * Puts a short into this byte vector. The byte vector is automatically enlarged if necessary. + * + * @param s a short. + * @return this byte vector. + */ + public ByteVector putShort(final int s) { + int length = this.length; + if (length + 2 > data.length) { + enlarge(2); + } + byte[] data = this.data; + data[length++] = (byte) (s >>> 8); + data[length++] = (byte) s; + this.length = length; + return this; + } + + /** + * Puts a byte and a short into this byte vector. The byte vector is automatically enlarged if necessary. + * + * @param b a byte. + * @param s a short. + * @return this byte vector. + */ + ByteVector put12(final int b, final int s) { + int length = this.length; + if (length + 3 > data.length) { + enlarge(3); + } + byte[] data = this.data; + data[length++] = (byte) b; + data[length++] = (byte) (s >>> 8); + data[length++] = (byte) s; + this.length = length; + return this; + } + + /** + * Puts an int into this byte vector. The byte vector is automatically enlarged if necessary. + * + * @param i an int. + * @return this byte vector. + */ + public ByteVector putInt(final int i) { + int length = this.length; + if (length + 4 > data.length) { + enlarge(4); + } + byte[] data = this.data; + data[length++] = (byte) (i >>> 24); + data[length++] = (byte) (i >>> 16); + data[length++] = (byte) (i >>> 8); + data[length++] = (byte) i; + this.length = length; + return this; + } + + /** + * Puts a long into this byte vector. The byte vector is automatically enlarged if necessary. + * + * @param l a long. + * @return this byte vector. + */ + public ByteVector putLong(final long l) { + int length = this.length; + if (length + 8 > data.length) { + enlarge(8); + } + byte[] data = this.data; + int i = (int) (l >>> 32); + data[length++] = (byte) (i >>> 24); + data[length++] = (byte) (i >>> 16); + data[length++] = (byte) (i >>> 8); + data[length++] = (byte) i; + i = (int) l; + data[length++] = (byte) (i >>> 24); + data[length++] = (byte) (i >>> 16); + data[length++] = (byte) (i >>> 8); + data[length++] = (byte) i; + this.length = length; + return this; + } + + /** + * Puts an UTF8 string into this byte vector. The byte vector is automatically enlarged if necessary. + * + * @param s a String whose UTF8 encoded length must be less than 65536. + * @return this byte vector. + */ + public ByteVector putUTF8(final String s) { + int charLength = s.length(); + if (charLength > 65535) { + throw new IllegalArgumentException(); + } + int len = length; + if (len + 2 + charLength > data.length) { + enlarge(2 + charLength); + } + byte[] data = this.data; + // optimistic algorithm: instead of computing the byte length and then + // serializing the string (which requires two loops), we assume the byte + // length is equal to char length (which is the most frequent case), and + // we start serializing the string right away. During the serialization, + // if we find that this assumption is wrong, we continue with the + // general method. + data[len++] = (byte) (charLength >>> 8); + data[len++] = (byte) charLength; + for (int i = 0; i < charLength; ++i) { + char c = s.charAt(i); + if (c >= '\001' && c <= '\177') { + data[len++] = (byte) c; + } else { + length = len; + return encodeUTF8(s, i, 65535); + } + } + length = len; + return this; + } + + /** + * Puts an UTF8 string into this byte vector. The byte vector is automatically enlarged if necessary. The string + * length is encoded in two bytes before the encoded characters, if there is space for that (i.e. if this.length - i + * - 2 >= 0). + * + * @param s the String to encode. + * @param i the index of the first character to encode. The previous characters are supposed to have already been + * encoded, using only one byte per character. + * @param maxByteLength the maximum byte length of the encoded string, including the already encoded characters. + * @return this byte vector. + */ + ByteVector encodeUTF8(final String s, int i, int maxByteLength) { + int charLength = s.length(); + int byteLength = i; + char c; + for (int j = i; j < charLength; ++j) { + c = s.charAt(j); + if (c >= '\001' && c <= '\177') { + byteLength++; + } else if (c > '\u07FF') { + byteLength += 3; + } else { + byteLength += 2; + } + } + if (byteLength > maxByteLength) { + throw new IllegalArgumentException(); + } + int start = length - i - 2; + if (start >= 0) { + data[start] = (byte) (byteLength >>> 8); + data[start + 1] = (byte) byteLength; + } + if (length + byteLength - i > data.length) { + enlarge(byteLength - i); + } + int len = length; + for (int j = i; j < charLength; ++j) { + c = s.charAt(j); + if (c >= '\001' && c <= '\177') { + data[len++] = (byte) c; + } else if (c > '\u07FF') { + data[len++] = (byte) (0xE0 | c >> 12 & 0xF); + data[len++] = (byte) (0x80 | c >> 6 & 0x3F); + data[len++] = (byte) (0x80 | c & 0x3F); + } else { + data[len++] = (byte) (0xC0 | c >> 6 & 0x1F); + data[len++] = (byte) (0x80 | c & 0x3F); + } + } + length = len; + return this; + } + + /** + * Puts an array of bytes into this byte vector. The byte vector is automatically enlarged if necessary. + * + * @param b an array of bytes. May be <tt>null</tt> to put <tt>len</tt> null bytes + * into this byte vector. + * @param off index of the fist byte of b that must be copied. + * @param len number of bytes of b that must be copied. + * @return this byte vector. + */ + public ByteVector putByteArray(final byte[] b, final int off, final int len) { + if (length + len > data.length) { + enlarge(len); + } + if (b != null) { + System.arraycopy(b, off, data, length, len); + } + length += len; + return this; + } + + /** + * Enlarge this byte vector so that it can receive n more bytes. + * + * @param size number of additional bytes that this byte vector should be able to receive. + */ + private void enlarge(final int size) { + int length1 = 2 * data.length; + int length2 = length + size; + byte[] newData = new byte[length1 > length2 ? length1 : length2]; + System.arraycopy(data, 0, newData, 0, length); + data = newData; + } +} diff --git a/src/main/java/org/redkale/asm/ClassReader.java b/src/main/java/org/redkale/asm/ClassReader.java index 9c0092f45..fd7c0b0e0 100644 --- a/src/main/java/org/redkale/asm/ClassReader.java +++ b/src/main/java/org/redkale/asm/ClassReader.java @@ -1,2610 +1,2610 @@ -/* - * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */ - -/* - * - * - * - * - * - * ASM: a very small and fast Java bytecode manipulation framework - * Copyright (c) 2000-2011 INRIA, France Telecom - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.redkale.asm; - -import java.io.IOException; -import java.io.InputStream; - -/** - * A Java class parser to make a {@link ClassVisitor} visit an existing class. This class parses a byte array conforming - * to the Java class file format and calls the appropriate visit methods of a given class visitor for each field, method - * and bytecode instruction encountered. - * - * @author Eric Bruneton - * @author Eugene Kuleshov - */ -public class ClassReader { - - /** - * Flag to skip method code. If this class is set CODE attribute won't be visited. This can be used, - * for example, to retrieve annotations for methods and method parameters. - */ - public static final int SKIP_CODE = 1; - - /** - * Flag to skip the debug information in the class. If this flag is set the debug information of the class is not - * visited, i.e. the {@link MethodVisitor#visitLocalVariable visitLocalVariable} and - * {@link MethodVisitor#visitLineNumber visitLineNumber} methods will not be called. - */ - public static final int SKIP_DEBUG = 2; - - /** - * Flag to skip the stack map frames in the class. If this flag is set the stack map frames of the class is not - * visited, i.e. the {@link MethodVisitor#visitFrame visitFrame} method will not be called. This flag is useful when - * the {@link ClassWriter#COMPUTE_FRAMES} option is used: it avoids visiting frames that will be ignored and - * recomputed from scratch in the class writer. - */ - public static final int SKIP_FRAMES = 4; - - /** - * Flag to expand the stack map frames. By default stack map frames are visited in their original format (i.e. - * "expanded" for classes whose version is less than V1_6, and "compressed" for the other classes). If this flag is - * set, stack map frames are always visited in expanded format (this option adds a decompression/recompression step - * in ClassReader and ClassWriter which degrades performances quite a lot). - */ - 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 not 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. The content of this array must not be modified. This field is intended for - * {@link Attribute} sub classes, and is normally not needed by class generators or adapters. - */ - public final byte[] b; - - /** - * The start index of each constant pool item in {@link #b b}, plus one. The one byte offset skips the constant pool - * item tag that indicates its type. - */ - private final int[] items; - - /** - * The String objects corresponding to the CONSTANT_Utf8 items. This cache avoids multiple parsing of a given - * CONSTANT_Utf8 constant pool item, which GREATLY improves performances (by a factor 2 to 3). This caching strategy - * could be extended to all constant pool items, but its benefit would not be so great for these items (because they - * are much less expensive to parse than CONSTANT_Utf8 items). - */ - private final String[] strings; - - /** Maximum length of the strings contained in the constant pool of the class. */ - private final int maxStringLength; - - /** Start index of the class header information (access, name...) in {@link #b b}. */ - public final int header; - - // ------------------------------------------------------------------------ - // Constructors - // ------------------------------------------------------------------------ - - /** - * Constructs a new {@link ClassReader} object. - * - * @param b the bytecode of the class to be read. - */ - public ClassReader(final byte[] b) { - this(b, 0, b.length); - } - - /** - * Constructs a new {@link ClassReader} object. - * - * @param b the bytecode of the class to be read. - * @param off the start offset of the class data. - * @param len the length of the class data. - */ - public ClassReader(final byte[] b, final int off, final int len) { - this.b = b; - // checks the class version - // if (readShort(off + 6) > Opcodes.V11) { - // throw new IllegalArgumentException(); - // } - // parses the constant pool - items = new int[readUnsignedShort(off + 8)]; - int n = items.length; - strings = new String[n]; - int max = 0; - int index = off + 10; - for (int i = 1; i < n; ++i) { - items[i] = index + 1; - int size; - switch (b[index]) { - case ClassWriter.FIELD: - case ClassWriter.METH: - case ClassWriter.IMETH: - case ClassWriter.INT: - case ClassWriter.FLOAT: - case ClassWriter.NAME_TYPE: - case ClassWriter.INDY: - // @@@ ClassWriter.CONDY - // Enables MethodHandles.lookup().defineClass to function correctly - // when it reads the class name - case 17: - size = 5; - break; - case ClassWriter.LONG: - case ClassWriter.DOUBLE: - size = 9; - ++i; - break; - case ClassWriter.UTF8: - size = 3 + readUnsignedShort(index + 1); - if (size > max) { - max = size; - } - break; - case ClassWriter.HANDLE: - size = 4; - break; - // case ClassWriter.CLASS: - // case ClassWriter.STR: - // case ClassWriter.MTYPE - // case ClassWriter.PACKAGE: - // case ClassWriter.MODULE: - default: - size = 3; - break; - } - index += size; - } - maxStringLength = max; - // the class header information starts just after the constant pool - header = index; - } - - /** - * Returns the class's access flags (see {@link Opcodes}). This value may not reflect Deprecated and Synthetic flags - * when bytecode is before 1.5 and those flags are represented by attributes. - * - * @return the class access flags - * @see ClassVisitor#visit(int, int, String, String, String, String[]) - */ - public int getAccess() { - return readUnsignedShort(header); - } - - /** - * Returns the internal name of the class (see {@link Type#getInternalName() getInternalName}). - * - * @return the internal class name - * @see ClassVisitor#visit(int, int, String, String, String, String[]) - */ - public String getClassName() { - return readClass(header + 2, new char[maxStringLength]); - } - - /** - * Returns the internal of name of the super class (see {@link Type#getInternalName() getInternalName}). For - * interfaces, the super class is {@link Object}. - * - * @return the internal name of super class, or <tt>null</tt> for {@link Object} class. - * @see ClassVisitor#visit(int, int, String, String, String, String[]) - */ - public String getSuperName() { - return readClass(header + 4, new char[maxStringLength]); - } - - /** - * Returns the internal names of the class's interfaces (see {@link Type#getInternalName() getInternalName}). - * - * @return the array of internal names for all implemented interfaces or <tt>null</tt>. - * @see ClassVisitor#visit(int, int, String, String, String, String[]) - */ - public String[] getInterfaces() { - int index = header + 6; - int n = readUnsignedShort(index); - String[] interfaces = new String[n]; - if (n > 0) { - char[] buf = new char[maxStringLength]; - for (int i = 0; i < n; ++i) { - index += 2; - interfaces[i] = readClass(index, buf); - } - } - return interfaces; - } - - /** - * Copies the constant pool data into the given {@link ClassWriter}. Should be called before the - * {@link #accept(ClassVisitor,int)} method. - * - * @param classWriter the {@link ClassWriter} to copy constant pool into. - */ - void copyPool(final ClassWriter classWriter) { - char[] buf = new char[maxStringLength]; - int ll = items.length; - Item[] items2 = new Item[ll]; - for (int i = 1; i < ll; i++) { - int index = items[i]; - int tag = b[index - 1]; - Item item = new Item(i); - int nameType; - switch (tag) { - case ClassWriter.FIELD: - case ClassWriter.METH: - case ClassWriter.IMETH: - nameType = items[readUnsignedShort(index + 2)]; - item.set(tag, readClass(index, buf), readUTF8(nameType, buf), readUTF8(nameType + 2, buf)); - break; - case ClassWriter.INT: - item.set(readInt(index)); - break; - case ClassWriter.FLOAT: - item.set(Float.intBitsToFloat(readInt(index))); - break; - case ClassWriter.NAME_TYPE: - item.set(tag, readUTF8(index, buf), readUTF8(index + 2, buf), null); - break; - case ClassWriter.LONG: - item.set(readLong(index)); - ++i; - break; - case ClassWriter.DOUBLE: - item.set(Double.longBitsToDouble(readLong(index))); - ++i; - break; - case ClassWriter.UTF8: { - String s = strings[i]; - if (s == null) { - index = items[i]; - s = strings[i] = readUTF(index + 2, readUnsignedShort(index), buf); - } - item.set(tag, s, null, null); - break; - } - case ClassWriter.HANDLE: { - int fieldOrMethodRef = items[readUnsignedShort(index + 1)]; - nameType = items[readUnsignedShort(fieldOrMethodRef + 2)]; - item.set( - ClassWriter.HANDLE_BASE + readByte(index), - readClass(fieldOrMethodRef, buf), - readUTF8(nameType, buf), - readUTF8(nameType + 2, buf)); - break; - } - case ClassWriter.INDY: - if (classWriter.bootstrapMethods == null) { - copyBootstrapMethods(classWriter, items2, buf); - } - nameType = items[readUnsignedShort(index + 2)]; - item.set(readUTF8(nameType, buf), readUTF8(nameType + 2, buf), readUnsignedShort(index)); - break; - // case ClassWriter.STR: - // case ClassWriter.CLASS: - // case ClassWriter.MTYPE: - // case ClassWriter.MODULE: - // case ClassWriter.PACKAGE: - default: - item.set(tag, readUTF8(index, buf), null, null); - break; - } - - int index2 = item.hashCode % items2.length; - item.next = items2[index2]; - items2[index2] = item; - } - - int off = items[1] - 1; - classWriter.pool.putByteArray(b, off, header - off); - classWriter.items = items2; - classWriter.threshold = (int) (0.75d * ll); - classWriter.index = ll; - } - - /** - * Copies the bootstrap method data into the given {@link ClassWriter}. Should be called before the - * {@link #accept(ClassVisitor,int)} method. - * - * @param classWriter the {@link ClassWriter} to copy bootstrap methods into. - */ - private void copyBootstrapMethods(final ClassWriter classWriter, final Item[] items, final char[] c) { - // finds the "BootstrapMethods" attribute - int u = getAttributes(); - boolean found = false; - for (int i = readUnsignedShort(u); i > 0; --i) { - String attrName = readUTF8(u + 2, c); - if ("BootstrapMethods".equals(attrName)) { - found = true; - break; - } - u += 6 + readInt(u + 4); - } - if (!found) { - return; - } - // copies the bootstrap methods in the class writer - int boostrapMethodCount = readUnsignedShort(u + 8); - for (int j = 0, v = u + 10; j < boostrapMethodCount; j++) { - int position = v - u - 10; - int hashCode = readConst(readUnsignedShort(v), c).hashCode(); - for (int k = readUnsignedShort(v + 2); k > 0; --k) { - hashCode ^= readConst(readUnsignedShort(v + 4), c).hashCode(); - v += 2; - } - v += 4; - Item item = new Item(j); - item.set(position, hashCode & 0x7FFFFFFF); - int index = item.hashCode % items.length; - item.next = items[index]; - items[index] = item; - } - int attrSize = readInt(u + 4); - ByteVector bootstrapMethods = new ByteVector(attrSize + 62); - bootstrapMethods.putByteArray(b, u + 10, attrSize - 2); - classWriter.bootstrapMethodsCount = boostrapMethodCount; - classWriter.bootstrapMethods = bootstrapMethods; - } - - /** - * Constructs a new {@link ClassReader} object. - * - * @param is an input stream from which to read the class. - * @throws IOException if a problem occurs during reading. - */ - public ClassReader(final InputStream is) throws IOException { - this(readClass(is, false)); - } - - /** - * Constructs a new {@link ClassReader} object. - * - * @param name the binary qualified name of the class to be read. - * @throws IOException if an exception occurs during reading. - */ - public ClassReader(final String name) throws IOException { - this(readClass(ClassLoader.getSystemResourceAsStream(name.replace('.', '/') + ".class"), true)); - } - - /** - * Reads the bytecode of a class. - * - * @param is an input stream from which to read the class. - * @param close true to close the input stream after reading. - * @return the bytecode read from the given input stream. - * @throws IOException if a problem occurs during reading. - */ - private static byte[] readClass(final InputStream is, boolean close) throws IOException { - if (is == null) { - throw new IOException("Class not found"); - } - try { - byte[] b = new byte[is.available()]; - int len = 0; - while (true) { - int n = is.read(b, len, b.length - len); - if (n == -1) { - if (len < b.length) { - byte[] c = new byte[len]; - System.arraycopy(b, 0, c, 0, len); - b = c; - } - return b; - } - len += n; - if (len == b.length) { - int last = is.read(); - if (last < 0) { - return b; - } - byte[] c = new byte[b.length + 1000]; - System.arraycopy(b, 0, c, 0, len); - c[len++] = (byte) last; - b = c; - } - } - } finally { - if (close) { - is.close(); - } - } - } - - // ------------------------------------------------------------------------ - // Public methods - // ------------------------------------------------------------------------ - - /** - * Makes the given visitor visit the Java class of this {@link ClassReader} . This class is the one specified in the - * constructor (see {@link #ClassReader(byte[]) ClassReader}). - * - * @param classVisitor the visitor that must visit this class. - * @param flags option flags that can be used to modify the default behavior of this class. See {@link #SKIP_DEBUG}, - * {@link #EXPAND_FRAMES} , {@link #SKIP_FRAMES}, {@link #SKIP_CODE}. - */ - public void accept(final ClassVisitor classVisitor, final int flags) { - accept(classVisitor, Attribute.DEFAULT_ATTRIBUTE_PROTOS, flags); - } - - /** - * Makes the given visitor visit the Java class of this {@link ClassReader}. This class is the one specified in the - * constructor (see {@link #ClassReader(byte[]) ClassReader}). - * - * @param classVisitor the visitor that must visit this class. - * @param attrs prototypes of the attributes that must be parsed during the visit of the class. Any attribute whose - * type is not equal to the type of one the prototypes will not be parsed: its byte array value will be passed - * unchanged to the ClassWriter. This may corrupt it if this value contains references to the constant pool, - * or has syntactic or semantic links with a class element that has been transformed by a class adapter between - * the reader and the writer. - * @param flags option flags that can be used to modify the default behavior of this class. See {@link #SKIP_DEBUG}, - * {@link #EXPAND_FRAMES} , {@link #SKIP_FRAMES}, {@link #SKIP_CODE}. - */ - public void accept(final ClassVisitor classVisitor, final Attribute[] attrs, final int flags) { - int u = header; // current offset in the class file - char[] c = new char[maxStringLength]; // buffer used to read strings - - Context context = new Context(); - context.attrs = attrs; - context.flags = flags; - context.buffer = c; - - // reads the class declaration - int access = readUnsignedShort(u); - String name = readClass(u + 2, c); - String superClass = readClass(u + 4, c); - String[] interfaces = new String[readUnsignedShort(u + 6)]; - u += 8; - for (int i = 0; i < interfaces.length; ++i) { - interfaces[i] = readClass(u, c); - u += 2; - } - - // reads the class attributes - String signature = null; - String sourceFile = null; - String sourceDebug = null; - 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(); - for (int i = readUnsignedShort(u); i > 0; --i) { - String attrName = readUTF8(u + 2, c); - // tests are sorted in decreasing frequency order - // (based on frequencies observed on typical classes) - if ("SourceFile".equals(attrName)) { - sourceFile = readUTF8(u + 8, c); - } else if ("InnerClasses".equals(attrName)) { - innerClasses = u + 8; - } else if ("EnclosingMethod".equals(attrName)) { - enclosingOwner = readClass(u + 8, c); - int item = readUnsignedShort(u + 10); - if (item != 0) { - enclosingName = readUTF8(items[item], c); - enclosingDesc = readUTF8(items[item] + 2, c); - } - } else if ("Signature".equals(attrName)) { - signature = readUTF8(u + 8, c); - } else if ("RuntimeVisibleAnnotations".equals(attrName)) { - anns = u + 8; - } else if ("RuntimeVisibleTypeAnnotations".equals(attrName)) { - tanns = u + 8; - } else if ("Deprecated".equals(attrName)) { - access |= Opcodes.ACC_DEPRECATED; - } else if ("Synthetic".equals(attrName)) { - access |= Opcodes.ACC_SYNTHETIC | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE; - } else if ("SourceDebugExtension".equals(attrName)) { - int len = readInt(u + 4); - sourceDebug = readUTF(u + 8, len, new char[len]); - } else if ("RuntimeInvisibleAnnotations".equals(attrName)) { - ianns = u + 8; - } 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++) { - bootstrapMethods[j] = v; - v += 2 + readUnsignedShort(v + 2) << 1; - } - context.bootstrapMethods = bootstrapMethods; - } else { - Attribute attr = readAttribute(attrs, attrName, u + 8, readInt(u + 4), c, -1, null); - if (attr != null) { - attr.next = attributes; - attributes = attr; - } - } - u += 6 + readInt(u + 4); - } - - // visits the class declaration - classVisitor.visit(readInt(items[1] - 7), access, name, signature, superClass, interfaces); - - // visits the source and debug info - if ((flags & SKIP_DEBUG) == 0 && (sourceFile != null || sourceDebug != null)) { - 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, enclosingDesc); - } - - // visits the class annotations and type annotations - 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 (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 (tanns != 0) { - for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) { - v = readAnnotationTarget(context, v); - v = readAnnotationValues( - v + 2, - c, - true, - classVisitor.visitTypeAnnotation(context.typeRef, context.typePath, readUTF8(v, c), true)); - } - } - if (itanns != 0) { - for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) { - v = readAnnotationTarget(context, v); - v = readAnnotationValues( - v + 2, - c, - true, - classVisitor.visitTypeAnnotation(context.typeRef, context.typePath, readUTF8(v, c), false)); - } - } - - // visits the attributes - while (attributes != null) { - Attribute attr = attributes.next; - attributes.next = null; - classVisitor.visitAttribute(attributes); - attributes = attr; - } - - // visits the inner classes - if (innerClasses != 0) { - int v = innerClasses + 2; - for (int i = readUnsignedShort(innerClasses); i > 0; --i) { - classVisitor.visitInnerClass( - readClass(v, c), readClass(v + 2, c), readUTF8(v + 4, c), readUnsignedShort(v + 6)); - v += 8; - } - } - - // visits the fields and methods - u = header + 10 + 2 * interfaces.length; - for (int i = readUnsignedShort(u - 2); i > 0; --i) { - u = readField(classVisitor, context, u); - } - u += 2; - for (int i = readUnsignedShort(u - 2); i > 0; --i) { - u = readMethod(classVisitor, context, u); - } - - // visits the end of the class - 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. - * - * @param classVisitor the visitor that must visit the field. - * @param context information about the class being parsed. - * @param u the start offset of the field in the class file. - * @return the offset of the first byte following the field in the class. - */ - private int readField(final ClassVisitor classVisitor, final Context context, int u) { - // reads the field declaration - char[] c = context.buffer; - int access = readUnsignedShort(u); - String name = readUTF8(u + 2, c); - String desc = readUTF8(u + 4, c); - u += 6; - - // reads the field attributes - String signature = null; - int anns = 0; - int ianns = 0; - int tanns = 0; - int itanns = 0; - Object value = null; - Attribute attributes = null; - - for (int i = readUnsignedShort(u); i > 0; --i) { - String attrName = readUTF8(u + 2, c); - // tests are sorted in decreasing frequency order - // (based on frequencies observed on typical classes) - if ("ConstantValue".equals(attrName)) { - int item = readUnsignedShort(u + 8); - value = item == 0 ? null : readConst(item, c); - } 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 ("RuntimeVisibleAnnotations".equals(attrName)) { - anns = u + 8; - } else if ("RuntimeVisibleTypeAnnotations".equals(attrName)) { - tanns = u + 8; - } else if ("RuntimeInvisibleAnnotations".equals(attrName)) { - ianns = u + 8; - } else if ("RuntimeInvisibleTypeAnnotations".equals(attrName)) { - itanns = u + 8; - } else { - Attribute attr = readAttribute(context.attrs, attrName, u + 8, readInt(u + 4), c, -1, null); - if (attr != null) { - attr.next = attributes; - attributes = attr; - } - } - u += 6 + readInt(u + 4); - } - u += 2; - - // visits the field declaration - FieldVisitor fv = classVisitor.visitField(access, name, desc, signature, value); - if (fv == null) { - return u; - } - - // visits the field annotations and type annotations - 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 (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 (tanns != 0) { - for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) { - v = readAnnotationTarget(context, v); - v = readAnnotationValues( - v + 2, - c, - true, - fv.visitTypeAnnotation(context.typeRef, context.typePath, readUTF8(v, c), true)); - } - } - if (itanns != 0) { - for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) { - v = readAnnotationTarget(context, v); - v = readAnnotationValues( - v + 2, - c, - true, - fv.visitTypeAnnotation(context.typeRef, context.typePath, readUTF8(v, c), false)); - } - } - - // visits the field attributes - while (attributes != null) { - Attribute attr = attributes.next; - attributes.next = null; - fv.visitAttribute(attributes); - attributes = attr; - } - - // visits the end of the field - fv.visitEnd(); - - return u; - } - - /** - * Reads a method and makes the given visitor visit it. - * - * @param classVisitor the visitor that must visit the method. - * @param context information about the class being parsed. - * @param u the start offset of the method in the class file. - * @return the offset of the first byte following the method in the class. - */ - private int readMethod(final ClassVisitor classVisitor, final Context context, int u) { - // reads the method declaration - char[] c = context.buffer; - context.access = readUnsignedShort(u); - context.name = readUTF8(u + 2, c); - context.desc = readUTF8(u + 4, c); - u += 6; - - // reads the method attributes - int code = 0; - int exception = 0; - String[] exceptions = null; - String signature = null; - int methodParameters = 0; - int anns = 0; - int ianns = 0; - int tanns = 0; - int itanns = 0; - int dann = 0; - int mpanns = 0; - int impanns = 0; - int firstAttribute = u; - Attribute attributes = null; - - for (int i = readUnsignedShort(u); i > 0; --i) { - String attrName = readUTF8(u + 2, c); - // tests are sorted in decreasing frequency order - // (based on frequencies observed on typical classes) - if ("Code".equals(attrName)) { - if ((context.flags & SKIP_CODE) == 0) { - code = u + 8; - } - } else if ("Exceptions".equals(attrName)) { - exceptions = new String[readUnsignedShort(u + 8)]; - exception = u + 10; - for (int j = 0; j < exceptions.length; ++j) { - exceptions[j] = readClass(exception, c); - exception += 2; - } - } else if ("Signature".equals(attrName)) { - signature = readUTF8(u + 8, c); - } else if ("Deprecated".equals(attrName)) { - context.access |= Opcodes.ACC_DEPRECATED; - } else if ("RuntimeVisibleAnnotations".equals(attrName)) { - anns = u + 8; - } else if ("RuntimeVisibleTypeAnnotations".equals(attrName)) { - tanns = u + 8; - } else if ("AnnotationDefault".equals(attrName)) { - dann = u + 8; - } else if ("Synthetic".equals(attrName)) { - context.access |= Opcodes.ACC_SYNTHETIC | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE; - } else if ("RuntimeInvisibleAnnotations".equals(attrName)) { - ianns = u + 8; - } else if ("RuntimeInvisibleTypeAnnotations".equals(attrName)) { - itanns = u + 8; - } else if ("RuntimeVisibleParameterAnnotations".equals(attrName)) { - mpanns = u + 8; - } else if ("RuntimeInvisibleParameterAnnotations".equals(attrName)) { - impanns = u + 8; - } else if ("MethodParameters".equals(attrName)) { - methodParameters = u + 8; - } else { - Attribute attr = readAttribute(context.attrs, attrName, u + 8, readInt(u + 4), c, -1, null); - if (attr != null) { - attr.next = attributes; - attributes = attr; - } - } - u += 6 + readInt(u + 4); - } - u += 2; - - // visits the method declaration - MethodVisitor mv = classVisitor.visitMethod(context.access, context.name, context.desc, signature, exceptions); - if (mv == null) { - return u; - } - - /* - * if the returned MethodVisitor is in fact a MethodWriter, it means - * there is no method adapter between the reader and the writer. If, in - * addition, the writer's constant pool was copied from this reader - * (mw.cw.cr == this), and the signature and exceptions of the method - * have not been changed, then it is possible to skip all visit events - * and just copy the original code of the method to the writer (the - * access, name and descriptor can have been changed, this is not - * important since they are not copied as is from the reader). - */ - if (mv instanceof MethodWriter) { - MethodWriter mw = (MethodWriter) mv; - if (mw.cw.cr == this && signature == mw.signature) { - boolean sameExceptions = false; - if (exceptions == null) { - sameExceptions = mw.exceptionCount == 0; - } else if (exceptions.length == mw.exceptionCount) { - sameExceptions = true; - for (int j = exceptions.length - 1; j >= 0; --j) { - exception -= 2; - if (mw.exceptions[j] != readUnsignedShort(exception)) { - sameExceptions = false; - break; - } - } - } - if (sameExceptions) { - /* - * we do not copy directly the code into MethodWriter to - * save a byte array copy operation. The real copy will be - * done in ClassWriter.toByteArray(). - */ - mw.classReaderOffset = firstAttribute; - mw.classReaderLength = u - firstAttribute; - return u; - } - } - } - - // visit the method parameters - if (methodParameters != 0) { - for (int i = b[methodParameters] & 0xFF, v = methodParameters + 1; i > 0; --i, v = v + 4) { - mv.visitParameter(readUTF8(v, c), readUnsignedShort(v + 2)); - } - } - - // visits the method annotations - if (dann != 0) { - AnnotationVisitor dv = mv.visitAnnotationDefault(); - readAnnotationValue(dann, c, null, dv); - if (dv != null) { - dv.visitEnd(); - } - } - 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 (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 (tanns != 0) { - for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) { - v = readAnnotationTarget(context, v); - v = readAnnotationValues( - v + 2, - c, - true, - mv.visitTypeAnnotation(context.typeRef, context.typePath, readUTF8(v, c), true)); - } - } - if (itanns != 0) { - for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) { - v = readAnnotationTarget(context, v); - v = readAnnotationValues( - v + 2, - c, - true, - mv.visitTypeAnnotation(context.typeRef, context.typePath, readUTF8(v, c), false)); - } - } - if (mpanns != 0) { - readParameterAnnotations(mv, context, mpanns, true); - } - if (impanns != 0) { - readParameterAnnotations(mv, context, impanns, false); - } - - // visits the method attributes - while (attributes != null) { - Attribute attr = attributes.next; - attributes.next = null; - mv.visitAttribute(attributes); - attributes = attr; - } - - // visits the method code - if (code != 0) { - mv.visitCode(); - readCode(mv, context, code); - } - - // visits the end of the method - mv.visitEnd(); - - return u; - } - - /** - * Reads the bytecode of a method and makes the given visitor visit it. - * - * @param mv the visitor that must visit the method's code. - * @param context information about the class being parsed. - * @param u the start offset of the code attribute in the class file. - */ - private void readCode(final MethodVisitor mv, final Context context, int u) { - // reads the header - byte[] b = this.b; - char[] c = context.buffer; - int maxStack = readUnsignedShort(u); - int maxLocals = readUnsignedShort(u + 2); - int codeLength = readInt(u + 4); - u += 8; - - // reads the bytecode to find the labels - int codeStart = u; - int codeEnd = u + codeLength; - Label[] labels = context.labels = new Label[codeLength + 2]; - createLabel(codeLength + 1, labels); - while (u < codeEnd) { - int offset = u - codeStart; - int opcode = b[u] & 0xFF; - switch (ClassWriter.TYPE[opcode]) { - case ClassWriter.NOARG_INSN: - case ClassWriter.IMPLVAR_INSN: - u += 1; - break; - case ClassWriter.LABEL_INSN: - 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: - case ClassWriter.ASM_LABELW_INSN: - createLabel(offset + readInt(u + 1), labels); - u += 5; - break; - case ClassWriter.WIDE_INSN: - opcode = b[u + 1] & 0xFF; - if (opcode == Opcodes.IINC) { - u += 6; - } else { - u += 4; - } - break; - case ClassWriter.TABL_INSN: - // skips 0 to 3 padding bytes - u = u + 4 - (offset & 3); - // reads instruction - createLabel(offset + readInt(u), labels); - for (int i = readInt(u + 8) - readInt(u + 4) + 1; i > 0; --i) { - createLabel(offset + readInt(u + 12), labels); - u += 4; - } - u += 12; - break; - case ClassWriter.LOOK_INSN: - // skips 0 to 3 padding bytes - u = u + 4 - (offset & 3); - // reads instruction - createLabel(offset + readInt(u), labels); - for (int i = readInt(u + 4); i > 0; --i) { - createLabel(offset + readInt(u + 12), labels); - u += 8; - } - u += 8; - break; - case ClassWriter.VAR_INSN: - case ClassWriter.SBYTE_INSN: - case ClassWriter.LDC_INSN: - u += 2; - break; - case ClassWriter.SHORT_INSN: - case ClassWriter.LDCW_INSN: - case ClassWriter.FIELDORMETH_INSN: - case ClassWriter.TYPE_INSN: - case ClassWriter.IINC_INSN: - u += 3; - break; - case ClassWriter.ITFMETH_INSN: - case ClassWriter.INDYMETH_INSN: - u += 5; - break; - // case MANA_INSN: - default: - u += 4; - break; - } - } - - // reads the try catch entries to find the labels, and also visits them - for (int i = readUnsignedShort(u); i > 0; --i) { - 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; - } - u += 2; - - // reads the code attributes - int[] tanns = null; // start index of each visible type annotation - int[] itanns = null; // start index of each invisible type annotation - int tann = 0; // current index in tanns array - int itann = 0; // current index in itanns array - int ntoff = -1; // next visible type annotation code offset - int nitoff = -1; // next invisible type annotation code offset - int varTable = 0; - int varTypeTable = 0; - boolean zip = true; - boolean unzip = (context.flags & EXPAND_FRAMES) != 0; - int stackMap = 0; - int stackMapSize = 0; - int frameCount = 0; - Context frame = null; - Attribute attributes = null; - - for (int i = readUnsignedShort(u); i > 0; --i) { - String attrName = readUTF8(u + 2, c); - if ("LocalVariableTable".equals(attrName)) { - if ((context.flags & SKIP_DEBUG) == 0) { - varTable = u + 8; - for (int j = readUnsignedShort(u + 8), v = u; j > 0; --j) { - int label = readUnsignedShort(v + 10); - createDebugLabel(label, labels); - label += readUnsignedShort(v + 12); - createDebugLabel(label, labels); - v += 10; - } - } - } else if ("LocalVariableTypeTable".equals(attrName)) { - varTypeTable = u + 8; - } else if ("LineNumberTable".equals(attrName)) { - if ((context.flags & SKIP_DEBUG) == 0) { - for (int j = readUnsignedShort(u + 8), v = u; j > 0; --j) { - int label = readUnsignedShort(v + 10); - createDebugLabel(label, labels); - Label l = labels[label]; - while (l.line > 0) { - if (l.next == null) { - l.next = new Label(); - } - l = l.next; - } - l.line = readUnsignedShort(v + 12); - v += 4; - } - } - } 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 ("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 ("StackMapTable".equals(attrName)) { - if ((context.flags & SKIP_FRAMES) == 0) { - stackMap = u + 10; - stackMapSize = readInt(u + 4); - frameCount = readUnsignedShort(u + 8); - } - /* - * here we do not extract the labels corresponding to the - * attribute content. This would require a full parsing of the - * attribute, which would need to be repeated in the second - * phase (see below). Instead the content of the attribute is - * read one frame at a time (i.e. after a frame has been - * visited, the next frame is read), and the labels it contains - * are also extracted one frame at a time. Thanks to the - * ordering of frames, having only a "one frame lookahead" is - * not a problem, i.e. it is not possible to see an offset - * smaller than the offset of the current insn and for which no - * Label exist. - */ - /* - * This is not true for UNINITIALIZED type offsets. We solve - * this by parsing the stack map table without a full decoding - * (see below). - */ - } else if ("StackMap".equals(attrName)) { - if ((context.flags & SKIP_FRAMES) == 0) { - zip = false; - stackMap = u + 10; - stackMapSize = readInt(u + 4); - frameCount = readUnsignedShort(u + 8); - } - /* - * IMPORTANT! here we assume that the frames are ordered, as in - * the StackMapTable attribute, although this is not guaranteed - * by the attribute format. - */ - } else { - for (int j = 0; j < context.attrs.length; ++j) { - if (context.attrs[j].type.equals(attrName)) { - Attribute attr = context.attrs[j].read(this, u + 8, readInt(u + 4), c, codeStart - 8, labels); - if (attr != null) { - attr.next = attributes; - attributes = attr; - } - } - } - } - u += 6 + readInt(u + 4); - } - u += 2; - - // generates the first (implicit) stack map frame - 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 - * allow the use of the "offset_delta + 1" rule in all cases - */ - frame = context; - frame.offset = -1; - frame.mode = 0; - frame.localCount = 0; - frame.localDiff = 0; - frame.stackCount = 0; - frame.local = new Object[maxLocals]; - frame.stack = new Object[maxStack]; - if (unzip) { - getImplicitFrame(context); - } - /* - * Finds labels for UNINITIALIZED frame types. Instead of decoding - * each element of the stack map table, we look for 3 consecutive - * bytes that "look like" an UNINITIALIZED type (tag 8, offset - * within code bounds, NEW instruction at this offset). We may find - * false positives (i.e. not real UNINITIALIZED types), but this - * should be rare, and the only consequence will be the creation of - * an unneeded label. This is better than creating a label for each - * NEW instruction, and faster than fully decoding the whole stack - * map table. - */ - for (int i = stackMap; i < stackMap + stackMapSize - 2; ++i) { - if (b[i] == 8) { // UNINITIALIZED FRAME TYPE - int v = readUnsignedShort(i + 1); - if (v >= 0 && v < codeLength) { - if ((b[codeStart + v] & 0xFF) == Opcodes.NEW) { - 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; - - // visits the label and line number for this offset, if any - Label l = labels[offset]; - if (l != null) { - Label next = l.next; - l.next = null; - mv.visitLabel(l); - if ((context.flags & SKIP_DEBUG) == 0 && l.line > 0) { - mv.visitLineNumber(l.line, l); - while (next != null) { - mv.visitLineNumber(next.line, l); - next = next.next; - } - } - } - - // visits the frame for this offset, if any - 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. - if (frame.offset != -1) { - if (!zip || unzip) { - mv.visitFrame(Opcodes.F_NEW, frame.localCount, frame.local, frame.stackCount, frame.stack); - } else { - 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); - --frameCount; - } else { - 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; - switch (ClassWriter.TYPE[opcode]) { - case ClassWriter.NOARG_INSN: - mv.visitInsn(opcode); - u += 1; - break; - case ClassWriter.IMPLVAR_INSN: - if (opcode > Opcodes.ISTORE) { - opcode -= 59; // ISTORE_0 - mv.visitVarInsn(Opcodes.ISTORE + (opcode >> 2), opcode & 0x3); - } else { - opcode -= 26; // ILOAD_0 - mv.visitVarInsn(Opcodes.ILOAD + (opcode >> 2), opcode & 0x3); - } - u += 1; - break; - case ClassWriter.LABEL_INSN: - mv.visitJumpInsn(opcode, labels[offset + readShort(u + 1)]); - u += 3; - break; - case ClassWriter.LABELW_INSN: - 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 - // with IFNOTxxx GOTO_W L:..., where IFNOTxxx is - // the "opposite" opcode of IFxxx (i.e., IFNE for IFEQ) - // and where 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 GOTO_W 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) { - mv.visitIincInsn(readUnsignedShort(u + 2), readShort(u + 4)); - u += 6; - } else { - mv.visitVarInsn(opcode, readUnsignedShort(u + 2)); - u += 4; - } - break; - case ClassWriter.TABL_INSN: { - // skips 0 to 3 padding bytes - u = u + 4 - (offset & 3); - // reads instruction - int label = offset + readInt(u); - int min = readInt(u + 4); - int max = readInt(u + 8); - Label[] table = new Label[max - min + 1]; - u += 12; - for (int i = 0; i < table.length; ++i) { - table[i] = labels[offset + readInt(u)]; - u += 4; - } - mv.visitTableSwitchInsn(min, max, labels[label], table); - break; - } - case ClassWriter.LOOK_INSN: { - // skips 0 to 3 padding bytes - u = u + 4 - (offset & 3); - // reads instruction - int label = offset + readInt(u); - int len = readInt(u + 4); - int[] keys = new int[len]; - Label[] values = new Label[len]; - u += 8; - for (int i = 0; i < len; ++i) { - keys[i] = readInt(u); - values[i] = labels[offset + readInt(u + 4)]; - u += 8; - } - mv.visitLookupSwitchInsn(labels[label], keys, values); - break; - } - case ClassWriter.VAR_INSN: - mv.visitVarInsn(opcode, b[u + 1] & 0xFF); - u += 2; - break; - case ClassWriter.SBYTE_INSN: - mv.visitIntInsn(opcode, b[u + 1]); - u += 2; - break; - case ClassWriter.SHORT_INSN: - mv.visitIntInsn(opcode, readShort(u + 1)); - u += 3; - break; - case ClassWriter.LDC_INSN: - mv.visitLdcInsn(readConst(b[u + 1] & 0xFF, c)); - u += 2; - break; - case ClassWriter.LDCW_INSN: - mv.visitLdcInsn(readConst(readUnsignedShort(u + 1), c)); - u += 3; - break; - case ClassWriter.FIELDORMETH_INSN: - case ClassWriter.ITFMETH_INSN: { - int cpIndex = items[readUnsignedShort(u + 1)]; - boolean itf = b[cpIndex - 1] == ClassWriter.IMETH; - String iowner = readClass(cpIndex, c); - cpIndex = items[readUnsignedShort(cpIndex + 2)]; - String iname = readUTF8(cpIndex, c); - String idesc = readUTF8(cpIndex + 2, c); - if (opcode < Opcodes.INVOKEVIRTUAL) { - mv.visitFieldInsn(opcode, iowner, iname, idesc); - } else { - mv.visitMethodInsn(opcode, iowner, iname, idesc, itf); - } - if (opcode == Opcodes.INVOKEINTERFACE) { - u += 5; - } else { - u += 3; - } - break; - } - case ClassWriter.INDYMETH_INSN: { - int cpIndex = items[readUnsignedShort(u + 1)]; - int bsmIndex = context.bootstrapMethods[readUnsignedShort(cpIndex)]; - Handle bsm = (Handle) readConst(readUnsignedShort(bsmIndex), c); - int bsmArgCount = readUnsignedShort(bsmIndex + 2); - Object[] bsmArgs = new Object[bsmArgCount]; - bsmIndex += 4; - for (int i = 0; i < bsmArgCount; i++) { - bsmArgs[i] = readConst(readUnsignedShort(bsmIndex), c); - bsmIndex += 2; - } - cpIndex = items[readUnsignedShort(cpIndex + 2)]; - String iname = readUTF8(cpIndex, c); - String idesc = readUTF8(cpIndex + 2, c); - mv.visitInvokeDynamicInsn(iname, idesc, bsm, bsmArgs); - u += 5; - break; - } - case ClassWriter.TYPE_INSN: - mv.visitTypeInsn(opcode, readClass(u + 1, c)); - u += 3; - break; - case ClassWriter.IINC_INSN: - mv.visitIincInsn(b[u + 1] & 0xFF, b[u + 2]); - u += 3; - break; - // case MANA_INSN: - default: - mv.visitMultiANewArrayInsn(readClass(u + 1, c), b[u + 3] & 0xFF); - u += 4; - break; - } - - // visit the instruction annotations, if any - while (tanns != null && tann < tanns.length && ntoff <= offset) { - if (ntoff == offset) { - int v = readAnnotationTarget(context, tanns[tann]); - readAnnotationValues( - v + 2, - c, - true, - mv.visitInsnAnnotation(context.typeRef, context.typePath, readUTF8(v, c), true)); - } - ntoff = ++tann >= tanns.length || readByte(tanns[tann]) < 0x43 - ? -1 - : readUnsignedShort(tanns[tann] + 1); - } - while (itanns != null && itann < itanns.length && nitoff <= offset) { - if (nitoff == offset) { - int v = readAnnotationTarget(context, itanns[itann]); - readAnnotationValues( - v + 2, - c, - true, - mv.visitInsnAnnotation(context.typeRef, context.typePath, readUTF8(v, c), false)); - } - nitoff = ++itann >= itanns.length || readByte(itanns[itann]) < 0x43 - ? -1 - : readUnsignedShort(itanns[itann] + 1); - } - } - if (labels[codeLength] != null) { - mv.visitLabel(labels[codeLength]); - } - - // visits the local variable tables - if ((context.flags & SKIP_DEBUG) == 0 && varTable != 0) { - int[] typeTable = null; - if (varTypeTable != 0) { - u = varTypeTable + 2; - typeTable = new int[readUnsignedShort(varTypeTable) * 3]; - for (int i = typeTable.length; i > 0; ) { - typeTable[--i] = u + 6; // signature - typeTable[--i] = readUnsignedShort(u + 8); // index - typeTable[--i] = readUnsignedShort(u); // start - u += 10; - } - } - u = varTable + 2; - for (int i = readUnsignedShort(varTable); i > 0; --i) { - int start = readUnsignedShort(u); - int length = readUnsignedShort(u + 2); - int index = readUnsignedShort(u + 8); - String vsignature = null; - if (typeTable != null) { - for (int j = 0; j < typeTable.length; j += 3) { - if (typeTable[j] == start && typeTable[j + 1] == index) { - vsignature = readUTF8(typeTable[j + 2], c); - break; - } - } - } - mv.visitLocalVariable( - readUTF8(u + 4, c), - readUTF8(u + 6, c), - vsignature, - labels[start], - labels[start + length], - index); - u += 10; - } - } - - // visits the local variables type annotations - if (tanns != null) { - for (int i = 0; i < tanns.length; ++i) { - if ((readByte(tanns[i]) >> 1) == (0x40 >> 1)) { - int v = readAnnotationTarget(context, tanns[i]); - v = readAnnotationValues( - v + 2, - c, - true, - mv.visitLocalVariableAnnotation( - context.typeRef, - context.typePath, - context.start, - context.end, - context.index, - readUTF8(v, c), - true)); - } - } - } - if (itanns != null) { - for (int i = 0; i < itanns.length; ++i) { - if ((readByte(itanns[i]) >> 1) == (0x40 >> 1)) { - int v = readAnnotationTarget(context, itanns[i]); - v = readAnnotationValues( - v + 2, - c, - true, - mv.visitLocalVariableAnnotation( - context.typeRef, - context.typePath, - context.start, - context.end, - context.index, - readUTF8(v, c), - false)); - } - } - } - - // visits the code attributes - while (attributes != null) { - Attribute attr = attributes.next; - attributes.next = null; - mv.visitAttribute(attributes); - attributes = attr; - } - - // visits the max stack and max locals values - mv.visitMaxs(maxStack, maxLocals); - } - - /** - * Parses a type annotation table to find the labels, and to visit the try catch block annotations. - * - * @param u the start offset of a type annotation table. - * @param mv the method visitor to be used to visit the try catch block annotations. - * @param context information about the class being parsed. - * @param visible if the type annotation table to parse contains runtime visible annotations. - * @return the start offset of each type annotation in the parsed table. - */ - private int[] readTypeAnnotations(final MethodVisitor mv, final Context context, int u, boolean visible) { - char[] c = context.buffer; - int[] offsets = new int[readUnsignedShort(u)]; - u += 2; - for (int i = 0; i < offsets.length; ++i) { - offsets[i] = u; - int target = readInt(u); - switch (target >>> 24) { - case 0x00: // CLASS_TYPE_PARAMETER - case 0x01: // METHOD_TYPE_PARAMETER - case 0x16: // METHOD_FORMAL_PARAMETER - u += 2; - break; - case 0x13: // FIELD - case 0x14: // METHOD_RETURN - case 0x15: // METHOD_RECEIVER - u += 1; - break; - case 0x40: // LOCAL_VARIABLE - case 0x41: // RESOURCE_VARIABLE - for (int j = readUnsignedShort(u + 1); j > 0; --j) { - int start = readUnsignedShort(u + 3); - int length = readUnsignedShort(u + 5); - createLabel(start, context.labels); - createLabel(start + length, context.labels); - u += 6; - } - u += 3; - break; - case 0x47: // CAST - case 0x48: // CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT - case 0x49: // METHOD_INVOCATION_TYPE_ARGUMENT - case 0x4A: // CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT - case 0x4B: // METHOD_REFERENCE_TYPE_ARGUMENT - u += 4; - break; - // case 0x10: // CLASS_EXTENDS - // case 0x11: // CLASS_TYPE_PARAMETER_BOUND - // case 0x12: // METHOD_TYPE_PARAMETER_BOUND - // case 0x17: // THROWS - // case 0x42: // EXCEPTION_PARAMETER - // case 0x43: // INSTANCEOF - // case 0x44: // NEW - // case 0x45: // CONSTRUCTOR_REFERENCE - // case 0x46: // METHOD_REFERENCE - default: - u += 3; - break; - } - int pathLength = readByte(u); - if ((target >>> 24) == 0x42) { - TypePath path = pathLength == 0 ? null : new TypePath(b, u); - u += 1 + 2 * pathLength; - u = readAnnotationValues( - u + 2, c, true, mv.visitTryCatchAnnotation(target, path, readUTF8(u, c), visible)); - } else { - u = readAnnotationValues(u + 3 + 2 * pathLength, c, true, null); - } - } - return offsets; - } - - /** - * Parses the header of a type annotation to extract its target_type and target_path (the result is stored in the - * given context), and returns the start offset of the rest of the type_annotation structure (i.e. the offset to the - * type_index field, which is followed by num_element_value_pairs and then the name,value pairs). - * - * @param context information about the class being parsed. This is where the extracted target_type and target_path - * must be stored. - * @param u the start offset of a type_annotation structure. - * @return the start offset of the rest of the type_annotation structure. - */ - private int readAnnotationTarget(final Context context, int u) { - int target = readInt(u); - switch (target >>> 24) { - case 0x00: // CLASS_TYPE_PARAMETER - case 0x01: // METHOD_TYPE_PARAMETER - case 0x16: // METHOD_FORMAL_PARAMETER - target &= 0xFFFF0000; - u += 2; - break; - case 0x13: // FIELD - case 0x14: // METHOD_RETURN - case 0x15: // METHOD_RECEIVER - target &= 0xFF000000; - u += 1; - break; - case 0x40: // LOCAL_VARIABLE - case 0x41: { // RESOURCE_VARIABLE - target &= 0xFF000000; - int n = readUnsignedShort(u + 1); - context.start = new Label[n]; - context.end = new Label[n]; - context.index = new int[n]; - u += 3; - for (int i = 0; i < n; ++i) { - int start = readUnsignedShort(u); - int length = readUnsignedShort(u + 2); - context.start[i] = createLabel(start, context.labels); - context.end[i] = createLabel(start + length, context.labels); - context.index[i] = readUnsignedShort(u + 4); - u += 6; - } - break; - } - case 0x47: // CAST - case 0x48: // CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT - case 0x49: // METHOD_INVOCATION_TYPE_ARGUMENT - case 0x4A: // CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT - case 0x4B: // METHOD_REFERENCE_TYPE_ARGUMENT - target &= 0xFF0000FF; - u += 4; - break; - // case 0x10: // CLASS_EXTENDS - // case 0x11: // CLASS_TYPE_PARAMETER_BOUND - // case 0x12: // METHOD_TYPE_PARAMETER_BOUND - // case 0x17: // THROWS - // case 0x42: // EXCEPTION_PARAMETER - // case 0x43: // INSTANCEOF - // case 0x44: // NEW - // case 0x45: // CONSTRUCTOR_REFERENCE - // case 0x46: // METHOD_REFERENCE - default: - target &= (target >>> 24) < 0x43 ? 0xFFFFFF00 : 0xFF000000; - u += 3; - break; - } - int pathLength = readByte(u); - context.typeRef = target; - context.typePath = pathLength == 0 ? null : new TypePath(b, u); - return u + 1 + 2 * pathLength; - } - - /** - * Reads parameter annotations and makes the given visitor visit them. - * - * @param mv the visitor that must visit the annotations. - * @param context information about the class being parsed. - * @param v start offset in {@link #b b} of the annotations to be read. - * @param visible <tt>true</tt> if the annotations to be read are visible at runtime. - */ - private void readParameterAnnotations(final MethodVisitor mv, final Context context, int v, final boolean visible) { - int i; - int n = b[v++] & 0xFF; - // workaround for a bug in javac (javac compiler generates a parameter - // annotation array whose size is equal to the number of parameters in - // the Java source file, while it should generate an array whose size is - // equal to the number of parameters in the method descriptor - which - // includes the synthetic parameters added by the compiler). This work- - // around supposes that the synthetic parameters are the first ones. - int synthetics = Type.getArgumentTypes(context.desc).length - n; - AnnotationVisitor av; - for (i = 0; i < synthetics; ++i) { - // virtual annotation to detect synthetic parameters in MethodWriter - av = mv.visitParameterAnnotation(i, "Ljava/lang/Synthetic;", false); - if (av != null) { - av.visitEnd(); - } - } - char[] c = context.buffer; - for (; i < n + synthetics; ++i) { - int j = readUnsignedShort(v); - v += 2; - for (; j > 0; --j) { - av = mv.visitParameterAnnotation(i, readUTF8(v, c), visible); - v = readAnnotationValues(v + 2, c, true, av); - } - } - } - - /** - * Reads the values of an annotation and makes the given visitor visit them. - * - * @param v the start offset in {@link #b b} of the values to be read (including the unsigned short that gives the - * number of values). - * @param buf buffer to be used to call {@link #readUTF8 readUTF8}, {@link #readClass(int,char[]) readClass} or - * {@link #readConst readConst}. - * @param named if the annotation values are named or not. - * @param av the visitor that must visit the values. - * @return the end offset of the annotation values. - */ - private int readAnnotationValues(int v, final char[] buf, final boolean named, final AnnotationVisitor av) { - int i = readUnsignedShort(v); - v += 2; - if (named) { - for (; i > 0; --i) { - v = readAnnotationValue(v + 2, buf, readUTF8(v, buf), av); - } - } else { - for (; i > 0; --i) { - v = readAnnotationValue(v, buf, null, av); - } - } - if (av != null) { - av.visitEnd(); - } - return v; - } - - /** - * Reads a value of an annotation and makes the given visitor visit it. - * - * @param v the start offset in {@link #b b} of the value to be read (not including the value name constant pool - * index). - * @param buf buffer to be used to call {@link #readUTF8 readUTF8}, {@link #readClass(int,char[]) readClass} or - * {@link #readConst readConst}. - * @param name the name of the value to be read. - * @param av the visitor that must visit the value. - * @return the end offset of the annotation value. - */ - private int readAnnotationValue(int v, final char[] buf, final String name, final AnnotationVisitor av) { - int i; - if (av == null) { - switch (b[v] & 0xFF) { - case 'e': // enum_const_value - return v + 5; - case '@': // annotation_value - return readAnnotationValues(v + 3, buf, true, null); - case '[': // array_value - return readAnnotationValues(v + 1, buf, false, null); - default: - return v + 3; - } - } - switch (b[v++] & 0xFF) { - case 'I': // pointer to CONSTANT_Integer - case 'J': // pointer to CONSTANT_Long - case 'F': // pointer to CONSTANT_Float - case 'D': // pointer to CONSTANT_Double - av.visit(name, readConst(readUnsignedShort(v), buf)); - v += 2; - break; - case 'B': // pointer to CONSTANT_Byte - av.visit(name, (byte) readInt(items[readUnsignedShort(v)])); - v += 2; - break; - case 'Z': // pointer to CONSTANT_Boolean - av.visit(name, readInt(items[readUnsignedShort(v)]) == 0 ? Boolean.FALSE : Boolean.TRUE); - v += 2; - break; - case 'S': // pointer to CONSTANT_Short - av.visit(name, (short) readInt(items[readUnsignedShort(v)])); - v += 2; - break; - case 'C': // pointer to CONSTANT_Char - av.visit(name, (char) readInt(items[readUnsignedShort(v)])); - v += 2; - break; - case 's': // pointer to CONSTANT_Utf8 - av.visit(name, readUTF8(v, buf)); - v += 2; - break; - case 'e': // enum_const_value - av.visitEnum(name, readUTF8(v, buf), readUTF8(v + 2, buf)); - v += 4; - break; - case 'c': // class_info - av.visit(name, Type.getType(readUTF8(v, buf))); - v += 2; - break; - case '@': // annotation_value - v = readAnnotationValues(v + 2, buf, true, av.visitAnnotation(name, readUTF8(v, buf))); - break; - case '[': // array_value - int size = readUnsignedShort(v); - v += 2; - if (size == 0) { - return readAnnotationValues(v - 2, buf, false, av.visitArray(name)); - } - switch (this.b[v++] & 0xFF) { - case 'B': - byte[] bv = new byte[size]; - for (i = 0; i < size; i++) { - bv[i] = (byte) readInt(items[readUnsignedShort(v)]); - v += 3; - } - av.visit(name, bv); - --v; - break; - case 'Z': - boolean[] zv = new boolean[size]; - for (i = 0; i < size; i++) { - zv[i] = readInt(items[readUnsignedShort(v)]) != 0; - v += 3; - } - av.visit(name, zv); - --v; - break; - case 'S': - short[] sv = new short[size]; - for (i = 0; i < size; i++) { - sv[i] = (short) readInt(items[readUnsignedShort(v)]); - v += 3; - } - av.visit(name, sv); - --v; - break; - case 'C': - char[] cv = new char[size]; - for (i = 0; i < size; i++) { - cv[i] = (char) readInt(items[readUnsignedShort(v)]); - v += 3; - } - av.visit(name, cv); - --v; - break; - case 'I': - int[] iv = new int[size]; - for (i = 0; i < size; i++) { - iv[i] = readInt(items[readUnsignedShort(v)]); - v += 3; - } - av.visit(name, iv); - --v; - break; - case 'J': - long[] lv = new long[size]; - for (i = 0; i < size; i++) { - lv[i] = readLong(items[readUnsignedShort(v)]); - v += 3; - } - av.visit(name, lv); - --v; - break; - case 'F': - float[] fv = new float[size]; - for (i = 0; i < size; i++) { - fv[i] = Float.intBitsToFloat(readInt(items[readUnsignedShort(v)])); - v += 3; - } - av.visit(name, fv); - --v; - break; - case 'D': - double[] dv = new double[size]; - for (i = 0; i < size; i++) { - dv[i] = Double.longBitsToDouble(readLong(items[readUnsignedShort(v)])); - v += 3; - } - av.visit(name, dv); - --v; - break; - default: - v = readAnnotationValues(v - 3, buf, false, av.visitArray(name)); - } - } - return v; - } - - /** - * Computes the implicit frame of the method currently being parsed (as defined in the given {@link Context}) and - * stores it in the given context. - * - * @param frame information about the class being parsed. - */ - private void getImplicitFrame(final Context frame) { - String desc = frame.desc; - Object[] locals = frame.local; - int local = 0; - if ((frame.access & Opcodes.ACC_STATIC) == 0) { - if ("".equals(frame.name)) { - locals[local++] = Opcodes.UNINITIALIZED_THIS; - } else { - locals[local++] = readClass(header + 2, frame.buffer); - } - } - int i = 1; - loop: - while (true) { - int j = i; - switch (desc.charAt(i++)) { - case 'Z': - case 'C': - case 'B': - case 'S': - case 'I': - locals[local++] = Opcodes.INTEGER; - break; - case 'F': - locals[local++] = Opcodes.FLOAT; - break; - case 'J': - locals[local++] = Opcodes.LONG; - break; - case 'D': - locals[local++] = Opcodes.DOUBLE; - break; - case '[': - while (desc.charAt(i) == '[') { - ++i; - } - if (desc.charAt(i) == 'L') { - ++i; - while (desc.charAt(i) != ';') { - ++i; - } - } - locals[local++] = desc.substring(j, ++i); - break; - case 'L': - while (desc.charAt(i) != ';') { - ++i; - } - locals[local++] = desc.substring(j + 1, i++); - break; - default: - break loop; - } - } - frame.localCount = local; - } - - /** - * Reads a stack map frame and stores the result in the given {@link Context} object. - * - * @param stackMap the start offset of a stack map frame in the class file. - * @param zip if the stack map frame at stackMap is compressed or not. - * @param unzip if the stack map frame must be uncompressed. - * @param frame where the parsed stack map frame must be stored. - * @return the offset of the first byte following the parsed frame. - */ - private int readFrame(int stackMap, boolean zip, boolean unzip, Context frame) { - char[] c = frame.buffer; - Label[] labels = frame.labels; - int tag; - int delta; - if (zip) { - tag = b[stackMap++] & 0xFF; - } else { - tag = MethodWriter.FULL_FRAME; - frame.offset = -1; - } - frame.localDiff = 0; - if (tag < MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME) { - delta = tag; - frame.mode = Opcodes.F_SAME; - frame.stackCount = 0; - } else if (tag < MethodWriter.RESERVED) { - delta = tag - MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME; - stackMap = readFrameType(frame.stack, 0, stackMap, c, labels); - frame.mode = Opcodes.F_SAME1; - frame.stackCount = 1; - } else { - delta = readUnsignedShort(stackMap); - stackMap += 2; - if (tag == MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) { - stackMap = readFrameType(frame.stack, 0, stackMap, c, labels); - frame.mode = Opcodes.F_SAME1; - frame.stackCount = 1; - } else if (tag >= MethodWriter.CHOP_FRAME && tag < MethodWriter.SAME_FRAME_EXTENDED) { - frame.mode = Opcodes.F_CHOP; - frame.localDiff = MethodWriter.SAME_FRAME_EXTENDED - tag; - frame.localCount -= frame.localDiff; - frame.stackCount = 0; - } else if (tag == MethodWriter.SAME_FRAME_EXTENDED) { - frame.mode = Opcodes.F_SAME; - frame.stackCount = 0; - } else if (tag < MethodWriter.FULL_FRAME) { - int local = unzip ? frame.localCount : 0; - for (int i = tag - MethodWriter.SAME_FRAME_EXTENDED; i > 0; i--) { - stackMap = readFrameType(frame.local, local++, stackMap, c, labels); - } - frame.mode = Opcodes.F_APPEND; - frame.localDiff = tag - MethodWriter.SAME_FRAME_EXTENDED; - frame.localCount += frame.localDiff; - frame.stackCount = 0; - } else { // if (tag == FULL_FRAME) { - frame.mode = Opcodes.F_FULL; - int n = readUnsignedShort(stackMap); - stackMap += 2; - frame.localDiff = n; - frame.localCount = n; - for (int local = 0; n > 0; n--) { - stackMap = readFrameType(frame.local, local++, stackMap, c, labels); - } - n = readUnsignedShort(stackMap); - stackMap += 2; - frame.stackCount = n; - for (int stack = 0; n > 0; n--) { - stackMap = readFrameType(frame.stack, stack++, stackMap, c, labels); - } - } - } - frame.offset += delta + 1; - createLabel(frame.offset, labels); - return stackMap; - } - - /** - * Reads a stack map frame type and stores it at the given index in the given array. - * - * @param frame the array where the parsed type must be stored. - * @param index the index in 'frame' where the parsed type must be stored. - * @param v the start offset of the stack map frame type to read. - * @param buf a buffer to read strings. - * @param labels the labels of the method currently being parsed, indexed by their offset. If the parsed type is an - * Uninitialized type, a new label for the corresponding NEW instruction is stored in this array if it does not - * already exist. - * @return the offset of the first byte after the parsed type. - */ - private int readFrameType(final Object[] frame, final int index, int v, final char[] buf, final Label[] labels) { - int type = b[v++] & 0xFF; - switch (type) { - case 0: - frame[index] = Opcodes.TOP; - break; - case 1: - frame[index] = Opcodes.INTEGER; - break; - case 2: - frame[index] = Opcodes.FLOAT; - break; - case 3: - frame[index] = Opcodes.DOUBLE; - break; - case 4: - frame[index] = Opcodes.LONG; - break; - case 5: - frame[index] = Opcodes.NULL; - break; - case 6: - frame[index] = Opcodes.UNINITIALIZED_THIS; - break; - case 7: // Object - frame[index] = readClass(v, buf); - v += 2; - break; - default: // Uninitialized - frame[index] = createLabel(readUnsignedShort(v), labels); - v += 2; - } - return v; - } - - /** - * Returns the label corresponding to the given offset. The default implementation of this method creates a label - * for the given offset if it has not been already created. - * - * @param offset a bytecode offset in a method. - * @param labels the already created labels, indexed by their offset. If a label already exists for offset this - * method must not create a new one. Otherwise it must store the new label in this array. - * @return a non null Label, which must be equal to labels[offset]. - */ - protected Label readLabel(int offset, Label[] labels) { - if (labels[offset] == null) { - labels[offset] = new Label(); - } - 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. - * - * @return the start index of the attribute_info structure of this class. - */ - private int getAttributes() { - // skips the header - int u = header + 8 + readUnsignedShort(header + 6) * 2; - // skips fields and methods - for (int i = readUnsignedShort(u); i > 0; --i) { - for (int j = readUnsignedShort(u + 8); j > 0; --j) { - u += 6 + readInt(u + 12); - } - u += 8; - } - u += 2; - for (int i = readUnsignedShort(u); i > 0; --i) { - for (int j = readUnsignedShort(u + 8); j > 0; --j) { - u += 6 + readInt(u + 12); - } - u += 8; - } - // the attribute_info structure starts just after the methods - return u + 2; - } - - /** - * Reads an attribute in {@link #b b}. - * - * @param attrs prototypes of the attributes that must be parsed during the visit of the class. Any attribute whose - * type is not equal to the type of one the prototypes is ignored (i.e. an empty {@link Attribute} instance is - * returned). - * @param type the type of the attribute. - * @param off index of the first byte of the attribute's content in {@link #b b}. The 6 attribute header bytes, - * containing the type and the length of the attribute, are not taken into account here (they have already been - * read). - * @param len the length of the attribute's content. - * @param buf buffer to be used to call {@link #readUTF8 readUTF8}, {@link #readClass(int,char[]) readClass} or - * {@link #readConst readConst}. - * @param codeOff index of the first byte of code's attribute content in {@link #b b}, or -1 if the attribute to be - * read is not a code attribute. The 6 attribute header bytes, containing the type and the length of the - * attribute, are not taken into account here. - * @param labels the labels of the method's code, or <tt>null</tt> if the attribute to be read is - * not a code attribute. - * @return the attribute that has been read, or <tt>null</tt> to skip this attribute. - */ - private Attribute readAttribute( - final Attribute[] attrs, - final String type, - final int off, - final int len, - final char[] buf, - final int codeOff, - final Label[] labels) { - for (int i = 0; i < attrs.length; ++i) { - if (attrs[i].type.equals(type)) { - return attrs[i].read(this, off, len, buf, codeOff, labels); - } - } - return new Attribute(type).read(this, off, len, null, -1, null); - } - - // ------------------------------------------------------------------------ - // Utility methods: low level parsing - // ------------------------------------------------------------------------ - - /** - * Returns the number of constant pool items in {@link #b b}. - * - * @return the number of constant pool items in {@link #b b}. - */ - public int getItemCount() { - return items.length; - } - - /** - * Returns the start index of the constant pool item in {@link #b b}, plus one. This method is intended for - * {@link Attribute} sub classes, and is normally not needed by class generators or adapters. - * - * @param item the index a constant pool item. - * @return the start index of the constant pool item in {@link #b b}, plus one. - */ - public int getItem(final int item) { - return items[item]; - } - - /** - * Returns the maximum length of the strings contained in the constant pool of the class. - * - * @return the maximum length of the strings contained in the constant pool of the class. - */ - public int getMaxStringLength() { - return maxStringLength; - } - - /** - * Reads a byte value in {@link #b b}. This method is intended for {@link Attribute} sub classes, and is normally - * not needed by class generators or adapters. - * - * @param index the start index of the value to be read in {@link #b b}. - * @return the read value. - */ - public int readByte(final int index) { - return b[index] & 0xFF; - } - - /** - * Reads an unsigned short value in {@link #b b}. This method is intended for {@link Attribute} sub classes, and - * is normally not needed by class generators or adapters. - * - * @param index the start index of the value to be read in {@link #b b}. - * @return the read value. - */ - public int readUnsignedShort(final int index) { - byte[] b = this.b; - return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF); - } - - /** - * Reads a signed short value in {@link #b b}. This method is intended for {@link Attribute} sub classes, and is - * normally not needed by class generators or adapters. - * - * @param index the start index of the value to be read in {@link #b b}. - * @return the read value. - */ - public short readShort(final int index) { - byte[] b = this.b; - return (short) (((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF)); - } - - /** - * Reads a signed int value in {@link #b b}. This method is intended for {@link Attribute} sub classes, and is - * normally not needed by class generators or adapters. - * - * @param index the start index of the value to be read in {@link #b b}. - * @return the read value. - */ - public int readInt(final int index) { - byte[] b = this.b; - return ((b[index] & 0xFF) << 24) - | ((b[index + 1] & 0xFF) << 16) - | ((b[index + 2] & 0xFF) << 8) - | (b[index + 3] & 0xFF); - } - - /** - * Reads a signed long value in {@link #b b}. This method is intended for {@link Attribute} sub classes, and is - * normally not needed by class generators or adapters. - * - * @param index the start index of the value to be read in {@link #b b}. - * @return the read value. - */ - public long readLong(final int index) { - long l1 = readInt(index); - long l0 = readInt(index + 4) & 0xFFFFFFFFL; - return (l1 << 32) | l0; - } - - /** - * Reads an UTF8 string constant pool item in {@link #b b}. This method is intended for {@link Attribute} sub - * classes, and is normally not needed by class generators or adapters. - * - * @param index the start index of an unsigned short value in {@link #b b}, whose value is the index of an UTF8 - * 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 UTF8 item. - */ - public String readUTF8(int index, final char[] buf) { - int item = readUnsignedShort(index); - if (index == 0 || item == 0) { - return null; - } - String s = strings[item]; - if (s != null) { - return s; - } - index = items[item]; - return strings[item] = readUTF(index + 2, readUnsignedShort(index), buf); - } - - /** - * Reads UTF8 string in {@link #b b}. - * - * @param index start offset of the UTF8 string to be read. - * @param utfLen length of the UTF8 string to be read. - * @param buf buffer to be used to read the string. This buffer must be sufficiently large. It is not automatically - * resized. - * @return the String corresponding to the specified UTF8 string. - */ - private String readUTF(int index, final int utfLen, final char[] buf) { - int endIndex = index + utfLen; - byte[] b = this.b; - int strLen = 0; - int c; - int st = 0; - char cc = 0; - while (index < endIndex) { - c = b[index++]; - switch (st) { - case 0: - c = c & 0xFF; - if (c < 0x80) { // 0xxxxxxx - buf[strLen++] = (char) c; - } else if (c < 0xE0 && c > 0xBF) { // 110x xxxx 10xx xxxx - cc = (char) (c & 0x1F); - st = 1; - } else { // 1110 xxxx 10xx xxxx 10xx xxxx - cc = (char) (c & 0x0F); - st = 2; - } - break; - - case 1: // byte 2 of 2-byte char or byte 3 of 3-byte char - buf[strLen++] = (char) ((cc << 6) | (c & 0x3F)); - st = 0; - break; - - case 2: // byte 2 of 3-byte char - cc = (char) ((cc << 6) | (c & 0x3F)); - st = 1; - break; - } - } - 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}. This method is intended for {@link Attribute} sub classes, - * and is normally not needed by class generators or adapters. - * - * @param index the start index of an unsigned short value in {@link #b b}, whose value is the index of a class - * 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 class item. - */ - public String readClass(final int index, final char[] buf) { - return readStringish(index, buf); - } - - /** - * Reads a module constant pool item in {@link #b b}. This method is intended for {@link Attribute} sub classes, - * and is normally not needed by class generators or adapters. - * - * @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(final int index, final char[] buf) { - return readStringish(index, buf); - } - - /** - * Reads a module constant pool item in {@link #b b}. This method is intended for {@link Attribute} sub classes, - * and is normally not needed by class generators or adapters. - * - * @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(final int index, final char[] buf) { - return readStringish(index, buf); - } - - /** - * Reads a numeric or string constant pool item in {@link #b b}. This method is intended for {@link Attribute} - * sub classes, and is normally not needed by class generators or adapters. - * - * @param item the index of a 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 {@link Integer}, {@link Float}, {@link Long}, {@link Double}, {@link String}, {@link Type} or - * {@link Handle} corresponding to the given constant pool item. - */ - public Object readConst(final int item, final char[] buf) { - int index = items[item]; - switch (b[index - 1]) { - case ClassWriter.INT: - return readInt(index); - case ClassWriter.FLOAT: - return Float.intBitsToFloat(readInt(index)); - case ClassWriter.LONG: - return readLong(index); - case ClassWriter.DOUBLE: - return Double.longBitsToDouble(readLong(index)); - case ClassWriter.CLASS: - return Type.getObjectType(readUTF8(index, buf)); - case ClassWriter.STR: - return readUTF8(index, buf); - case ClassWriter.MTYPE: - return Type.getMethodType(readUTF8(index, buf)); - default: // case ClassWriter.HANDLE_BASE + [1..9]: - int tag = readByte(index); - int[] items = this.items; - int cpIndex = items[readUnsignedShort(index + 1)]; - boolean itf = b[cpIndex - 1] == ClassWriter.IMETH; - String owner = readClass(cpIndex, buf); - cpIndex = items[readUnsignedShort(cpIndex + 2)]; - String name = readUTF8(cpIndex, buf); - String desc = readUTF8(cpIndex + 2, buf); - return new Handle(tag, owner, name, desc, itf); - } - } -} +/* + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ + +/* + * + * + * + * + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.redkale.asm; + +import java.io.IOException; +import java.io.InputStream; + +/** + * A Java class parser to make a {@link ClassVisitor} visit an existing class. This class parses a byte array conforming + * to the Java class file format and calls the appropriate visit methods of a given class visitor for each field, method + * and bytecode instruction encountered. + * + * @author Eric Bruneton + * @author Eugene Kuleshov + */ +public class ClassReader { + + /** + * Flag to skip method code. If this class is set CODE attribute won't be visited. This can be used, + * for example, to retrieve annotations for methods and method parameters. + */ + public static final int SKIP_CODE = 1; + + /** + * Flag to skip the debug information in the class. If this flag is set the debug information of the class is not + * visited, i.e. the {@link MethodVisitor#visitLocalVariable visitLocalVariable} and + * {@link MethodVisitor#visitLineNumber visitLineNumber} methods will not be called. + */ + public static final int SKIP_DEBUG = 2; + + /** + * Flag to skip the stack map frames in the class. If this flag is set the stack map frames of the class is not + * visited, i.e. the {@link MethodVisitor#visitFrame visitFrame} method will not be called. This flag is useful when + * the {@link ClassWriter#COMPUTE_FRAMES} option is used: it avoids visiting frames that will be ignored and + * recomputed from scratch in the class writer. + */ + public static final int SKIP_FRAMES = 4; + + /** + * Flag to expand the stack map frames. By default stack map frames are visited in their original format (i.e. + * "expanded" for classes whose version is less than V1_6, and "compressed" for the other classes). If this flag is + * set, stack map frames are always visited in expanded format (this option adds a decompression/recompression step + * in ClassReader and ClassWriter which degrades performances quite a lot). + */ + 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 not 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. The content of this array must not be modified. This field is intended for + * {@link Attribute} sub classes, and is normally not needed by class generators or adapters. + */ + public final byte[] b; + + /** + * The start index of each constant pool item in {@link #b b}, plus one. The one byte offset skips the constant pool + * item tag that indicates its type. + */ + private final int[] items; + + /** + * The String objects corresponding to the CONSTANT_Utf8 items. This cache avoids multiple parsing of a given + * CONSTANT_Utf8 constant pool item, which GREATLY improves performances (by a factor 2 to 3). This caching strategy + * could be extended to all constant pool items, but its benefit would not be so great for these items (because they + * are much less expensive to parse than CONSTANT_Utf8 items). + */ + private final String[] strings; + + /** Maximum length of the strings contained in the constant pool of the class. */ + private final int maxStringLength; + + /** Start index of the class header information (access, name...) in {@link #b b}. */ + public final int header; + + // ------------------------------------------------------------------------ + // Constructors + // ------------------------------------------------------------------------ + + /** + * Constructs a new {@link ClassReader} object. + * + * @param b the bytecode of the class to be read. + */ + public ClassReader(final byte[] b) { + this(b, 0, b.length); + } + + /** + * Constructs a new {@link ClassReader} object. + * + * @param b the bytecode of the class to be read. + * @param off the start offset of the class data. + * @param len the length of the class data. + */ + public ClassReader(final byte[] b, final int off, final int len) { + this.b = b; + // checks the class version + // if (readShort(off + 6) > Opcodes.V11) { + // throw new IllegalArgumentException(); + // } + // parses the constant pool + items = new int[readUnsignedShort(off + 8)]; + int n = items.length; + strings = new String[n]; + int max = 0; + int index = off + 10; + for (int i = 1; i < n; ++i) { + items[i] = index + 1; + int size; + switch (b[index]) { + case ClassWriter.FIELD: + case ClassWriter.METH: + case ClassWriter.IMETH: + case ClassWriter.INT: + case ClassWriter.FLOAT: + case ClassWriter.NAME_TYPE: + case ClassWriter.INDY: + // @@@ ClassWriter.CONDY + // Enables MethodHandles.lookup().defineClass to function correctly + // when it reads the class name + case 17: + size = 5; + break; + case ClassWriter.LONG: + case ClassWriter.DOUBLE: + size = 9; + ++i; + break; + case ClassWriter.UTF8: + size = 3 + readUnsignedShort(index + 1); + if (size > max) { + max = size; + } + break; + case ClassWriter.HANDLE: + size = 4; + break; + // case ClassWriter.CLASS: + // case ClassWriter.STR: + // case ClassWriter.MTYPE + // case ClassWriter.PACKAGE: + // case ClassWriter.MODULE: + default: + size = 3; + break; + } + index += size; + } + maxStringLength = max; + // the class header information starts just after the constant pool + header = index; + } + + /** + * Returns the class's access flags (see {@link Opcodes}). This value may not reflect Deprecated and Synthetic flags + * when bytecode is before 1.5 and those flags are represented by attributes. + * + * @return the class access flags + * @see ClassVisitor#visit(int, int, String, String, String, String[]) + */ + public int getAccess() { + return readUnsignedShort(header); + } + + /** + * Returns the internal name of the class (see {@link Type#getInternalName() getInternalName}). + * + * @return the internal class name + * @see ClassVisitor#visit(int, int, String, String, String, String[]) + */ + public String getClassName() { + return readClass(header + 2, new char[maxStringLength]); + } + + /** + * Returns the internal of name of the super class (see {@link Type#getInternalName() getInternalName}). For + * interfaces, the super class is {@link Object}. + * + * @return the internal name of super class, or <tt>null</tt> for {@link Object} class. + * @see ClassVisitor#visit(int, int, String, String, String, String[]) + */ + public String getSuperName() { + return readClass(header + 4, new char[maxStringLength]); + } + + /** + * Returns the internal names of the class's interfaces (see {@link Type#getInternalName() getInternalName}). + * + * @return the array of internal names for all implemented interfaces or <tt>null</tt>. + * @see ClassVisitor#visit(int, int, String, String, String, String[]) + */ + public String[] getInterfaces() { + int index = header + 6; + int n = readUnsignedShort(index); + String[] interfaces = new String[n]; + if (n > 0) { + char[] buf = new char[maxStringLength]; + for (int i = 0; i < n; ++i) { + index += 2; + interfaces[i] = readClass(index, buf); + } + } + return interfaces; + } + + /** + * Copies the constant pool data into the given {@link ClassWriter}. Should be called before the + * {@link #accept(ClassVisitor,int)} method. + * + * @param classWriter the {@link ClassWriter} to copy constant pool into. + */ + void copyPool(final ClassWriter classWriter) { + char[] buf = new char[maxStringLength]; + int ll = items.length; + Item[] items2 = new Item[ll]; + for (int i = 1; i < ll; i++) { + int index = items[i]; + int tag = b[index - 1]; + Item item = new Item(i); + int nameType; + switch (tag) { + case ClassWriter.FIELD: + case ClassWriter.METH: + case ClassWriter.IMETH: + nameType = items[readUnsignedShort(index + 2)]; + item.set(tag, readClass(index, buf), readUTF8(nameType, buf), readUTF8(nameType + 2, buf)); + break; + case ClassWriter.INT: + item.set(readInt(index)); + break; + case ClassWriter.FLOAT: + item.set(Float.intBitsToFloat(readInt(index))); + break; + case ClassWriter.NAME_TYPE: + item.set(tag, readUTF8(index, buf), readUTF8(index + 2, buf), null); + break; + case ClassWriter.LONG: + item.set(readLong(index)); + ++i; + break; + case ClassWriter.DOUBLE: + item.set(Double.longBitsToDouble(readLong(index))); + ++i; + break; + case ClassWriter.UTF8: { + String s = strings[i]; + if (s == null) { + index = items[i]; + s = strings[i] = readUTF(index + 2, readUnsignedShort(index), buf); + } + item.set(tag, s, null, null); + break; + } + case ClassWriter.HANDLE: { + int fieldOrMethodRef = items[readUnsignedShort(index + 1)]; + nameType = items[readUnsignedShort(fieldOrMethodRef + 2)]; + item.set( + ClassWriter.HANDLE_BASE + readByte(index), + readClass(fieldOrMethodRef, buf), + readUTF8(nameType, buf), + readUTF8(nameType + 2, buf)); + break; + } + case ClassWriter.INDY: + if (classWriter.bootstrapMethods == null) { + copyBootstrapMethods(classWriter, items2, buf); + } + nameType = items[readUnsignedShort(index + 2)]; + item.set(readUTF8(nameType, buf), readUTF8(nameType + 2, buf), readUnsignedShort(index)); + break; + // case ClassWriter.STR: + // case ClassWriter.CLASS: + // case ClassWriter.MTYPE: + // case ClassWriter.MODULE: + // case ClassWriter.PACKAGE: + default: + item.set(tag, readUTF8(index, buf), null, null); + break; + } + + int index2 = item.hashCode % items2.length; + item.next = items2[index2]; + items2[index2] = item; + } + + int off = items[1] - 1; + classWriter.pool.putByteArray(b, off, header - off); + classWriter.items = items2; + classWriter.threshold = (int) (0.75d * ll); + classWriter.index = ll; + } + + /** + * Copies the bootstrap method data into the given {@link ClassWriter}. Should be called before the + * {@link #accept(ClassVisitor,int)} method. + * + * @param classWriter the {@link ClassWriter} to copy bootstrap methods into. + */ + private void copyBootstrapMethods(final ClassWriter classWriter, final Item[] items, final char[] c) { + // finds the "BootstrapMethods" attribute + int u = getAttributes(); + boolean found = false; + for (int i = readUnsignedShort(u); i > 0; --i) { + String attrName = readUTF8(u + 2, c); + if ("BootstrapMethods".equals(attrName)) { + found = true; + break; + } + u += 6 + readInt(u + 4); + } + if (!found) { + return; + } + // copies the bootstrap methods in the class writer + int boostrapMethodCount = readUnsignedShort(u + 8); + for (int j = 0, v = u + 10; j < boostrapMethodCount; j++) { + int position = v - u - 10; + int hashCode = readConst(readUnsignedShort(v), c).hashCode(); + for (int k = readUnsignedShort(v + 2); k > 0; --k) { + hashCode ^= readConst(readUnsignedShort(v + 4), c).hashCode(); + v += 2; + } + v += 4; + Item item = new Item(j); + item.set(position, hashCode & 0x7FFFFFFF); + int index = item.hashCode % items.length; + item.next = items[index]; + items[index] = item; + } + int attrSize = readInt(u + 4); + ByteVector bootstrapMethods = new ByteVector(attrSize + 62); + bootstrapMethods.putByteArray(b, u + 10, attrSize - 2); + classWriter.bootstrapMethodsCount = boostrapMethodCount; + classWriter.bootstrapMethods = bootstrapMethods; + } + + /** + * Constructs a new {@link ClassReader} object. + * + * @param is an input stream from which to read the class. + * @throws IOException if a problem occurs during reading. + */ + public ClassReader(final InputStream is) throws IOException { + this(readClass(is, false)); + } + + /** + * Constructs a new {@link ClassReader} object. + * + * @param name the binary qualified name of the class to be read. + * @throws IOException if an exception occurs during reading. + */ + public ClassReader(final String name) throws IOException { + this(readClass(ClassLoader.getSystemResourceAsStream(name.replace('.', '/') + ".class"), true)); + } + + /** + * Reads the bytecode of a class. + * + * @param is an input stream from which to read the class. + * @param close true to close the input stream after reading. + * @return the bytecode read from the given input stream. + * @throws IOException if a problem occurs during reading. + */ + private static byte[] readClass(final InputStream is, boolean close) throws IOException { + if (is == null) { + throw new IOException("Class not found"); + } + try { + byte[] b = new byte[is.available()]; + int len = 0; + while (true) { + int n = is.read(b, len, b.length - len); + if (n == -1) { + if (len < b.length) { + byte[] c = new byte[len]; + System.arraycopy(b, 0, c, 0, len); + b = c; + } + return b; + } + len += n; + if (len == b.length) { + int last = is.read(); + if (last < 0) { + return b; + } + byte[] c = new byte[b.length + 1000]; + System.arraycopy(b, 0, c, 0, len); + c[len++] = (byte) last; + b = c; + } + } + } finally { + if (close) { + is.close(); + } + } + } + + // ------------------------------------------------------------------------ + // Public methods + // ------------------------------------------------------------------------ + + /** + * Makes the given visitor visit the Java class of this {@link ClassReader} . This class is the one specified in the + * constructor (see {@link #ClassReader(byte[]) ClassReader}). + * + * @param classVisitor the visitor that must visit this class. + * @param flags option flags that can be used to modify the default behavior of this class. See {@link #SKIP_DEBUG}, + * {@link #EXPAND_FRAMES} , {@link #SKIP_FRAMES}, {@link #SKIP_CODE}. + */ + public void accept(final ClassVisitor classVisitor, final int flags) { + accept(classVisitor, Attribute.DEFAULT_ATTRIBUTE_PROTOS, flags); + } + + /** + * Makes the given visitor visit the Java class of this {@link ClassReader}. This class is the one specified in the + * constructor (see {@link #ClassReader(byte[]) ClassReader}). + * + * @param classVisitor the visitor that must visit this class. + * @param attrs prototypes of the attributes that must be parsed during the visit of the class. Any attribute whose + * type is not equal to the type of one the prototypes will not be parsed: its byte array value will be passed + * unchanged to the ClassWriter. This may corrupt it if this value contains references to the constant pool, + * or has syntactic or semantic links with a class element that has been transformed by a class adapter between + * the reader and the writer. + * @param flags option flags that can be used to modify the default behavior of this class. See {@link #SKIP_DEBUG}, + * {@link #EXPAND_FRAMES} , {@link #SKIP_FRAMES}, {@link #SKIP_CODE}. + */ + public void accept(final ClassVisitor classVisitor, final Attribute[] attrs, final int flags) { + int u = header; // current offset in the class file + char[] c = new char[maxStringLength]; // buffer used to read strings + + Context context = new Context(); + context.attrs = attrs; + context.flags = flags; + context.buffer = c; + + // reads the class declaration + int access = readUnsignedShort(u); + String name = readClass(u + 2, c); + String superClass = readClass(u + 4, c); + String[] interfaces = new String[readUnsignedShort(u + 6)]; + u += 8; + for (int i = 0; i < interfaces.length; ++i) { + interfaces[i] = readClass(u, c); + u += 2; + } + + // reads the class attributes + String signature = null; + String sourceFile = null; + String sourceDebug = null; + 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(); + for (int i = readUnsignedShort(u); i > 0; --i) { + String attrName = readUTF8(u + 2, c); + // tests are sorted in decreasing frequency order + // (based on frequencies observed on typical classes) + if ("SourceFile".equals(attrName)) { + sourceFile = readUTF8(u + 8, c); + } else if ("InnerClasses".equals(attrName)) { + innerClasses = u + 8; + } else if ("EnclosingMethod".equals(attrName)) { + enclosingOwner = readClass(u + 8, c); + int item = readUnsignedShort(u + 10); + if (item != 0) { + enclosingName = readUTF8(items[item], c); + enclosingDesc = readUTF8(items[item] + 2, c); + } + } else if ("Signature".equals(attrName)) { + signature = readUTF8(u + 8, c); + } else if ("RuntimeVisibleAnnotations".equals(attrName)) { + anns = u + 8; + } else if ("RuntimeVisibleTypeAnnotations".equals(attrName)) { + tanns = u + 8; + } else if ("Deprecated".equals(attrName)) { + access |= Opcodes.ACC_DEPRECATED; + } else if ("Synthetic".equals(attrName)) { + access |= Opcodes.ACC_SYNTHETIC | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE; + } else if ("SourceDebugExtension".equals(attrName)) { + int len = readInt(u + 4); + sourceDebug = readUTF(u + 8, len, new char[len]); + } else if ("RuntimeInvisibleAnnotations".equals(attrName)) { + ianns = u + 8; + } 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++) { + bootstrapMethods[j] = v; + v += 2 + readUnsignedShort(v + 2) << 1; + } + context.bootstrapMethods = bootstrapMethods; + } else { + Attribute attr = readAttribute(attrs, attrName, u + 8, readInt(u + 4), c, -1, null); + if (attr != null) { + attr.next = attributes; + attributes = attr; + } + } + u += 6 + readInt(u + 4); + } + + // visits the class declaration + classVisitor.visit(readInt(items[1] - 7), access, name, signature, superClass, interfaces); + + // visits the source and debug info + if ((flags & SKIP_DEBUG) == 0 && (sourceFile != null || sourceDebug != null)) { + 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, enclosingDesc); + } + + // visits the class annotations and type annotations + 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 (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 (tanns != 0) { + for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) { + v = readAnnotationTarget(context, v); + v = readAnnotationValues( + v + 2, + c, + true, + classVisitor.visitTypeAnnotation(context.typeRef, context.typePath, readUTF8(v, c), true)); + } + } + if (itanns != 0) { + for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) { + v = readAnnotationTarget(context, v); + v = readAnnotationValues( + v + 2, + c, + true, + classVisitor.visitTypeAnnotation(context.typeRef, context.typePath, readUTF8(v, c), false)); + } + } + + // visits the attributes + while (attributes != null) { + Attribute attr = attributes.next; + attributes.next = null; + classVisitor.visitAttribute(attributes); + attributes = attr; + } + + // visits the inner classes + if (innerClasses != 0) { + int v = innerClasses + 2; + for (int i = readUnsignedShort(innerClasses); i > 0; --i) { + classVisitor.visitInnerClass( + readClass(v, c), readClass(v + 2, c), readUTF8(v + 4, c), readUnsignedShort(v + 6)); + v += 8; + } + } + + // visits the fields and methods + u = header + 10 + 2 * interfaces.length; + for (int i = readUnsignedShort(u - 2); i > 0; --i) { + u = readField(classVisitor, context, u); + } + u += 2; + for (int i = readUnsignedShort(u - 2); i > 0; --i) { + u = readMethod(classVisitor, context, u); + } + + // visits the end of the class + 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. + * + * @param classVisitor the visitor that must visit the field. + * @param context information about the class being parsed. + * @param u the start offset of the field in the class file. + * @return the offset of the first byte following the field in the class. + */ + private int readField(final ClassVisitor classVisitor, final Context context, int u) { + // reads the field declaration + char[] c = context.buffer; + int access = readUnsignedShort(u); + String name = readUTF8(u + 2, c); + String desc = readUTF8(u + 4, c); + u += 6; + + // reads the field attributes + String signature = null; + int anns = 0; + int ianns = 0; + int tanns = 0; + int itanns = 0; + Object value = null; + Attribute attributes = null; + + for (int i = readUnsignedShort(u); i > 0; --i) { + String attrName = readUTF8(u + 2, c); + // tests are sorted in decreasing frequency order + // (based on frequencies observed on typical classes) + if ("ConstantValue".equals(attrName)) { + int item = readUnsignedShort(u + 8); + value = item == 0 ? null : readConst(item, c); + } 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 ("RuntimeVisibleAnnotations".equals(attrName)) { + anns = u + 8; + } else if ("RuntimeVisibleTypeAnnotations".equals(attrName)) { + tanns = u + 8; + } else if ("RuntimeInvisibleAnnotations".equals(attrName)) { + ianns = u + 8; + } else if ("RuntimeInvisibleTypeAnnotations".equals(attrName)) { + itanns = u + 8; + } else { + Attribute attr = readAttribute(context.attrs, attrName, u + 8, readInt(u + 4), c, -1, null); + if (attr != null) { + attr.next = attributes; + attributes = attr; + } + } + u += 6 + readInt(u + 4); + } + u += 2; + + // visits the field declaration + FieldVisitor fv = classVisitor.visitField(access, name, desc, signature, value); + if (fv == null) { + return u; + } + + // visits the field annotations and type annotations + 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 (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 (tanns != 0) { + for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) { + v = readAnnotationTarget(context, v); + v = readAnnotationValues( + v + 2, + c, + true, + fv.visitTypeAnnotation(context.typeRef, context.typePath, readUTF8(v, c), true)); + } + } + if (itanns != 0) { + for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) { + v = readAnnotationTarget(context, v); + v = readAnnotationValues( + v + 2, + c, + true, + fv.visitTypeAnnotation(context.typeRef, context.typePath, readUTF8(v, c), false)); + } + } + + // visits the field attributes + while (attributes != null) { + Attribute attr = attributes.next; + attributes.next = null; + fv.visitAttribute(attributes); + attributes = attr; + } + + // visits the end of the field + fv.visitEnd(); + + return u; + } + + /** + * Reads a method and makes the given visitor visit it. + * + * @param classVisitor the visitor that must visit the method. + * @param context information about the class being parsed. + * @param u the start offset of the method in the class file. + * @return the offset of the first byte following the method in the class. + */ + private int readMethod(final ClassVisitor classVisitor, final Context context, int u) { + // reads the method declaration + char[] c = context.buffer; + context.access = readUnsignedShort(u); + context.name = readUTF8(u + 2, c); + context.desc = readUTF8(u + 4, c); + u += 6; + + // reads the method attributes + int code = 0; + int exception = 0; + String[] exceptions = null; + String signature = null; + int methodParameters = 0; + int anns = 0; + int ianns = 0; + int tanns = 0; + int itanns = 0; + int dann = 0; + int mpanns = 0; + int impanns = 0; + int firstAttribute = u; + Attribute attributes = null; + + for (int i = readUnsignedShort(u); i > 0; --i) { + String attrName = readUTF8(u + 2, c); + // tests are sorted in decreasing frequency order + // (based on frequencies observed on typical classes) + if ("Code".equals(attrName)) { + if ((context.flags & SKIP_CODE) == 0) { + code = u + 8; + } + } else if ("Exceptions".equals(attrName)) { + exceptions = new String[readUnsignedShort(u + 8)]; + exception = u + 10; + for (int j = 0; j < exceptions.length; ++j) { + exceptions[j] = readClass(exception, c); + exception += 2; + } + } else if ("Signature".equals(attrName)) { + signature = readUTF8(u + 8, c); + } else if ("Deprecated".equals(attrName)) { + context.access |= Opcodes.ACC_DEPRECATED; + } else if ("RuntimeVisibleAnnotations".equals(attrName)) { + anns = u + 8; + } else if ("RuntimeVisibleTypeAnnotations".equals(attrName)) { + tanns = u + 8; + } else if ("AnnotationDefault".equals(attrName)) { + dann = u + 8; + } else if ("Synthetic".equals(attrName)) { + context.access |= Opcodes.ACC_SYNTHETIC | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE; + } else if ("RuntimeInvisibleAnnotations".equals(attrName)) { + ianns = u + 8; + } else if ("RuntimeInvisibleTypeAnnotations".equals(attrName)) { + itanns = u + 8; + } else if ("RuntimeVisibleParameterAnnotations".equals(attrName)) { + mpanns = u + 8; + } else if ("RuntimeInvisibleParameterAnnotations".equals(attrName)) { + impanns = u + 8; + } else if ("MethodParameters".equals(attrName)) { + methodParameters = u + 8; + } else { + Attribute attr = readAttribute(context.attrs, attrName, u + 8, readInt(u + 4), c, -1, null); + if (attr != null) { + attr.next = attributes; + attributes = attr; + } + } + u += 6 + readInt(u + 4); + } + u += 2; + + // visits the method declaration + MethodVisitor mv = classVisitor.visitMethod(context.access, context.name, context.desc, signature, exceptions); + if (mv == null) { + return u; + } + + /* + * if the returned MethodVisitor is in fact a MethodWriter, it means + * there is no method adapter between the reader and the writer. If, in + * addition, the writer's constant pool was copied from this reader + * (mw.cw.cr == this), and the signature and exceptions of the method + * have not been changed, then it is possible to skip all visit events + * and just copy the original code of the method to the writer (the + * access, name and descriptor can have been changed, this is not + * important since they are not copied as is from the reader). + */ + if (mv instanceof MethodWriter) { + MethodWriter mw = (MethodWriter) mv; + if (mw.cw.cr == this && signature == mw.signature) { + boolean sameExceptions = false; + if (exceptions == null) { + sameExceptions = mw.exceptionCount == 0; + } else if (exceptions.length == mw.exceptionCount) { + sameExceptions = true; + for (int j = exceptions.length - 1; j >= 0; --j) { + exception -= 2; + if (mw.exceptions[j] != readUnsignedShort(exception)) { + sameExceptions = false; + break; + } + } + } + if (sameExceptions) { + /* + * we do not copy directly the code into MethodWriter to + * save a byte array copy operation. The real copy will be + * done in ClassWriter.toByteArray(). + */ + mw.classReaderOffset = firstAttribute; + mw.classReaderLength = u - firstAttribute; + return u; + } + } + } + + // visit the method parameters + if (methodParameters != 0) { + for (int i = b[methodParameters] & 0xFF, v = methodParameters + 1; i > 0; --i, v = v + 4) { + mv.visitParameter(readUTF8(v, c), readUnsignedShort(v + 2)); + } + } + + // visits the method annotations + if (dann != 0) { + AnnotationVisitor dv = mv.visitAnnotationDefault(); + readAnnotationValue(dann, c, null, dv); + if (dv != null) { + dv.visitEnd(); + } + } + 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 (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 (tanns != 0) { + for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) { + v = readAnnotationTarget(context, v); + v = readAnnotationValues( + v + 2, + c, + true, + mv.visitTypeAnnotation(context.typeRef, context.typePath, readUTF8(v, c), true)); + } + } + if (itanns != 0) { + for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) { + v = readAnnotationTarget(context, v); + v = readAnnotationValues( + v + 2, + c, + true, + mv.visitTypeAnnotation(context.typeRef, context.typePath, readUTF8(v, c), false)); + } + } + if (mpanns != 0) { + readParameterAnnotations(mv, context, mpanns, true); + } + if (impanns != 0) { + readParameterAnnotations(mv, context, impanns, false); + } + + // visits the method attributes + while (attributes != null) { + Attribute attr = attributes.next; + attributes.next = null; + mv.visitAttribute(attributes); + attributes = attr; + } + + // visits the method code + if (code != 0) { + mv.visitCode(); + readCode(mv, context, code); + } + + // visits the end of the method + mv.visitEnd(); + + return u; + } + + /** + * Reads the bytecode of a method and makes the given visitor visit it. + * + * @param mv the visitor that must visit the method's code. + * @param context information about the class being parsed. + * @param u the start offset of the code attribute in the class file. + */ + private void readCode(final MethodVisitor mv, final Context context, int u) { + // reads the header + byte[] b = this.b; + char[] c = context.buffer; + int maxStack = readUnsignedShort(u); + int maxLocals = readUnsignedShort(u + 2); + int codeLength = readInt(u + 4); + u += 8; + + // reads the bytecode to find the labels + int codeStart = u; + int codeEnd = u + codeLength; + Label[] labels = context.labels = new Label[codeLength + 2]; + createLabel(codeLength + 1, labels); + while (u < codeEnd) { + int offset = u - codeStart; + int opcode = b[u] & 0xFF; + switch (ClassWriter.TYPE[opcode]) { + case ClassWriter.NOARG_INSN: + case ClassWriter.IMPLVAR_INSN: + u += 1; + break; + case ClassWriter.LABEL_INSN: + 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: + case ClassWriter.ASM_LABELW_INSN: + createLabel(offset + readInt(u + 1), labels); + u += 5; + break; + case ClassWriter.WIDE_INSN: + opcode = b[u + 1] & 0xFF; + if (opcode == Opcodes.IINC) { + u += 6; + } else { + u += 4; + } + break; + case ClassWriter.TABL_INSN: + // skips 0 to 3 padding bytes + u = u + 4 - (offset & 3); + // reads instruction + createLabel(offset + readInt(u), labels); + for (int i = readInt(u + 8) - readInt(u + 4) + 1; i > 0; --i) { + createLabel(offset + readInt(u + 12), labels); + u += 4; + } + u += 12; + break; + case ClassWriter.LOOK_INSN: + // skips 0 to 3 padding bytes + u = u + 4 - (offset & 3); + // reads instruction + createLabel(offset + readInt(u), labels); + for (int i = readInt(u + 4); i > 0; --i) { + createLabel(offset + readInt(u + 12), labels); + u += 8; + } + u += 8; + break; + case ClassWriter.VAR_INSN: + case ClassWriter.SBYTE_INSN: + case ClassWriter.LDC_INSN: + u += 2; + break; + case ClassWriter.SHORT_INSN: + case ClassWriter.LDCW_INSN: + case ClassWriter.FIELDORMETH_INSN: + case ClassWriter.TYPE_INSN: + case ClassWriter.IINC_INSN: + u += 3; + break; + case ClassWriter.ITFMETH_INSN: + case ClassWriter.INDYMETH_INSN: + u += 5; + break; + // case MANA_INSN: + default: + u += 4; + break; + } + } + + // reads the try catch entries to find the labels, and also visits them + for (int i = readUnsignedShort(u); i > 0; --i) { + 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; + } + u += 2; + + // reads the code attributes + int[] tanns = null; // start index of each visible type annotation + int[] itanns = null; // start index of each invisible type annotation + int tann = 0; // current index in tanns array + int itann = 0; // current index in itanns array + int ntoff = -1; // next visible type annotation code offset + int nitoff = -1; // next invisible type annotation code offset + int varTable = 0; + int varTypeTable = 0; + boolean zip = true; + boolean unzip = (context.flags & EXPAND_FRAMES) != 0; + int stackMap = 0; + int stackMapSize = 0; + int frameCount = 0; + Context frame = null; + Attribute attributes = null; + + for (int i = readUnsignedShort(u); i > 0; --i) { + String attrName = readUTF8(u + 2, c); + if ("LocalVariableTable".equals(attrName)) { + if ((context.flags & SKIP_DEBUG) == 0) { + varTable = u + 8; + for (int j = readUnsignedShort(u + 8), v = u; j > 0; --j) { + int label = readUnsignedShort(v + 10); + createDebugLabel(label, labels); + label += readUnsignedShort(v + 12); + createDebugLabel(label, labels); + v += 10; + } + } + } else if ("LocalVariableTypeTable".equals(attrName)) { + varTypeTable = u + 8; + } else if ("LineNumberTable".equals(attrName)) { + if ((context.flags & SKIP_DEBUG) == 0) { + for (int j = readUnsignedShort(u + 8), v = u; j > 0; --j) { + int label = readUnsignedShort(v + 10); + createDebugLabel(label, labels); + Label l = labels[label]; + while (l.line > 0) { + if (l.next == null) { + l.next = new Label(); + } + l = l.next; + } + l.line = readUnsignedShort(v + 12); + v += 4; + } + } + } 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 ("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 ("StackMapTable".equals(attrName)) { + if ((context.flags & SKIP_FRAMES) == 0) { + stackMap = u + 10; + stackMapSize = readInt(u + 4); + frameCount = readUnsignedShort(u + 8); + } + /* + * here we do not extract the labels corresponding to the + * attribute content. This would require a full parsing of the + * attribute, which would need to be repeated in the second + * phase (see below). Instead the content of the attribute is + * read one frame at a time (i.e. after a frame has been + * visited, the next frame is read), and the labels it contains + * are also extracted one frame at a time. Thanks to the + * ordering of frames, having only a "one frame lookahead" is + * not a problem, i.e. it is not possible to see an offset + * smaller than the offset of the current insn and for which no + * Label exist. + */ + /* + * This is not true for UNINITIALIZED type offsets. We solve + * this by parsing the stack map table without a full decoding + * (see below). + */ + } else if ("StackMap".equals(attrName)) { + if ((context.flags & SKIP_FRAMES) == 0) { + zip = false; + stackMap = u + 10; + stackMapSize = readInt(u + 4); + frameCount = readUnsignedShort(u + 8); + } + /* + * IMPORTANT! here we assume that the frames are ordered, as in + * the StackMapTable attribute, although this is not guaranteed + * by the attribute format. + */ + } else { + for (int j = 0; j < context.attrs.length; ++j) { + if (context.attrs[j].type.equals(attrName)) { + Attribute attr = context.attrs[j].read(this, u + 8, readInt(u + 4), c, codeStart - 8, labels); + if (attr != null) { + attr.next = attributes; + attributes = attr; + } + } + } + } + u += 6 + readInt(u + 4); + } + u += 2; + + // generates the first (implicit) stack map frame + 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 + * allow the use of the "offset_delta + 1" rule in all cases + */ + frame = context; + frame.offset = -1; + frame.mode = 0; + frame.localCount = 0; + frame.localDiff = 0; + frame.stackCount = 0; + frame.local = new Object[maxLocals]; + frame.stack = new Object[maxStack]; + if (unzip) { + getImplicitFrame(context); + } + /* + * Finds labels for UNINITIALIZED frame types. Instead of decoding + * each element of the stack map table, we look for 3 consecutive + * bytes that "look like" an UNINITIALIZED type (tag 8, offset + * within code bounds, NEW instruction at this offset). We may find + * false positives (i.e. not real UNINITIALIZED types), but this + * should be rare, and the only consequence will be the creation of + * an unneeded label. This is better than creating a label for each + * NEW instruction, and faster than fully decoding the whole stack + * map table. + */ + for (int i = stackMap; i < stackMap + stackMapSize - 2; ++i) { + if (b[i] == 8) { // UNINITIALIZED FRAME TYPE + int v = readUnsignedShort(i + 1); + if (v >= 0 && v < codeLength) { + if ((b[codeStart + v] & 0xFF) == Opcodes.NEW) { + 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; + + // visits the label and line number for this offset, if any + Label l = labels[offset]; + if (l != null) { + Label next = l.next; + l.next = null; + mv.visitLabel(l); + if ((context.flags & SKIP_DEBUG) == 0 && l.line > 0) { + mv.visitLineNumber(l.line, l); + while (next != null) { + mv.visitLineNumber(next.line, l); + next = next.next; + } + } + } + + // visits the frame for this offset, if any + 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. + if (frame.offset != -1) { + if (!zip || unzip) { + mv.visitFrame(Opcodes.F_NEW, frame.localCount, frame.local, frame.stackCount, frame.stack); + } else { + 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); + --frameCount; + } else { + 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; + switch (ClassWriter.TYPE[opcode]) { + case ClassWriter.NOARG_INSN: + mv.visitInsn(opcode); + u += 1; + break; + case ClassWriter.IMPLVAR_INSN: + if (opcode > Opcodes.ISTORE) { + opcode -= 59; // ISTORE_0 + mv.visitVarInsn(Opcodes.ISTORE + (opcode >> 2), opcode & 0x3); + } else { + opcode -= 26; // ILOAD_0 + mv.visitVarInsn(Opcodes.ILOAD + (opcode >> 2), opcode & 0x3); + } + u += 1; + break; + case ClassWriter.LABEL_INSN: + mv.visitJumpInsn(opcode, labels[offset + readShort(u + 1)]); + u += 3; + break; + case ClassWriter.LABELW_INSN: + 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 + // with IFNOTxxx GOTO_W L:..., where IFNOTxxx is + // the "opposite" opcode of IFxxx (i.e., IFNE for IFEQ) + // and where 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 GOTO_W 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) { + mv.visitIincInsn(readUnsignedShort(u + 2), readShort(u + 4)); + u += 6; + } else { + mv.visitVarInsn(opcode, readUnsignedShort(u + 2)); + u += 4; + } + break; + case ClassWriter.TABL_INSN: { + // skips 0 to 3 padding bytes + u = u + 4 - (offset & 3); + // reads instruction + int label = offset + readInt(u); + int min = readInt(u + 4); + int max = readInt(u + 8); + Label[] table = new Label[max - min + 1]; + u += 12; + for (int i = 0; i < table.length; ++i) { + table[i] = labels[offset + readInt(u)]; + u += 4; + } + mv.visitTableSwitchInsn(min, max, labels[label], table); + break; + } + case ClassWriter.LOOK_INSN: { + // skips 0 to 3 padding bytes + u = u + 4 - (offset & 3); + // reads instruction + int label = offset + readInt(u); + int len = readInt(u + 4); + int[] keys = new int[len]; + Label[] values = new Label[len]; + u += 8; + for (int i = 0; i < len; ++i) { + keys[i] = readInt(u); + values[i] = labels[offset + readInt(u + 4)]; + u += 8; + } + mv.visitLookupSwitchInsn(labels[label], keys, values); + break; + } + case ClassWriter.VAR_INSN: + mv.visitVarInsn(opcode, b[u + 1] & 0xFF); + u += 2; + break; + case ClassWriter.SBYTE_INSN: + mv.visitIntInsn(opcode, b[u + 1]); + u += 2; + break; + case ClassWriter.SHORT_INSN: + mv.visitIntInsn(opcode, readShort(u + 1)); + u += 3; + break; + case ClassWriter.LDC_INSN: + mv.visitLdcInsn(readConst(b[u + 1] & 0xFF, c)); + u += 2; + break; + case ClassWriter.LDCW_INSN: + mv.visitLdcInsn(readConst(readUnsignedShort(u + 1), c)); + u += 3; + break; + case ClassWriter.FIELDORMETH_INSN: + case ClassWriter.ITFMETH_INSN: { + int cpIndex = items[readUnsignedShort(u + 1)]; + boolean itf = b[cpIndex - 1] == ClassWriter.IMETH; + String iowner = readClass(cpIndex, c); + cpIndex = items[readUnsignedShort(cpIndex + 2)]; + String iname = readUTF8(cpIndex, c); + String idesc = readUTF8(cpIndex + 2, c); + if (opcode < Opcodes.INVOKEVIRTUAL) { + mv.visitFieldInsn(opcode, iowner, iname, idesc); + } else { + mv.visitMethodInsn(opcode, iowner, iname, idesc, itf); + } + if (opcode == Opcodes.INVOKEINTERFACE) { + u += 5; + } else { + u += 3; + } + break; + } + case ClassWriter.INDYMETH_INSN: { + int cpIndex = items[readUnsignedShort(u + 1)]; + int bsmIndex = context.bootstrapMethods[readUnsignedShort(cpIndex)]; + Handle bsm = (Handle) readConst(readUnsignedShort(bsmIndex), c); + int bsmArgCount = readUnsignedShort(bsmIndex + 2); + Object[] bsmArgs = new Object[bsmArgCount]; + bsmIndex += 4; + for (int i = 0; i < bsmArgCount; i++) { + bsmArgs[i] = readConst(readUnsignedShort(bsmIndex), c); + bsmIndex += 2; + } + cpIndex = items[readUnsignedShort(cpIndex + 2)]; + String iname = readUTF8(cpIndex, c); + String idesc = readUTF8(cpIndex + 2, c); + mv.visitInvokeDynamicInsn(iname, idesc, bsm, bsmArgs); + u += 5; + break; + } + case ClassWriter.TYPE_INSN: + mv.visitTypeInsn(opcode, readClass(u + 1, c)); + u += 3; + break; + case ClassWriter.IINC_INSN: + mv.visitIincInsn(b[u + 1] & 0xFF, b[u + 2]); + u += 3; + break; + // case MANA_INSN: + default: + mv.visitMultiANewArrayInsn(readClass(u + 1, c), b[u + 3] & 0xFF); + u += 4; + break; + } + + // visit the instruction annotations, if any + while (tanns != null && tann < tanns.length && ntoff <= offset) { + if (ntoff == offset) { + int v = readAnnotationTarget(context, tanns[tann]); + readAnnotationValues( + v + 2, + c, + true, + mv.visitInsnAnnotation(context.typeRef, context.typePath, readUTF8(v, c), true)); + } + ntoff = ++tann >= tanns.length || readByte(tanns[tann]) < 0x43 + ? -1 + : readUnsignedShort(tanns[tann] + 1); + } + while (itanns != null && itann < itanns.length && nitoff <= offset) { + if (nitoff == offset) { + int v = readAnnotationTarget(context, itanns[itann]); + readAnnotationValues( + v + 2, + c, + true, + mv.visitInsnAnnotation(context.typeRef, context.typePath, readUTF8(v, c), false)); + } + nitoff = ++itann >= itanns.length || readByte(itanns[itann]) < 0x43 + ? -1 + : readUnsignedShort(itanns[itann] + 1); + } + } + if (labels[codeLength] != null) { + mv.visitLabel(labels[codeLength]); + } + + // visits the local variable tables + if ((context.flags & SKIP_DEBUG) == 0 && varTable != 0) { + int[] typeTable = null; + if (varTypeTable != 0) { + u = varTypeTable + 2; + typeTable = new int[readUnsignedShort(varTypeTable) * 3]; + for (int i = typeTable.length; i > 0; ) { + typeTable[--i] = u + 6; // signature + typeTable[--i] = readUnsignedShort(u + 8); // index + typeTable[--i] = readUnsignedShort(u); // start + u += 10; + } + } + u = varTable + 2; + for (int i = readUnsignedShort(varTable); i > 0; --i) { + int start = readUnsignedShort(u); + int length = readUnsignedShort(u + 2); + int index = readUnsignedShort(u + 8); + String vsignature = null; + if (typeTable != null) { + for (int j = 0; j < typeTable.length; j += 3) { + if (typeTable[j] == start && typeTable[j + 1] == index) { + vsignature = readUTF8(typeTable[j + 2], c); + break; + } + } + } + mv.visitLocalVariable( + readUTF8(u + 4, c), + readUTF8(u + 6, c), + vsignature, + labels[start], + labels[start + length], + index); + u += 10; + } + } + + // visits the local variables type annotations + if (tanns != null) { + for (int i = 0; i < tanns.length; ++i) { + if ((readByte(tanns[i]) >> 1) == (0x40 >> 1)) { + int v = readAnnotationTarget(context, tanns[i]); + v = readAnnotationValues( + v + 2, + c, + true, + mv.visitLocalVariableAnnotation( + context.typeRef, + context.typePath, + context.start, + context.end, + context.index, + readUTF8(v, c), + true)); + } + } + } + if (itanns != null) { + for (int i = 0; i < itanns.length; ++i) { + if ((readByte(itanns[i]) >> 1) == (0x40 >> 1)) { + int v = readAnnotationTarget(context, itanns[i]); + v = readAnnotationValues( + v + 2, + c, + true, + mv.visitLocalVariableAnnotation( + context.typeRef, + context.typePath, + context.start, + context.end, + context.index, + readUTF8(v, c), + false)); + } + } + } + + // visits the code attributes + while (attributes != null) { + Attribute attr = attributes.next; + attributes.next = null; + mv.visitAttribute(attributes); + attributes = attr; + } + + // visits the max stack and max locals values + mv.visitMaxs(maxStack, maxLocals); + } + + /** + * Parses a type annotation table to find the labels, and to visit the try catch block annotations. + * + * @param u the start offset of a type annotation table. + * @param mv the method visitor to be used to visit the try catch block annotations. + * @param context information about the class being parsed. + * @param visible if the type annotation table to parse contains runtime visible annotations. + * @return the start offset of each type annotation in the parsed table. + */ + private int[] readTypeAnnotations(final MethodVisitor mv, final Context context, int u, boolean visible) { + char[] c = context.buffer; + int[] offsets = new int[readUnsignedShort(u)]; + u += 2; + for (int i = 0; i < offsets.length; ++i) { + offsets[i] = u; + int target = readInt(u); + switch (target >>> 24) { + case 0x00: // CLASS_TYPE_PARAMETER + case 0x01: // METHOD_TYPE_PARAMETER + case 0x16: // METHOD_FORMAL_PARAMETER + u += 2; + break; + case 0x13: // FIELD + case 0x14: // METHOD_RETURN + case 0x15: // METHOD_RECEIVER + u += 1; + break; + case 0x40: // LOCAL_VARIABLE + case 0x41: // RESOURCE_VARIABLE + for (int j = readUnsignedShort(u + 1); j > 0; --j) { + int start = readUnsignedShort(u + 3); + int length = readUnsignedShort(u + 5); + createLabel(start, context.labels); + createLabel(start + length, context.labels); + u += 6; + } + u += 3; + break; + case 0x47: // CAST + case 0x48: // CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT + case 0x49: // METHOD_INVOCATION_TYPE_ARGUMENT + case 0x4A: // CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT + case 0x4B: // METHOD_REFERENCE_TYPE_ARGUMENT + u += 4; + break; + // case 0x10: // CLASS_EXTENDS + // case 0x11: // CLASS_TYPE_PARAMETER_BOUND + // case 0x12: // METHOD_TYPE_PARAMETER_BOUND + // case 0x17: // THROWS + // case 0x42: // EXCEPTION_PARAMETER + // case 0x43: // INSTANCEOF + // case 0x44: // NEW + // case 0x45: // CONSTRUCTOR_REFERENCE + // case 0x46: // METHOD_REFERENCE + default: + u += 3; + break; + } + int pathLength = readByte(u); + if ((target >>> 24) == 0x42) { + TypePath path = pathLength == 0 ? null : new TypePath(b, u); + u += 1 + 2 * pathLength; + u = readAnnotationValues( + u + 2, c, true, mv.visitTryCatchAnnotation(target, path, readUTF8(u, c), visible)); + } else { + u = readAnnotationValues(u + 3 + 2 * pathLength, c, true, null); + } + } + return offsets; + } + + /** + * Parses the header of a type annotation to extract its target_type and target_path (the result is stored in the + * given context), and returns the start offset of the rest of the type_annotation structure (i.e. the offset to the + * type_index field, which is followed by num_element_value_pairs and then the name,value pairs). + * + * @param context information about the class being parsed. This is where the extracted target_type and target_path + * must be stored. + * @param u the start offset of a type_annotation structure. + * @return the start offset of the rest of the type_annotation structure. + */ + private int readAnnotationTarget(final Context context, int u) { + int target = readInt(u); + switch (target >>> 24) { + case 0x00: // CLASS_TYPE_PARAMETER + case 0x01: // METHOD_TYPE_PARAMETER + case 0x16: // METHOD_FORMAL_PARAMETER + target &= 0xFFFF0000; + u += 2; + break; + case 0x13: // FIELD + case 0x14: // METHOD_RETURN + case 0x15: // METHOD_RECEIVER + target &= 0xFF000000; + u += 1; + break; + case 0x40: // LOCAL_VARIABLE + case 0x41: { // RESOURCE_VARIABLE + target &= 0xFF000000; + int n = readUnsignedShort(u + 1); + context.start = new Label[n]; + context.end = new Label[n]; + context.index = new int[n]; + u += 3; + for (int i = 0; i < n; ++i) { + int start = readUnsignedShort(u); + int length = readUnsignedShort(u + 2); + context.start[i] = createLabel(start, context.labels); + context.end[i] = createLabel(start + length, context.labels); + context.index[i] = readUnsignedShort(u + 4); + u += 6; + } + break; + } + case 0x47: // CAST + case 0x48: // CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT + case 0x49: // METHOD_INVOCATION_TYPE_ARGUMENT + case 0x4A: // CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT + case 0x4B: // METHOD_REFERENCE_TYPE_ARGUMENT + target &= 0xFF0000FF; + u += 4; + break; + // case 0x10: // CLASS_EXTENDS + // case 0x11: // CLASS_TYPE_PARAMETER_BOUND + // case 0x12: // METHOD_TYPE_PARAMETER_BOUND + // case 0x17: // THROWS + // case 0x42: // EXCEPTION_PARAMETER + // case 0x43: // INSTANCEOF + // case 0x44: // NEW + // case 0x45: // CONSTRUCTOR_REFERENCE + // case 0x46: // METHOD_REFERENCE + default: + target &= (target >>> 24) < 0x43 ? 0xFFFFFF00 : 0xFF000000; + u += 3; + break; + } + int pathLength = readByte(u); + context.typeRef = target; + context.typePath = pathLength == 0 ? null : new TypePath(b, u); + return u + 1 + 2 * pathLength; + } + + /** + * Reads parameter annotations and makes the given visitor visit them. + * + * @param mv the visitor that must visit the annotations. + * @param context information about the class being parsed. + * @param v start offset in {@link #b b} of the annotations to be read. + * @param visible <tt>true</tt> if the annotations to be read are visible at runtime. + */ + private void readParameterAnnotations(final MethodVisitor mv, final Context context, int v, final boolean visible) { + int i; + int n = b[v++] & 0xFF; + // workaround for a bug in javac (javac compiler generates a parameter + // annotation array whose size is equal to the number of parameters in + // the Java source file, while it should generate an array whose size is + // equal to the number of parameters in the method descriptor - which + // includes the synthetic parameters added by the compiler). This work- + // around supposes that the synthetic parameters are the first ones. + int synthetics = Type.getArgumentTypes(context.desc).length - n; + AnnotationVisitor av; + for (i = 0; i < synthetics; ++i) { + // virtual annotation to detect synthetic parameters in MethodWriter + av = mv.visitParameterAnnotation(i, "Ljava/lang/Synthetic;", false); + if (av != null) { + av.visitEnd(); + } + } + char[] c = context.buffer; + for (; i < n + synthetics; ++i) { + int j = readUnsignedShort(v); + v += 2; + for (; j > 0; --j) { + av = mv.visitParameterAnnotation(i, readUTF8(v, c), visible); + v = readAnnotationValues(v + 2, c, true, av); + } + } + } + + /** + * Reads the values of an annotation and makes the given visitor visit them. + * + * @param v the start offset in {@link #b b} of the values to be read (including the unsigned short that gives the + * number of values). + * @param buf buffer to be used to call {@link #readUTF8 readUTF8}, {@link #readClass(int,char[]) readClass} or + * {@link #readConst readConst}. + * @param named if the annotation values are named or not. + * @param av the visitor that must visit the values. + * @return the end offset of the annotation values. + */ + private int readAnnotationValues(int v, final char[] buf, final boolean named, final AnnotationVisitor av) { + int i = readUnsignedShort(v); + v += 2; + if (named) { + for (; i > 0; --i) { + v = readAnnotationValue(v + 2, buf, readUTF8(v, buf), av); + } + } else { + for (; i > 0; --i) { + v = readAnnotationValue(v, buf, null, av); + } + } + if (av != null) { + av.visitEnd(); + } + return v; + } + + /** + * Reads a value of an annotation and makes the given visitor visit it. + * + * @param v the start offset in {@link #b b} of the value to be read (not including the value name constant pool + * index). + * @param buf buffer to be used to call {@link #readUTF8 readUTF8}, {@link #readClass(int,char[]) readClass} or + * {@link #readConst readConst}. + * @param name the name of the value to be read. + * @param av the visitor that must visit the value. + * @return the end offset of the annotation value. + */ + private int readAnnotationValue(int v, final char[] buf, final String name, final AnnotationVisitor av) { + int i; + if (av == null) { + switch (b[v] & 0xFF) { + case 'e': // enum_const_value + return v + 5; + case '@': // annotation_value + return readAnnotationValues(v + 3, buf, true, null); + case '[': // array_value + return readAnnotationValues(v + 1, buf, false, null); + default: + return v + 3; + } + } + switch (b[v++] & 0xFF) { + case 'I': // pointer to CONSTANT_Integer + case 'J': // pointer to CONSTANT_Long + case 'F': // pointer to CONSTANT_Float + case 'D': // pointer to CONSTANT_Double + av.visit(name, readConst(readUnsignedShort(v), buf)); + v += 2; + break; + case 'B': // pointer to CONSTANT_Byte + av.visit(name, (byte) readInt(items[readUnsignedShort(v)])); + v += 2; + break; + case 'Z': // pointer to CONSTANT_Boolean + av.visit(name, readInt(items[readUnsignedShort(v)]) == 0 ? Boolean.FALSE : Boolean.TRUE); + v += 2; + break; + case 'S': // pointer to CONSTANT_Short + av.visit(name, (short) readInt(items[readUnsignedShort(v)])); + v += 2; + break; + case 'C': // pointer to CONSTANT_Char + av.visit(name, (char) readInt(items[readUnsignedShort(v)])); + v += 2; + break; + case 's': // pointer to CONSTANT_Utf8 + av.visit(name, readUTF8(v, buf)); + v += 2; + break; + case 'e': // enum_const_value + av.visitEnum(name, readUTF8(v, buf), readUTF8(v + 2, buf)); + v += 4; + break; + case 'c': // class_info + av.visit(name, Type.getType(readUTF8(v, buf))); + v += 2; + break; + case '@': // annotation_value + v = readAnnotationValues(v + 2, buf, true, av.visitAnnotation(name, readUTF8(v, buf))); + break; + case '[': // array_value + int size = readUnsignedShort(v); + v += 2; + if (size == 0) { + return readAnnotationValues(v - 2, buf, false, av.visitArray(name)); + } + switch (this.b[v++] & 0xFF) { + case 'B': + byte[] bv = new byte[size]; + for (i = 0; i < size; i++) { + bv[i] = (byte) readInt(items[readUnsignedShort(v)]); + v += 3; + } + av.visit(name, bv); + --v; + break; + case 'Z': + boolean[] zv = new boolean[size]; + for (i = 0; i < size; i++) { + zv[i] = readInt(items[readUnsignedShort(v)]) != 0; + v += 3; + } + av.visit(name, zv); + --v; + break; + case 'S': + short[] sv = new short[size]; + for (i = 0; i < size; i++) { + sv[i] = (short) readInt(items[readUnsignedShort(v)]); + v += 3; + } + av.visit(name, sv); + --v; + break; + case 'C': + char[] cv = new char[size]; + for (i = 0; i < size; i++) { + cv[i] = (char) readInt(items[readUnsignedShort(v)]); + v += 3; + } + av.visit(name, cv); + --v; + break; + case 'I': + int[] iv = new int[size]; + for (i = 0; i < size; i++) { + iv[i] = readInt(items[readUnsignedShort(v)]); + v += 3; + } + av.visit(name, iv); + --v; + break; + case 'J': + long[] lv = new long[size]; + for (i = 0; i < size; i++) { + lv[i] = readLong(items[readUnsignedShort(v)]); + v += 3; + } + av.visit(name, lv); + --v; + break; + case 'F': + float[] fv = new float[size]; + for (i = 0; i < size; i++) { + fv[i] = Float.intBitsToFloat(readInt(items[readUnsignedShort(v)])); + v += 3; + } + av.visit(name, fv); + --v; + break; + case 'D': + double[] dv = new double[size]; + for (i = 0; i < size; i++) { + dv[i] = Double.longBitsToDouble(readLong(items[readUnsignedShort(v)])); + v += 3; + } + av.visit(name, dv); + --v; + break; + default: + v = readAnnotationValues(v - 3, buf, false, av.visitArray(name)); + } + } + return v; + } + + /** + * Computes the implicit frame of the method currently being parsed (as defined in the given {@link Context}) and + * stores it in the given context. + * + * @param frame information about the class being parsed. + */ + private void getImplicitFrame(final Context frame) { + String desc = frame.desc; + Object[] locals = frame.local; + int local = 0; + if ((frame.access & Opcodes.ACC_STATIC) == 0) { + if ("".equals(frame.name)) { + locals[local++] = Opcodes.UNINITIALIZED_THIS; + } else { + locals[local++] = readClass(header + 2, frame.buffer); + } + } + int i = 1; + loop: + while (true) { + int j = i; + switch (desc.charAt(i++)) { + case 'Z': + case 'C': + case 'B': + case 'S': + case 'I': + locals[local++] = Opcodes.INTEGER; + break; + case 'F': + locals[local++] = Opcodes.FLOAT; + break; + case 'J': + locals[local++] = Opcodes.LONG; + break; + case 'D': + locals[local++] = Opcodes.DOUBLE; + break; + case '[': + while (desc.charAt(i) == '[') { + ++i; + } + if (desc.charAt(i) == 'L') { + ++i; + while (desc.charAt(i) != ';') { + ++i; + } + } + locals[local++] = desc.substring(j, ++i); + break; + case 'L': + while (desc.charAt(i) != ';') { + ++i; + } + locals[local++] = desc.substring(j + 1, i++); + break; + default: + break loop; + } + } + frame.localCount = local; + } + + /** + * Reads a stack map frame and stores the result in the given {@link Context} object. + * + * @param stackMap the start offset of a stack map frame in the class file. + * @param zip if the stack map frame at stackMap is compressed or not. + * @param unzip if the stack map frame must be uncompressed. + * @param frame where the parsed stack map frame must be stored. + * @return the offset of the first byte following the parsed frame. + */ + private int readFrame(int stackMap, boolean zip, boolean unzip, Context frame) { + char[] c = frame.buffer; + Label[] labels = frame.labels; + int tag; + int delta; + if (zip) { + tag = b[stackMap++] & 0xFF; + } else { + tag = MethodWriter.FULL_FRAME; + frame.offset = -1; + } + frame.localDiff = 0; + if (tag < MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME) { + delta = tag; + frame.mode = Opcodes.F_SAME; + frame.stackCount = 0; + } else if (tag < MethodWriter.RESERVED) { + delta = tag - MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME; + stackMap = readFrameType(frame.stack, 0, stackMap, c, labels); + frame.mode = Opcodes.F_SAME1; + frame.stackCount = 1; + } else { + delta = readUnsignedShort(stackMap); + stackMap += 2; + if (tag == MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) { + stackMap = readFrameType(frame.stack, 0, stackMap, c, labels); + frame.mode = Opcodes.F_SAME1; + frame.stackCount = 1; + } else if (tag >= MethodWriter.CHOP_FRAME && tag < MethodWriter.SAME_FRAME_EXTENDED) { + frame.mode = Opcodes.F_CHOP; + frame.localDiff = MethodWriter.SAME_FRAME_EXTENDED - tag; + frame.localCount -= frame.localDiff; + frame.stackCount = 0; + } else if (tag == MethodWriter.SAME_FRAME_EXTENDED) { + frame.mode = Opcodes.F_SAME; + frame.stackCount = 0; + } else if (tag < MethodWriter.FULL_FRAME) { + int local = unzip ? frame.localCount : 0; + for (int i = tag - MethodWriter.SAME_FRAME_EXTENDED; i > 0; i--) { + stackMap = readFrameType(frame.local, local++, stackMap, c, labels); + } + frame.mode = Opcodes.F_APPEND; + frame.localDiff = tag - MethodWriter.SAME_FRAME_EXTENDED; + frame.localCount += frame.localDiff; + frame.stackCount = 0; + } else { // if (tag == FULL_FRAME) { + frame.mode = Opcodes.F_FULL; + int n = readUnsignedShort(stackMap); + stackMap += 2; + frame.localDiff = n; + frame.localCount = n; + for (int local = 0; n > 0; n--) { + stackMap = readFrameType(frame.local, local++, stackMap, c, labels); + } + n = readUnsignedShort(stackMap); + stackMap += 2; + frame.stackCount = n; + for (int stack = 0; n > 0; n--) { + stackMap = readFrameType(frame.stack, stack++, stackMap, c, labels); + } + } + } + frame.offset += delta + 1; + createLabel(frame.offset, labels); + return stackMap; + } + + /** + * Reads a stack map frame type and stores it at the given index in the given array. + * + * @param frame the array where the parsed type must be stored. + * @param index the index in 'frame' where the parsed type must be stored. + * @param v the start offset of the stack map frame type to read. + * @param buf a buffer to read strings. + * @param labels the labels of the method currently being parsed, indexed by their offset. If the parsed type is an + * Uninitialized type, a new label for the corresponding NEW instruction is stored in this array if it does not + * already exist. + * @return the offset of the first byte after the parsed type. + */ + private int readFrameType(final Object[] frame, final int index, int v, final char[] buf, final Label[] labels) { + int type = b[v++] & 0xFF; + switch (type) { + case 0: + frame[index] = Opcodes.TOP; + break; + case 1: + frame[index] = Opcodes.INTEGER; + break; + case 2: + frame[index] = Opcodes.FLOAT; + break; + case 3: + frame[index] = Opcodes.DOUBLE; + break; + case 4: + frame[index] = Opcodes.LONG; + break; + case 5: + frame[index] = Opcodes.NULL; + break; + case 6: + frame[index] = Opcodes.UNINITIALIZED_THIS; + break; + case 7: // Object + frame[index] = readClass(v, buf); + v += 2; + break; + default: // Uninitialized + frame[index] = createLabel(readUnsignedShort(v), labels); + v += 2; + } + return v; + } + + /** + * Returns the label corresponding to the given offset. The default implementation of this method creates a label + * for the given offset if it has not been already created. + * + * @param offset a bytecode offset in a method. + * @param labels the already created labels, indexed by their offset. If a label already exists for offset this + * method must not create a new one. Otherwise it must store the new label in this array. + * @return a non null Label, which must be equal to labels[offset]. + */ + protected Label readLabel(int offset, Label[] labels) { + if (labels[offset] == null) { + labels[offset] = new Label(); + } + 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. + * + * @return the start index of the attribute_info structure of this class. + */ + private int getAttributes() { + // skips the header + int u = header + 8 + readUnsignedShort(header + 6) * 2; + // skips fields and methods + for (int i = readUnsignedShort(u); i > 0; --i) { + for (int j = readUnsignedShort(u + 8); j > 0; --j) { + u += 6 + readInt(u + 12); + } + u += 8; + } + u += 2; + for (int i = readUnsignedShort(u); i > 0; --i) { + for (int j = readUnsignedShort(u + 8); j > 0; --j) { + u += 6 + readInt(u + 12); + } + u += 8; + } + // the attribute_info structure starts just after the methods + return u + 2; + } + + /** + * Reads an attribute in {@link #b b}. + * + * @param attrs prototypes of the attributes that must be parsed during the visit of the class. Any attribute whose + * type is not equal to the type of one the prototypes is ignored (i.e. an empty {@link Attribute} instance is + * returned). + * @param type the type of the attribute. + * @param off index of the first byte of the attribute's content in {@link #b b}. The 6 attribute header bytes, + * containing the type and the length of the attribute, are not taken into account here (they have already been + * read). + * @param len the length of the attribute's content. + * @param buf buffer to be used to call {@link #readUTF8 readUTF8}, {@link #readClass(int,char[]) readClass} or + * {@link #readConst readConst}. + * @param codeOff index of the first byte of code's attribute content in {@link #b b}, or -1 if the attribute to be + * read is not a code attribute. The 6 attribute header bytes, containing the type and the length of the + * attribute, are not taken into account here. + * @param labels the labels of the method's code, or <tt>null</tt> if the attribute to be read is + * not a code attribute. + * @return the attribute that has been read, or <tt>null</tt> to skip this attribute. + */ + private Attribute readAttribute( + final Attribute[] attrs, + final String type, + final int off, + final int len, + final char[] buf, + final int codeOff, + final Label[] labels) { + for (int i = 0; i < attrs.length; ++i) { + if (attrs[i].type.equals(type)) { + return attrs[i].read(this, off, len, buf, codeOff, labels); + } + } + return new Attribute(type).read(this, off, len, null, -1, null); + } + + // ------------------------------------------------------------------------ + // Utility methods: low level parsing + // ------------------------------------------------------------------------ + + /** + * Returns the number of constant pool items in {@link #b b}. + * + * @return the number of constant pool items in {@link #b b}. + */ + public int getItemCount() { + return items.length; + } + + /** + * Returns the start index of the constant pool item in {@link #b b}, plus one. This method is intended for + * {@link Attribute} sub classes, and is normally not needed by class generators or adapters. + * + * @param item the index a constant pool item. + * @return the start index of the constant pool item in {@link #b b}, plus one. + */ + public int getItem(final int item) { + return items[item]; + } + + /** + * Returns the maximum length of the strings contained in the constant pool of the class. + * + * @return the maximum length of the strings contained in the constant pool of the class. + */ + public int getMaxStringLength() { + return maxStringLength; + } + + /** + * Reads a byte value in {@link #b b}. This method is intended for {@link Attribute} sub classes, and is normally + * not needed by class generators or adapters. + * + * @param index the start index of the value to be read in {@link #b b}. + * @return the read value. + */ + public int readByte(final int index) { + return b[index] & 0xFF; + } + + /** + * Reads an unsigned short value in {@link #b b}. This method is intended for {@link Attribute} sub classes, and + * is normally not needed by class generators or adapters. + * + * @param index the start index of the value to be read in {@link #b b}. + * @return the read value. + */ + public int readUnsignedShort(final int index) { + byte[] b = this.b; + return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF); + } + + /** + * Reads a signed short value in {@link #b b}. This method is intended for {@link Attribute} sub classes, and is + * normally not needed by class generators or adapters. + * + * @param index the start index of the value to be read in {@link #b b}. + * @return the read value. + */ + public short readShort(final int index) { + byte[] b = this.b; + return (short) (((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF)); + } + + /** + * Reads a signed int value in {@link #b b}. This method is intended for {@link Attribute} sub classes, and is + * normally not needed by class generators or adapters. + * + * @param index the start index of the value to be read in {@link #b b}. + * @return the read value. + */ + public int readInt(final int index) { + byte[] b = this.b; + return ((b[index] & 0xFF) << 24) + | ((b[index + 1] & 0xFF) << 16) + | ((b[index + 2] & 0xFF) << 8) + | (b[index + 3] & 0xFF); + } + + /** + * Reads a signed long value in {@link #b b}. This method is intended for {@link Attribute} sub classes, and is + * normally not needed by class generators or adapters. + * + * @param index the start index of the value to be read in {@link #b b}. + * @return the read value. + */ + public long readLong(final int index) { + long l1 = readInt(index); + long l0 = readInt(index + 4) & 0xFFFFFFFFL; + return (l1 << 32) | l0; + } + + /** + * Reads an UTF8 string constant pool item in {@link #b b}. This method is intended for {@link Attribute} sub + * classes, and is normally not needed by class generators or adapters. + * + * @param index the start index of an unsigned short value in {@link #b b}, whose value is the index of an UTF8 + * 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 UTF8 item. + */ + public String readUTF8(int index, final char[] buf) { + int item = readUnsignedShort(index); + if (index == 0 || item == 0) { + return null; + } + String s = strings[item]; + if (s != null) { + return s; + } + index = items[item]; + return strings[item] = readUTF(index + 2, readUnsignedShort(index), buf); + } + + /** + * Reads UTF8 string in {@link #b b}. + * + * @param index start offset of the UTF8 string to be read. + * @param utfLen length of the UTF8 string to be read. + * @param buf buffer to be used to read the string. This buffer must be sufficiently large. It is not automatically + * resized. + * @return the String corresponding to the specified UTF8 string. + */ + private String readUTF(int index, final int utfLen, final char[] buf) { + int endIndex = index + utfLen; + byte[] b = this.b; + int strLen = 0; + int c; + int st = 0; + char cc = 0; + while (index < endIndex) { + c = b[index++]; + switch (st) { + case 0: + c = c & 0xFF; + if (c < 0x80) { // 0xxxxxxx + buf[strLen++] = (char) c; + } else if (c < 0xE0 && c > 0xBF) { // 110x xxxx 10xx xxxx + cc = (char) (c & 0x1F); + st = 1; + } else { // 1110 xxxx 10xx xxxx 10xx xxxx + cc = (char) (c & 0x0F); + st = 2; + } + break; + + case 1: // byte 2 of 2-byte char or byte 3 of 3-byte char + buf[strLen++] = (char) ((cc << 6) | (c & 0x3F)); + st = 0; + break; + + case 2: // byte 2 of 3-byte char + cc = (char) ((cc << 6) | (c & 0x3F)); + st = 1; + break; + } + } + 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}. This method is intended for {@link Attribute} sub classes, + * and is normally not needed by class generators or adapters. + * + * @param index the start index of an unsigned short value in {@link #b b}, whose value is the index of a class + * 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 class item. + */ + public String readClass(final int index, final char[] buf) { + return readStringish(index, buf); + } + + /** + * Reads a module constant pool item in {@link #b b}. This method is intended for {@link Attribute} sub classes, + * and is normally not needed by class generators or adapters. + * + * @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(final int index, final char[] buf) { + return readStringish(index, buf); + } + + /** + * Reads a module constant pool item in {@link #b b}. This method is intended for {@link Attribute} sub classes, + * and is normally not needed by class generators or adapters. + * + * @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(final int index, final char[] buf) { + return readStringish(index, buf); + } + + /** + * Reads a numeric or string constant pool item in {@link #b b}. This method is intended for {@link Attribute} + * sub classes, and is normally not needed by class generators or adapters. + * + * @param item the index of a 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 {@link Integer}, {@link Float}, {@link Long}, {@link Double}, {@link String}, {@link Type} or + * {@link Handle} corresponding to the given constant pool item. + */ + public Object readConst(final int item, final char[] buf) { + int index = items[item]; + switch (b[index - 1]) { + case ClassWriter.INT: + return readInt(index); + case ClassWriter.FLOAT: + return Float.intBitsToFloat(readInt(index)); + case ClassWriter.LONG: + return readLong(index); + case ClassWriter.DOUBLE: + return Double.longBitsToDouble(readLong(index)); + case ClassWriter.CLASS: + return Type.getObjectType(readUTF8(index, buf)); + case ClassWriter.STR: + return readUTF8(index, buf); + case ClassWriter.MTYPE: + return Type.getMethodType(readUTF8(index, buf)); + default: // case ClassWriter.HANDLE_BASE + [1..9]: + int tag = readByte(index); + int[] items = this.items; + int cpIndex = items[readUnsignedShort(index + 1)]; + boolean itf = b[cpIndex - 1] == ClassWriter.IMETH; + String owner = readClass(cpIndex, buf); + cpIndex = items[readUnsignedShort(cpIndex + 2)]; + String name = readUTF8(cpIndex, buf); + String desc = readUTF8(cpIndex + 2, buf); + return new Handle(tag, owner, name, desc, itf); + } + } +} diff --git a/src/main/java/org/redkale/asm/ClassVisitor.java b/src/main/java/org/redkale/asm/ClassVisitor.java index dacce8dc2..57ae69cfd 100644 --- a/src/main/java/org/redkale/asm/ClassVisitor.java +++ b/src/main/java/org/redkale/asm/ClassVisitor.java @@ -1,292 +1,292 @@ -/* - * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */ - -/* - * - * - * - * - * - * ASM: a very small and fast Java bytecode manipulation framework - * Copyright (c) 2000-2011 INRIA, France Telecom - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.redkale.asm; - -/** - * A visitor to visit a Java class. The methods of this class must be called in the following order: - * <tt>visit</tt> [ <tt>visitSource</tt> ] [ <tt>visitModule</tt> ][ - * <tt>visitOuterClass</tt> ] ( <tt>visitAnnotation</tt> | - * <tt>visitTypeAnnotation</tt> | <tt>visitAttribute</tt> )* ( - * <tt>visitInnerClass</tt> | <tt>visitField</tt> | <tt>visitMethod</tt> - * )* <tt>visitEnd</tt>. - * - * @author Eric Bruneton - */ -public abstract class ClassVisitor { - - /** - * The ASM API version implemented by this visitor. The value of this field must be one of {@link Opcodes#ASM4}, - * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. - */ - protected final int api; - - /** The class visitor to which this visitor must delegate method calls. May be null. */ - protected ClassVisitor cv; - - /** - * Constructs a new {@link ClassVisitor}. - * - * @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4}, - * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. - */ - public ClassVisitor(final int api) { - this(api, null); - } - - /** - * Constructs a new {@link ClassVisitor}. - * - * @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4}, - * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. - * @param cv the class visitor to which this visitor must delegate method calls. May be null. - */ - public ClassVisitor(final int api, final ClassVisitor cv) { - this.api = api; - this.cv = cv; - } - - /** - * Visits the header of the class. - * - * @param version the class version. - * @param access the class's access flags (see {@link Opcodes}). This parameter also indicates if the class is - * deprecated. - * @param name the internal name of the class (see {@link Type#getInternalName() getInternalName}). - * @param signature the signature of this class. May be <tt>null</tt> if the class is not a generic - * one, and does not extend or implement generic classes or interfaces. - * @param superName the internal of name of the super class (see {@link Type#getInternalName() getInternalName}). - * For interfaces, the super class is {@link Object}. May be <tt>null</tt>, but only for the - * {@link Object} class. - * @param interfaces the internal names of the class's interfaces (see {@link Type#getInternalName() - * getInternalName}). May be <tt>null</tt>. - */ - public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { - if (cv != null) { - cv.visit(version, access, name, signature, superName, interfaces); - } - } - - /** - * Visits the source of the class. - * - * @param source the name of the source file from which the class was compiled. May be - * <tt>null</tt>. - * @param debug additional debug information to compute the correspondance between source and compiled elements of - * the class. May be <tt>null</tt>. - */ - public void visitSource(String source, String debug) { - if (cv != null) { - cv.visitSource(source, debug); - } - } - - /** - * Visit the module corresponding to the class. - * - * @param name module name - * @param access module flags, among {@code ACC_OPEN}, {@code ACC_SYNTHETIC} and {@code ACC_MANDATED}. - * @param version module version or null. - * @return a visitor to visit the module values, or <tt>null</tt> if this visitor is not interested - * in visiting this module. - */ - public ModuleVisitor visitModule(String name, int access, String version) { - if (api < Opcodes.ASM6) { - throw new RuntimeException(); - } - if (cv != null) { - return cv.visitModule(name, access, version); - } - return null; - } - - /** - * Visits the enclosing class of the class. This method must be called only if the class has an enclosing class. - * - * @param owner internal name of the enclosing class of the class. - * @param name the name of the method that contains the class, or <tt>null</tt> if the class is not - * enclosed in a method of its enclosing class. - * @param desc the descriptor of the method that contains the class, or <tt>null</tt> if the class - * is not enclosed in a method of its enclosing class. - */ - public void visitOuterClass(String owner, String name, String desc) { - if (cv != null) { - cv.visitOuterClass(owner, name, desc); - } - } - - /** - * Visits an annotation of the class. - * - * @param desc the class descriptor of the annotation class. - * @param visible <tt>true</tt> if the annotation is visible at runtime. - * @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not - * interested in visiting this annotation. - */ - public AnnotationVisitor visitAnnotation(String desc, boolean visible) { - if (cv != null) { - return cv.visitAnnotation(desc, visible); - } - return null; - } - - /** - * Visits an annotation on a type in the class signature. - * - * @param typeRef a reference to the annotated type. The sort of this type reference must be - * {@link TypeReference#CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER}, - * {@link TypeReference#CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} or - * {@link TypeReference#CLASS_EXTENDS CLASS_EXTENDS}. See {@link TypeReference}. - * @param typePath the path to the annotated type argument, wildcard bound, array element type, or static inner type - * within 'typeRef'. May be <tt>null</tt> if the annotation targets 'typeRef' as a whole. - * @param desc the class descriptor of the annotation class. - * @param visible <tt>true</tt> if the annotation is visible at runtime. - * @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not - * interested in visiting this annotation. - */ - public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) { - if (cv != null) { - return cv.visitTypeAnnotation(typeRef, typePath, desc, visible); - } - return null; - } - - /** - * Visits a non standard attribute of the class. - * - * @param attr an attribute. - */ - public void visitAttribute(Attribute attr) { - if (cv != null) { - cv.visitAttribute(attr); - } - } - - /** - * Visits information about an inner class. This inner class is not necessarily a member of the class being visited. - * - * @param name the internal name of an inner class (see {@link Type#getInternalName() getInternalName}). - * @param outerName the internal name of the class to which the inner class belongs (see - * {@link Type#getInternalName() getInternalName}). May be <tt>null</tt> for not member classes. - * @param innerName the (simple) name of the inner class inside its enclosing class. May be - * <tt>null</tt> for anonymous inner classes. - * @param access the access flags of the inner class as originally declared in the enclosing class. - */ - public void visitInnerClass(String name, String outerName, String innerName, int access) { - if (cv != null) { - cv.visitInnerClass(name, outerName, innerName, access); - } - } - - /** - * Visits a field of the class. - * - * @param access the field's access flags (see {@link Opcodes}). This parameter also indicates if the field is - * synthetic and/or deprecated. - * @param name the field's name. - * @param desc the field's descriptor (see {@link Type Type}). - * @param signature the field's signature. May be <tt>null</tt> if the field's type does not use - * generic types. - * @param value the field's initial value. This parameter, which may be <tt>null</tt> if the field - * does not have an initial value, must be an {@link Integer}, a {@link Float}, a {@link Long}, a {@link Double} - * or a {@link String} (for <tt>int</tt>, <tt>float</tt>, - * <tt>long</tt> or <tt>String</tt> fields respectively). This parameter is - * only used for static fields. Its value is ignored for non static fields, which must be initialized - * through bytecode instructions in constructors or methods. - * @return a visitor to visit field annotations and attributes, or <tt>null</tt> if this class - * visitor is not interested in visiting these annotations and attributes. - */ - public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) { - if (cv != null) { - return cv.visitField(access, name, desc, signature, value); - } - return null; - } - - /** - * Visits a method of the class. This method must return a new {@link MethodVisitor} instance (or - * <tt>null</tt>) each time it is called, i.e., it should not return a previously returned visitor. - * - * @param access the method's access flags (see {@link Opcodes}). This parameter also indicates if the method is - * synthetic and/or deprecated. - * @param name the method's name. - * @param desc the method's descriptor (see {@link Type Type}). - * @param signature the method's signature. May be <tt>null</tt> if the method parameters, return - * type and exceptions do not use generic types. - * @param exceptions the internal names of the method's exception classes (see {@link Type#getInternalName() - * getInternalName}). May be <tt>null</tt>. - * @return an object to visit the byte code of the method, or <tt>null</tt> if this class visitor is - * not interested in visiting the code of this method. - */ - public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { - if (cv != null) { - return cv.visitMethod(access, name, desc, signature, exceptions); - } - return null; - } - - /** - * Visits the end of the class. This method, which is the last one to be called, is used to inform the visitor that - * all the fields and methods of the class have been visited. - */ - public void visitEnd() { - if (cv != null) { - cv.visitEnd(); - } - } -} +/* + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ + +/* + * + * + * + * + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.redkale.asm; + +/** + * A visitor to visit a Java class. The methods of this class must be called in the following order: + * <tt>visit</tt> [ <tt>visitSource</tt> ] [ <tt>visitModule</tt> ][ + * <tt>visitOuterClass</tt> ] ( <tt>visitAnnotation</tt> | + * <tt>visitTypeAnnotation</tt> | <tt>visitAttribute</tt> )* ( + * <tt>visitInnerClass</tt> | <tt>visitField</tt> | <tt>visitMethod</tt> + * )* <tt>visitEnd</tt>. + * + * @author Eric Bruneton + */ +public abstract class ClassVisitor { + + /** + * The ASM API version implemented by this visitor. The value of this field must be one of {@link Opcodes#ASM4}, + * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. + */ + protected final int api; + + /** The class visitor to which this visitor must delegate method calls. May be null. */ + protected ClassVisitor cv; + + /** + * Constructs a new {@link ClassVisitor}. + * + * @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4}, + * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. + */ + public ClassVisitor(final int api) { + this(api, null); + } + + /** + * Constructs a new {@link ClassVisitor}. + * + * @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4}, + * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. + * @param cv the class visitor to which this visitor must delegate method calls. May be null. + */ + public ClassVisitor(final int api, final ClassVisitor cv) { + this.api = api; + this.cv = cv; + } + + /** + * Visits the header of the class. + * + * @param version the class version. + * @param access the class's access flags (see {@link Opcodes}). This parameter also indicates if the class is + * deprecated. + * @param name the internal name of the class (see {@link Type#getInternalName() getInternalName}). + * @param signature the signature of this class. May be <tt>null</tt> if the class is not a generic + * one, and does not extend or implement generic classes or interfaces. + * @param superName the internal of name of the super class (see {@link Type#getInternalName() getInternalName}). + * For interfaces, the super class is {@link Object}. May be <tt>null</tt>, but only for the + * {@link Object} class. + * @param interfaces the internal names of the class's interfaces (see {@link Type#getInternalName() + * getInternalName}). May be <tt>null</tt>. + */ + public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { + if (cv != null) { + cv.visit(version, access, name, signature, superName, interfaces); + } + } + + /** + * Visits the source of the class. + * + * @param source the name of the source file from which the class was compiled. May be + * <tt>null</tt>. + * @param debug additional debug information to compute the correspondance between source and compiled elements of + * the class. May be <tt>null</tt>. + */ + public void visitSource(String source, String debug) { + if (cv != null) { + cv.visitSource(source, debug); + } + } + + /** + * Visit the module corresponding to the class. + * + * @param name module name + * @param access module flags, among {@code ACC_OPEN}, {@code ACC_SYNTHETIC} and {@code ACC_MANDATED}. + * @param version module version or null. + * @return a visitor to visit the module values, or <tt>null</tt> if this visitor is not interested + * in visiting this module. + */ + public ModuleVisitor visitModule(String name, int access, String version) { + if (api < Opcodes.ASM6) { + throw new RuntimeException(); + } + if (cv != null) { + return cv.visitModule(name, access, version); + } + return null; + } + + /** + * Visits the enclosing class of the class. This method must be called only if the class has an enclosing class. + * + * @param owner internal name of the enclosing class of the class. + * @param name the name of the method that contains the class, or <tt>null</tt> if the class is not + * enclosed in a method of its enclosing class. + * @param desc the descriptor of the method that contains the class, or <tt>null</tt> if the class + * is not enclosed in a method of its enclosing class. + */ + public void visitOuterClass(String owner, String name, String desc) { + if (cv != null) { + cv.visitOuterClass(owner, name, desc); + } + } + + /** + * Visits an annotation of the class. + * + * @param desc the class descriptor of the annotation class. + * @param visible <tt>true</tt> if the annotation is visible at runtime. + * @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not + * interested in visiting this annotation. + */ + public AnnotationVisitor visitAnnotation(String desc, boolean visible) { + if (cv != null) { + return cv.visitAnnotation(desc, visible); + } + return null; + } + + /** + * Visits an annotation on a type in the class signature. + * + * @param typeRef a reference to the annotated type. The sort of this type reference must be + * {@link TypeReference#CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER}, + * {@link TypeReference#CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} or + * {@link TypeReference#CLASS_EXTENDS CLASS_EXTENDS}. See {@link TypeReference}. + * @param typePath the path to the annotated type argument, wildcard bound, array element type, or static inner type + * within 'typeRef'. May be <tt>null</tt> if the annotation targets 'typeRef' as a whole. + * @param desc the class descriptor of the annotation class. + * @param visible <tt>true</tt> if the annotation is visible at runtime. + * @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not + * interested in visiting this annotation. + */ + public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) { + if (cv != null) { + return cv.visitTypeAnnotation(typeRef, typePath, desc, visible); + } + return null; + } + + /** + * Visits a non standard attribute of the class. + * + * @param attr an attribute. + */ + public void visitAttribute(Attribute attr) { + if (cv != null) { + cv.visitAttribute(attr); + } + } + + /** + * Visits information about an inner class. This inner class is not necessarily a member of the class being visited. + * + * @param name the internal name of an inner class (see {@link Type#getInternalName() getInternalName}). + * @param outerName the internal name of the class to which the inner class belongs (see + * {@link Type#getInternalName() getInternalName}). May be <tt>null</tt> for not member classes. + * @param innerName the (simple) name of the inner class inside its enclosing class. May be + * <tt>null</tt> for anonymous inner classes. + * @param access the access flags of the inner class as originally declared in the enclosing class. + */ + public void visitInnerClass(String name, String outerName, String innerName, int access) { + if (cv != null) { + cv.visitInnerClass(name, outerName, innerName, access); + } + } + + /** + * Visits a field of the class. + * + * @param access the field's access flags (see {@link Opcodes}). This parameter also indicates if the field is + * synthetic and/or deprecated. + * @param name the field's name. + * @param desc the field's descriptor (see {@link Type Type}). + * @param signature the field's signature. May be <tt>null</tt> if the field's type does not use + * generic types. + * @param value the field's initial value. This parameter, which may be <tt>null</tt> if the field + * does not have an initial value, must be an {@link Integer}, a {@link Float}, a {@link Long}, a {@link Double} + * or a {@link String} (for <tt>int</tt>, <tt>float</tt>, + * <tt>long</tt> or <tt>String</tt> fields respectively). This parameter is + * only used for static fields. Its value is ignored for non static fields, which must be initialized + * through bytecode instructions in constructors or methods. + * @return a visitor to visit field annotations and attributes, or <tt>null</tt> if this class + * visitor is not interested in visiting these annotations and attributes. + */ + public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) { + if (cv != null) { + return cv.visitField(access, name, desc, signature, value); + } + return null; + } + + /** + * Visits a method of the class. This method must return a new {@link MethodVisitor} instance (or + * <tt>null</tt>) each time it is called, i.e., it should not return a previously returned visitor. + * + * @param access the method's access flags (see {@link Opcodes}). This parameter also indicates if the method is + * synthetic and/or deprecated. + * @param name the method's name. + * @param desc the method's descriptor (see {@link Type Type}). + * @param signature the method's signature. May be <tt>null</tt> if the method parameters, return + * type and exceptions do not use generic types. + * @param exceptions the internal names of the method's exception classes (see {@link Type#getInternalName() + * getInternalName}). May be <tt>null</tt>. + * @return an object to visit the byte code of the method, or <tt>null</tt> if this class visitor is + * not interested in visiting the code of this method. + */ + public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { + if (cv != null) { + return cv.visitMethod(access, name, desc, signature, exceptions); + } + return null; + } + + /** + * Visits the end of the class. This method, which is the last one to be called, is used to inform the visitor that + * all the fields and methods of the class have been visited. + */ + public void visitEnd() { + if (cv != null) { + cv.visitEnd(); + } + } +} diff --git a/src/main/java/org/redkale/asm/ClassWriter.java b/src/main/java/org/redkale/asm/ClassWriter.java index d241f2294..ad9386113 100644 --- a/src/main/java/org/redkale/asm/ClassWriter.java +++ b/src/main/java/org/redkale/asm/ClassWriter.java @@ -1,1541 +1,1541 @@ -/* - * 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 {@link ClassVisitor} that generates classes in bytecode form. More precisely this visitor generates a byte array - * conforming to the Java class file format. It can be used alone, to generate a Java class "from scratch", or with one - * or more {@link ClassReader ClassReader} and adapter class visitor to generate a modified class from one or more - * existing Java classes. - * - * @author Eric Bruneton - */ -public class ClassWriter extends ClassVisitor { - - /** - * Flag to automatically compute the maximum stack size and the maximum number of local variables of methods. If - * this flag is set, then the arguments of the {@link MethodVisitor#visitMaxs visitMaxs} method of the - * {@link MethodVisitor} returned by the {@link #visitMethod visitMethod} method will be ignored, and computed - * automatically from the signature and the bytecode of each method. - * - * @see #ClassWriter(int) - */ - public static final int COMPUTE_MAXS = 1; - - /** - * Flag to automatically compute the stack map frames of methods from scratch. If this flag is set, then the calls - * to the {@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, COMPUTE_FRAMES implies COMPUTE_MAXS. - * - * @see #ClassWriter(int) - */ - public static final int COMPUTE_FRAMES = 2; - - /** Pseudo access flag to distinguish between the synthetic attribute and the synthetic access flag. */ - static final int ACC_SYNTHETIC_ATTRIBUTE = 0x40000; - - /** Factor to convert from ACC_SYNTHETIC_ATTRIBUTE to Opcode.ACC_SYNTHETIC. */ - static final int TO_ACC_SYNTHETIC = ACC_SYNTHETIC_ATTRIBUTE / Opcodes.ACC_SYNTHETIC; - - /** The type of instructions without any argument. */ - static final int NOARG_INSN = 0; - - /** The type of instructions with an signed byte argument. */ - static final int SBYTE_INSN = 1; - - /** The type of instructions with an signed short argument. */ - static final int SHORT_INSN = 2; - - /** The type of instructions with a local variable index argument. */ - static final int VAR_INSN = 3; - - /** The type of instructions with an implicit local variable index argument. */ - static final int IMPLVAR_INSN = 4; - - /** The type of instructions with a type descriptor argument. */ - static final int TYPE_INSN = 5; - - /** The type of field and method invocations instructions. */ - static final int FIELDORMETH_INSN = 6; - - /** The type of the INVOKEINTERFACE/INVOKEDYNAMIC instruction. */ - static final int ITFMETH_INSN = 7; - - /** The type of the INVOKEDYNAMIC instruction. */ - static final int INDYMETH_INSN = 8; - - /** The type of instructions with a 2 bytes bytecode offset label. */ - static final int LABEL_INSN = 9; - - /** The type of instructions with a 4 bytes bytecode offset label. */ - static final int LABELW_INSN = 10; - - /** The type of the LDC instruction. */ - static final int LDC_INSN = 11; - - /** The type of the LDC_W and LDC2_W instructions. */ - static final int LDCW_INSN = 12; - - /** The type of the IINC instruction. */ - static final int IINC_INSN = 13; - - /** The type of the TABLESWITCH instruction. */ - static final int TABL_INSN = 14; - - /** The type of the LOOKUPSWITCH instruction. */ - static final int LOOK_INSN = 15; - - /** The type of the MULTIANEWARRAY instruction. */ - static final int MANA_INSN = 16; - - /** The type of the WIDE instruction. */ - 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. */ - static final byte[] TYPE; - - /** The type of CONSTANT_Class constant pool items. */ - static final int CLASS = 7; - - /** The type of CONSTANT_Fieldref constant pool items. */ - static final int FIELD = 9; - - /** The type of CONSTANT_Methodref constant pool items. */ - static final int METH = 10; - - /** The type of CONSTANT_InterfaceMethodref constant pool items. */ - static final int IMETH = 11; - - /** The type of CONSTANT_String constant pool items. */ - static final int STR = 8; - - /** The type of CONSTANT_Integer constant pool items. */ - static final int INT = 3; - - /** The type of CONSTANT_Float constant pool items. */ - static final int FLOAT = 4; - - /** The type of CONSTANT_Long constant pool items. */ - static final int LONG = 5; - - /** The type of CONSTANT_Double constant pool items. */ - static final int DOUBLE = 6; - - /** The type of CONSTANT_NameAndType constant pool items. */ - static final int NAME_TYPE = 12; - - /** The type of CONSTANT_Utf8 constant pool items. */ - static final int UTF8 = 1; - - /** The type of CONSTANT_MethodType constant pool items. */ - static final int MTYPE = 16; - - /** The type of CONSTANT_MethodHandle constant pool items. */ - static final int HANDLE = 15; - - /** The type of CONSTANT_InvokeDynamic constant pool items. */ - static final int INDY = 18; - - /** The type of CONSTANT_Module constant pool items. */ - static final int MODULE = 19; - - /** The type of CONSTANT_Package constant pool items. */ - static final int PACKAGE = 20; - - /** - * The base value for all CONSTANT_MethodHandle constant pool items. Internally, ASM store the 9 variations of - * CONSTANT_MethodHandle into 9 different items (from 21 to 29). - */ - static final int HANDLE_BASE = 20; - - /** - * Normal type Item stored in the ClassWriter {@link ClassWriter#typeTable}, instead of the constant pool, in order - * to avoid clashes with normal constant pool items in the ClassWriter constant pool's hash table. - */ - static final int TYPE_NORMAL = 30; - - /** - * Uninitialized type Item stored in the ClassWriter {@link ClassWriter#typeTable}, instead of the constant pool, in - * order to avoid clashes with normal constant pool items in the ClassWriter constant pool's hash table. - */ - static final int TYPE_UNINIT = 31; - - /** - * Merged type Item stored in the ClassWriter {@link ClassWriter#typeTable}, instead of the constant pool, in order - * to avoid clashes with normal constant pool items in the ClassWriter constant pool's hash table. - */ - static final int TYPE_MERGED = 32; - - /** - * The type of BootstrapMethods items. These items are stored in a special class attribute named BootstrapMethods - * and not in the constant pool. - */ - static final int BSM = 33; - - /** The class reader from which this class writer was constructed, if any. */ - ClassReader cr; - - /** Minor and major version numbers of the class to be generated. */ - int version; - - /** Index of the next item to be added in the constant pool. */ - int index; - - /** The constant pool of this class. */ - final ByteVector pool; - - /** The constant pool's hash table data. */ - Item[] items; - - /** The threshold of the constant pool's hash table. */ - int threshold; - - /** A reusable key used to look for items in the {@link #items} hash table. */ - final Item key; - - /** A reusable key used to look for items in the {@link #items} hash table. */ - final Item key2; - - /** A reusable key used to look for items in the {@link #items} hash table. */ - final Item key3; - - /** A reusable key used to look for items in the {@link #items} hash table. */ - final Item key4; - - /** - * A type table used to temporarily store internal names that will not necessarily be stored in the constant pool. - * This type table is used by the control flow and data flow analysis algorithm used to compute stack map frames - * from scratch. This array associates to each index <tt>i</tt> the Item whose index is - * <tt>i</tt>. All Item objects stored in this array are also stored in the {@link #items} hash - * table. These two arrays allow to retrieve an Item from its index or, conversely, to get the index of an Item from - * its value. Each Item stores an internal name in its {@link Item#strVal1} field. - */ - Item[] typeTable; - - /** Number of elements in the {@link #typeTable} array. */ - private short typeCount; - - /** The access flags of this class. */ - private int access; - - /** The constant pool item that contains the internal name of this class. */ - private int name; - - /** The internal name of this class. */ - String thisName; - - /** The constant pool item that contains the signature of this class. */ - private int signature; - - /** The constant pool item that contains the internal name of the super class of this class. */ - private int superName; - - /** Number of interfaces implemented or extended by this class or interface. */ - private int interfaceCount; - - /** - * The interfaces implemented or extended by this class or interface. More precisely, this array contains the - * indexes of the constant pool items that contain the internal names of these interfaces. - */ - private int[] interfaces; - - /** - * The index of the constant pool item that contains the name of the source file from which this class was compiled. - */ - private int sourceFile; - - /** The SourceDebug attribute of this class. */ - 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. */ - private int enclosingMethodOwner; - - /** The constant pool item that contains the name and descriptor of the enclosing method of this class. */ - private int enclosingMethod; - - /** The runtime visible annotations of this class. */ - private AnnotationWriter anns; - - /** The runtime invisible annotations of this class. */ - private AnnotationWriter ianns; - - /** The runtime visible type annotations of this class. */ - private AnnotationWriter tanns; - - /** The runtime invisible type annotations of this class. */ - private AnnotationWriter itanns; - - /** The non standard attributes of this class. */ - private Attribute attrs; - - /** The number of entries in the InnerClasses attribute. */ - private int innerClassesCount; - - /** The InnerClasses attribute. */ - private ByteVector innerClasses; - - /** The number of entries in the BootstrapMethods attribute. */ - int bootstrapMethodsCount; - - /** The BootstrapMethods attribute. */ - ByteVector bootstrapMethods; - - /** - * The fields of this class. These fields are stored in a linked list of {@link FieldWriter} objects, linked to each - * other by their {@link FieldWriter#fv} field. This field stores the first element of this list. - */ - FieldWriter firstField; - - /** - * The fields of this class. These fields are stored in a linked list of {@link FieldWriter} objects, linked to each - * other by their {@link FieldWriter#fv} field. This field stores the last element of this list. - */ - FieldWriter lastField; - - /** - * The methods of this class. These methods are stored in a linked list of {@link MethodWriter} objects, linked to - * each other by their {@link MethodWriter#mv} field. This field stores the first element of this list. - */ - MethodWriter firstMethod; - - /** - * The methods of this class. These methods are stored in a linked list of {@link MethodWriter} objects, linked to - * each other by their {@link MethodWriter#mv} field. This field stores the last element of this list. - */ - MethodWriter lastMethod; - - /** - * Indicates what must be automatically computed. - * - * @see MethodWriter#compute - */ - private int compute; - - /** - * <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. - */ - boolean hasAsmInsns; - - // ------------------------------------------------------------------------ - // Static initializer - // ------------------------------------------------------------------------ - - /** Computes the instruction types of JVM opcodes. */ - static { - int i; - byte[] b = new byte[221]; - String s = "AAAAAAAAAAAAAAAABCLMMDDDDDEEEEEEEEEEEEEEEEEEEEAAAAAAAADD" - + "DDDEEEEEEEEEEEEEEEEEEEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - + "AAAAAAAAAAAAAAAAANAAAAAAAAAAAAAAAAAAAAJJJJJJJJJJJJJJJJDOPAA" - + "AAAAGGGGGGGHIFBFAAFFAARQJJKKSSSSSSSSSSSSSSSSSST"; - for (i = 0; i < b.length; ++i) { - b[i] = (byte) (s.charAt(i) - 'A'); - } - TYPE = b; - - // code to generate the above string - // - // // SBYTE_INSN instructions - // b[Constants.NEWARRAY] = SBYTE_INSN; - // b[Constants.BIPUSH] = SBYTE_INSN; - // - // // SHORT_INSN instructions - // b[Constants.SIPUSH] = SHORT_INSN; - // - // // (IMPL)VAR_INSN instructions - // b[Constants.RET] = VAR_INSN; - // for (i = Constants.ILOAD; i <= Constants.ALOAD; ++i) { - // b[i] = VAR_INSN; - // } - // for (i = Constants.ISTORE; i <= Constants.ASTORE; ++i) { - // b[i] = VAR_INSN; - // } - // for (i = 26; i <= 45; ++i) { // ILOAD_0 to ALOAD_3 - // b[i] = IMPLVAR_INSN; - // } - // for (i = 59; i <= 78; ++i) { // ISTORE_0 to ASTORE_3 - // b[i] = IMPLVAR_INSN; - // } - // - // // TYPE_INSN instructions - // b[Constants.NEW] = TYPE_INSN; - // b[Constants.ANEWARRAY] = TYPE_INSN; - // b[Constants.CHECKCAST] = TYPE_INSN; - // b[Constants.INSTANCEOF] = TYPE_INSN; - // - // // (Set)FIELDORMETH_INSN instructions - // for (i = Constants.GETSTATIC; i <= Constants.INVOKESTATIC; ++i) { - // b[i] = FIELDORMETH_INSN; - // } - // b[Constants.INVOKEINTERFACE] = ITFMETH_INSN; - // b[Constants.INVOKEDYNAMIC] = INDYMETH_INSN; - // - // // LABEL(W)_INSN instructions - // for (i = Constants.IFEQ; i <= Constants.JSR; ++i) { - // b[i] = LABEL_INSN; - // } - // b[Constants.IFNULL] = LABEL_INSN; - // b[Constants.IFNONNULL] = LABEL_INSN; - // b[200] = LABELW_INSN; // GOTO_W - // b[201] = LABELW_INSN; // JSR_W - // // temporary opcodes used internally by ASM - see Label and - // MethodWriter - // for (i = 202; i < 220; ++i) { - // b[i] = ASM_LABEL_INSN; - // } - // b[220] = ASM_LABELW_INSN; - // - // // LDC(_W) instructions - // b[Constants.LDC] = LDC_INSN; - // b[19] = LDCW_INSN; // LDC_W - // b[20] = LDCW_INSN; // LDC2_W - // - // // special instructions - // b[Constants.IINC] = IINC_INSN; - // b[Constants.TABLESWITCH] = TABL_INSN; - // b[Constants.LOOKUPSWITCH] = LOOK_INSN; - // b[Constants.MULTIANEWARRAY] = MANA_INSN; - // b[196] = WIDE_INSN; // WIDE - // - // for (i = 0; i < b.length; ++i) { - // System.err.print((char)('A' + b[i])); - // } - // System.err.println(); - } - - // ------------------------------------------------------------------------ - // Constructor - // ------------------------------------------------------------------------ - - /** - * Constructs a new {@link ClassWriter} object. - * - * @param flags option flags that can be used to modify the default behavior of this class. See - * {@link #COMPUTE_MAXS}, {@link #COMPUTE_FRAMES}. - */ - public ClassWriter(final int flags) { - super(Opcodes.ASM6); - index = 1; - pool = new ByteVector(); - items = new Item[256]; - threshold = (int) (0.75d * items.length); - key = new Item(); - key2 = new Item(); - key3 = new Item(); - key4 = new Item(); - this.compute = (flags & COMPUTE_FRAMES) != 0 - ? MethodWriter.FRAMES - : ((flags & COMPUTE_MAXS) != 0 ? MethodWriter.MAXS : MethodWriter.NOTHING); - } - - /** - * Constructs a new {@link ClassWriter} object and enables optimizations for "mostly add" bytecode transformations. - * These optimizations are the following: - * - *

- * - * @param classReader the {@link ClassReader} used to read the original class. It will be used to copy the entire - * constant pool from the original class and also to copy other fragments of original bytecode where applicable. - * @param flags option flags that can be used to modify the default behavior of this class. These option flags do - * not affect methods 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. See {@link #COMPUTE_MAXS}, {@link #COMPUTE_FRAMES}. - */ - public ClassWriter(final ClassReader classReader, final int flags) { - this(flags); - classReader.copyPool(this); - this.cr = classReader; - } - - // ------------------------------------------------------------------------ - // Implementation of the ClassVisitor abstract class - // ------------------------------------------------------------------------ - - @Override - public final void visit( - final int version, - final int access, - final String name, - final String signature, - final String superName, - final String[] interfaces) { - this.version = version; - this.access = access; - this.name = newClass(name); - thisName = name; - if (signature != null) { - this.signature = newUTF8(signature); - } - this.superName = superName == null ? 0 : newClass(superName); - if (interfaces != null && interfaces.length > 0) { - interfaceCount = interfaces.length; - this.interfaces = new int[interfaceCount]; - for (int i = 0; i < interfaceCount; ++i) { - this.interfaces[i] = newClass(interfaces[i]); - } - } - } - - @Override - public final void visitSource(final String file, final String debug) { - if (file != null) { - sourceFile = newUTF8(file); - } - if (debug != null) { - sourceDebug = new ByteVector().encodeUTF8(debug, 0, Integer.MAX_VALUE); - } - } - - @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) { - enclosingMethodOwner = newClass(owner); - if (name != null && desc != null) { - enclosingMethod = newNameType(name, desc); - } - } - - @Override - public final AnnotationVisitor visitAnnotation(final String desc, final boolean visible) { - ByteVector bv = new ByteVector(); - // write type, and reserve space for values count - bv.putShort(newUTF8(desc)).putShort(0); - AnnotationWriter aw = new AnnotationWriter(this, true, bv, bv, 2); - if (visible) { - aw.next = anns; - anns = aw; - } else { - aw.next = ianns; - ianns = aw; - } - return aw; - } - - @Override - public final AnnotationVisitor visitTypeAnnotation( - int typeRef, TypePath typePath, final String desc, final boolean visible) { - ByteVector bv = new ByteVector(); - // write target_type and target_info - AnnotationWriter.putTarget(typeRef, typePath, bv); - // write type, and reserve space for values count - bv.putShort(newUTF8(desc)).putShort(0); - AnnotationWriter aw = new AnnotationWriter(this, true, bv, bv, bv.length - 2); - if (visible) { - aw.next = tanns; - tanns = aw; - } else { - aw.next = itanns; - itanns = aw; - } - return aw; - } - - @Override - public final void visitAttribute(final Attribute attr) { - attr.next = attrs; - attrs = attr; - } - - @Override - public final void visitInnerClass( - final String name, final String outerName, final String innerName, final int access) { - if (innerClasses == null) { - innerClasses = new ByteVector(); - } - // Sec. 4.7.6 of the JVMS states "Every CONSTANT_Class_info entry in the - // constant_pool table which represents a class or interface C that is - // not a package member must have exactly one corresponding entry in the - // classes array". To avoid duplicates we keep track in the intVal field - // of the Item of each CONSTANT_Class_info entry C whether an inner - // class entry has already been added for C (this field is unused for - // class entries, and changing its value does not change the hashcode - // 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 = newStringishItem(CLASS, name); - if (nameItem.intVal == 0) { - ++innerClassesCount; - innerClasses.putShort(nameItem.index); - innerClasses.putShort(outerName == null ? 0 : newClass(outerName)); - innerClasses.putShort(innerName == null ? 0 : newUTF8(innerName)); - innerClasses.putShort(access); - nameItem.intVal = innerClassesCount; - } else { - // Compare the inner classes entry nameItem.intVal - 1 with the - // arguments of this method and throw an exception if there is a - // difference? - } - } - - @Override - public final FieldVisitor visitField( - final int access, final String name, final String desc, final String signature, final Object value) { - return new FieldWriter(this, access, name, desc, signature, value); - } - - @Override - 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, compute); - } - - @Override - public final void visitEnd() { - // do nothing - } - - // ------------------------------------------------------------------------ - // Other public methods - // ------------------------------------------------------------------------ - - /** - * Returns the bytecode of the class that was build with this class writer. - * - * @return the bytecode of the class that was build with this class writer. - */ - public byte[] toByteArray() { - if (index > 0xFFFF) { - throw new RuntimeException("Class file too large!"); - } - // computes the real size of the bytecode of this class - int size = 24 + 2 * interfaceCount; - int nbFields = 0; - FieldWriter fb = firstField; - while (fb != null) { - ++nbFields; - size += fb.getSize(); - fb = (FieldWriter) fb.fv; - } - int nbMethods = 0; - MethodWriter mb = firstMethod; - while (mb != null) { - ++nbMethods; - size += mb.getSize(); - mb = (MethodWriter) mb.mv; - } - int attributeCount = 0; - if (bootstrapMethods != null) { - // we put it as first attribute in order to improve a bit - // ClassReader.copyBootstrapMethods - ++attributeCount; - size += 8 + bootstrapMethods.length; - newUTF8("BootstrapMethods"); - } - if (signature != 0) { - ++attributeCount; - size += 8; - newUTF8("Signature"); - } - if (sourceFile != 0) { - ++attributeCount; - size += 8; - newUTF8("SourceFile"); - } - if (sourceDebug != null) { - ++attributeCount; - size += sourceDebug.length + 6; - newUTF8("SourceDebugExtension"); - } - if (enclosingMethodOwner != 0) { - ++attributeCount; - size += 10; - newUTF8("EnclosingMethod"); - } - if ((access & Opcodes.ACC_DEPRECATED) != 0) { - ++attributeCount; - size += 6; - newUTF8("Deprecated"); - } - if ((access & Opcodes.ACC_SYNTHETIC) != 0) { - if ((version & 0xFFFF) < Opcodes.V1_5 || (access & ACC_SYNTHETIC_ATTRIBUTE) != 0) { - ++attributeCount; - size += 6; - newUTF8("Synthetic"); - } - } - if (innerClasses != null) { - ++attributeCount; - size += 8 + innerClasses.length; - newUTF8("InnerClasses"); - } - if (anns != null) { - ++attributeCount; - size += 8 + anns.getSize(); - newUTF8("RuntimeVisibleAnnotations"); - } - if (ianns != null) { - ++attributeCount; - size += 8 + ianns.getSize(); - newUTF8("RuntimeInvisibleAnnotations"); - } - if (tanns != null) { - ++attributeCount; - size += 8 + tanns.getSize(); - newUTF8("RuntimeVisibleTypeAnnotations"); - } - 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); - } - size += pool.length; - // allocates a byte vector of this size, in order to avoid unnecessary - // arraycopy operations in the ByteVector.enlarge() method - ByteVector out = new ByteVector(size); - out.putInt(0xCAFEBABE).putInt(version); - out.putShort(index).putByteArray(pool.data, 0, pool.length); - int mask = Opcodes.ACC_DEPRECATED - | ACC_SYNTHETIC_ATTRIBUTE - | ((access & ACC_SYNTHETIC_ATTRIBUTE) / TO_ACC_SYNTHETIC); - out.putShort(access & ~mask).putShort(name).putShort(superName); - out.putShort(interfaceCount); - for (int i = 0; i < interfaceCount; ++i) { - out.putShort(interfaces[i]); - } - out.putShort(nbFields); - fb = firstField; - while (fb != null) { - fb.put(out); - fb = (FieldWriter) fb.fv; - } - out.putShort(nbMethods); - mb = firstMethod; - while (mb != null) { - mb.put(out); - mb = (MethodWriter) mb.mv; - } - out.putShort(attributeCount); - if (bootstrapMethods != null) { - out.putShort(newUTF8("BootstrapMethods")); - out.putInt(bootstrapMethods.length + 2).putShort(bootstrapMethodsCount); - out.putByteArray(bootstrapMethods.data, 0, bootstrapMethods.length); - } - if (signature != 0) { - out.putShort(newUTF8("Signature")).putInt(2).putShort(signature); - } - if (sourceFile != 0) { - out.putShort(newUTF8("SourceFile")).putInt(2).putShort(sourceFile); - } - if (sourceDebug != null) { - int len = sourceDebug.length; - 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); - } - if ((access & Opcodes.ACC_DEPRECATED) != 0) { - out.putShort(newUTF8("Deprecated")).putInt(0); - } - if ((access & Opcodes.ACC_SYNTHETIC) != 0) { - if ((version & 0xFFFF) < Opcodes.V1_5 || (access & ACC_SYNTHETIC_ATTRIBUTE) != 0) { - out.putShort(newUTF8("Synthetic")).putInt(0); - } - } - if (innerClasses != null) { - out.putShort(newUTF8("InnerClasses")); - out.putInt(innerClasses.length + 2).putShort(innerClassesCount); - out.putByteArray(innerClasses.data, 0, innerClasses.length); - } - if (anns != null) { - out.putShort(newUTF8("RuntimeVisibleAnnotations")); - anns.put(out); - } - if (ianns != null) { - out.putShort(newUTF8("RuntimeInvisibleAnnotations")); - ianns.put(out); - } - if (tanns != null) { - out.putShort(newUTF8("RuntimeVisibleTypeAnnotations")); - tanns.put(out); - } - if (itanns != null) { - out.putShort(newUTF8("RuntimeInvisibleTypeAnnotations")); - itanns.put(out); - } - if (attrs != null) { - attrs.put(this, null, 0, -1, -1, out); - } - if (hasAsmInsns) { - boolean hasFrames = false; - mb = firstMethod; - while (mb != null) { - hasFrames |= mb.frameCount > 0; - mb = (MethodWriter) mb.mv; - } - anns = null; - ianns = null; - attrs = null; - moduleWriter = null; - firstField = null; - lastField = null; - firstMethod = null; - lastMethod = null; - 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; - } - - // ------------------------------------------------------------------------ - // Utility methods: constant pool management - // ------------------------------------------------------------------------ - - /** - * Adds a number or string constant to the constant pool of the class being build. Does nothing if the constant pool - * already contains a similar item. - * - * @param cst the value of the constant to be added to the constant pool. This parameter must be an {@link Integer}, - * a {@link Float}, a {@link Long}, a {@link Double}, a {@link String} or a {@link Type}. - * @return a new or already existing constant item with the given value. - */ - Item newConstItem(final Object cst) { - if (cst instanceof Integer) { - int val = ((Integer) cst).intValue(); - return newInteger(val); - } else if (cst instanceof Byte) { - int val = ((Byte) cst).intValue(); - return newInteger(val); - } else if (cst instanceof Character) { - int val = ((Character) cst).charValue(); - return newInteger(val); - } else if (cst instanceof Short) { - int val = ((Short) cst).intValue(); - return newInteger(val); - } else if (cst instanceof Boolean) { - int val = ((Boolean) cst).booleanValue() ? 1 : 0; - return newInteger(val); - } else if (cst instanceof Float) { - float val = ((Float) cst).floatValue(); - return newFloat(val); - } else if (cst instanceof Long) { - long val = ((Long) cst).longValue(); - return newLong(val); - } else if (cst instanceof Double) { - double val = ((Double) cst).doubleValue(); - return newDouble(val); - } else if (cst instanceof String) { - return newStringishItem(STR, (String) cst); - } else if (cst instanceof Type) { - Type t = (Type) cst; - int s = t.getSort(); - if (s == Type.OBJECT) { - return newStringishItem(CLASS, t.getInternalName()); - } else if (s == Type.METHOD) { - return newStringishItem(MTYPE, t.getDescriptor()); - } else { // s == primitive type or array - return newStringishItem(CLASS, t.getDescriptor()); - } - } else if (cst instanceof Handle) { - Handle h = (Handle) cst; - return newHandleItem(h.tag, h.owner, h.name, h.desc, h.itf); - } else { - throw new IllegalArgumentException("value " + cst); - } - } - - /** - * Adds a number or string constant to the constant pool of the class being build. Does nothing if the constant pool - * already contains a similar item. This method is intended for {@link Attribute} sub classes, and is normally - * not needed by class generators or adapters. - * - * @param cst the value of the constant to be added to the constant pool. This parameter must be an {@link Integer}, - * a {@link Float}, a {@link Long}, a {@link Double} or a {@link String}. - * @return the index of a new or already existing constant item with the given value. - */ - public int newConst(final Object cst) { - return newConstItem(cst).index; - } - - /** - * Adds an UTF8 string to the constant pool of the class being build. Does nothing if the constant pool already - * contains a similar item. This method is intended for {@link Attribute} sub classes, and is normally not needed - * by class generators or adapters. - * - * @param value the String value. - * @return the index of a new or already existing UTF8 item. - */ - public int newUTF8(final String value) { - key.set(UTF8, value, null, null); - Item result = get(key); - if (result == null) { - pool.putByte(UTF8).putUTF8(value); - result = new Item(index++, key); - put(result); - } - return result.index; - } - - /** - * 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. - * - * @param type a type among STR, CLASS, MTYPE, MODULE or PACKAGE - * @param value string value of the reference. - * @return a new or already existing reference item. - */ - Item newStringishItem(final int type, final String value) { - key2.set(type, value, null, null); - Item result = get(key2); - if (result == null) { - pool.put12(type, newUTF8(value)); - result = new Item(index++, key2); - put(result); - } - return result; - } - - /** - * Adds a class reference to the constant pool of the class being build. Does nothing if the constant pool already - * contains a similar item. This method is intended for {@link Attribute} sub classes, and is normally not needed - * by class generators or adapters. - * - * @param value the internal name of the class. - * @return the index of a new or already existing class reference item. - */ - public int newClass(final String value) { - return newStringishItem(CLASS, value).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. This method is intended for {@link Attribute} sub classes, and is normally - * not needed by class generators or adapters. - * - * @param methodDesc method descriptor of the method type. - * @return the index of a new or already existing method type reference item. - */ - public int newMethodType(final String methodDesc) { - 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. This method is intended for {@link Attribute} sub classes, and is normally not needed - * by class generators or adapters. - * - * @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. This method is intended for {@link Attribute} sub classes, and is normally not needed - * by class generators or adapters. - * - * @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; - } - - /** - * Adds a handle to the constant pool of the class being build. Does nothing if the constant pool already contains a - * similar item. This method is intended for {@link Attribute} sub classes, and is normally not needed by class - * generators or adapters. - * - * @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. - * @param itf true if the owner is an interface. - * @return a new or an already existing method type reference item. - */ - Item newHandleItem(final int tag, final String owner, final String name, final String desc, final boolean itf) { - key4.set(HANDLE_BASE + tag, owner, name, desc); - Item result = get(key4); - if (result == null) { - if (tag <= Opcodes.H_PUTSTATIC) { - put112(HANDLE, tag, newField(owner, name, desc)); - } else { - put112(HANDLE, tag, newMethod(owner, name, desc, itf)); - } - result = new Item(index++, key4); - put(result); - } - 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. This method is intended for {@link Attribute} sub classes, and is normally not needed by class - * generators or adapters. - * - * @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. - * @param itf true if the owner is an interface. - * @return the index of a new or already existing method type reference item. - */ - public int newHandle(final int tag, final String owner, final String name, final String desc, final boolean itf) { - return newHandleItem(tag, owner, name, desc, itf).index; - } - - /** - * Adds an invokedynamic reference to the constant pool of the class being build. Does nothing if the constant pool - * already contains a similar item. This method is intended for {@link Attribute} sub classes, and is normally - * not needed by class generators or adapters. - * - * @param name name of the invoked method. - * @param desc descriptor of the invoke method. - * @param bsm the bootstrap method. - * @param bsmArgs the bootstrap method constant arguments. - * @return a new or an already existing invokedynamic type reference item. - */ - Item newInvokeDynamicItem(final String name, final String desc, final Handle bsm, final Object... bsmArgs) { - // cache for performance - ByteVector bootstrapMethods = this.bootstrapMethods; - if (bootstrapMethods == null) { - bootstrapMethods = this.bootstrapMethods = new ByteVector(); - } - - int position = bootstrapMethods.length; // record current position - - int hashCode = bsm.hashCode(); - bootstrapMethods.putShort(newHandle(bsm.tag, bsm.owner, bsm.name, bsm.desc, bsm.isInterface())); - - int argsLength = bsmArgs.length; - bootstrapMethods.putShort(argsLength); - - for (int i = 0; i < argsLength; i++) { - Object bsmArg = bsmArgs[i]; - hashCode ^= bsmArg.hashCode(); - bootstrapMethods.putShort(newConst(bsmArg)); - } - - byte[] data = bootstrapMethods.data; - int length = (1 + 1 + argsLength) << 1; // (bsm + argCount + arguments) - hashCode &= 0x7FFFFFFF; - Item result = items[hashCode % items.length]; - loop: - while (result != null) { - if (result.type != BSM || result.hashCode != hashCode) { - result = result.next; - continue; - } - - // because the data encode the size of the argument - // we don't need to test if these size are equals - int resultPosition = result.intVal; - for (int p = 0; p < length; p++) { - if (data[position + p] != data[resultPosition + p]) { - result = result.next; - continue loop; - } - } - break; - } - - int bootstrapMethodIndex; - if (result != null) { - bootstrapMethodIndex = result.index; - bootstrapMethods.length = position; // revert to old position - } else { - bootstrapMethodIndex = bootstrapMethodsCount++; - result = new Item(bootstrapMethodIndex); - result.set(position, hashCode); - put(result); - } - - // now, create the InvokeDynamic constant - key3.set(name, desc, bootstrapMethodIndex); - result = get(key3); - if (result == null) { - put122(INDY, bootstrapMethodIndex, newNameType(name, desc)); - result = new Item(index++, key3); - put(result); - } - return result; - } - - /** - * Adds an invokedynamic reference to the constant pool of the class being build. Does nothing if the constant pool - * already contains a similar item. This method is intended for {@link Attribute} sub classes, and is normally - * not needed by class generators or adapters. - * - * @param name name of the invoked method. - * @param desc descriptor of the invoke method. - * @param bsm the bootstrap method. - * @param bsmArgs the bootstrap method constant arguments. - * @return the index of a new or already existing invokedynamic reference item. - */ - public int newInvokeDynamic(final String name, final String desc, final Handle bsm, final Object... bsmArgs) { - return newInvokeDynamicItem(name, desc, bsm, bsmArgs).index; - } - - /** - * Adds a field reference to the constant pool of the class being build. Does nothing if the constant pool already - * contains a similar item. - * - * @param owner the internal name of the field's owner class. - * @param name the field's name. - * @param desc the field's descriptor. - * @return a new or already existing field reference item. - */ - Item newFieldItem(final String owner, final String name, final String desc) { - key3.set(FIELD, owner, name, desc); - Item result = get(key3); - if (result == null) { - put122(FIELD, newClass(owner), newNameType(name, desc)); - result = new Item(index++, key3); - put(result); - } - return result; - } - - /** - * Adds a field reference to the constant pool of the class being build. Does nothing if the constant pool already - * contains a similar item. This method is intended for {@link Attribute} sub classes, and is normally not needed - * by class generators or adapters. - * - * @param owner the internal name of the field's owner class. - * @param name the field's name. - * @param desc the field's descriptor. - * @return the index of a new or already existing field reference item. - */ - public int newField(final String owner, final String name, final String desc) { - return newFieldItem(owner, name, desc).index; - } - - /** - * Adds a method reference to the constant pool of the class being build. Does nothing if the constant pool already - * contains a similar item. - * - * @param owner the internal name of the method's owner class. - * @param name the method's name. - * @param desc the method's descriptor. - * @param itf <tt>true</tt> if <tt>owner</tt> is an interface. - * @return a new or already existing method reference item. - */ - Item newMethodItem(final String owner, final String name, final String desc, final boolean itf) { - int type = itf ? IMETH : METH; - key3.set(type, owner, name, desc); - Item result = get(key3); - if (result == null) { - put122(type, newClass(owner), newNameType(name, desc)); - result = new Item(index++, key3); - put(result); - } - return result; - } - - /** - * Adds a method reference to the constant pool of the class being build. Does nothing if the constant pool already - * contains a similar item. This method is intended for {@link Attribute} sub classes, and is normally not needed - * by class generators or adapters. - * - * @param owner the internal name of the method's owner class. - * @param name the method's name. - * @param desc the method's descriptor. - * @param itf <tt>true</tt> if <tt>owner</tt> is an interface. - * @return the index of a new or already existing method reference item. - */ - public int newMethod(final String owner, final String name, final String desc, final boolean itf) { - return newMethodItem(owner, name, desc, itf).index; - } - - /** - * Adds an integer to the constant pool of the class being build. Does nothing if the constant pool already contains - * a similar item. - * - * @param value the int value. - * @return a new or already existing int item. - */ - Item newInteger(final int value) { - key.set(value); - Item result = get(key); - if (result == null) { - pool.putByte(INT).putInt(value); - result = new Item(index++, key); - put(result); - } - return result; - } - - /** - * Adds a float to the constant pool of the class being build. Does nothing if the constant pool already contains a - * similar item. - * - * @param value the float value. - * @return a new or already existing float item. - */ - Item newFloat(final float value) { - key.set(value); - Item result = get(key); - if (result == null) { - pool.putByte(FLOAT).putInt(key.intVal); - result = new Item(index++, key); - put(result); - } - return result; - } - - /** - * Adds a long to the constant pool of the class being build. Does nothing if the constant pool already contains a - * similar item. - * - * @param value the long value. - * @return a new or already existing long item. - */ - Item newLong(final long value) { - key.set(value); - Item result = get(key); - if (result == null) { - pool.putByte(LONG).putLong(value); - result = new Item(index, key); - index += 2; - put(result); - } - return result; - } - - /** - * Adds a double to the constant pool of the class being build. Does nothing if the constant pool already contains a - * similar item. - * - * @param value the double value. - * @return a new or already existing double item. - */ - Item newDouble(final double value) { - key.set(value); - Item result = get(key); - if (result == null) { - pool.putByte(DOUBLE).putLong(key.longVal); - result = new Item(index, key); - index += 2; - 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. This method is intended for {@link Attribute} sub classes, and is normally not needed - * by class generators or adapters. - * - * @param name a name. - * @param desc a type descriptor. - * @return the index of a new or already existing name and type item. - */ - public int newNameType(final String name, final String desc) { - return newNameTypeItem(name, desc).index; - } - - /** - * 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. - * - * @param name a name. - * @param desc a type descriptor. - * @return a new or already existing name and type item. - */ - Item newNameTypeItem(final String name, final String desc) { - key2.set(NAME_TYPE, name, desc, null); - Item result = get(key2); - if (result == null) { - put122(NAME_TYPE, newUTF8(name), newUTF8(desc)); - result = new Item(index++, key2); - put(result); - } - return result; - } - - /** - * Adds the given internal name to {@link #typeTable} and returns its index. Does nothing if the type table already - * contains this internal name. - * - * @param type the internal name to be added to the type table. - * @return the index of this internal name in the type table. - */ - int addType(final String type) { - key.set(TYPE_NORMAL, type, null, null); - Item result = get(key); - if (result == null) { - result = addType(key); - } - return result.index; - } - - /** - * Adds the given "uninitialized" type to {@link #typeTable} and returns its index. This method is used for - * UNINITIALIZED types, made of an internal name and a bytecode offset. - * - * @param type the internal name to be added to the type table. - * @param offset the bytecode offset of the NEW instruction that created this UNINITIALIZED type value. - * @return the index of this internal name in the type table. - */ - int addUninitializedType(final String type, final int offset) { - key.type = TYPE_UNINIT; - key.intVal = offset; - key.strVal1 = type; - key.hashCode = 0x7FFFFFFF & (TYPE_UNINIT + type.hashCode() + offset); - Item result = get(key); - if (result == null) { - result = addType(key); - } - return result.index; - } - - /** - * Adds the given Item to {@link #typeTable}. - * - * @param item the value to be added to the type table. - * @return the added Item, which a new Item instance with the same value as the given Item. - */ - private Item addType(final Item item) { - ++typeCount; - Item result = new Item(typeCount, key); - put(result); - if (typeTable == null) { - typeTable = new Item[16]; - } - if (typeCount == typeTable.length) { - Item[] newTable = new Item[2 * typeTable.length]; - System.arraycopy(typeTable, 0, newTable, 0, typeTable.length); - typeTable = newTable; - } - typeTable[typeCount] = result; - return result; - } - - /** - * Returns the index of the common super type of the two given types. This method calls {@link #getCommonSuperClass} - * and caches the result in the {@link #items} hash table to speedup future calls with the same parameters. - * - * @param type1 index of an internal name in {@link #typeTable}. - * @param type2 index of an internal name in {@link #typeTable}. - * @return the index of the common super type of the two given types. - */ - int getMergedType(final int type1, final int type2) { - key2.type = TYPE_MERGED; - key2.longVal = type1 | (((long) type2) << 32); - key2.hashCode = 0x7FFFFFFF & (TYPE_MERGED + type1 + type2); - Item result = get(key2); - if (result == null) { - String t = typeTable[type1].strVal1; - String u = typeTable[type2].strVal1; - key2.intVal = addType(getCommonSuperClass(t, u)); - result = new Item((short) 0, key2); - put(result); - } - return result.intVal; - } - - /** - * Returns the common super type of the two given types. The default implementation of this method loads the - * two given classes and uses the java.lang.Class methods to find the common super class. It can be overridden to - * compute this common super type in other ways, in particular without actually loading any class, or to take into - * account the class that is currently being generated by this ClassWriter, which can of course not be loaded since - * it is under construction. - * - * @param type1 the internal name of a class. - * @param type2 the internal name of another class. - * @return the internal name of the common super class of the two given classes. - */ - protected String getCommonSuperClass(final String type1, final String type2) { - Class c, d; - ClassLoader classLoader = getClass().getClassLoader(); - try { - c = Class.forName(type1.replace('/', '.'), false, classLoader); - d = Class.forName(type2.replace('/', '.'), false, classLoader); - } catch (Exception e) { - throw new RuntimeException(e.toString()); - } - if (c.isAssignableFrom(d)) { - return type1; - } - if (d.isAssignableFrom(c)) { - return type2; - } - if (c.isInterface() || d.isInterface()) { - return "java/lang/Object"; - } else { - do { - c = c.getSuperclass(); - } while (!c.isAssignableFrom(d)); - return c.getName().replace('.', '/'); - } - } - - /** - * Returns the constant pool's hash table item which is equal to the given item. - * - * @param key a constant pool item. - * @return the constant pool's hash table item which is equal to the given item, or <tt>null</tt> if - * there is no such item. - */ - private Item get(final Item key) { - Item i = items[key.hashCode % items.length]; - while (i != null && (i.type != key.type || !key.isEqualTo(i))) { - i = i.next; - } - return i; - } - - /** - * Puts the given item in the constant pool's hash table. The hash table must not already contains this item. - * - * @param i the item to be added to the constant pool's hash table. - */ - private void put(final Item i) { - if (index + typeCount > threshold) { - int ll = items.length; - int nl = ll * 2 + 1; - Item[] newItems = new Item[nl]; - for (int l = ll - 1; l >= 0; --l) { - Item j = items[l]; - while (j != null) { - int index = j.hashCode % newItems.length; - Item k = j.next; - j.next = newItems[index]; - newItems[index] = j; - j = k; - } - } - items = newItems; - threshold = (int) (nl * 0.75); - } - int index = i.hashCode % items.length; - i.next = items[index]; - items[index] = i; - } - - /** - * Puts one byte and two shorts into the constant pool. - * - * @param b a byte. - * @param s1 a short. - * @param s2 another short. - */ - private void put122(final int b, final int s1, final int s2) { - pool.put12(b, s1).putShort(s2); - } - - /** - * Puts two bytes and one short into the constant pool. - * - * @param b1 a byte. - * @param b2 another byte. - * @param s a short. - */ - private void put112(final int b1, final int b2, final int s) { - pool.put11(b1, b2).putShort(s); - } -} +/* + * 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 {@link ClassVisitor} that generates classes in bytecode form. More precisely this visitor generates a byte array + * conforming to the Java class file format. It can be used alone, to generate a Java class "from scratch", or with one + * or more {@link ClassReader ClassReader} and adapter class visitor to generate a modified class from one or more + * existing Java classes. + * + * @author Eric Bruneton + */ +public class ClassWriter extends ClassVisitor { + + /** + * Flag to automatically compute the maximum stack size and the maximum number of local variables of methods. If + * this flag is set, then the arguments of the {@link MethodVisitor#visitMaxs visitMaxs} method of the + * {@link MethodVisitor} returned by the {@link #visitMethod visitMethod} method will be ignored, and computed + * automatically from the signature and the bytecode of each method. + * + * @see #ClassWriter(int) + */ + public static final int COMPUTE_MAXS = 1; + + /** + * Flag to automatically compute the stack map frames of methods from scratch. If this flag is set, then the calls + * to the {@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, COMPUTE_FRAMES implies COMPUTE_MAXS. + * + * @see #ClassWriter(int) + */ + public static final int COMPUTE_FRAMES = 2; + + /** Pseudo access flag to distinguish between the synthetic attribute and the synthetic access flag. */ + static final int ACC_SYNTHETIC_ATTRIBUTE = 0x40000; + + /** Factor to convert from ACC_SYNTHETIC_ATTRIBUTE to Opcode.ACC_SYNTHETIC. */ + static final int TO_ACC_SYNTHETIC = ACC_SYNTHETIC_ATTRIBUTE / Opcodes.ACC_SYNTHETIC; + + /** The type of instructions without any argument. */ + static final int NOARG_INSN = 0; + + /** The type of instructions with an signed byte argument. */ + static final int SBYTE_INSN = 1; + + /** The type of instructions with an signed short argument. */ + static final int SHORT_INSN = 2; + + /** The type of instructions with a local variable index argument. */ + static final int VAR_INSN = 3; + + /** The type of instructions with an implicit local variable index argument. */ + static final int IMPLVAR_INSN = 4; + + /** The type of instructions with a type descriptor argument. */ + static final int TYPE_INSN = 5; + + /** The type of field and method invocations instructions. */ + static final int FIELDORMETH_INSN = 6; + + /** The type of the INVOKEINTERFACE/INVOKEDYNAMIC instruction. */ + static final int ITFMETH_INSN = 7; + + /** The type of the INVOKEDYNAMIC instruction. */ + static final int INDYMETH_INSN = 8; + + /** The type of instructions with a 2 bytes bytecode offset label. */ + static final int LABEL_INSN = 9; + + /** The type of instructions with a 4 bytes bytecode offset label. */ + static final int LABELW_INSN = 10; + + /** The type of the LDC instruction. */ + static final int LDC_INSN = 11; + + /** The type of the LDC_W and LDC2_W instructions. */ + static final int LDCW_INSN = 12; + + /** The type of the IINC instruction. */ + static final int IINC_INSN = 13; + + /** The type of the TABLESWITCH instruction. */ + static final int TABL_INSN = 14; + + /** The type of the LOOKUPSWITCH instruction. */ + static final int LOOK_INSN = 15; + + /** The type of the MULTIANEWARRAY instruction. */ + static final int MANA_INSN = 16; + + /** The type of the WIDE instruction. */ + 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. */ + static final byte[] TYPE; + + /** The type of CONSTANT_Class constant pool items. */ + static final int CLASS = 7; + + /** The type of CONSTANT_Fieldref constant pool items. */ + static final int FIELD = 9; + + /** The type of CONSTANT_Methodref constant pool items. */ + static final int METH = 10; + + /** The type of CONSTANT_InterfaceMethodref constant pool items. */ + static final int IMETH = 11; + + /** The type of CONSTANT_String constant pool items. */ + static final int STR = 8; + + /** The type of CONSTANT_Integer constant pool items. */ + static final int INT = 3; + + /** The type of CONSTANT_Float constant pool items. */ + static final int FLOAT = 4; + + /** The type of CONSTANT_Long constant pool items. */ + static final int LONG = 5; + + /** The type of CONSTANT_Double constant pool items. */ + static final int DOUBLE = 6; + + /** The type of CONSTANT_NameAndType constant pool items. */ + static final int NAME_TYPE = 12; + + /** The type of CONSTANT_Utf8 constant pool items. */ + static final int UTF8 = 1; + + /** The type of CONSTANT_MethodType constant pool items. */ + static final int MTYPE = 16; + + /** The type of CONSTANT_MethodHandle constant pool items. */ + static final int HANDLE = 15; + + /** The type of CONSTANT_InvokeDynamic constant pool items. */ + static final int INDY = 18; + + /** The type of CONSTANT_Module constant pool items. */ + static final int MODULE = 19; + + /** The type of CONSTANT_Package constant pool items. */ + static final int PACKAGE = 20; + + /** + * The base value for all CONSTANT_MethodHandle constant pool items. Internally, ASM store the 9 variations of + * CONSTANT_MethodHandle into 9 different items (from 21 to 29). + */ + static final int HANDLE_BASE = 20; + + /** + * Normal type Item stored in the ClassWriter {@link ClassWriter#typeTable}, instead of the constant pool, in order + * to avoid clashes with normal constant pool items in the ClassWriter constant pool's hash table. + */ + static final int TYPE_NORMAL = 30; + + /** + * Uninitialized type Item stored in the ClassWriter {@link ClassWriter#typeTable}, instead of the constant pool, in + * order to avoid clashes with normal constant pool items in the ClassWriter constant pool's hash table. + */ + static final int TYPE_UNINIT = 31; + + /** + * Merged type Item stored in the ClassWriter {@link ClassWriter#typeTable}, instead of the constant pool, in order + * to avoid clashes with normal constant pool items in the ClassWriter constant pool's hash table. + */ + static final int TYPE_MERGED = 32; + + /** + * The type of BootstrapMethods items. These items are stored in a special class attribute named BootstrapMethods + * and not in the constant pool. + */ + static final int BSM = 33; + + /** The class reader from which this class writer was constructed, if any. */ + ClassReader cr; + + /** Minor and major version numbers of the class to be generated. */ + int version; + + /** Index of the next item to be added in the constant pool. */ + int index; + + /** The constant pool of this class. */ + final ByteVector pool; + + /** The constant pool's hash table data. */ + Item[] items; + + /** The threshold of the constant pool's hash table. */ + int threshold; + + /** A reusable key used to look for items in the {@link #items} hash table. */ + final Item key; + + /** A reusable key used to look for items in the {@link #items} hash table. */ + final Item key2; + + /** A reusable key used to look for items in the {@link #items} hash table. */ + final Item key3; + + /** A reusable key used to look for items in the {@link #items} hash table. */ + final Item key4; + + /** + * A type table used to temporarily store internal names that will not necessarily be stored in the constant pool. + * This type table is used by the control flow and data flow analysis algorithm used to compute stack map frames + * from scratch. This array associates to each index <tt>i</tt> the Item whose index is + * <tt>i</tt>. All Item objects stored in this array are also stored in the {@link #items} hash + * table. These two arrays allow to retrieve an Item from its index or, conversely, to get the index of an Item from + * its value. Each Item stores an internal name in its {@link Item#strVal1} field. + */ + Item[] typeTable; + + /** Number of elements in the {@link #typeTable} array. */ + private short typeCount; + + /** The access flags of this class. */ + private int access; + + /** The constant pool item that contains the internal name of this class. */ + private int name; + + /** The internal name of this class. */ + String thisName; + + /** The constant pool item that contains the signature of this class. */ + private int signature; + + /** The constant pool item that contains the internal name of the super class of this class. */ + private int superName; + + /** Number of interfaces implemented or extended by this class or interface. */ + private int interfaceCount; + + /** + * The interfaces implemented or extended by this class or interface. More precisely, this array contains the + * indexes of the constant pool items that contain the internal names of these interfaces. + */ + private int[] interfaces; + + /** + * The index of the constant pool item that contains the name of the source file from which this class was compiled. + */ + private int sourceFile; + + /** The SourceDebug attribute of this class. */ + 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. */ + private int enclosingMethodOwner; + + /** The constant pool item that contains the name and descriptor of the enclosing method of this class. */ + private int enclosingMethod; + + /** The runtime visible annotations of this class. */ + private AnnotationWriter anns; + + /** The runtime invisible annotations of this class. */ + private AnnotationWriter ianns; + + /** The runtime visible type annotations of this class. */ + private AnnotationWriter tanns; + + /** The runtime invisible type annotations of this class. */ + private AnnotationWriter itanns; + + /** The non standard attributes of this class. */ + private Attribute attrs; + + /** The number of entries in the InnerClasses attribute. */ + private int innerClassesCount; + + /** The InnerClasses attribute. */ + private ByteVector innerClasses; + + /** The number of entries in the BootstrapMethods attribute. */ + int bootstrapMethodsCount; + + /** The BootstrapMethods attribute. */ + ByteVector bootstrapMethods; + + /** + * The fields of this class. These fields are stored in a linked list of {@link FieldWriter} objects, linked to each + * other by their {@link FieldWriter#fv} field. This field stores the first element of this list. + */ + FieldWriter firstField; + + /** + * The fields of this class. These fields are stored in a linked list of {@link FieldWriter} objects, linked to each + * other by their {@link FieldWriter#fv} field. This field stores the last element of this list. + */ + FieldWriter lastField; + + /** + * The methods of this class. These methods are stored in a linked list of {@link MethodWriter} objects, linked to + * each other by their {@link MethodWriter#mv} field. This field stores the first element of this list. + */ + MethodWriter firstMethod; + + /** + * The methods of this class. These methods are stored in a linked list of {@link MethodWriter} objects, linked to + * each other by their {@link MethodWriter#mv} field. This field stores the last element of this list. + */ + MethodWriter lastMethod; + + /** + * Indicates what must be automatically computed. + * + * @see MethodWriter#compute + */ + private int compute; + + /** + * <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. + */ + boolean hasAsmInsns; + + // ------------------------------------------------------------------------ + // Static initializer + // ------------------------------------------------------------------------ + + /** Computes the instruction types of JVM opcodes. */ + static { + int i; + byte[] b = new byte[221]; + String s = "AAAAAAAAAAAAAAAABCLMMDDDDDEEEEEEEEEEEEEEEEEEEEAAAAAAAADD" + + "DDDEEEEEEEEEEEEEEEEEEEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAANAAAAAAAAAAAAAAAAAAAAJJJJJJJJJJJJJJJJDOPAA" + + "AAAAGGGGGGGHIFBFAAFFAARQJJKKSSSSSSSSSSSSSSSSSST"; + for (i = 0; i < b.length; ++i) { + b[i] = (byte) (s.charAt(i) - 'A'); + } + TYPE = b; + + // code to generate the above string + // + // // SBYTE_INSN instructions + // b[Constants.NEWARRAY] = SBYTE_INSN; + // b[Constants.BIPUSH] = SBYTE_INSN; + // + // // SHORT_INSN instructions + // b[Constants.SIPUSH] = SHORT_INSN; + // + // // (IMPL)VAR_INSN instructions + // b[Constants.RET] = VAR_INSN; + // for (i = Constants.ILOAD; i <= Constants.ALOAD; ++i) { + // b[i] = VAR_INSN; + // } + // for (i = Constants.ISTORE; i <= Constants.ASTORE; ++i) { + // b[i] = VAR_INSN; + // } + // for (i = 26; i <= 45; ++i) { // ILOAD_0 to ALOAD_3 + // b[i] = IMPLVAR_INSN; + // } + // for (i = 59; i <= 78; ++i) { // ISTORE_0 to ASTORE_3 + // b[i] = IMPLVAR_INSN; + // } + // + // // TYPE_INSN instructions + // b[Constants.NEW] = TYPE_INSN; + // b[Constants.ANEWARRAY] = TYPE_INSN; + // b[Constants.CHECKCAST] = TYPE_INSN; + // b[Constants.INSTANCEOF] = TYPE_INSN; + // + // // (Set)FIELDORMETH_INSN instructions + // for (i = Constants.GETSTATIC; i <= Constants.INVOKESTATIC; ++i) { + // b[i] = FIELDORMETH_INSN; + // } + // b[Constants.INVOKEINTERFACE] = ITFMETH_INSN; + // b[Constants.INVOKEDYNAMIC] = INDYMETH_INSN; + // + // // LABEL(W)_INSN instructions + // for (i = Constants.IFEQ; i <= Constants.JSR; ++i) { + // b[i] = LABEL_INSN; + // } + // b[Constants.IFNULL] = LABEL_INSN; + // b[Constants.IFNONNULL] = LABEL_INSN; + // b[200] = LABELW_INSN; // GOTO_W + // b[201] = LABELW_INSN; // JSR_W + // // temporary opcodes used internally by ASM - see Label and + // MethodWriter + // for (i = 202; i < 220; ++i) { + // b[i] = ASM_LABEL_INSN; + // } + // b[220] = ASM_LABELW_INSN; + // + // // LDC(_W) instructions + // b[Constants.LDC] = LDC_INSN; + // b[19] = LDCW_INSN; // LDC_W + // b[20] = LDCW_INSN; // LDC2_W + // + // // special instructions + // b[Constants.IINC] = IINC_INSN; + // b[Constants.TABLESWITCH] = TABL_INSN; + // b[Constants.LOOKUPSWITCH] = LOOK_INSN; + // b[Constants.MULTIANEWARRAY] = MANA_INSN; + // b[196] = WIDE_INSN; // WIDE + // + // for (i = 0; i < b.length; ++i) { + // System.err.print((char)('A' + b[i])); + // } + // System.err.println(); + } + + // ------------------------------------------------------------------------ + // Constructor + // ------------------------------------------------------------------------ + + /** + * Constructs a new {@link ClassWriter} object. + * + * @param flags option flags that can be used to modify the default behavior of this class. See + * {@link #COMPUTE_MAXS}, {@link #COMPUTE_FRAMES}. + */ + public ClassWriter(final int flags) { + super(Opcodes.ASM6); + index = 1; + pool = new ByteVector(); + items = new Item[256]; + threshold = (int) (0.75d * items.length); + key = new Item(); + key2 = new Item(); + key3 = new Item(); + key4 = new Item(); + this.compute = (flags & COMPUTE_FRAMES) != 0 + ? MethodWriter.FRAMES + : ((flags & COMPUTE_MAXS) != 0 ? MethodWriter.MAXS : MethodWriter.NOTHING); + } + + /** + * Constructs a new {@link ClassWriter} object and enables optimizations for "mostly add" bytecode transformations. + * These optimizations are the following: + * + * + * + * @param classReader the {@link ClassReader} used to read the original class. It will be used to copy the entire + * constant pool from the original class and also to copy other fragments of original bytecode where applicable. + * @param flags option flags that can be used to modify the default behavior of this class. These option flags do + * not affect methods 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. See {@link #COMPUTE_MAXS}, {@link #COMPUTE_FRAMES}. + */ + public ClassWriter(final ClassReader classReader, final int flags) { + this(flags); + classReader.copyPool(this); + this.cr = classReader; + } + + // ------------------------------------------------------------------------ + // Implementation of the ClassVisitor abstract class + // ------------------------------------------------------------------------ + + @Override + public final void visit( + final int version, + final int access, + final String name, + final String signature, + final String superName, + final String[] interfaces) { + this.version = version; + this.access = access; + this.name = newClass(name); + thisName = name; + if (signature != null) { + this.signature = newUTF8(signature); + } + this.superName = superName == null ? 0 : newClass(superName); + if (interfaces != null && interfaces.length > 0) { + interfaceCount = interfaces.length; + this.interfaces = new int[interfaceCount]; + for (int i = 0; i < interfaceCount; ++i) { + this.interfaces[i] = newClass(interfaces[i]); + } + } + } + + @Override + public final void visitSource(final String file, final String debug) { + if (file != null) { + sourceFile = newUTF8(file); + } + if (debug != null) { + sourceDebug = new ByteVector().encodeUTF8(debug, 0, Integer.MAX_VALUE); + } + } + + @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) { + enclosingMethodOwner = newClass(owner); + if (name != null && desc != null) { + enclosingMethod = newNameType(name, desc); + } + } + + @Override + public final AnnotationVisitor visitAnnotation(final String desc, final boolean visible) { + ByteVector bv = new ByteVector(); + // write type, and reserve space for values count + bv.putShort(newUTF8(desc)).putShort(0); + AnnotationWriter aw = new AnnotationWriter(this, true, bv, bv, 2); + if (visible) { + aw.next = anns; + anns = aw; + } else { + aw.next = ianns; + ianns = aw; + } + return aw; + } + + @Override + public final AnnotationVisitor visitTypeAnnotation( + int typeRef, TypePath typePath, final String desc, final boolean visible) { + ByteVector bv = new ByteVector(); + // write target_type and target_info + AnnotationWriter.putTarget(typeRef, typePath, bv); + // write type, and reserve space for values count + bv.putShort(newUTF8(desc)).putShort(0); + AnnotationWriter aw = new AnnotationWriter(this, true, bv, bv, bv.length - 2); + if (visible) { + aw.next = tanns; + tanns = aw; + } else { + aw.next = itanns; + itanns = aw; + } + return aw; + } + + @Override + public final void visitAttribute(final Attribute attr) { + attr.next = attrs; + attrs = attr; + } + + @Override + public final void visitInnerClass( + final String name, final String outerName, final String innerName, final int access) { + if (innerClasses == null) { + innerClasses = new ByteVector(); + } + // Sec. 4.7.6 of the JVMS states "Every CONSTANT_Class_info entry in the + // constant_pool table which represents a class or interface C that is + // not a package member must have exactly one corresponding entry in the + // classes array". To avoid duplicates we keep track in the intVal field + // of the Item of each CONSTANT_Class_info entry C whether an inner + // class entry has already been added for C (this field is unused for + // class entries, and changing its value does not change the hashcode + // 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 = newStringishItem(CLASS, name); + if (nameItem.intVal == 0) { + ++innerClassesCount; + innerClasses.putShort(nameItem.index); + innerClasses.putShort(outerName == null ? 0 : newClass(outerName)); + innerClasses.putShort(innerName == null ? 0 : newUTF8(innerName)); + innerClasses.putShort(access); + nameItem.intVal = innerClassesCount; + } else { + // Compare the inner classes entry nameItem.intVal - 1 with the + // arguments of this method and throw an exception if there is a + // difference? + } + } + + @Override + public final FieldVisitor visitField( + final int access, final String name, final String desc, final String signature, final Object value) { + return new FieldWriter(this, access, name, desc, signature, value); + } + + @Override + 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, compute); + } + + @Override + public final void visitEnd() { + // do nothing + } + + // ------------------------------------------------------------------------ + // Other public methods + // ------------------------------------------------------------------------ + + /** + * Returns the bytecode of the class that was build with this class writer. + * + * @return the bytecode of the class that was build with this class writer. + */ + public byte[] toByteArray() { + if (index > 0xFFFF) { + throw new RuntimeException("Class file too large!"); + } + // computes the real size of the bytecode of this class + int size = 24 + 2 * interfaceCount; + int nbFields = 0; + FieldWriter fb = firstField; + while (fb != null) { + ++nbFields; + size += fb.getSize(); + fb = (FieldWriter) fb.fv; + } + int nbMethods = 0; + MethodWriter mb = firstMethod; + while (mb != null) { + ++nbMethods; + size += mb.getSize(); + mb = (MethodWriter) mb.mv; + } + int attributeCount = 0; + if (bootstrapMethods != null) { + // we put it as first attribute in order to improve a bit + // ClassReader.copyBootstrapMethods + ++attributeCount; + size += 8 + bootstrapMethods.length; + newUTF8("BootstrapMethods"); + } + if (signature != 0) { + ++attributeCount; + size += 8; + newUTF8("Signature"); + } + if (sourceFile != 0) { + ++attributeCount; + size += 8; + newUTF8("SourceFile"); + } + if (sourceDebug != null) { + ++attributeCount; + size += sourceDebug.length + 6; + newUTF8("SourceDebugExtension"); + } + if (enclosingMethodOwner != 0) { + ++attributeCount; + size += 10; + newUTF8("EnclosingMethod"); + } + if ((access & Opcodes.ACC_DEPRECATED) != 0) { + ++attributeCount; + size += 6; + newUTF8("Deprecated"); + } + if ((access & Opcodes.ACC_SYNTHETIC) != 0) { + if ((version & 0xFFFF) < Opcodes.V1_5 || (access & ACC_SYNTHETIC_ATTRIBUTE) != 0) { + ++attributeCount; + size += 6; + newUTF8("Synthetic"); + } + } + if (innerClasses != null) { + ++attributeCount; + size += 8 + innerClasses.length; + newUTF8("InnerClasses"); + } + if (anns != null) { + ++attributeCount; + size += 8 + anns.getSize(); + newUTF8("RuntimeVisibleAnnotations"); + } + if (ianns != null) { + ++attributeCount; + size += 8 + ianns.getSize(); + newUTF8("RuntimeInvisibleAnnotations"); + } + if (tanns != null) { + ++attributeCount; + size += 8 + tanns.getSize(); + newUTF8("RuntimeVisibleTypeAnnotations"); + } + 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); + } + size += pool.length; + // allocates a byte vector of this size, in order to avoid unnecessary + // arraycopy operations in the ByteVector.enlarge() method + ByteVector out = new ByteVector(size); + out.putInt(0xCAFEBABE).putInt(version); + out.putShort(index).putByteArray(pool.data, 0, pool.length); + int mask = Opcodes.ACC_DEPRECATED + | ACC_SYNTHETIC_ATTRIBUTE + | ((access & ACC_SYNTHETIC_ATTRIBUTE) / TO_ACC_SYNTHETIC); + out.putShort(access & ~mask).putShort(name).putShort(superName); + out.putShort(interfaceCount); + for (int i = 0; i < interfaceCount; ++i) { + out.putShort(interfaces[i]); + } + out.putShort(nbFields); + fb = firstField; + while (fb != null) { + fb.put(out); + fb = (FieldWriter) fb.fv; + } + out.putShort(nbMethods); + mb = firstMethod; + while (mb != null) { + mb.put(out); + mb = (MethodWriter) mb.mv; + } + out.putShort(attributeCount); + if (bootstrapMethods != null) { + out.putShort(newUTF8("BootstrapMethods")); + out.putInt(bootstrapMethods.length + 2).putShort(bootstrapMethodsCount); + out.putByteArray(bootstrapMethods.data, 0, bootstrapMethods.length); + } + if (signature != 0) { + out.putShort(newUTF8("Signature")).putInt(2).putShort(signature); + } + if (sourceFile != 0) { + out.putShort(newUTF8("SourceFile")).putInt(2).putShort(sourceFile); + } + if (sourceDebug != null) { + int len = sourceDebug.length; + 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); + } + if ((access & Opcodes.ACC_DEPRECATED) != 0) { + out.putShort(newUTF8("Deprecated")).putInt(0); + } + if ((access & Opcodes.ACC_SYNTHETIC) != 0) { + if ((version & 0xFFFF) < Opcodes.V1_5 || (access & ACC_SYNTHETIC_ATTRIBUTE) != 0) { + out.putShort(newUTF8("Synthetic")).putInt(0); + } + } + if (innerClasses != null) { + out.putShort(newUTF8("InnerClasses")); + out.putInt(innerClasses.length + 2).putShort(innerClassesCount); + out.putByteArray(innerClasses.data, 0, innerClasses.length); + } + if (anns != null) { + out.putShort(newUTF8("RuntimeVisibleAnnotations")); + anns.put(out); + } + if (ianns != null) { + out.putShort(newUTF8("RuntimeInvisibleAnnotations")); + ianns.put(out); + } + if (tanns != null) { + out.putShort(newUTF8("RuntimeVisibleTypeAnnotations")); + tanns.put(out); + } + if (itanns != null) { + out.putShort(newUTF8("RuntimeInvisibleTypeAnnotations")); + itanns.put(out); + } + if (attrs != null) { + attrs.put(this, null, 0, -1, -1, out); + } + if (hasAsmInsns) { + boolean hasFrames = false; + mb = firstMethod; + while (mb != null) { + hasFrames |= mb.frameCount > 0; + mb = (MethodWriter) mb.mv; + } + anns = null; + ianns = null; + attrs = null; + moduleWriter = null; + firstField = null; + lastField = null; + firstMethod = null; + lastMethod = null; + 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; + } + + // ------------------------------------------------------------------------ + // Utility methods: constant pool management + // ------------------------------------------------------------------------ + + /** + * Adds a number or string constant to the constant pool of the class being build. Does nothing if the constant pool + * already contains a similar item. + * + * @param cst the value of the constant to be added to the constant pool. This parameter must be an {@link Integer}, + * a {@link Float}, a {@link Long}, a {@link Double}, a {@link String} or a {@link Type}. + * @return a new or already existing constant item with the given value. + */ + Item newConstItem(final Object cst) { + if (cst instanceof Integer) { + int val = ((Integer) cst).intValue(); + return newInteger(val); + } else if (cst instanceof Byte) { + int val = ((Byte) cst).intValue(); + return newInteger(val); + } else if (cst instanceof Character) { + int val = ((Character) cst).charValue(); + return newInteger(val); + } else if (cst instanceof Short) { + int val = ((Short) cst).intValue(); + return newInteger(val); + } else if (cst instanceof Boolean) { + int val = ((Boolean) cst).booleanValue() ? 1 : 0; + return newInteger(val); + } else if (cst instanceof Float) { + float val = ((Float) cst).floatValue(); + return newFloat(val); + } else if (cst instanceof Long) { + long val = ((Long) cst).longValue(); + return newLong(val); + } else if (cst instanceof Double) { + double val = ((Double) cst).doubleValue(); + return newDouble(val); + } else if (cst instanceof String) { + return newStringishItem(STR, (String) cst); + } else if (cst instanceof Type) { + Type t = (Type) cst; + int s = t.getSort(); + if (s == Type.OBJECT) { + return newStringishItem(CLASS, t.getInternalName()); + } else if (s == Type.METHOD) { + return newStringishItem(MTYPE, t.getDescriptor()); + } else { // s == primitive type or array + return newStringishItem(CLASS, t.getDescriptor()); + } + } else if (cst instanceof Handle) { + Handle h = (Handle) cst; + return newHandleItem(h.tag, h.owner, h.name, h.desc, h.itf); + } else { + throw new IllegalArgumentException("value " + cst); + } + } + + /** + * Adds a number or string constant to the constant pool of the class being build. Does nothing if the constant pool + * already contains a similar item. This method is intended for {@link Attribute} sub classes, and is normally + * not needed by class generators or adapters. + * + * @param cst the value of the constant to be added to the constant pool. This parameter must be an {@link Integer}, + * a {@link Float}, a {@link Long}, a {@link Double} or a {@link String}. + * @return the index of a new or already existing constant item with the given value. + */ + public int newConst(final Object cst) { + return newConstItem(cst).index; + } + + /** + * Adds an UTF8 string to the constant pool of the class being build. Does nothing if the constant pool already + * contains a similar item. This method is intended for {@link Attribute} sub classes, and is normally not needed + * by class generators or adapters. + * + * @param value the String value. + * @return the index of a new or already existing UTF8 item. + */ + public int newUTF8(final String value) { + key.set(UTF8, value, null, null); + Item result = get(key); + if (result == null) { + pool.putByte(UTF8).putUTF8(value); + result = new Item(index++, key); + put(result); + } + return result.index; + } + + /** + * 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. + * + * @param type a type among STR, CLASS, MTYPE, MODULE or PACKAGE + * @param value string value of the reference. + * @return a new or already existing reference item. + */ + Item newStringishItem(final int type, final String value) { + key2.set(type, value, null, null); + Item result = get(key2); + if (result == null) { + pool.put12(type, newUTF8(value)); + result = new Item(index++, key2); + put(result); + } + return result; + } + + /** + * Adds a class reference to the constant pool of the class being build. Does nothing if the constant pool already + * contains a similar item. This method is intended for {@link Attribute} sub classes, and is normally not needed + * by class generators or adapters. + * + * @param value the internal name of the class. + * @return the index of a new or already existing class reference item. + */ + public int newClass(final String value) { + return newStringishItem(CLASS, value).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. This method is intended for {@link Attribute} sub classes, and is normally + * not needed by class generators or adapters. + * + * @param methodDesc method descriptor of the method type. + * @return the index of a new or already existing method type reference item. + */ + public int newMethodType(final String methodDesc) { + 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. This method is intended for {@link Attribute} sub classes, and is normally not needed + * by class generators or adapters. + * + * @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. This method is intended for {@link Attribute} sub classes, and is normally not needed + * by class generators or adapters. + * + * @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; + } + + /** + * Adds a handle to the constant pool of the class being build. Does nothing if the constant pool already contains a + * similar item. This method is intended for {@link Attribute} sub classes, and is normally not needed by class + * generators or adapters. + * + * @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. + * @param itf true if the owner is an interface. + * @return a new or an already existing method type reference item. + */ + Item newHandleItem(final int tag, final String owner, final String name, final String desc, final boolean itf) { + key4.set(HANDLE_BASE + tag, owner, name, desc); + Item result = get(key4); + if (result == null) { + if (tag <= Opcodes.H_PUTSTATIC) { + put112(HANDLE, tag, newField(owner, name, desc)); + } else { + put112(HANDLE, tag, newMethod(owner, name, desc, itf)); + } + result = new Item(index++, key4); + put(result); + } + 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. This method is intended for {@link Attribute} sub classes, and is normally not needed by class + * generators or adapters. + * + * @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. + * @param itf true if the owner is an interface. + * @return the index of a new or already existing method type reference item. + */ + public int newHandle(final int tag, final String owner, final String name, final String desc, final boolean itf) { + return newHandleItem(tag, owner, name, desc, itf).index; + } + + /** + * Adds an invokedynamic reference to the constant pool of the class being build. Does nothing if the constant pool + * already contains a similar item. This method is intended for {@link Attribute} sub classes, and is normally + * not needed by class generators or adapters. + * + * @param name name of the invoked method. + * @param desc descriptor of the invoke method. + * @param bsm the bootstrap method. + * @param bsmArgs the bootstrap method constant arguments. + * @return a new or an already existing invokedynamic type reference item. + */ + Item newInvokeDynamicItem(final String name, final String desc, final Handle bsm, final Object... bsmArgs) { + // cache for performance + ByteVector bootstrapMethods = this.bootstrapMethods; + if (bootstrapMethods == null) { + bootstrapMethods = this.bootstrapMethods = new ByteVector(); + } + + int position = bootstrapMethods.length; // record current position + + int hashCode = bsm.hashCode(); + bootstrapMethods.putShort(newHandle(bsm.tag, bsm.owner, bsm.name, bsm.desc, bsm.isInterface())); + + int argsLength = bsmArgs.length; + bootstrapMethods.putShort(argsLength); + + for (int i = 0; i < argsLength; i++) { + Object bsmArg = bsmArgs[i]; + hashCode ^= bsmArg.hashCode(); + bootstrapMethods.putShort(newConst(bsmArg)); + } + + byte[] data = bootstrapMethods.data; + int length = (1 + 1 + argsLength) << 1; // (bsm + argCount + arguments) + hashCode &= 0x7FFFFFFF; + Item result = items[hashCode % items.length]; + loop: + while (result != null) { + if (result.type != BSM || result.hashCode != hashCode) { + result = result.next; + continue; + } + + // because the data encode the size of the argument + // we don't need to test if these size are equals + int resultPosition = result.intVal; + for (int p = 0; p < length; p++) { + if (data[position + p] != data[resultPosition + p]) { + result = result.next; + continue loop; + } + } + break; + } + + int bootstrapMethodIndex; + if (result != null) { + bootstrapMethodIndex = result.index; + bootstrapMethods.length = position; // revert to old position + } else { + bootstrapMethodIndex = bootstrapMethodsCount++; + result = new Item(bootstrapMethodIndex); + result.set(position, hashCode); + put(result); + } + + // now, create the InvokeDynamic constant + key3.set(name, desc, bootstrapMethodIndex); + result = get(key3); + if (result == null) { + put122(INDY, bootstrapMethodIndex, newNameType(name, desc)); + result = new Item(index++, key3); + put(result); + } + return result; + } + + /** + * Adds an invokedynamic reference to the constant pool of the class being build. Does nothing if the constant pool + * already contains a similar item. This method is intended for {@link Attribute} sub classes, and is normally + * not needed by class generators or adapters. + * + * @param name name of the invoked method. + * @param desc descriptor of the invoke method. + * @param bsm the bootstrap method. + * @param bsmArgs the bootstrap method constant arguments. + * @return the index of a new or already existing invokedynamic reference item. + */ + public int newInvokeDynamic(final String name, final String desc, final Handle bsm, final Object... bsmArgs) { + return newInvokeDynamicItem(name, desc, bsm, bsmArgs).index; + } + + /** + * Adds a field reference to the constant pool of the class being build. Does nothing if the constant pool already + * contains a similar item. + * + * @param owner the internal name of the field's owner class. + * @param name the field's name. + * @param desc the field's descriptor. + * @return a new or already existing field reference item. + */ + Item newFieldItem(final String owner, final String name, final String desc) { + key3.set(FIELD, owner, name, desc); + Item result = get(key3); + if (result == null) { + put122(FIELD, newClass(owner), newNameType(name, desc)); + result = new Item(index++, key3); + put(result); + } + return result; + } + + /** + * Adds a field reference to the constant pool of the class being build. Does nothing if the constant pool already + * contains a similar item. This method is intended for {@link Attribute} sub classes, and is normally not needed + * by class generators or adapters. + * + * @param owner the internal name of the field's owner class. + * @param name the field's name. + * @param desc the field's descriptor. + * @return the index of a new or already existing field reference item. + */ + public int newField(final String owner, final String name, final String desc) { + return newFieldItem(owner, name, desc).index; + } + + /** + * Adds a method reference to the constant pool of the class being build. Does nothing if the constant pool already + * contains a similar item. + * + * @param owner the internal name of the method's owner class. + * @param name the method's name. + * @param desc the method's descriptor. + * @param itf <tt>true</tt> if <tt>owner</tt> is an interface. + * @return a new or already existing method reference item. + */ + Item newMethodItem(final String owner, final String name, final String desc, final boolean itf) { + int type = itf ? IMETH : METH; + key3.set(type, owner, name, desc); + Item result = get(key3); + if (result == null) { + put122(type, newClass(owner), newNameType(name, desc)); + result = new Item(index++, key3); + put(result); + } + return result; + } + + /** + * Adds a method reference to the constant pool of the class being build. Does nothing if the constant pool already + * contains a similar item. This method is intended for {@link Attribute} sub classes, and is normally not needed + * by class generators or adapters. + * + * @param owner the internal name of the method's owner class. + * @param name the method's name. + * @param desc the method's descriptor. + * @param itf <tt>true</tt> if <tt>owner</tt> is an interface. + * @return the index of a new or already existing method reference item. + */ + public int newMethod(final String owner, final String name, final String desc, final boolean itf) { + return newMethodItem(owner, name, desc, itf).index; + } + + /** + * Adds an integer to the constant pool of the class being build. Does nothing if the constant pool already contains + * a similar item. + * + * @param value the int value. + * @return a new or already existing int item. + */ + Item newInteger(final int value) { + key.set(value); + Item result = get(key); + if (result == null) { + pool.putByte(INT).putInt(value); + result = new Item(index++, key); + put(result); + } + return result; + } + + /** + * Adds a float to the constant pool of the class being build. Does nothing if the constant pool already contains a + * similar item. + * + * @param value the float value. + * @return a new or already existing float item. + */ + Item newFloat(final float value) { + key.set(value); + Item result = get(key); + if (result == null) { + pool.putByte(FLOAT).putInt(key.intVal); + result = new Item(index++, key); + put(result); + } + return result; + } + + /** + * Adds a long to the constant pool of the class being build. Does nothing if the constant pool already contains a + * similar item. + * + * @param value the long value. + * @return a new or already existing long item. + */ + Item newLong(final long value) { + key.set(value); + Item result = get(key); + if (result == null) { + pool.putByte(LONG).putLong(value); + result = new Item(index, key); + index += 2; + put(result); + } + return result; + } + + /** + * Adds a double to the constant pool of the class being build. Does nothing if the constant pool already contains a + * similar item. + * + * @param value the double value. + * @return a new or already existing double item. + */ + Item newDouble(final double value) { + key.set(value); + Item result = get(key); + if (result == null) { + pool.putByte(DOUBLE).putLong(key.longVal); + result = new Item(index, key); + index += 2; + 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. This method is intended for {@link Attribute} sub classes, and is normally not needed + * by class generators or adapters. + * + * @param name a name. + * @param desc a type descriptor. + * @return the index of a new or already existing name and type item. + */ + public int newNameType(final String name, final String desc) { + return newNameTypeItem(name, desc).index; + } + + /** + * 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. + * + * @param name a name. + * @param desc a type descriptor. + * @return a new or already existing name and type item. + */ + Item newNameTypeItem(final String name, final String desc) { + key2.set(NAME_TYPE, name, desc, null); + Item result = get(key2); + if (result == null) { + put122(NAME_TYPE, newUTF8(name), newUTF8(desc)); + result = new Item(index++, key2); + put(result); + } + return result; + } + + /** + * Adds the given internal name to {@link #typeTable} and returns its index. Does nothing if the type table already + * contains this internal name. + * + * @param type the internal name to be added to the type table. + * @return the index of this internal name in the type table. + */ + int addType(final String type) { + key.set(TYPE_NORMAL, type, null, null); + Item result = get(key); + if (result == null) { + result = addType(key); + } + return result.index; + } + + /** + * Adds the given "uninitialized" type to {@link #typeTable} and returns its index. This method is used for + * UNINITIALIZED types, made of an internal name and a bytecode offset. + * + * @param type the internal name to be added to the type table. + * @param offset the bytecode offset of the NEW instruction that created this UNINITIALIZED type value. + * @return the index of this internal name in the type table. + */ + int addUninitializedType(final String type, final int offset) { + key.type = TYPE_UNINIT; + key.intVal = offset; + key.strVal1 = type; + key.hashCode = 0x7FFFFFFF & (TYPE_UNINIT + type.hashCode() + offset); + Item result = get(key); + if (result == null) { + result = addType(key); + } + return result.index; + } + + /** + * Adds the given Item to {@link #typeTable}. + * + * @param item the value to be added to the type table. + * @return the added Item, which a new Item instance with the same value as the given Item. + */ + private Item addType(final Item item) { + ++typeCount; + Item result = new Item(typeCount, key); + put(result); + if (typeTable == null) { + typeTable = new Item[16]; + } + if (typeCount == typeTable.length) { + Item[] newTable = new Item[2 * typeTable.length]; + System.arraycopy(typeTable, 0, newTable, 0, typeTable.length); + typeTable = newTable; + } + typeTable[typeCount] = result; + return result; + } + + /** + * Returns the index of the common super type of the two given types. This method calls {@link #getCommonSuperClass} + * and caches the result in the {@link #items} hash table to speedup future calls with the same parameters. + * + * @param type1 index of an internal name in {@link #typeTable}. + * @param type2 index of an internal name in {@link #typeTable}. + * @return the index of the common super type of the two given types. + */ + int getMergedType(final int type1, final int type2) { + key2.type = TYPE_MERGED; + key2.longVal = type1 | (((long) type2) << 32); + key2.hashCode = 0x7FFFFFFF & (TYPE_MERGED + type1 + type2); + Item result = get(key2); + if (result == null) { + String t = typeTable[type1].strVal1; + String u = typeTable[type2].strVal1; + key2.intVal = addType(getCommonSuperClass(t, u)); + result = new Item((short) 0, key2); + put(result); + } + return result.intVal; + } + + /** + * Returns the common super type of the two given types. The default implementation of this method loads the + * two given classes and uses the java.lang.Class methods to find the common super class. It can be overridden to + * compute this common super type in other ways, in particular without actually loading any class, or to take into + * account the class that is currently being generated by this ClassWriter, which can of course not be loaded since + * it is under construction. + * + * @param type1 the internal name of a class. + * @param type2 the internal name of another class. + * @return the internal name of the common super class of the two given classes. + */ + protected String getCommonSuperClass(final String type1, final String type2) { + Class c, d; + ClassLoader classLoader = getClass().getClassLoader(); + try { + c = Class.forName(type1.replace('/', '.'), false, classLoader); + d = Class.forName(type2.replace('/', '.'), false, classLoader); + } catch (Exception e) { + throw new RuntimeException(e.toString()); + } + if (c.isAssignableFrom(d)) { + return type1; + } + if (d.isAssignableFrom(c)) { + return type2; + } + if (c.isInterface() || d.isInterface()) { + return "java/lang/Object"; + } else { + do { + c = c.getSuperclass(); + } while (!c.isAssignableFrom(d)); + return c.getName().replace('.', '/'); + } + } + + /** + * Returns the constant pool's hash table item which is equal to the given item. + * + * @param key a constant pool item. + * @return the constant pool's hash table item which is equal to the given item, or <tt>null</tt> if + * there is no such item. + */ + private Item get(final Item key) { + Item i = items[key.hashCode % items.length]; + while (i != null && (i.type != key.type || !key.isEqualTo(i))) { + i = i.next; + } + return i; + } + + /** + * Puts the given item in the constant pool's hash table. The hash table must not already contains this item. + * + * @param i the item to be added to the constant pool's hash table. + */ + private void put(final Item i) { + if (index + typeCount > threshold) { + int ll = items.length; + int nl = ll * 2 + 1; + Item[] newItems = new Item[nl]; + for (int l = ll - 1; l >= 0; --l) { + Item j = items[l]; + while (j != null) { + int index = j.hashCode % newItems.length; + Item k = j.next; + j.next = newItems[index]; + newItems[index] = j; + j = k; + } + } + items = newItems; + threshold = (int) (nl * 0.75); + } + int index = i.hashCode % items.length; + i.next = items[index]; + items[index] = i; + } + + /** + * Puts one byte and two shorts into the constant pool. + * + * @param b a byte. + * @param s1 a short. + * @param s2 another short. + */ + private void put122(final int b, final int s1, final int s2) { + pool.put12(b, s1).putShort(s2); + } + + /** + * Puts two bytes and one short into the constant pool. + * + * @param b1 a byte. + * @param b2 another byte. + * @param s a short. + */ + private void put112(final int b1, final int b2, final int s) { + pool.put11(b1, b2).putShort(s); + } +} diff --git a/src/main/java/org/redkale/asm/Context.java b/src/main/java/org/redkale/asm/Context.java index c3436c682..8e0397895 100644 --- a/src/main/java/org/redkale/asm/Context.java +++ b/src/main/java/org/redkale/asm/Context.java @@ -1,143 +1,143 @@ -/* - * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */ - -/* - * - * - * - * - * - * ASM: a very small and fast Java bytecode manipulation framework - * Copyright (c) 2000-2011 INRIA, France Telecom - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -package org.redkale.asm; - -/** - * Information about a class being parsed in a {@link ClassReader}. - * - * @author Eric Bruneton - */ -class Context { - - /** Prototypes of the attributes that must be parsed for this class. */ - Attribute[] attrs; - - /** The {@link ClassReader} option flags for the parsing of this class. */ - int flags; - - /** The buffer used to read strings. */ - char[] buffer; - - /** The start index of each bootstrap method. */ - int[] bootstrapMethods; - - /** The access flags of the method currently being parsed. */ - int access; - - /** The name of the method currently being parsed. */ - String name; - - /** The descriptor of the method currently being parsed. */ - String desc; - - /** - * The label objects, indexed by bytecode offset, of the method currently being parsed (only bytecode offsets for - * which a label is needed have a non null associated Label object). - */ - Label[] labels; - - /** The target of the type annotation currently being parsed. */ - int typeRef; - - /** The path of the type annotation currently being parsed. */ - TypePath typePath; - - /** The offset of the latest stack map frame that has been parsed. */ - int offset; - - /** - * The labels corresponding to the start of the local variable ranges in the local variable type annotation - * currently being parsed. - */ - Label[] start; - - /** - * The labels corresponding to the end of the local variable ranges in the local variable type annotation currently - * being parsed. - */ - Label[] end; - - /** - * The local variable indices for each local variable range in the local variable type annotation currently being - * parsed. - */ - int[] index; - - /** The encoding of the latest stack map frame that has been parsed. */ - int mode; - - /** The number of locals in the latest stack map frame that has been parsed. */ - int localCount; - - /** - * The number locals in the latest stack map frame that has been parsed, minus the number of locals in the previous - * frame. - */ - int localDiff; - - /** The local values of the latest stack map frame that has been parsed. */ - Object[] local; - - /** The stack size of the latest stack map frame that has been parsed. */ - int stackCount; - - /** The stack values of the latest stack map frame that has been parsed. */ - Object[] stack; -} +/* + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ + +/* + * + * + * + * + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.redkale.asm; + +/** + * Information about a class being parsed in a {@link ClassReader}. + * + * @author Eric Bruneton + */ +class Context { + + /** Prototypes of the attributes that must be parsed for this class. */ + Attribute[] attrs; + + /** The {@link ClassReader} option flags for the parsing of this class. */ + int flags; + + /** The buffer used to read strings. */ + char[] buffer; + + /** The start index of each bootstrap method. */ + int[] bootstrapMethods; + + /** The access flags of the method currently being parsed. */ + int access; + + /** The name of the method currently being parsed. */ + String name; + + /** The descriptor of the method currently being parsed. */ + String desc; + + /** + * The label objects, indexed by bytecode offset, of the method currently being parsed (only bytecode offsets for + * which a label is needed have a non null associated Label object). + */ + Label[] labels; + + /** The target of the type annotation currently being parsed. */ + int typeRef; + + /** The path of the type annotation currently being parsed. */ + TypePath typePath; + + /** The offset of the latest stack map frame that has been parsed. */ + int offset; + + /** + * The labels corresponding to the start of the local variable ranges in the local variable type annotation + * currently being parsed. + */ + Label[] start; + + /** + * The labels corresponding to the end of the local variable ranges in the local variable type annotation currently + * being parsed. + */ + Label[] end; + + /** + * The local variable indices for each local variable range in the local variable type annotation currently being + * parsed. + */ + int[] index; + + /** The encoding of the latest stack map frame that has been parsed. */ + int mode; + + /** The number of locals in the latest stack map frame that has been parsed. */ + int localCount; + + /** + * The number locals in the latest stack map frame that has been parsed, minus the number of locals in the previous + * frame. + */ + int localDiff; + + /** The local values of the latest stack map frame that has been parsed. */ + Object[] local; + + /** The stack size of the latest stack map frame that has been parsed. */ + int stackCount; + + /** The stack values of the latest stack map frame that has been parsed. */ + Object[] stack; +} diff --git a/src/main/java/org/redkale/asm/CurrentFrame.java b/src/main/java/org/redkale/asm/CurrentFrame.java index 846fd9b25..329641787 100644 --- a/src/main/java/org/redkale/asm/CurrentFrame.java +++ b/src/main/java/org/redkale/asm/CurrentFrame.java @@ -1,83 +1,83 @@ -/* - * 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; - } -} +/* + * 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; + } +} diff --git a/src/main/java/org/redkale/asm/Edge.java b/src/main/java/org/redkale/asm/Edge.java index c7ea12ac9..57da1c9d9 100644 --- a/src/main/java/org/redkale/asm/Edge.java +++ b/src/main/java/org/redkale/asm/Edge.java @@ -1,94 +1,94 @@ -/* - * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */ - -/* - * - * - * - * - * - * ASM: a very small and fast Java bytecode manipulation framework - * Copyright (c) 2000-2011 INRIA, France Telecom - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.redkale.asm; - -/** - * An edge in the control flow graph of a method body. See {@link Label Label}. - * - * @author Eric Bruneton - */ -class Edge { - - /** Denotes a normal control flow graph edge. */ - static final int NORMAL = 0; - - /** - * Denotes a control flow graph edge corresponding to an exception handler. More precisely any {@link Edge} whose - * {@link #info} is strictly positive corresponds to an exception handler. The actual value of {@link #info} is the - * index, in the {@link ClassWriter} type table, of the exception that is catched. - */ - static final int EXCEPTION = 0x7FFFFFFF; - - /** - * Information about this control flow graph edge. If {@link ClassWriter#COMPUTE_MAXS} is used this field is the - * (relative) stack size in the basic block from which this edge originates. This size is equal to the stack size at - * the "jump" instruction to which this edge corresponds, relatively to the stack size at the beginning of the - * originating basic block. If {@link ClassWriter#COMPUTE_FRAMES} is used, this field is the kind of this control - * flow graph edge (i.e. NORMAL or EXCEPTION). - */ - int info; - - /** The successor block of the basic block from which this edge originates. */ - Label successor; - - /** - * The next edge in the list of successors of the originating basic block. See {@link Label#successors successors}. - */ - Edge next; -} +/* + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ + +/* + * + * + * + * + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.redkale.asm; + +/** + * An edge in the control flow graph of a method body. See {@link Label Label}. + * + * @author Eric Bruneton + */ +class Edge { + + /** Denotes a normal control flow graph edge. */ + static final int NORMAL = 0; + + /** + * Denotes a control flow graph edge corresponding to an exception handler. More precisely any {@link Edge} whose + * {@link #info} is strictly positive corresponds to an exception handler. The actual value of {@link #info} is the + * index, in the {@link ClassWriter} type table, of the exception that is catched. + */ + static final int EXCEPTION = 0x7FFFFFFF; + + /** + * Information about this control flow graph edge. If {@link ClassWriter#COMPUTE_MAXS} is used this field is the + * (relative) stack size in the basic block from which this edge originates. This size is equal to the stack size at + * the "jump" instruction to which this edge corresponds, relatively to the stack size at the beginning of the + * originating basic block. If {@link ClassWriter#COMPUTE_FRAMES} is used, this field is the kind of this control + * flow graph edge (i.e. NORMAL or EXCEPTION). + */ + int info; + + /** The successor block of the basic block from which this edge originates. */ + Label successor; + + /** + * The next edge in the list of successors of the originating basic block. See {@link Label#successors successors}. + */ + Edge next; +} diff --git a/src/main/java/org/redkale/asm/FieldVisitor.java b/src/main/java/org/redkale/asm/FieldVisitor.java index f0af182bf..b506c4da9 100644 --- a/src/main/java/org/redkale/asm/FieldVisitor.java +++ b/src/main/java/org/redkale/asm/FieldVisitor.java @@ -1,155 +1,155 @@ -/* - * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */ - -/* - * - * - * - * - * - * ASM: a very small and fast Java bytecode manipulation framework - * Copyright (c) 2000-2011 INRIA, France Telecom - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.redkale.asm; - -/** - * A visitor to visit a Java field. The methods of this class must be called in the following order: ( - * <tt>visitAnnotation</tt> | <tt>visitTypeAnnotation</tt> | - * <tt>visitAttribute</tt> )* <tt>visitEnd</tt>. - * - * @author Eric Bruneton - */ -public abstract class FieldVisitor { - - /** - * The ASM API version implemented by this visitor. The value of this field must be one of {@link Opcodes#ASM4}, - * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. - */ - protected final int api; - - /** The field visitor to which this visitor must delegate method calls. May be null. */ - protected FieldVisitor fv; - - /** - * Constructs a new {@link FieldVisitor}. - * - * @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4}, - * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. - */ - public FieldVisitor(final int api) { - this(api, null); - } - - /** - * Constructs a new {@link FieldVisitor}. - * - * @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4}, - * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. - * @param fv the field visitor to which this visitor must delegate method calls. May be null. - */ - public FieldVisitor(final int api, final FieldVisitor fv) { - this.api = api; - this.fv = fv; - } - - /** - * Visits an annotation of the field. - * - * @param desc the class descriptor of the annotation class. - * @param visible <tt>true</tt> if the annotation is visible at runtime. - * @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not - * interested in visiting this annotation. - */ - public AnnotationVisitor visitAnnotation(String desc, boolean visible) { - if (fv != null) { - return fv.visitAnnotation(desc, visible); - } - return null; - } - - /** - * Visits an annotation on the type of the field. - * - * @param typeRef a reference to the annotated type. The sort of this type reference must be - * {@link TypeReference#FIELD FIELD}. See {@link TypeReference}. - * @param typePath the path to the annotated type argument, wildcard bound, array element type, or static inner type - * within 'typeRef'. May be <tt>null</tt> if the annotation targets 'typeRef' as a whole. - * @param desc the class descriptor of the annotation class. - * @param visible <tt>true</tt> if the annotation is visible at runtime. - * @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not - * interested in visiting this annotation. - */ - public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) { - if (fv != null) { - return fv.visitTypeAnnotation(typeRef, typePath, desc, visible); - } - return null; - } - - /** - * Visits a non standard attribute of the field. - * - * @param attr an attribute. - */ - public void visitAttribute(Attribute attr) { - if (fv != null) { - fv.visitAttribute(attr); - } - } - - /** - * Visits the end of the field. This method, which is the last one to be called, is used to inform the visitor that - * all the annotations and attributes of the field have been visited. - */ - public void visitEnd() { - if (fv != null) { - fv.visitEnd(); - } - } -} +/* + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ + +/* + * + * + * + * + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.redkale.asm; + +/** + * A visitor to visit a Java field. The methods of this class must be called in the following order: ( + * <tt>visitAnnotation</tt> | <tt>visitTypeAnnotation</tt> | + * <tt>visitAttribute</tt> )* <tt>visitEnd</tt>. + * + * @author Eric Bruneton + */ +public abstract class FieldVisitor { + + /** + * The ASM API version implemented by this visitor. The value of this field must be one of {@link Opcodes#ASM4}, + * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. + */ + protected final int api; + + /** The field visitor to which this visitor must delegate method calls. May be null. */ + protected FieldVisitor fv; + + /** + * Constructs a new {@link FieldVisitor}. + * + * @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4}, + * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. + */ + public FieldVisitor(final int api) { + this(api, null); + } + + /** + * Constructs a new {@link FieldVisitor}. + * + * @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4}, + * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. + * @param fv the field visitor to which this visitor must delegate method calls. May be null. + */ + public FieldVisitor(final int api, final FieldVisitor fv) { + this.api = api; + this.fv = fv; + } + + /** + * Visits an annotation of the field. + * + * @param desc the class descriptor of the annotation class. + * @param visible <tt>true</tt> if the annotation is visible at runtime. + * @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not + * interested in visiting this annotation. + */ + public AnnotationVisitor visitAnnotation(String desc, boolean visible) { + if (fv != null) { + return fv.visitAnnotation(desc, visible); + } + return null; + } + + /** + * Visits an annotation on the type of the field. + * + * @param typeRef a reference to the annotated type. The sort of this type reference must be + * {@link TypeReference#FIELD FIELD}. See {@link TypeReference}. + * @param typePath the path to the annotated type argument, wildcard bound, array element type, or static inner type + * within 'typeRef'. May be <tt>null</tt> if the annotation targets 'typeRef' as a whole. + * @param desc the class descriptor of the annotation class. + * @param visible <tt>true</tt> if the annotation is visible at runtime. + * @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not + * interested in visiting this annotation. + */ + public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) { + if (fv != null) { + return fv.visitTypeAnnotation(typeRef, typePath, desc, visible); + } + return null; + } + + /** + * Visits a non standard attribute of the field. + * + * @param attr an attribute. + */ + public void visitAttribute(Attribute attr) { + if (fv != null) { + fv.visitAttribute(attr); + } + } + + /** + * Visits the end of the field. This method, which is the last one to be called, is used to inform the visitor that + * all the annotations and attributes of the field have been visited. + */ + public void visitEnd() { + if (fv != null) { + fv.visitEnd(); + } + } +} diff --git a/src/main/java/org/redkale/asm/FieldWriter.java b/src/main/java/org/redkale/asm/FieldWriter.java index b46c52dbb..afab5f93e 100644 --- a/src/main/java/org/redkale/asm/FieldWriter.java +++ b/src/main/java/org/redkale/asm/FieldWriter.java @@ -1,320 +1,320 @@ -/* - * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */ - -/* - * - * - * - * - * - * ASM: a very small and fast Java bytecode manipulation framework - * Copyright (c) 2000-2011 INRIA, France Telecom - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.redkale.asm; - -/** - * An {@link FieldVisitor} that generates Java fields in bytecode form. - * - * @author Eric Bruneton - */ -final class FieldWriter extends FieldVisitor { - - /** The class writer to which this field must be added. */ - private final ClassWriter cw; - - /** Access flags of this field. */ - private final int access; - - /** The index of the constant pool item that contains the name of this method. */ - private final int name; - - /** The index of the constant pool item that contains the descriptor of this field. */ - private final int desc; - - /** The index of the constant pool item that contains the signature of this field. */ - private int signature; - - /** The index of the constant pool item that contains the constant value of this field. */ - private int value; - - /** The runtime visible annotations of this field. May be <tt>null</tt>. */ - private AnnotationWriter anns; - - /** The runtime invisible annotations of this field. May be <tt>null</tt>. */ - private AnnotationWriter ianns; - - /** The runtime visible type annotations of this field. May be <tt>null</tt>. */ - private AnnotationWriter tanns; - - /** The runtime invisible type annotations of this field. May be <tt>null</tt>. */ - private AnnotationWriter itanns; - - /** The non standard attributes of this field. May be <tt>null</tt>. */ - private Attribute attrs; - - // ------------------------------------------------------------------------ - // Constructor - // ------------------------------------------------------------------------ - - /** - * Constructs a new {@link FieldWriter}. - * - * @param cw the class writer to which this field must be added. - * @param access the field's access flags (see {@link Opcodes}). - * @param name the field's name. - * @param desc the field's descriptor (see {@link Type}). - * @param signature the field's signature. May be <tt>null</tt>. - * @param value the field's constant value. May be <tt>null</tt>. - */ - FieldWriter( - final ClassWriter cw, - final int access, - final String name, - final String desc, - final String signature, - final Object value) { - super(Opcodes.ASM6); - if (cw.firstField == null) { - cw.firstField = this; - } else { - cw.lastField.fv = this; - } - cw.lastField = this; - this.cw = cw; - this.access = access; - this.name = cw.newUTF8(name); - this.desc = cw.newUTF8(desc); - if (signature != null) { - this.signature = cw.newUTF8(signature); - } - if (value != null) { - this.value = cw.newConstItem(value).index; - } - } - - // ------------------------------------------------------------------------ - // Implementation of the FieldVisitor abstract class - // ------------------------------------------------------------------------ - - @Override - public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) { - ByteVector bv = new ByteVector(); - // write type, and reserve space for values count - bv.putShort(cw.newUTF8(desc)).putShort(0); - AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2); - if (visible) { - aw.next = anns; - anns = aw; - } else { - aw.next = ianns; - ianns = aw; - } - return aw; - } - - @Override - public AnnotationVisitor visitTypeAnnotation( - final int typeRef, final TypePath typePath, final String desc, final boolean visible) { - ByteVector bv = new ByteVector(); - // write target_type and target_info - AnnotationWriter.putTarget(typeRef, typePath, bv); - // write type, and reserve space for values count - bv.putShort(cw.newUTF8(desc)).putShort(0); - AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, bv.length - 2); - if (visible) { - aw.next = tanns; - tanns = aw; - } else { - aw.next = itanns; - itanns = aw; - } - return aw; - } - - @Override - public void visitAttribute(final Attribute attr) { - attr.next = attrs; - attrs = attr; - } - - @Override - public void visitEnd() { - // do nothing - } - - // ------------------------------------------------------------------------ - // Utility methods - // ------------------------------------------------------------------------ - - /** - * Returns the size of this field. - * - * @return the size of this field. - */ - int getSize() { - int size = 8; - if (value != 0) { - cw.newUTF8("ConstantValue"); - size += 8; - } - if ((access & Opcodes.ACC_SYNTHETIC) != 0) { - if ((cw.version & 0xFFFF) < Opcodes.V1_5 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) { - cw.newUTF8("Synthetic"); - size += 6; - } - } - if ((access & Opcodes.ACC_DEPRECATED) != 0) { - cw.newUTF8("Deprecated"); - size += 6; - } - if (signature != 0) { - cw.newUTF8("Signature"); - size += 8; - } - if (anns != null) { - cw.newUTF8("RuntimeVisibleAnnotations"); - size += 8 + anns.getSize(); - } - if (ianns != null) { - cw.newUTF8("RuntimeInvisibleAnnotations"); - size += 8 + ianns.getSize(); - } - if (tanns != null) { - cw.newUTF8("RuntimeVisibleTypeAnnotations"); - size += 8 + tanns.getSize(); - } - if (itanns != null) { - cw.newUTF8("RuntimeInvisibleTypeAnnotations"); - size += 8 + itanns.getSize(); - } - if (attrs != null) { - size += attrs.getSize(cw, null, 0, -1, -1); - } - return size; - } - - /** - * Puts the content of this field into the given byte vector. - * - * @param out where the content of this field must be put. - */ - void put(final ByteVector out) { - final int FACTOR = ClassWriter.TO_ACC_SYNTHETIC; - int mask = Opcodes.ACC_DEPRECATED - | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE - | ((access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) / FACTOR); - out.putShort(access & ~mask).putShort(name).putShort(desc); - int attributeCount = 0; - if (value != 0) { - ++attributeCount; - } - if ((access & Opcodes.ACC_SYNTHETIC) != 0) { - if ((cw.version & 0xFFFF) < Opcodes.V1_5 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) { - ++attributeCount; - } - } - if ((access & Opcodes.ACC_DEPRECATED) != 0) { - ++attributeCount; - } - if (signature != 0) { - ++attributeCount; - } - if (anns != null) { - ++attributeCount; - } - if (ianns != null) { - ++attributeCount; - } - if (tanns != null) { - ++attributeCount; - } - if (itanns != null) { - ++attributeCount; - } - if (attrs != null) { - attributeCount += attrs.getCount(); - } - out.putShort(attributeCount); - if (value != 0) { - out.putShort(cw.newUTF8("ConstantValue")); - out.putInt(2).putShort(value); - } - if ((access & Opcodes.ACC_SYNTHETIC) != 0) { - if ((cw.version & 0xFFFF) < Opcodes.V1_5 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) { - out.putShort(cw.newUTF8("Synthetic")).putInt(0); - } - } - if ((access & Opcodes.ACC_DEPRECATED) != 0) { - out.putShort(cw.newUTF8("Deprecated")).putInt(0); - } - if (signature != 0) { - out.putShort(cw.newUTF8("Signature")); - out.putInt(2).putShort(signature); - } - if (anns != null) { - out.putShort(cw.newUTF8("RuntimeVisibleAnnotations")); - anns.put(out); - } - if (ianns != null) { - out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations")); - ianns.put(out); - } - if (tanns != null) { - out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations")); - tanns.put(out); - } - if (itanns != null) { - out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations")); - itanns.put(out); - } - if (attrs != null) { - attrs.put(cw, null, 0, -1, -1, out); - } - } -} +/* + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ + +/* + * + * + * + * + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.redkale.asm; + +/** + * An {@link FieldVisitor} that generates Java fields in bytecode form. + * + * @author Eric Bruneton + */ +final class FieldWriter extends FieldVisitor { + + /** The class writer to which this field must be added. */ + private final ClassWriter cw; + + /** Access flags of this field. */ + private final int access; + + /** The index of the constant pool item that contains the name of this method. */ + private final int name; + + /** The index of the constant pool item that contains the descriptor of this field. */ + private final int desc; + + /** The index of the constant pool item that contains the signature of this field. */ + private int signature; + + /** The index of the constant pool item that contains the constant value of this field. */ + private int value; + + /** The runtime visible annotations of this field. May be <tt>null</tt>. */ + private AnnotationWriter anns; + + /** The runtime invisible annotations of this field. May be <tt>null</tt>. */ + private AnnotationWriter ianns; + + /** The runtime visible type annotations of this field. May be <tt>null</tt>. */ + private AnnotationWriter tanns; + + /** The runtime invisible type annotations of this field. May be <tt>null</tt>. */ + private AnnotationWriter itanns; + + /** The non standard attributes of this field. May be <tt>null</tt>. */ + private Attribute attrs; + + // ------------------------------------------------------------------------ + // Constructor + // ------------------------------------------------------------------------ + + /** + * Constructs a new {@link FieldWriter}. + * + * @param cw the class writer to which this field must be added. + * @param access the field's access flags (see {@link Opcodes}). + * @param name the field's name. + * @param desc the field's descriptor (see {@link Type}). + * @param signature the field's signature. May be <tt>null</tt>. + * @param value the field's constant value. May be <tt>null</tt>. + */ + FieldWriter( + final ClassWriter cw, + final int access, + final String name, + final String desc, + final String signature, + final Object value) { + super(Opcodes.ASM6); + if (cw.firstField == null) { + cw.firstField = this; + } else { + cw.lastField.fv = this; + } + cw.lastField = this; + this.cw = cw; + this.access = access; + this.name = cw.newUTF8(name); + this.desc = cw.newUTF8(desc); + if (signature != null) { + this.signature = cw.newUTF8(signature); + } + if (value != null) { + this.value = cw.newConstItem(value).index; + } + } + + // ------------------------------------------------------------------------ + // Implementation of the FieldVisitor abstract class + // ------------------------------------------------------------------------ + + @Override + public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) { + ByteVector bv = new ByteVector(); + // write type, and reserve space for values count + bv.putShort(cw.newUTF8(desc)).putShort(0); + AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2); + if (visible) { + aw.next = anns; + anns = aw; + } else { + aw.next = ianns; + ianns = aw; + } + return aw; + } + + @Override + public AnnotationVisitor visitTypeAnnotation( + final int typeRef, final TypePath typePath, final String desc, final boolean visible) { + ByteVector bv = new ByteVector(); + // write target_type and target_info + AnnotationWriter.putTarget(typeRef, typePath, bv); + // write type, and reserve space for values count + bv.putShort(cw.newUTF8(desc)).putShort(0); + AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, bv.length - 2); + if (visible) { + aw.next = tanns; + tanns = aw; + } else { + aw.next = itanns; + itanns = aw; + } + return aw; + } + + @Override + public void visitAttribute(final Attribute attr) { + attr.next = attrs; + attrs = attr; + } + + @Override + public void visitEnd() { + // do nothing + } + + // ------------------------------------------------------------------------ + // Utility methods + // ------------------------------------------------------------------------ + + /** + * Returns the size of this field. + * + * @return the size of this field. + */ + int getSize() { + int size = 8; + if (value != 0) { + cw.newUTF8("ConstantValue"); + size += 8; + } + if ((access & Opcodes.ACC_SYNTHETIC) != 0) { + if ((cw.version & 0xFFFF) < Opcodes.V1_5 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) { + cw.newUTF8("Synthetic"); + size += 6; + } + } + if ((access & Opcodes.ACC_DEPRECATED) != 0) { + cw.newUTF8("Deprecated"); + size += 6; + } + if (signature != 0) { + cw.newUTF8("Signature"); + size += 8; + } + if (anns != null) { + cw.newUTF8("RuntimeVisibleAnnotations"); + size += 8 + anns.getSize(); + } + if (ianns != null) { + cw.newUTF8("RuntimeInvisibleAnnotations"); + size += 8 + ianns.getSize(); + } + if (tanns != null) { + cw.newUTF8("RuntimeVisibleTypeAnnotations"); + size += 8 + tanns.getSize(); + } + if (itanns != null) { + cw.newUTF8("RuntimeInvisibleTypeAnnotations"); + size += 8 + itanns.getSize(); + } + if (attrs != null) { + size += attrs.getSize(cw, null, 0, -1, -1); + } + return size; + } + + /** + * Puts the content of this field into the given byte vector. + * + * @param out where the content of this field must be put. + */ + void put(final ByteVector out) { + final int FACTOR = ClassWriter.TO_ACC_SYNTHETIC; + int mask = Opcodes.ACC_DEPRECATED + | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE + | ((access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) / FACTOR); + out.putShort(access & ~mask).putShort(name).putShort(desc); + int attributeCount = 0; + if (value != 0) { + ++attributeCount; + } + if ((access & Opcodes.ACC_SYNTHETIC) != 0) { + if ((cw.version & 0xFFFF) < Opcodes.V1_5 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) { + ++attributeCount; + } + } + if ((access & Opcodes.ACC_DEPRECATED) != 0) { + ++attributeCount; + } + if (signature != 0) { + ++attributeCount; + } + if (anns != null) { + ++attributeCount; + } + if (ianns != null) { + ++attributeCount; + } + if (tanns != null) { + ++attributeCount; + } + if (itanns != null) { + ++attributeCount; + } + if (attrs != null) { + attributeCount += attrs.getCount(); + } + out.putShort(attributeCount); + if (value != 0) { + out.putShort(cw.newUTF8("ConstantValue")); + out.putInt(2).putShort(value); + } + if ((access & Opcodes.ACC_SYNTHETIC) != 0) { + if ((cw.version & 0xFFFF) < Opcodes.V1_5 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) { + out.putShort(cw.newUTF8("Synthetic")).putInt(0); + } + } + if ((access & Opcodes.ACC_DEPRECATED) != 0) { + out.putShort(cw.newUTF8("Deprecated")).putInt(0); + } + if (signature != 0) { + out.putShort(cw.newUTF8("Signature")); + out.putInt(2).putShort(signature); + } + if (anns != null) { + out.putShort(cw.newUTF8("RuntimeVisibleAnnotations")); + anns.put(out); + } + if (ianns != null) { + out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations")); + ianns.put(out); + } + if (tanns != null) { + out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations")); + tanns.put(out); + } + if (itanns != null) { + out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations")); + itanns.put(out); + } + if (attrs != null) { + attrs.put(cw, null, 0, -1, -1, out); + } + } +} diff --git a/src/main/java/org/redkale/asm/Frame.java b/src/main/java/org/redkale/asm/Frame.java index 1d67bd8fa..22dae1486 100644 --- a/src/main/java/org/redkale/asm/Frame.java +++ b/src/main/java/org/redkale/asm/Frame.java @@ -1,1458 +1,1458 @@ -/* - * 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 and output stack map frames of a basic block. - * - * @author Eric Bruneton - */ -class Frame { - - /* - * Frames are computed in a two steps process: during the visit of each - * instruction, the state of the frame at the end of current basic block is - * updated by simulating the action of the instruction on the previous state - * of this so called "output frame". In visitMaxs, a fix point algorithm is - * used to compute the "input frame" of each basic block, i.e. the stack map - * frame at the beginning of the basic block, starting from the input frame - * of the first basic block (which is computed from the method descriptor), - * and by using the previously computed output frames to compute the input - * state of the other blocks. - * - * All output and input frames are stored as arrays of integers. Reference - * and array types are represented by an index into a type table (which is - * not the same as the constant pool of the class, in order to avoid adding - * unnecessary constants in the pool - not all computed frames will end up - * being stored in the stack map table). This allows very fast type - * comparisons. - * - * Output stack map frames are computed relatively to the input frame of the - * basic block, which is not yet known when output frames are computed. It - * is therefore necessary to be able to represent abstract types such as - * "the type at position x in the input frame locals" or "the type at - * position x from the top of the input frame stack" or even "the type at - * position x in the input frame, with y more (or less) array dimensions". - * This explains the rather complicated type format used in output frames. - * - * This format is the following: DIM KIND VALUE (4, 4 and 24 bits). DIM is a - * signed number of array dimensions (from -8 to 7). KIND is either BASE, - * LOCAL or STACK. BASE is used for types that are not relative to the input - * frame. LOCAL is used for types that are relative to the input local - * variable types. STACK is used for types that are relative to the input - * stack types. VALUE depends on KIND. For LOCAL types, it is an index in - * the input local variable types. For STACK types, it is a position - * relatively to the top of input frame stack. For BASE types, it is either - * one of the constants defined below, or for OBJECT and UNINITIALIZED - * types, a tag and an index in the type table. - * - * Output frames can contain types of any kind and with a positive or - * negative dimension (and even unassigned types, represented by 0 - which - * does not correspond to any valid type value). Input frames can only - * contain BASE types of positive or null dimension. In all cases the type - * table contains only internal type names (array type descriptors are - * forbidden - dimensions must be represented through the DIM field). - * - * The LONG and DOUBLE types are always represented by using two slots (LONG - * + TOP or DOUBLE + TOP), for local variable types as well as in the - * operand stack. This is necessary to be able to simulate DUPx_y - * instructions, whose effect would be dependent on the actual type values - * if types were always represented by a single slot in the stack (and this - * is not possible, since actual type values are not always known - cf LOCAL - * and STACK type kinds). - */ - - /** Mask to get the dimension of a frame type. This dimension is a signed integer between -8 and 7. */ - static final int DIM = 0xF0000000; - - /** Constant to be added to a type to get a type with one more dimension. */ - static final int ARRAY_OF = 0x10000000; - - /** Constant to be added to a type to get a type with one less dimension. */ - static final int ELEMENT_OF = 0xF0000000; - - /** - * Mask to get the kind of a frame type. - * - * @see #BASE - * @see #LOCAL - * @see #STACK - */ - static final int KIND = 0xF000000; - - /** - * Flag used for LOCAL and STACK types. Indicates that if this type happens to be a long or double type (during the - * computations of input frames), then it must be set to TOP because the second word of this value has been reused - * to store other data in the basic block. Hence the first word no longer stores a valid long or double value. - */ - static final int TOP_IF_LONG_OR_DOUBLE = 0x800000; - - /** Mask to get the value of a frame type. */ - static final int VALUE = 0x7FFFFF; - - /** Mask to get the kind of base types. */ - static final int BASE_KIND = 0xFF00000; - - /** Mask to get the value of base types. */ - static final int BASE_VALUE = 0xFFFFF; - - /** Kind of the types that are not relative to an input stack map frame. */ - static final int BASE = 0x1000000; - - /** Base kind of the base reference types. The BASE_VALUE of such types is an index into the type table. */ - static final int OBJECT = BASE | 0x700000; - - /** - * Base kind of the uninitialized base types. The BASE_VALUE of such types in an index into the type table (the Item - * at that index contains both an instruction offset and an internal class name). - */ - static final int UNINITIALIZED = BASE | 0x800000; - - /** - * Kind of the types that are relative to the local variable types of an input stack map frame. The value of such - * types is a local variable index. - */ - private static final int LOCAL = 0x2000000; - - /** - * 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. - */ - private static final int STACK = 0x3000000; - - /** The TOP type. This is a BASE type. */ - static final int TOP = BASE | 0; - - /** The BOOLEAN type. This is a BASE type mainly used for array types. */ - static final int BOOLEAN = BASE | 9; - - /** The BYTE type. This is a BASE type mainly used for array types. */ - static final int BYTE = BASE | 10; - - /** The CHAR type. This is a BASE type mainly used for array types. */ - static final int CHAR = BASE | 11; - - /** The SHORT type. This is a BASE type mainly used for array types. */ - static final int SHORT = BASE | 12; - - /** The INTEGER type. This is a BASE type. */ - static final int INTEGER = BASE | 1; - - /** The FLOAT type. This is a BASE type. */ - static final int FLOAT = BASE | 2; - - /** The DOUBLE type. This is a BASE type. */ - static final int DOUBLE = BASE | 3; - - /** The LONG type. This is a BASE type. */ - static final int LONG = BASE | 4; - - /** The NULL type. This is a BASE type. */ - static final int NULL = BASE | 5; - - /** The UNINITIALIZED_THIS type. This is a BASE type. */ - static final int UNINITIALIZED_THIS = BASE | 6; - - /** - * The stack size variation corresponding to each JVM instruction. This stack variation is equal to the size of the - * values produced by an instruction, minus the size of the values consumed by this instruction. - */ - static final int[] SIZE; - - /** Computes the stack size variation corresponding to each JVM instruction. */ - static { - int i; - int[] b = new int[202]; - String s = "EFFFFFFFFGGFFFGGFFFEEFGFGFEEEEEEEEEEEEEEEEEEEEDEDEDDDDD" - + "CDCDEEEEEEEEEEEEEEEEEEEEBABABBBBDCFFFGGGEDCDCDCDCDCDCDCDCD" - + "CDCEEEEDDDDDDDCDCDCEFEFDDEEFFDEDEEEBDDBBDDDDDDCCCCCCCCEFED" - + "DDCDCDEEEEEEEEEEFEEEEEEDDEEDDEE"; - for (i = 0; i < b.length; ++i) { - b[i] = s.charAt(i) - 'E'; - } - SIZE = b; - - // code to generate the above string - // - // int NA = 0; // not applicable (unused opcode or variable size opcode) - // - // b = new int[] { - // 0, //NOP, // visitInsn - // 1, //ACONST_NULL, // - - // 1, //ICONST_M1, // - - // 1, //ICONST_0, // - - // 1, //ICONST_1, // - - // 1, //ICONST_2, // - - // 1, //ICONST_3, // - - // 1, //ICONST_4, // - - // 1, //ICONST_5, // - - // 2, //LCONST_0, // - - // 2, //LCONST_1, // - - // 1, //FCONST_0, // - - // 1, //FCONST_1, // - - // 1, //FCONST_2, // - - // 2, //DCONST_0, // - - // 2, //DCONST_1, // - - // 1, //BIPUSH, // visitIntInsn - // 1, //SIPUSH, // - - // 1, //LDC, // visitLdcInsn - // NA, //LDC_W, // - - // NA, //LDC2_W, // - - // 1, //ILOAD, // visitVarInsn - // 2, //LLOAD, // - - // 1, //FLOAD, // - - // 2, //DLOAD, // - - // 1, //ALOAD, // - - // NA, //ILOAD_0, // - - // NA, //ILOAD_1, // - - // NA, //ILOAD_2, // - - // NA, //ILOAD_3, // - - // NA, //LLOAD_0, // - - // NA, //LLOAD_1, // - - // NA, //LLOAD_2, // - - // NA, //LLOAD_3, // - - // NA, //FLOAD_0, // - - // NA, //FLOAD_1, // - - // NA, //FLOAD_2, // - - // NA, //FLOAD_3, // - - // NA, //DLOAD_0, // - - // NA, //DLOAD_1, // - - // NA, //DLOAD_2, // - - // NA, //DLOAD_3, // - - // NA, //ALOAD_0, // - - // NA, //ALOAD_1, // - - // NA, //ALOAD_2, // - - // NA, //ALOAD_3, // - - // -1, //IALOAD, // visitInsn - // 0, //LALOAD, // - - // -1, //FALOAD, // - - // 0, //DALOAD, // - - // -1, //AALOAD, // - - // -1, //BALOAD, // - - // -1, //CALOAD, // - - // -1, //SALOAD, // - - // -1, //ISTORE, // visitVarInsn - // -2, //LSTORE, // - - // -1, //FSTORE, // - - // -2, //DSTORE, // - - // -1, //ASTORE, // - - // NA, //ISTORE_0, // - - // NA, //ISTORE_1, // - - // NA, //ISTORE_2, // - - // NA, //ISTORE_3, // - - // NA, //LSTORE_0, // - - // NA, //LSTORE_1, // - - // NA, //LSTORE_2, // - - // NA, //LSTORE_3, // - - // NA, //FSTORE_0, // - - // NA, //FSTORE_1, // - - // NA, //FSTORE_2, // - - // NA, //FSTORE_3, // - - // NA, //DSTORE_0, // - - // NA, //DSTORE_1, // - - // NA, //DSTORE_2, // - - // NA, //DSTORE_3, // - - // NA, //ASTORE_0, // - - // NA, //ASTORE_1, // - - // NA, //ASTORE_2, // - - // NA, //ASTORE_3, // - - // -3, //IASTORE, // visitInsn - // -4, //LASTORE, // - - // -3, //FASTORE, // - - // -4, //DASTORE, // - - // -3, //AASTORE, // - - // -3, //BASTORE, // - - // -3, //CASTORE, // - - // -3, //SASTORE, // - - // -1, //POP, // - - // -2, //POP2, // - - // 1, //DUP, // - - // 1, //DUP_X1, // - - // 1, //DUP_X2, // - - // 2, //DUP2, // - - // 2, //DUP2_X1, // - - // 2, //DUP2_X2, // - - // 0, //SWAP, // - - // -1, //IADD, // - - // -2, //LADD, // - - // -1, //FADD, // - - // -2, //DADD, // - - // -1, //ISUB, // - - // -2, //LSUB, // - - // -1, //FSUB, // - - // -2, //DSUB, // - - // -1, //IMUL, // - - // -2, //LMUL, // - - // -1, //FMUL, // - - // -2, //DMUL, // - - // -1, //IDIV, // - - // -2, //LDIV, // - - // -1, //FDIV, // - - // -2, //DDIV, // - - // -1, //IREM, // - - // -2, //LREM, // - - // -1, //FREM, // - - // -2, //DREM, // - - // 0, //INEG, // - - // 0, //LNEG, // - - // 0, //FNEG, // - - // 0, //DNEG, // - - // -1, //ISHL, // - - // -1, //LSHL, // - - // -1, //ISHR, // - - // -1, //LSHR, // - - // -1, //IUSHR, // - - // -1, //LUSHR, // - - // -1, //IAND, // - - // -2, //LAND, // - - // -1, //IOR, // - - // -2, //LOR, // - - // -1, //IXOR, // - - // -2, //LXOR, // - - // 0, //IINC, // visitIincInsn - // 1, //I2L, // visitInsn - // 0, //I2F, // - - // 1, //I2D, // - - // -1, //L2I, // - - // -1, //L2F, // - - // 0, //L2D, // - - // 0, //F2I, // - - // 1, //F2L, // - - // 1, //F2D, // - - // -1, //D2I, // - - // 0, //D2L, // - - // -1, //D2F, // - - // 0, //I2B, // - - // 0, //I2C, // - - // 0, //I2S, // - - // -3, //LCMP, // - - // -1, //FCMPL, // - - // -1, //FCMPG, // - - // -3, //DCMPL, // - - // -3, //DCMPG, // - - // -1, //IFEQ, // visitJumpInsn - // -1, //IFNE, // - - // -1, //IFLT, // - - // -1, //IFGE, // - - // -1, //IFGT, // - - // -1, //IFLE, // - - // -2, //IF_ICMPEQ, // - - // -2, //IF_ICMPNE, // - - // -2, //IF_ICMPLT, // - - // -2, //IF_ICMPGE, // - - // -2, //IF_ICMPGT, // - - // -2, //IF_ICMPLE, // - - // -2, //IF_ACMPEQ, // - - // -2, //IF_ACMPNE, // - - // 0, //GOTO, // - - // 1, //JSR, // - - // 0, //RET, // visitVarInsn - // -1, //TABLESWITCH, // visiTableSwitchInsn - // -1, //LOOKUPSWITCH, // visitLookupSwitch - // -1, //IRETURN, // visitInsn - // -2, //LRETURN, // - - // -1, //FRETURN, // - - // -2, //DRETURN, // - - // -1, //ARETURN, // - - // 0, //RETURN, // - - // NA, //GETSTATIC, // visitFieldInsn - // NA, //PUTSTATIC, // - - // NA, //GETFIELD, // - - // NA, //PUTFIELD, // - - // NA, //INVOKEVIRTUAL, // visitMethodInsn - // NA, //INVOKESPECIAL, // - - // NA, //INVOKESTATIC, // - - // NA, //INVOKEINTERFACE, // - - // NA, //INVOKEDYNAMIC, // visitInvokeDynamicInsn - // 1, //NEW, // visitTypeInsn - // 0, //NEWARRAY, // visitIntInsn - // 0, //ANEWARRAY, // visitTypeInsn - // 0, //ARRAYLENGTH, // visitInsn - // NA, //ATHROW, // - - // 0, //CHECKCAST, // visitTypeInsn - // 0, //INSTANCEOF, // - - // -1, //MONITORENTER, // visitInsn - // -1, //MONITOREXIT, // - - // NA, //WIDE, // NOT VISITED - // NA, //MULTIANEWARRAY, // visitMultiANewArrayInsn - // -1, //IFNULL, // visitJumpInsn - // -1, //IFNONNULL, // - - // NA, //GOTO_W, // - - // NA, //JSR_W, // - - // }; - // for (i = 0; i < b.length; ++i) { - // System.err.print((char)('E' + b[i])); - // } - // System.err.println(); - } - - /** The label (i.e. basic block) to which these input and output stack map frames correspond. */ - Label owner; - - /** The input stack map frame locals. */ - int[] inputLocals; - - /** The input stack map frame stack. */ - int[] inputStack; - - /** The output stack map frame locals. */ - private int[] outputLocals; - - /** The output stack map frame stack. */ - private int[] outputStack; - - /** - * Relative size of the output stack. The exact semantics of this field depends on the algorithm that is used. - * - *

When only the maximum stack size is computed, this field is the size of the output stack relatively to the top - * of the input stack. - * - *

When the stack map frames are completely computed, this field is the actual number of types in - * {@link #outputStack}. - */ - int outputStackTop; - - /** - * Number of types that are initialized in the basic block. - * - * @see #initializations - */ - private int initializationCount; - - /** - * The types that are initialized in the basic block. A constructor invocation on an UNINITIALIZED or - * UNINITIALIZED_THIS type must replace every occurence of this type in the local variables and in the - * operand stack. This cannot be done during the first phase of the algorithm since, during this phase, the local - * variables and the operand stack are not completely computed. It is therefore necessary to store the types on - * which constructors are invoked in the basic block, in order to do this replacement during the second phase of the - * algorithm, where the frames are fully computed. Note that this array can contain types that are relative to input - * locals or to the input stack (see below for the description of the algorithm). - */ - 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. - * - * @param local the index of the local that must be returned. - * @return the output frame local variable type at the given index. - */ - private int get(final int local) { - if (outputLocals == null || local >= outputLocals.length) { - // this local has never been assigned in this basic block, - // so it is still equal to its value in the input frame - return LOCAL | local; - } else { - int type = outputLocals[local]; - if (type == 0) { - // this local has never been assigned in this basic block, - // so it is still equal to its value in the input frame - type = outputLocals[local] = LOCAL | local; - } - return type; - } - } - - /** - * Sets the output frame local variable type at the given index. - * - * @param local the index of the local that must be set. - * @param type the value of the local that must be set. - */ - private void set(final int local, final int type) { - // creates and/or resizes the output local variables array if necessary - if (outputLocals == null) { - outputLocals = new int[10]; - } - int n = outputLocals.length; - if (local >= n) { - int[] t = new int[Math.max(local + 1, 2 * n)]; - System.arraycopy(outputLocals, 0, t, 0, n); - outputLocals = t; - } - // sets the local variable - outputLocals[local] = type; - } - - /** - * Pushes a new type onto the output frame stack. - * - * @param type the type that must be pushed. - */ - private void push(final int type) { - // creates and/or resizes the output stack array if necessary - if (outputStack == null) { - outputStack = new int[10]; - } - int n = outputStack.length; - if (outputStackTop >= n) { - int[] t = new int[Math.max(outputStackTop + 1, 2 * n)]; - System.arraycopy(outputStack, 0, t, 0, n); - outputStack = t; - } - // pushes the type on the output stack - outputStack[outputStackTop++] = type; - // updates the maximum height reached by the output stack, if needed - int top = owner.inputStackTop + outputStackTop; - if (top > owner.outputStackMax) { - owner.outputStackMax = top; - } - } - - /** - * Pushes a new type onto the output frame stack. - * - * @param cw the ClassWriter to which this label belongs. - * @param desc the descriptor of the type to be pushed. Can also be a method descriptor (in this case this method - * pushes its return type onto the output frame stack). - */ - private void push(final ClassWriter cw, final String desc) { - int type = type(cw, desc); - if (type != 0) { - push(type); - if (type == LONG || type == DOUBLE) { - push(TOP); - } - } - } - - /** - * Returns the int encoding of the given type. - * - * @param cw the ClassWriter to which this label belongs. - * @param desc a type descriptor. - * @return the int encoding of the given type. - */ - static int type(final ClassWriter cw, final String desc) { - String t; - int index = desc.charAt(0) == '(' ? desc.indexOf(')') + 1 : 0; - switch (desc.charAt(index)) { - case 'V': - return 0; - case 'Z': - case 'C': - case 'B': - case 'S': - case 'I': - return INTEGER; - case 'F': - return FLOAT; - case 'J': - return LONG; - case 'D': - return DOUBLE; - case 'L': - // stores the internal name, not the descriptor! - t = desc.substring(index + 1, desc.length() - 1); - return OBJECT | cw.addType(t); - // case '[': - default: - // extracts the dimensions and the element type - int data; - int dims = index + 1; - while (desc.charAt(dims) == '[') { - ++dims; - } - switch (desc.charAt(dims)) { - case 'Z': - data = BOOLEAN; - break; - case 'C': - data = CHAR; - break; - case 'B': - data = BYTE; - break; - case 'S': - data = SHORT; - break; - case 'I': - data = INTEGER; - break; - case 'F': - data = FLOAT; - break; - case 'J': - data = LONG; - break; - case 'D': - data = DOUBLE; - break; - // case 'L': - default: - // stores the internal name, not the descriptor - t = desc.substring(dims + 1, desc.length() - 1); - data = OBJECT | cw.addType(t); - } - return (dims - index) << 28 | data; - } - } - - /** - * Pops a type from the output frame stack and returns its value. - * - * @return the type that has been popped from the output frame stack. - */ - private int pop() { - if (outputStackTop > 0) { - return outputStack[--outputStackTop]; - } else { - // if the output frame stack is empty, pops from the input stack - return STACK | -(--owner.inputStackTop); - } - } - - /** - * Pops the given number of types from the output frame stack. - * - * @param elements the number of types that must be popped. - */ - private void pop(final int elements) { - if (outputStackTop >= elements) { - outputStackTop -= elements; - } else { - // if the number of elements to be popped is greater than the number - // of elements in the output stack, clear it, and pops the remaining - // elements from the input stack. - owner.inputStackTop -= elements - outputStackTop; - outputStackTop = 0; - } - } - - /** - * Pops a type from the output frame stack. - * - * @param desc the descriptor of the type to be popped. Can also be a method descriptor (in this case this method - * pops the types corresponding to the method arguments). - */ - private void pop(final String desc) { - char c = desc.charAt(0); - if (c == '(') { - pop((Type.getArgumentsAndReturnSizes(desc) >> 2) - 1); - } else if (c == 'J' || c == 'D') { - pop(2); - } else { - pop(1); - } - } - - /** - * Adds a new type to the list of types on which a constructor is invoked in the basic block. - * - * @param var a type on a which a constructor is invoked. - */ - private void init(final int var) { - // creates and/or resizes the initializations array if necessary - if (initializations == null) { - initializations = new int[2]; - } - int n = initializations.length; - if (initializationCount >= n) { - int[] t = new int[Math.max(initializationCount + 1, 2 * n)]; - System.arraycopy(initializations, 0, t, 0, n); - initializations = t; - } - // stores the type to be initialized - initializations[initializationCount++] = var; - } - - /** - * Replaces the given type with the appropriate type if it is one of the types on which a constructor is invoked in - * the basic block. - * - * @param cw the ClassWriter to which this label belongs. - * @param t a type - * @return t or, if t is one of the types on which a constructor is invoked in the basic block, the type - * corresponding to this constructor. - */ - private int init(final ClassWriter cw, final int t) { - int s; - if (t == UNINITIALIZED_THIS) { - s = OBJECT | cw.addType(cw.thisName); - } else if ((t & (DIM | BASE_KIND)) == UNINITIALIZED) { - String type = cw.typeTable[t & BASE_VALUE].strVal1; - s = OBJECT | cw.addType(type); - } else { - return t; - } - for (int j = 0; j < initializationCount; ++j) { - int u = initializations[j]; - int dim = u & DIM; - int kind = u & KIND; - if (kind == LOCAL) { - u = dim + inputLocals[u & VALUE]; - } else if (kind == STACK) { - u = dim + inputStack[inputStack.length - (u & VALUE)]; - } - if (t == u) { - return s; - } - } - return t; - } - - /** - * Initializes the input frame of the first basic block from the method descriptor. - * - * @param cw the ClassWriter to which this label belongs. - * @param access the access flags of the method to which this label belongs. - * @param args the formal parameter types of this method. - * @param maxLocals the maximum number of local variables of this method. - */ - final void initInputFrame(final ClassWriter cw, final int access, final Type[] args, final int maxLocals) { - inputLocals = new int[maxLocals]; - inputStack = new int[0]; - int i = 0; - if ((access & Opcodes.ACC_STATIC) == 0) { - if ((access & MethodWriter.ACC_CONSTRUCTOR) == 0) { - inputLocals[i++] = OBJECT | cw.addType(cw.thisName); - } else { - inputLocals[i++] = UNINITIALIZED_THIS; - } - } - for (int j = 0; j < args.length; ++j) { - int t = type(cw, args[j].getDescriptor()); - inputLocals[i++] = t; - if (t == LONG || t == DOUBLE) { - inputLocals[i++] = TOP; - } - } - while (i < maxLocals) { - inputLocals[i++] = TOP; - } - } - - /** - * Simulates the action of the given instruction on the output stack frame. - * - * @param opcode the opcode of the instruction. - * @param arg the operand of the instruction, if any. - * @param cw the class writer to which this label belongs. - * @param item the operand of the instructions, if any. - */ - void execute(final int opcode, final int arg, final ClassWriter cw, final Item item) { - int t1, t2, t3, t4; - switch (opcode) { - case Opcodes.NOP: - case Opcodes.INEG: - case Opcodes.LNEG: - case Opcodes.FNEG: - case Opcodes.DNEG: - case Opcodes.I2B: - case Opcodes.I2C: - case Opcodes.I2S: - case Opcodes.GOTO: - case Opcodes.RETURN: - break; - case Opcodes.ACONST_NULL: - push(NULL); - break; - case Opcodes.ICONST_M1: - case Opcodes.ICONST_0: - case Opcodes.ICONST_1: - case Opcodes.ICONST_2: - case Opcodes.ICONST_3: - case Opcodes.ICONST_4: - case Opcodes.ICONST_5: - case Opcodes.BIPUSH: - case Opcodes.SIPUSH: - case Opcodes.ILOAD: - push(INTEGER); - break; - case Opcodes.LCONST_0: - case Opcodes.LCONST_1: - case Opcodes.LLOAD: - push(LONG); - push(TOP); - break; - case Opcodes.FCONST_0: - case Opcodes.FCONST_1: - case Opcodes.FCONST_2: - case Opcodes.FLOAD: - push(FLOAT); - break; - case Opcodes.DCONST_0: - case Opcodes.DCONST_1: - case Opcodes.DLOAD: - push(DOUBLE); - push(TOP); - break; - case Opcodes.LDC: - switch (item.type) { - case ClassWriter.INT: - push(INTEGER); - break; - case ClassWriter.LONG: - push(LONG); - push(TOP); - break; - case ClassWriter.FLOAT: - push(FLOAT); - break; - case ClassWriter.DOUBLE: - push(DOUBLE); - push(TOP); - break; - case ClassWriter.CLASS: - push(OBJECT | cw.addType("java/lang/Class")); - break; - case ClassWriter.STR: - push(OBJECT | cw.addType("java/lang/String")); - break; - case ClassWriter.MTYPE: - push(OBJECT | cw.addType("java/lang/invoke/MethodType")); - break; - // case ClassWriter.HANDLE_BASE + [1..9]: - default: - push(OBJECT | cw.addType("java/lang/invoke/MethodHandle")); - } - break; - case Opcodes.ALOAD: - push(get(arg)); - break; - case Opcodes.IALOAD: - case Opcodes.BALOAD: - case Opcodes.CALOAD: - case Opcodes.SALOAD: - pop(2); - push(INTEGER); - break; - case Opcodes.LALOAD: - case Opcodes.D2L: - pop(2); - push(LONG); - push(TOP); - break; - case Opcodes.FALOAD: - pop(2); - push(FLOAT); - break; - case Opcodes.DALOAD: - case Opcodes.L2D: - pop(2); - push(DOUBLE); - push(TOP); - break; - case Opcodes.AALOAD: - pop(1); - t1 = pop(); - push(t1 == NULL ? t1 : ELEMENT_OF + t1); - break; - case Opcodes.ISTORE: - case Opcodes.FSTORE: - case Opcodes.ASTORE: - t1 = pop(); - set(arg, t1); - if (arg > 0) { - t2 = get(arg - 1); - // if t2 is of kind STACK or LOCAL we cannot know its size! - if (t2 == LONG || t2 == DOUBLE) { - set(arg - 1, TOP); - } else if ((t2 & KIND) != BASE) { - set(arg - 1, t2 | TOP_IF_LONG_OR_DOUBLE); - } - } - break; - case Opcodes.LSTORE: - case Opcodes.DSTORE: - pop(1); - t1 = pop(); - set(arg, t1); - set(arg + 1, TOP); - if (arg > 0) { - t2 = get(arg - 1); - // if t2 is of kind STACK or LOCAL we cannot know its size! - if (t2 == LONG || t2 == DOUBLE) { - set(arg - 1, TOP); - } else if ((t2 & KIND) != BASE) { - set(arg - 1, t2 | TOP_IF_LONG_OR_DOUBLE); - } - } - break; - case Opcodes.IASTORE: - case Opcodes.BASTORE: - case Opcodes.CASTORE: - case Opcodes.SASTORE: - case Opcodes.FASTORE: - case Opcodes.AASTORE: - pop(3); - break; - case Opcodes.LASTORE: - case Opcodes.DASTORE: - pop(4); - break; - case Opcodes.POP: - case Opcodes.IFEQ: - case Opcodes.IFNE: - case Opcodes.IFLT: - case Opcodes.IFGE: - case Opcodes.IFGT: - case Opcodes.IFLE: - case Opcodes.IRETURN: - case Opcodes.FRETURN: - case Opcodes.ARETURN: - case Opcodes.TABLESWITCH: - case Opcodes.LOOKUPSWITCH: - case Opcodes.ATHROW: - case Opcodes.MONITORENTER: - case Opcodes.MONITOREXIT: - case Opcodes.IFNULL: - case Opcodes.IFNONNULL: - pop(1); - break; - case Opcodes.POP2: - case Opcodes.IF_ICMPEQ: - case Opcodes.IF_ICMPNE: - case Opcodes.IF_ICMPLT: - case Opcodes.IF_ICMPGE: - case Opcodes.IF_ICMPGT: - case Opcodes.IF_ICMPLE: - case Opcodes.IF_ACMPEQ: - case Opcodes.IF_ACMPNE: - case Opcodes.LRETURN: - case Opcodes.DRETURN: - pop(2); - break; - case Opcodes.DUP: - t1 = pop(); - push(t1); - push(t1); - break; - case Opcodes.DUP_X1: - t1 = pop(); - t2 = pop(); - push(t1); - push(t2); - push(t1); - break; - case Opcodes.DUP_X2: - t1 = pop(); - t2 = pop(); - t3 = pop(); - push(t1); - push(t3); - push(t2); - push(t1); - break; - case Opcodes.DUP2: - t1 = pop(); - t2 = pop(); - push(t2); - push(t1); - push(t2); - push(t1); - break; - case Opcodes.DUP2_X1: - t1 = pop(); - t2 = pop(); - t3 = pop(); - push(t2); - push(t1); - push(t3); - push(t2); - push(t1); - break; - case Opcodes.DUP2_X2: - t1 = pop(); - t2 = pop(); - t3 = pop(); - t4 = pop(); - push(t2); - push(t1); - push(t4); - push(t3); - push(t2); - push(t1); - break; - case Opcodes.SWAP: - t1 = pop(); - t2 = pop(); - push(t1); - push(t2); - break; - case Opcodes.IADD: - case Opcodes.ISUB: - case Opcodes.IMUL: - case Opcodes.IDIV: - case Opcodes.IREM: - case Opcodes.IAND: - case Opcodes.IOR: - case Opcodes.IXOR: - case Opcodes.ISHL: - case Opcodes.ISHR: - case Opcodes.IUSHR: - case Opcodes.L2I: - case Opcodes.D2I: - case Opcodes.FCMPL: - case Opcodes.FCMPG: - pop(2); - push(INTEGER); - break; - case Opcodes.LADD: - case Opcodes.LSUB: - case Opcodes.LMUL: - case Opcodes.LDIV: - case Opcodes.LREM: - case Opcodes.LAND: - case Opcodes.LOR: - case Opcodes.LXOR: - pop(4); - push(LONG); - push(TOP); - break; - case Opcodes.FADD: - case Opcodes.FSUB: - case Opcodes.FMUL: - case Opcodes.FDIV: - case Opcodes.FREM: - case Opcodes.L2F: - case Opcodes.D2F: - pop(2); - push(FLOAT); - break; - case Opcodes.DADD: - case Opcodes.DSUB: - case Opcodes.DMUL: - case Opcodes.DDIV: - case Opcodes.DREM: - pop(4); - push(DOUBLE); - push(TOP); - break; - case Opcodes.LSHL: - case Opcodes.LSHR: - case Opcodes.LUSHR: - pop(3); - push(LONG); - push(TOP); - break; - case Opcodes.IINC: - set(arg, INTEGER); - break; - case Opcodes.I2L: - case Opcodes.F2L: - pop(1); - push(LONG); - push(TOP); - break; - case Opcodes.I2F: - pop(1); - push(FLOAT); - break; - case Opcodes.I2D: - case Opcodes.F2D: - pop(1); - push(DOUBLE); - push(TOP); - break; - case Opcodes.F2I: - case Opcodes.ARRAYLENGTH: - case Opcodes.INSTANCEOF: - pop(1); - push(INTEGER); - break; - case Opcodes.LCMP: - case Opcodes.DCMPL: - case Opcodes.DCMPG: - pop(4); - push(INTEGER); - break; - case Opcodes.JSR: - case Opcodes.RET: - throw new RuntimeException("JSR/RET are not supported with computeFrames option"); - case Opcodes.GETSTATIC: - push(cw, item.strVal3); - break; - case Opcodes.PUTSTATIC: - pop(item.strVal3); - break; - case Opcodes.GETFIELD: - pop(1); - push(cw, item.strVal3); - break; - case Opcodes.PUTFIELD: - pop(item.strVal3); - pop(); - break; - case Opcodes.INVOKEVIRTUAL: - case Opcodes.INVOKESPECIAL: - case Opcodes.INVOKESTATIC: - case Opcodes.INVOKEINTERFACE: - pop(item.strVal3); - if (opcode != Opcodes.INVOKESTATIC) { - t1 = pop(); - if (opcode == Opcodes.INVOKESPECIAL && item.strVal2.charAt(0) == '<') { - init(t1); - } - } - push(cw, item.strVal3); - break; - case Opcodes.INVOKEDYNAMIC: - pop(item.strVal2); - push(cw, item.strVal2); - break; - case Opcodes.NEW: - push(UNINITIALIZED | cw.addUninitializedType(item.strVal1, arg)); - break; - case Opcodes.NEWARRAY: - pop(); - switch (arg) { - case Opcodes.T_BOOLEAN: - push(ARRAY_OF | BOOLEAN); - break; - case Opcodes.T_CHAR: - push(ARRAY_OF | CHAR); - break; - case Opcodes.T_BYTE: - push(ARRAY_OF | BYTE); - break; - case Opcodes.T_SHORT: - push(ARRAY_OF | SHORT); - break; - case Opcodes.T_INT: - push(ARRAY_OF | INTEGER); - break; - case Opcodes.T_FLOAT: - push(ARRAY_OF | FLOAT); - break; - case Opcodes.T_DOUBLE: - push(ARRAY_OF | DOUBLE); - break; - // case Opcodes.T_LONG: - default: - push(ARRAY_OF | LONG); - break; - } - break; - case Opcodes.ANEWARRAY: - String s = item.strVal1; - pop(); - if (s.charAt(0) == '[') { - push(cw, '[' + s); - } else { - push(ARRAY_OF | OBJECT | cw.addType(s)); - } - break; - case Opcodes.CHECKCAST: - s = item.strVal1; - pop(); - if (s.charAt(0) == '[') { - push(cw, s); - } else { - push(OBJECT | cw.addType(s)); - } - break; - // case Opcodes.MULTIANEWARRAY: - default: - pop(arg); - push(cw, item.strVal1); - break; - } - } - - /** - * Merges the input frame of the given basic block with the input and output frames of this basic block. Returns - * <tt>true</tt> if the input frame of the given label has been changed by this operation. - * - * @param cw the ClassWriter to which this label belongs. - * @param frame the basic block whose input frame must be updated. - * @param edge the kind of the {@link Edge} between this label and 'label'. See {@link Edge#info}. - * @return <tt>true</tt> if the input frame of the given label has been changed by this operation. - */ - final boolean merge(final ClassWriter cw, final Frame frame, final int edge) { - boolean changed = false; - int i, s, dim, kind, t; - - int nLocal = inputLocals.length; - int nStack = inputStack.length; - if (frame.inputLocals == null) { - frame.inputLocals = new int[nLocal]; - changed = true; - } - - for (i = 0; i < nLocal; ++i) { - if (outputLocals != null && i < outputLocals.length) { - s = outputLocals[i]; - if (s == 0) { - t = inputLocals[i]; - } else { - dim = s & DIM; - kind = s & KIND; - if (kind == BASE) { - t = s; - } else { - if (kind == LOCAL) { - t = dim + inputLocals[s & VALUE]; - } else { - t = dim + inputStack[nStack - (s & VALUE)]; - } - if ((s & TOP_IF_LONG_OR_DOUBLE) != 0 && (t == LONG || t == DOUBLE)) { - t = TOP; - } - } - } - } else { - t = inputLocals[i]; - } - if (initializations != null) { - t = init(cw, t); - } - changed |= merge(cw, t, frame.inputLocals, i); - } - - if (edge > 0) { - for (i = 0; i < nLocal; ++i) { - t = inputLocals[i]; - changed |= merge(cw, t, frame.inputLocals, i); - } - if (frame.inputStack == null) { - frame.inputStack = new int[1]; - changed = true; - } - changed |= merge(cw, edge, frame.inputStack, 0); - return changed; - } - - int nInputStack = inputStack.length + owner.inputStackTop; - if (frame.inputStack == null) { - frame.inputStack = new int[nInputStack + outputStackTop]; - changed = true; - } - - for (i = 0; i < nInputStack; ++i) { - t = inputStack[i]; - if (initializations != null) { - t = init(cw, t); - } - changed |= merge(cw, t, frame.inputStack, i); - } - for (i = 0; i < outputStackTop; ++i) { - s = outputStack[i]; - dim = s & DIM; - kind = s & KIND; - if (kind == BASE) { - t = s; - } else { - if (kind == LOCAL) { - t = dim + inputLocals[s & VALUE]; - } else { - t = dim + inputStack[nStack - (s & VALUE)]; - } - if ((s & TOP_IF_LONG_OR_DOUBLE) != 0 && (t == LONG || t == DOUBLE)) { - t = TOP; - } - } - if (initializations != null) { - t = init(cw, t); - } - changed |= merge(cw, t, frame.inputStack, nInputStack + i); - } - return changed; - } - - /** - * Merges the type at the given index in the given type array with the given type. Returns - * <tt>true</tt> if the type array has been modified by this operation. - * - * @param cw the ClassWriter to which this label belongs. - * @param t the type with which the type array element must be merged. - * @param types an array of types. - * @param index the index of the type that must be merged in 'types'. - * @return <tt>true</tt> if the type array has been modified by this operation. - */ - private static boolean merge(final ClassWriter cw, int t, final int[] types, final int index) { - int u = types[index]; - if (u == t) { - // if the types are equal, merge(u,t)=u, so there is no change - return false; - } - if ((t & ~DIM) == NULL) { - if (u == NULL) { - return false; - } - t = NULL; - } - if (u == 0) { - // if types[index] has never been assigned, merge(u,t)=t - types[index] = t; - return true; - } - int v; - if ((u & BASE_KIND) == OBJECT || (u & DIM) != 0) { - // if u is a reference type of any dimension - if (t == NULL) { - // if t is the NULL type, merge(u,t)=u, so there is no change - return false; - } else if ((t & (DIM | BASE_KIND)) == (u & (DIM | BASE_KIND))) { - // if t and u have the same dimension and same base kind - if ((u & BASE_KIND) == OBJECT) { - // if t is also a reference type, and if u and t have the - // same dimension merge(u,t) = dim(t) | common parent of the - // element types of u and t - v = (t & DIM) | OBJECT | cw.getMergedType(t & BASE_VALUE, u & BASE_VALUE); - } else { - // if u and t are array types, but not with the same element - // type, merge(u,t) = dim(u) - 1 | java/lang/Object - int vdim = ELEMENT_OF + (u & DIM); - v = vdim | OBJECT | cw.addType("java/lang/Object"); - } - } else if ((t & BASE_KIND) == OBJECT || (t & DIM) != 0) { - // if t is any other reference or array type, the merged type - // is min(udim, tdim) | java/lang/Object, where udim is the - // array dimension of u, minus 1 if u is an array type with a - // primitive element type (and similarly for tdim). - int tdim = (((t & DIM) == 0 || (t & BASE_KIND) == OBJECT) ? 0 : ELEMENT_OF) + (t & DIM); - int udim = (((u & DIM) == 0 || (u & BASE_KIND) == OBJECT) ? 0 : ELEMENT_OF) + (u & DIM); - v = Math.min(tdim, udim) | OBJECT | cw.addType("java/lang/Object"); - } else { - // if t is any other type, merge(u,t)=TOP - v = TOP; - } - } else if (u == NULL) { - // if u is the NULL type, merge(u,t)=t, - // or TOP if t is not a reference type - v = (t & BASE_KIND) == OBJECT || (t & DIM) != 0 ? t : TOP; - } else { - // if u is any other type, merge(u,t)=TOP whatever t - v = TOP; - } - if (u != v) { - types[index] = v; - return true; - } - return false; - } -} +/* + * 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 and output stack map frames of a basic block. + * + * @author Eric Bruneton + */ +class Frame { + + /* + * Frames are computed in a two steps process: during the visit of each + * instruction, the state of the frame at the end of current basic block is + * updated by simulating the action of the instruction on the previous state + * of this so called "output frame". In visitMaxs, a fix point algorithm is + * used to compute the "input frame" of each basic block, i.e. the stack map + * frame at the beginning of the basic block, starting from the input frame + * of the first basic block (which is computed from the method descriptor), + * and by using the previously computed output frames to compute the input + * state of the other blocks. + * + * All output and input frames are stored as arrays of integers. Reference + * and array types are represented by an index into a type table (which is + * not the same as the constant pool of the class, in order to avoid adding + * unnecessary constants in the pool - not all computed frames will end up + * being stored in the stack map table). This allows very fast type + * comparisons. + * + * Output stack map frames are computed relatively to the input frame of the + * basic block, which is not yet known when output frames are computed. It + * is therefore necessary to be able to represent abstract types such as + * "the type at position x in the input frame locals" or "the type at + * position x from the top of the input frame stack" or even "the type at + * position x in the input frame, with y more (or less) array dimensions". + * This explains the rather complicated type format used in output frames. + * + * This format is the following: DIM KIND VALUE (4, 4 and 24 bits). DIM is a + * signed number of array dimensions (from -8 to 7). KIND is either BASE, + * LOCAL or STACK. BASE is used for types that are not relative to the input + * frame. LOCAL is used for types that are relative to the input local + * variable types. STACK is used for types that are relative to the input + * stack types. VALUE depends on KIND. For LOCAL types, it is an index in + * the input local variable types. For STACK types, it is a position + * relatively to the top of input frame stack. For BASE types, it is either + * one of the constants defined below, or for OBJECT and UNINITIALIZED + * types, a tag and an index in the type table. + * + * Output frames can contain types of any kind and with a positive or + * negative dimension (and even unassigned types, represented by 0 - which + * does not correspond to any valid type value). Input frames can only + * contain BASE types of positive or null dimension. In all cases the type + * table contains only internal type names (array type descriptors are + * forbidden - dimensions must be represented through the DIM field). + * + * The LONG and DOUBLE types are always represented by using two slots (LONG + * + TOP or DOUBLE + TOP), for local variable types as well as in the + * operand stack. This is necessary to be able to simulate DUPx_y + * instructions, whose effect would be dependent on the actual type values + * if types were always represented by a single slot in the stack (and this + * is not possible, since actual type values are not always known - cf LOCAL + * and STACK type kinds). + */ + + /** Mask to get the dimension of a frame type. This dimension is a signed integer between -8 and 7. */ + static final int DIM = 0xF0000000; + + /** Constant to be added to a type to get a type with one more dimension. */ + static final int ARRAY_OF = 0x10000000; + + /** Constant to be added to a type to get a type with one less dimension. */ + static final int ELEMENT_OF = 0xF0000000; + + /** + * Mask to get the kind of a frame type. + * + * @see #BASE + * @see #LOCAL + * @see #STACK + */ + static final int KIND = 0xF000000; + + /** + * Flag used for LOCAL and STACK types. Indicates that if this type happens to be a long or double type (during the + * computations of input frames), then it must be set to TOP because the second word of this value has been reused + * to store other data in the basic block. Hence the first word no longer stores a valid long or double value. + */ + static final int TOP_IF_LONG_OR_DOUBLE = 0x800000; + + /** Mask to get the value of a frame type. */ + static final int VALUE = 0x7FFFFF; + + /** Mask to get the kind of base types. */ + static final int BASE_KIND = 0xFF00000; + + /** Mask to get the value of base types. */ + static final int BASE_VALUE = 0xFFFFF; + + /** Kind of the types that are not relative to an input stack map frame. */ + static final int BASE = 0x1000000; + + /** Base kind of the base reference types. The BASE_VALUE of such types is an index into the type table. */ + static final int OBJECT = BASE | 0x700000; + + /** + * Base kind of the uninitialized base types. The BASE_VALUE of such types in an index into the type table (the Item + * at that index contains both an instruction offset and an internal class name). + */ + static final int UNINITIALIZED = BASE | 0x800000; + + /** + * Kind of the types that are relative to the local variable types of an input stack map frame. The value of such + * types is a local variable index. + */ + private static final int LOCAL = 0x2000000; + + /** + * 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. + */ + private static final int STACK = 0x3000000; + + /** The TOP type. This is a BASE type. */ + static final int TOP = BASE | 0; + + /** The BOOLEAN type. This is a BASE type mainly used for array types. */ + static final int BOOLEAN = BASE | 9; + + /** The BYTE type. This is a BASE type mainly used for array types. */ + static final int BYTE = BASE | 10; + + /** The CHAR type. This is a BASE type mainly used for array types. */ + static final int CHAR = BASE | 11; + + /** The SHORT type. This is a BASE type mainly used for array types. */ + static final int SHORT = BASE | 12; + + /** The INTEGER type. This is a BASE type. */ + static final int INTEGER = BASE | 1; + + /** The FLOAT type. This is a BASE type. */ + static final int FLOAT = BASE | 2; + + /** The DOUBLE type. This is a BASE type. */ + static final int DOUBLE = BASE | 3; + + /** The LONG type. This is a BASE type. */ + static final int LONG = BASE | 4; + + /** The NULL type. This is a BASE type. */ + static final int NULL = BASE | 5; + + /** The UNINITIALIZED_THIS type. This is a BASE type. */ + static final int UNINITIALIZED_THIS = BASE | 6; + + /** + * The stack size variation corresponding to each JVM instruction. This stack variation is equal to the size of the + * values produced by an instruction, minus the size of the values consumed by this instruction. + */ + static final int[] SIZE; + + /** Computes the stack size variation corresponding to each JVM instruction. */ + static { + int i; + int[] b = new int[202]; + String s = "EFFFFFFFFGGFFFGGFFFEEFGFGFEEEEEEEEEEEEEEEEEEEEDEDEDDDDD" + + "CDCDEEEEEEEEEEEEEEEEEEEEBABABBBBDCFFFGGGEDCDCDCDCDCDCDCDCD" + + "CDCEEEEDDDDDDDCDCDCEFEFDDEEFFDEDEEEBDDBBDDDDDDCCCCCCCCEFED" + + "DDCDCDEEEEEEEEEEFEEEEEEDDEEDDEE"; + for (i = 0; i < b.length; ++i) { + b[i] = s.charAt(i) - 'E'; + } + SIZE = b; + + // code to generate the above string + // + // int NA = 0; // not applicable (unused opcode or variable size opcode) + // + // b = new int[] { + // 0, //NOP, // visitInsn + // 1, //ACONST_NULL, // - + // 1, //ICONST_M1, // - + // 1, //ICONST_0, // - + // 1, //ICONST_1, // - + // 1, //ICONST_2, // - + // 1, //ICONST_3, // - + // 1, //ICONST_4, // - + // 1, //ICONST_5, // - + // 2, //LCONST_0, // - + // 2, //LCONST_1, // - + // 1, //FCONST_0, // - + // 1, //FCONST_1, // - + // 1, //FCONST_2, // - + // 2, //DCONST_0, // - + // 2, //DCONST_1, // - + // 1, //BIPUSH, // visitIntInsn + // 1, //SIPUSH, // - + // 1, //LDC, // visitLdcInsn + // NA, //LDC_W, // - + // NA, //LDC2_W, // - + // 1, //ILOAD, // visitVarInsn + // 2, //LLOAD, // - + // 1, //FLOAD, // - + // 2, //DLOAD, // - + // 1, //ALOAD, // - + // NA, //ILOAD_0, // - + // NA, //ILOAD_1, // - + // NA, //ILOAD_2, // - + // NA, //ILOAD_3, // - + // NA, //LLOAD_0, // - + // NA, //LLOAD_1, // - + // NA, //LLOAD_2, // - + // NA, //LLOAD_3, // - + // NA, //FLOAD_0, // - + // NA, //FLOAD_1, // - + // NA, //FLOAD_2, // - + // NA, //FLOAD_3, // - + // NA, //DLOAD_0, // - + // NA, //DLOAD_1, // - + // NA, //DLOAD_2, // - + // NA, //DLOAD_3, // - + // NA, //ALOAD_0, // - + // NA, //ALOAD_1, // - + // NA, //ALOAD_2, // - + // NA, //ALOAD_3, // - + // -1, //IALOAD, // visitInsn + // 0, //LALOAD, // - + // -1, //FALOAD, // - + // 0, //DALOAD, // - + // -1, //AALOAD, // - + // -1, //BALOAD, // - + // -1, //CALOAD, // - + // -1, //SALOAD, // - + // -1, //ISTORE, // visitVarInsn + // -2, //LSTORE, // - + // -1, //FSTORE, // - + // -2, //DSTORE, // - + // -1, //ASTORE, // - + // NA, //ISTORE_0, // - + // NA, //ISTORE_1, // - + // NA, //ISTORE_2, // - + // NA, //ISTORE_3, // - + // NA, //LSTORE_0, // - + // NA, //LSTORE_1, // - + // NA, //LSTORE_2, // - + // NA, //LSTORE_3, // - + // NA, //FSTORE_0, // - + // NA, //FSTORE_1, // - + // NA, //FSTORE_2, // - + // NA, //FSTORE_3, // - + // NA, //DSTORE_0, // - + // NA, //DSTORE_1, // - + // NA, //DSTORE_2, // - + // NA, //DSTORE_3, // - + // NA, //ASTORE_0, // - + // NA, //ASTORE_1, // - + // NA, //ASTORE_2, // - + // NA, //ASTORE_3, // - + // -3, //IASTORE, // visitInsn + // -4, //LASTORE, // - + // -3, //FASTORE, // - + // -4, //DASTORE, // - + // -3, //AASTORE, // - + // -3, //BASTORE, // - + // -3, //CASTORE, // - + // -3, //SASTORE, // - + // -1, //POP, // - + // -2, //POP2, // - + // 1, //DUP, // - + // 1, //DUP_X1, // - + // 1, //DUP_X2, // - + // 2, //DUP2, // - + // 2, //DUP2_X1, // - + // 2, //DUP2_X2, // - + // 0, //SWAP, // - + // -1, //IADD, // - + // -2, //LADD, // - + // -1, //FADD, // - + // -2, //DADD, // - + // -1, //ISUB, // - + // -2, //LSUB, // - + // -1, //FSUB, // - + // -2, //DSUB, // - + // -1, //IMUL, // - + // -2, //LMUL, // - + // -1, //FMUL, // - + // -2, //DMUL, // - + // -1, //IDIV, // - + // -2, //LDIV, // - + // -1, //FDIV, // - + // -2, //DDIV, // - + // -1, //IREM, // - + // -2, //LREM, // - + // -1, //FREM, // - + // -2, //DREM, // - + // 0, //INEG, // - + // 0, //LNEG, // - + // 0, //FNEG, // - + // 0, //DNEG, // - + // -1, //ISHL, // - + // -1, //LSHL, // - + // -1, //ISHR, // - + // -1, //LSHR, // - + // -1, //IUSHR, // - + // -1, //LUSHR, // - + // -1, //IAND, // - + // -2, //LAND, // - + // -1, //IOR, // - + // -2, //LOR, // - + // -1, //IXOR, // - + // -2, //LXOR, // - + // 0, //IINC, // visitIincInsn + // 1, //I2L, // visitInsn + // 0, //I2F, // - + // 1, //I2D, // - + // -1, //L2I, // - + // -1, //L2F, // - + // 0, //L2D, // - + // 0, //F2I, // - + // 1, //F2L, // - + // 1, //F2D, // - + // -1, //D2I, // - + // 0, //D2L, // - + // -1, //D2F, // - + // 0, //I2B, // - + // 0, //I2C, // - + // 0, //I2S, // - + // -3, //LCMP, // - + // -1, //FCMPL, // - + // -1, //FCMPG, // - + // -3, //DCMPL, // - + // -3, //DCMPG, // - + // -1, //IFEQ, // visitJumpInsn + // -1, //IFNE, // - + // -1, //IFLT, // - + // -1, //IFGE, // - + // -1, //IFGT, // - + // -1, //IFLE, // - + // -2, //IF_ICMPEQ, // - + // -2, //IF_ICMPNE, // - + // -2, //IF_ICMPLT, // - + // -2, //IF_ICMPGE, // - + // -2, //IF_ICMPGT, // - + // -2, //IF_ICMPLE, // - + // -2, //IF_ACMPEQ, // - + // -2, //IF_ACMPNE, // - + // 0, //GOTO, // - + // 1, //JSR, // - + // 0, //RET, // visitVarInsn + // -1, //TABLESWITCH, // visiTableSwitchInsn + // -1, //LOOKUPSWITCH, // visitLookupSwitch + // -1, //IRETURN, // visitInsn + // -2, //LRETURN, // - + // -1, //FRETURN, // - + // -2, //DRETURN, // - + // -1, //ARETURN, // - + // 0, //RETURN, // - + // NA, //GETSTATIC, // visitFieldInsn + // NA, //PUTSTATIC, // - + // NA, //GETFIELD, // - + // NA, //PUTFIELD, // - + // NA, //INVOKEVIRTUAL, // visitMethodInsn + // NA, //INVOKESPECIAL, // - + // NA, //INVOKESTATIC, // - + // NA, //INVOKEINTERFACE, // - + // NA, //INVOKEDYNAMIC, // visitInvokeDynamicInsn + // 1, //NEW, // visitTypeInsn + // 0, //NEWARRAY, // visitIntInsn + // 0, //ANEWARRAY, // visitTypeInsn + // 0, //ARRAYLENGTH, // visitInsn + // NA, //ATHROW, // - + // 0, //CHECKCAST, // visitTypeInsn + // 0, //INSTANCEOF, // - + // -1, //MONITORENTER, // visitInsn + // -1, //MONITOREXIT, // - + // NA, //WIDE, // NOT VISITED + // NA, //MULTIANEWARRAY, // visitMultiANewArrayInsn + // -1, //IFNULL, // visitJumpInsn + // -1, //IFNONNULL, // - + // NA, //GOTO_W, // - + // NA, //JSR_W, // - + // }; + // for (i = 0; i < b.length; ++i) { + // System.err.print((char)('E' + b[i])); + // } + // System.err.println(); + } + + /** The label (i.e. basic block) to which these input and output stack map frames correspond. */ + Label owner; + + /** The input stack map frame locals. */ + int[] inputLocals; + + /** The input stack map frame stack. */ + int[] inputStack; + + /** The output stack map frame locals. */ + private int[] outputLocals; + + /** The output stack map frame stack. */ + private int[] outputStack; + + /** + * Relative size of the output stack. The exact semantics of this field depends on the algorithm that is used. + * + *

When only the maximum stack size is computed, this field is the size of the output stack relatively to the top + * of the input stack. + * + *

When the stack map frames are completely computed, this field is the actual number of types in + * {@link #outputStack}. + */ + int outputStackTop; + + /** + * Number of types that are initialized in the basic block. + * + * @see #initializations + */ + private int initializationCount; + + /** + * The types that are initialized in the basic block. A constructor invocation on an UNINITIALIZED or + * UNINITIALIZED_THIS type must replace every occurence of this type in the local variables and in the + * operand stack. This cannot be done during the first phase of the algorithm since, during this phase, the local + * variables and the operand stack are not completely computed. It is therefore necessary to store the types on + * which constructors are invoked in the basic block, in order to do this replacement during the second phase of the + * algorithm, where the frames are fully computed. Note that this array can contain types that are relative to input + * locals or to the input stack (see below for the description of the algorithm). + */ + 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. + * + * @param local the index of the local that must be returned. + * @return the output frame local variable type at the given index. + */ + private int get(final int local) { + if (outputLocals == null || local >= outputLocals.length) { + // this local has never been assigned in this basic block, + // so it is still equal to its value in the input frame + return LOCAL | local; + } else { + int type = outputLocals[local]; + if (type == 0) { + // this local has never been assigned in this basic block, + // so it is still equal to its value in the input frame + type = outputLocals[local] = LOCAL | local; + } + return type; + } + } + + /** + * Sets the output frame local variable type at the given index. + * + * @param local the index of the local that must be set. + * @param type the value of the local that must be set. + */ + private void set(final int local, final int type) { + // creates and/or resizes the output local variables array if necessary + if (outputLocals == null) { + outputLocals = new int[10]; + } + int n = outputLocals.length; + if (local >= n) { + int[] t = new int[Math.max(local + 1, 2 * n)]; + System.arraycopy(outputLocals, 0, t, 0, n); + outputLocals = t; + } + // sets the local variable + outputLocals[local] = type; + } + + /** + * Pushes a new type onto the output frame stack. + * + * @param type the type that must be pushed. + */ + private void push(final int type) { + // creates and/or resizes the output stack array if necessary + if (outputStack == null) { + outputStack = new int[10]; + } + int n = outputStack.length; + if (outputStackTop >= n) { + int[] t = new int[Math.max(outputStackTop + 1, 2 * n)]; + System.arraycopy(outputStack, 0, t, 0, n); + outputStack = t; + } + // pushes the type on the output stack + outputStack[outputStackTop++] = type; + // updates the maximum height reached by the output stack, if needed + int top = owner.inputStackTop + outputStackTop; + if (top > owner.outputStackMax) { + owner.outputStackMax = top; + } + } + + /** + * Pushes a new type onto the output frame stack. + * + * @param cw the ClassWriter to which this label belongs. + * @param desc the descriptor of the type to be pushed. Can also be a method descriptor (in this case this method + * pushes its return type onto the output frame stack). + */ + private void push(final ClassWriter cw, final String desc) { + int type = type(cw, desc); + if (type != 0) { + push(type); + if (type == LONG || type == DOUBLE) { + push(TOP); + } + } + } + + /** + * Returns the int encoding of the given type. + * + * @param cw the ClassWriter to which this label belongs. + * @param desc a type descriptor. + * @return the int encoding of the given type. + */ + static int type(final ClassWriter cw, final String desc) { + String t; + int index = desc.charAt(0) == '(' ? desc.indexOf(')') + 1 : 0; + switch (desc.charAt(index)) { + case 'V': + return 0; + case 'Z': + case 'C': + case 'B': + case 'S': + case 'I': + return INTEGER; + case 'F': + return FLOAT; + case 'J': + return LONG; + case 'D': + return DOUBLE; + case 'L': + // stores the internal name, not the descriptor! + t = desc.substring(index + 1, desc.length() - 1); + return OBJECT | cw.addType(t); + // case '[': + default: + // extracts the dimensions and the element type + int data; + int dims = index + 1; + while (desc.charAt(dims) == '[') { + ++dims; + } + switch (desc.charAt(dims)) { + case 'Z': + data = BOOLEAN; + break; + case 'C': + data = CHAR; + break; + case 'B': + data = BYTE; + break; + case 'S': + data = SHORT; + break; + case 'I': + data = INTEGER; + break; + case 'F': + data = FLOAT; + break; + case 'J': + data = LONG; + break; + case 'D': + data = DOUBLE; + break; + // case 'L': + default: + // stores the internal name, not the descriptor + t = desc.substring(dims + 1, desc.length() - 1); + data = OBJECT | cw.addType(t); + } + return (dims - index) << 28 | data; + } + } + + /** + * Pops a type from the output frame stack and returns its value. + * + * @return the type that has been popped from the output frame stack. + */ + private int pop() { + if (outputStackTop > 0) { + return outputStack[--outputStackTop]; + } else { + // if the output frame stack is empty, pops from the input stack + return STACK | -(--owner.inputStackTop); + } + } + + /** + * Pops the given number of types from the output frame stack. + * + * @param elements the number of types that must be popped. + */ + private void pop(final int elements) { + if (outputStackTop >= elements) { + outputStackTop -= elements; + } else { + // if the number of elements to be popped is greater than the number + // of elements in the output stack, clear it, and pops the remaining + // elements from the input stack. + owner.inputStackTop -= elements - outputStackTop; + outputStackTop = 0; + } + } + + /** + * Pops a type from the output frame stack. + * + * @param desc the descriptor of the type to be popped. Can also be a method descriptor (in this case this method + * pops the types corresponding to the method arguments). + */ + private void pop(final String desc) { + char c = desc.charAt(0); + if (c == '(') { + pop((Type.getArgumentsAndReturnSizes(desc) >> 2) - 1); + } else if (c == 'J' || c == 'D') { + pop(2); + } else { + pop(1); + } + } + + /** + * Adds a new type to the list of types on which a constructor is invoked in the basic block. + * + * @param var a type on a which a constructor is invoked. + */ + private void init(final int var) { + // creates and/or resizes the initializations array if necessary + if (initializations == null) { + initializations = new int[2]; + } + int n = initializations.length; + if (initializationCount >= n) { + int[] t = new int[Math.max(initializationCount + 1, 2 * n)]; + System.arraycopy(initializations, 0, t, 0, n); + initializations = t; + } + // stores the type to be initialized + initializations[initializationCount++] = var; + } + + /** + * Replaces the given type with the appropriate type if it is one of the types on which a constructor is invoked in + * the basic block. + * + * @param cw the ClassWriter to which this label belongs. + * @param t a type + * @return t or, if t is one of the types on which a constructor is invoked in the basic block, the type + * corresponding to this constructor. + */ + private int init(final ClassWriter cw, final int t) { + int s; + if (t == UNINITIALIZED_THIS) { + s = OBJECT | cw.addType(cw.thisName); + } else if ((t & (DIM | BASE_KIND)) == UNINITIALIZED) { + String type = cw.typeTable[t & BASE_VALUE].strVal1; + s = OBJECT | cw.addType(type); + } else { + return t; + } + for (int j = 0; j < initializationCount; ++j) { + int u = initializations[j]; + int dim = u & DIM; + int kind = u & KIND; + if (kind == LOCAL) { + u = dim + inputLocals[u & VALUE]; + } else if (kind == STACK) { + u = dim + inputStack[inputStack.length - (u & VALUE)]; + } + if (t == u) { + return s; + } + } + return t; + } + + /** + * Initializes the input frame of the first basic block from the method descriptor. + * + * @param cw the ClassWriter to which this label belongs. + * @param access the access flags of the method to which this label belongs. + * @param args the formal parameter types of this method. + * @param maxLocals the maximum number of local variables of this method. + */ + final void initInputFrame(final ClassWriter cw, final int access, final Type[] args, final int maxLocals) { + inputLocals = new int[maxLocals]; + inputStack = new int[0]; + int i = 0; + if ((access & Opcodes.ACC_STATIC) == 0) { + if ((access & MethodWriter.ACC_CONSTRUCTOR) == 0) { + inputLocals[i++] = OBJECT | cw.addType(cw.thisName); + } else { + inputLocals[i++] = UNINITIALIZED_THIS; + } + } + for (int j = 0; j < args.length; ++j) { + int t = type(cw, args[j].getDescriptor()); + inputLocals[i++] = t; + if (t == LONG || t == DOUBLE) { + inputLocals[i++] = TOP; + } + } + while (i < maxLocals) { + inputLocals[i++] = TOP; + } + } + + /** + * Simulates the action of the given instruction on the output stack frame. + * + * @param opcode the opcode of the instruction. + * @param arg the operand of the instruction, if any. + * @param cw the class writer to which this label belongs. + * @param item the operand of the instructions, if any. + */ + void execute(final int opcode, final int arg, final ClassWriter cw, final Item item) { + int t1, t2, t3, t4; + switch (opcode) { + case Opcodes.NOP: + case Opcodes.INEG: + case Opcodes.LNEG: + case Opcodes.FNEG: + case Opcodes.DNEG: + case Opcodes.I2B: + case Opcodes.I2C: + case Opcodes.I2S: + case Opcodes.GOTO: + case Opcodes.RETURN: + break; + case Opcodes.ACONST_NULL: + push(NULL); + break; + case Opcodes.ICONST_M1: + case Opcodes.ICONST_0: + case Opcodes.ICONST_1: + case Opcodes.ICONST_2: + case Opcodes.ICONST_3: + case Opcodes.ICONST_4: + case Opcodes.ICONST_5: + case Opcodes.BIPUSH: + case Opcodes.SIPUSH: + case Opcodes.ILOAD: + push(INTEGER); + break; + case Opcodes.LCONST_0: + case Opcodes.LCONST_1: + case Opcodes.LLOAD: + push(LONG); + push(TOP); + break; + case Opcodes.FCONST_0: + case Opcodes.FCONST_1: + case Opcodes.FCONST_2: + case Opcodes.FLOAD: + push(FLOAT); + break; + case Opcodes.DCONST_0: + case Opcodes.DCONST_1: + case Opcodes.DLOAD: + push(DOUBLE); + push(TOP); + break; + case Opcodes.LDC: + switch (item.type) { + case ClassWriter.INT: + push(INTEGER); + break; + case ClassWriter.LONG: + push(LONG); + push(TOP); + break; + case ClassWriter.FLOAT: + push(FLOAT); + break; + case ClassWriter.DOUBLE: + push(DOUBLE); + push(TOP); + break; + case ClassWriter.CLASS: + push(OBJECT | cw.addType("java/lang/Class")); + break; + case ClassWriter.STR: + push(OBJECT | cw.addType("java/lang/String")); + break; + case ClassWriter.MTYPE: + push(OBJECT | cw.addType("java/lang/invoke/MethodType")); + break; + // case ClassWriter.HANDLE_BASE + [1..9]: + default: + push(OBJECT | cw.addType("java/lang/invoke/MethodHandle")); + } + break; + case Opcodes.ALOAD: + push(get(arg)); + break; + case Opcodes.IALOAD: + case Opcodes.BALOAD: + case Opcodes.CALOAD: + case Opcodes.SALOAD: + pop(2); + push(INTEGER); + break; + case Opcodes.LALOAD: + case Opcodes.D2L: + pop(2); + push(LONG); + push(TOP); + break; + case Opcodes.FALOAD: + pop(2); + push(FLOAT); + break; + case Opcodes.DALOAD: + case Opcodes.L2D: + pop(2); + push(DOUBLE); + push(TOP); + break; + case Opcodes.AALOAD: + pop(1); + t1 = pop(); + push(t1 == NULL ? t1 : ELEMENT_OF + t1); + break; + case Opcodes.ISTORE: + case Opcodes.FSTORE: + case Opcodes.ASTORE: + t1 = pop(); + set(arg, t1); + if (arg > 0) { + t2 = get(arg - 1); + // if t2 is of kind STACK or LOCAL we cannot know its size! + if (t2 == LONG || t2 == DOUBLE) { + set(arg - 1, TOP); + } else if ((t2 & KIND) != BASE) { + set(arg - 1, t2 | TOP_IF_LONG_OR_DOUBLE); + } + } + break; + case Opcodes.LSTORE: + case Opcodes.DSTORE: + pop(1); + t1 = pop(); + set(arg, t1); + set(arg + 1, TOP); + if (arg > 0) { + t2 = get(arg - 1); + // if t2 is of kind STACK or LOCAL we cannot know its size! + if (t2 == LONG || t2 == DOUBLE) { + set(arg - 1, TOP); + } else if ((t2 & KIND) != BASE) { + set(arg - 1, t2 | TOP_IF_LONG_OR_DOUBLE); + } + } + break; + case Opcodes.IASTORE: + case Opcodes.BASTORE: + case Opcodes.CASTORE: + case Opcodes.SASTORE: + case Opcodes.FASTORE: + case Opcodes.AASTORE: + pop(3); + break; + case Opcodes.LASTORE: + case Opcodes.DASTORE: + pop(4); + break; + case Opcodes.POP: + case Opcodes.IFEQ: + case Opcodes.IFNE: + case Opcodes.IFLT: + case Opcodes.IFGE: + case Opcodes.IFGT: + case Opcodes.IFLE: + case Opcodes.IRETURN: + case Opcodes.FRETURN: + case Opcodes.ARETURN: + case Opcodes.TABLESWITCH: + case Opcodes.LOOKUPSWITCH: + case Opcodes.ATHROW: + case Opcodes.MONITORENTER: + case Opcodes.MONITOREXIT: + case Opcodes.IFNULL: + case Opcodes.IFNONNULL: + pop(1); + break; + case Opcodes.POP2: + case Opcodes.IF_ICMPEQ: + case Opcodes.IF_ICMPNE: + case Opcodes.IF_ICMPLT: + case Opcodes.IF_ICMPGE: + case Opcodes.IF_ICMPGT: + case Opcodes.IF_ICMPLE: + case Opcodes.IF_ACMPEQ: + case Opcodes.IF_ACMPNE: + case Opcodes.LRETURN: + case Opcodes.DRETURN: + pop(2); + break; + case Opcodes.DUP: + t1 = pop(); + push(t1); + push(t1); + break; + case Opcodes.DUP_X1: + t1 = pop(); + t2 = pop(); + push(t1); + push(t2); + push(t1); + break; + case Opcodes.DUP_X2: + t1 = pop(); + t2 = pop(); + t3 = pop(); + push(t1); + push(t3); + push(t2); + push(t1); + break; + case Opcodes.DUP2: + t1 = pop(); + t2 = pop(); + push(t2); + push(t1); + push(t2); + push(t1); + break; + case Opcodes.DUP2_X1: + t1 = pop(); + t2 = pop(); + t3 = pop(); + push(t2); + push(t1); + push(t3); + push(t2); + push(t1); + break; + case Opcodes.DUP2_X2: + t1 = pop(); + t2 = pop(); + t3 = pop(); + t4 = pop(); + push(t2); + push(t1); + push(t4); + push(t3); + push(t2); + push(t1); + break; + case Opcodes.SWAP: + t1 = pop(); + t2 = pop(); + push(t1); + push(t2); + break; + case Opcodes.IADD: + case Opcodes.ISUB: + case Opcodes.IMUL: + case Opcodes.IDIV: + case Opcodes.IREM: + case Opcodes.IAND: + case Opcodes.IOR: + case Opcodes.IXOR: + case Opcodes.ISHL: + case Opcodes.ISHR: + case Opcodes.IUSHR: + case Opcodes.L2I: + case Opcodes.D2I: + case Opcodes.FCMPL: + case Opcodes.FCMPG: + pop(2); + push(INTEGER); + break; + case Opcodes.LADD: + case Opcodes.LSUB: + case Opcodes.LMUL: + case Opcodes.LDIV: + case Opcodes.LREM: + case Opcodes.LAND: + case Opcodes.LOR: + case Opcodes.LXOR: + pop(4); + push(LONG); + push(TOP); + break; + case Opcodes.FADD: + case Opcodes.FSUB: + case Opcodes.FMUL: + case Opcodes.FDIV: + case Opcodes.FREM: + case Opcodes.L2F: + case Opcodes.D2F: + pop(2); + push(FLOAT); + break; + case Opcodes.DADD: + case Opcodes.DSUB: + case Opcodes.DMUL: + case Opcodes.DDIV: + case Opcodes.DREM: + pop(4); + push(DOUBLE); + push(TOP); + break; + case Opcodes.LSHL: + case Opcodes.LSHR: + case Opcodes.LUSHR: + pop(3); + push(LONG); + push(TOP); + break; + case Opcodes.IINC: + set(arg, INTEGER); + break; + case Opcodes.I2L: + case Opcodes.F2L: + pop(1); + push(LONG); + push(TOP); + break; + case Opcodes.I2F: + pop(1); + push(FLOAT); + break; + case Opcodes.I2D: + case Opcodes.F2D: + pop(1); + push(DOUBLE); + push(TOP); + break; + case Opcodes.F2I: + case Opcodes.ARRAYLENGTH: + case Opcodes.INSTANCEOF: + pop(1); + push(INTEGER); + break; + case Opcodes.LCMP: + case Opcodes.DCMPL: + case Opcodes.DCMPG: + pop(4); + push(INTEGER); + break; + case Opcodes.JSR: + case Opcodes.RET: + throw new RuntimeException("JSR/RET are not supported with computeFrames option"); + case Opcodes.GETSTATIC: + push(cw, item.strVal3); + break; + case Opcodes.PUTSTATIC: + pop(item.strVal3); + break; + case Opcodes.GETFIELD: + pop(1); + push(cw, item.strVal3); + break; + case Opcodes.PUTFIELD: + pop(item.strVal3); + pop(); + break; + case Opcodes.INVOKEVIRTUAL: + case Opcodes.INVOKESPECIAL: + case Opcodes.INVOKESTATIC: + case Opcodes.INVOKEINTERFACE: + pop(item.strVal3); + if (opcode != Opcodes.INVOKESTATIC) { + t1 = pop(); + if (opcode == Opcodes.INVOKESPECIAL && item.strVal2.charAt(0) == '<') { + init(t1); + } + } + push(cw, item.strVal3); + break; + case Opcodes.INVOKEDYNAMIC: + pop(item.strVal2); + push(cw, item.strVal2); + break; + case Opcodes.NEW: + push(UNINITIALIZED | cw.addUninitializedType(item.strVal1, arg)); + break; + case Opcodes.NEWARRAY: + pop(); + switch (arg) { + case Opcodes.T_BOOLEAN: + push(ARRAY_OF | BOOLEAN); + break; + case Opcodes.T_CHAR: + push(ARRAY_OF | CHAR); + break; + case Opcodes.T_BYTE: + push(ARRAY_OF | BYTE); + break; + case Opcodes.T_SHORT: + push(ARRAY_OF | SHORT); + break; + case Opcodes.T_INT: + push(ARRAY_OF | INTEGER); + break; + case Opcodes.T_FLOAT: + push(ARRAY_OF | FLOAT); + break; + case Opcodes.T_DOUBLE: + push(ARRAY_OF | DOUBLE); + break; + // case Opcodes.T_LONG: + default: + push(ARRAY_OF | LONG); + break; + } + break; + case Opcodes.ANEWARRAY: + String s = item.strVal1; + pop(); + if (s.charAt(0) == '[') { + push(cw, '[' + s); + } else { + push(ARRAY_OF | OBJECT | cw.addType(s)); + } + break; + case Opcodes.CHECKCAST: + s = item.strVal1; + pop(); + if (s.charAt(0) == '[') { + push(cw, s); + } else { + push(OBJECT | cw.addType(s)); + } + break; + // case Opcodes.MULTIANEWARRAY: + default: + pop(arg); + push(cw, item.strVal1); + break; + } + } + + /** + * Merges the input frame of the given basic block with the input and output frames of this basic block. Returns + * <tt>true</tt> if the input frame of the given label has been changed by this operation. + * + * @param cw the ClassWriter to which this label belongs. + * @param frame the basic block whose input frame must be updated. + * @param edge the kind of the {@link Edge} between this label and 'label'. See {@link Edge#info}. + * @return <tt>true</tt> if the input frame of the given label has been changed by this operation. + */ + final boolean merge(final ClassWriter cw, final Frame frame, final int edge) { + boolean changed = false; + int i, s, dim, kind, t; + + int nLocal = inputLocals.length; + int nStack = inputStack.length; + if (frame.inputLocals == null) { + frame.inputLocals = new int[nLocal]; + changed = true; + } + + for (i = 0; i < nLocal; ++i) { + if (outputLocals != null && i < outputLocals.length) { + s = outputLocals[i]; + if (s == 0) { + t = inputLocals[i]; + } else { + dim = s & DIM; + kind = s & KIND; + if (kind == BASE) { + t = s; + } else { + if (kind == LOCAL) { + t = dim + inputLocals[s & VALUE]; + } else { + t = dim + inputStack[nStack - (s & VALUE)]; + } + if ((s & TOP_IF_LONG_OR_DOUBLE) != 0 && (t == LONG || t == DOUBLE)) { + t = TOP; + } + } + } + } else { + t = inputLocals[i]; + } + if (initializations != null) { + t = init(cw, t); + } + changed |= merge(cw, t, frame.inputLocals, i); + } + + if (edge > 0) { + for (i = 0; i < nLocal; ++i) { + t = inputLocals[i]; + changed |= merge(cw, t, frame.inputLocals, i); + } + if (frame.inputStack == null) { + frame.inputStack = new int[1]; + changed = true; + } + changed |= merge(cw, edge, frame.inputStack, 0); + return changed; + } + + int nInputStack = inputStack.length + owner.inputStackTop; + if (frame.inputStack == null) { + frame.inputStack = new int[nInputStack + outputStackTop]; + changed = true; + } + + for (i = 0; i < nInputStack; ++i) { + t = inputStack[i]; + if (initializations != null) { + t = init(cw, t); + } + changed |= merge(cw, t, frame.inputStack, i); + } + for (i = 0; i < outputStackTop; ++i) { + s = outputStack[i]; + dim = s & DIM; + kind = s & KIND; + if (kind == BASE) { + t = s; + } else { + if (kind == LOCAL) { + t = dim + inputLocals[s & VALUE]; + } else { + t = dim + inputStack[nStack - (s & VALUE)]; + } + if ((s & TOP_IF_LONG_OR_DOUBLE) != 0 && (t == LONG || t == DOUBLE)) { + t = TOP; + } + } + if (initializations != null) { + t = init(cw, t); + } + changed |= merge(cw, t, frame.inputStack, nInputStack + i); + } + return changed; + } + + /** + * Merges the type at the given index in the given type array with the given type. Returns + * <tt>true</tt> if the type array has been modified by this operation. + * + * @param cw the ClassWriter to which this label belongs. + * @param t the type with which the type array element must be merged. + * @param types an array of types. + * @param index the index of the type that must be merged in 'types'. + * @return <tt>true</tt> if the type array has been modified by this operation. + */ + private static boolean merge(final ClassWriter cw, int t, final int[] types, final int index) { + int u = types[index]; + if (u == t) { + // if the types are equal, merge(u,t)=u, so there is no change + return false; + } + if ((t & ~DIM) == NULL) { + if (u == NULL) { + return false; + } + t = NULL; + } + if (u == 0) { + // if types[index] has never been assigned, merge(u,t)=t + types[index] = t; + return true; + } + int v; + if ((u & BASE_KIND) == OBJECT || (u & DIM) != 0) { + // if u is a reference type of any dimension + if (t == NULL) { + // if t is the NULL type, merge(u,t)=u, so there is no change + return false; + } else if ((t & (DIM | BASE_KIND)) == (u & (DIM | BASE_KIND))) { + // if t and u have the same dimension and same base kind + if ((u & BASE_KIND) == OBJECT) { + // if t is also a reference type, and if u and t have the + // same dimension merge(u,t) = dim(t) | common parent of the + // element types of u and t + v = (t & DIM) | OBJECT | cw.getMergedType(t & BASE_VALUE, u & BASE_VALUE); + } else { + // if u and t are array types, but not with the same element + // type, merge(u,t) = dim(u) - 1 | java/lang/Object + int vdim = ELEMENT_OF + (u & DIM); + v = vdim | OBJECT | cw.addType("java/lang/Object"); + } + } else if ((t & BASE_KIND) == OBJECT || (t & DIM) != 0) { + // if t is any other reference or array type, the merged type + // is min(udim, tdim) | java/lang/Object, where udim is the + // array dimension of u, minus 1 if u is an array type with a + // primitive element type (and similarly for tdim). + int tdim = (((t & DIM) == 0 || (t & BASE_KIND) == OBJECT) ? 0 : ELEMENT_OF) + (t & DIM); + int udim = (((u & DIM) == 0 || (u & BASE_KIND) == OBJECT) ? 0 : ELEMENT_OF) + (u & DIM); + v = Math.min(tdim, udim) | OBJECT | cw.addType("java/lang/Object"); + } else { + // if t is any other type, merge(u,t)=TOP + v = TOP; + } + } else if (u == NULL) { + // if u is the NULL type, merge(u,t)=t, + // or TOP if t is not a reference type + v = (t & BASE_KIND) == OBJECT || (t & DIM) != 0 ? t : TOP; + } else { + // if u is any other type, merge(u,t)=TOP whatever t + v = TOP; + } + if (u != v) { + types[index] = v; + return true; + } + return false; + } +} diff --git a/src/main/java/org/redkale/asm/Handle.java b/src/main/java/org/redkale/asm/Handle.java index cd3d9008f..d3da4d3d1 100644 --- a/src/main/java/org/redkale/asm/Handle.java +++ b/src/main/java/org/redkale/asm/Handle.java @@ -1,190 +1,190 @@ -/* - * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */ - -/* - * - * - * - * - * - * ASM: a very small and fast Java bytecode manipulation framework - * Copyright (c) 2000-2011 INRIA, France Telecom - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -package org.redkale.asm; - -/** - * A reference to a field or a method. - * - * @author Remi Forax - * @author Eric Bruneton - */ -public final class Handle { - - /** - * The kind of field or method designated by this Handle. Should be {@link Opcodes#H_GETFIELD}, - * {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, - * {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, - * {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}. - */ - final int tag; - - /** The internal name of the class that owns the field or method designated by this handle. */ - final String owner; - - /** The name of the field or method designated by this handle. */ - final String name; - - /** The descriptor of the field or method designated by this handle. */ - final String desc; - - /** Indicate if the owner is an interface or not. */ - final boolean itf; - - /** - * Constructs a new field or method handle. - * - * @param tag the kind of field or method designated by this Handle. Must be {@link Opcodes#H_GETFIELD}, - * {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, - * {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, - * {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}. - * @param owner the internal name of the class that owns the field or method designated by this handle. - * @param name the name of the field or method designated by this handle. - * @param desc the descriptor of the field or method designated by this handle. - * @param itf true if the owner is an interface. - */ - public Handle(int tag, String owner, String name, String desc, boolean itf) { - this.tag = tag; - this.owner = owner; - this.name = name; - this.desc = desc; - this.itf = itf; - } - - /** - * Returns the kind of field or method designated by this handle. - * - * @return {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, - * {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, - * {@link Opcodes#H_INVOKESPECIAL}, {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}. - */ - public int getTag() { - return tag; - } - - /** - * Returns the internal name of the class that owns the field or method designated by this handle. - * - * @return the internal name of the class that owns the field or method designated by this handle. - */ - public String getOwner() { - return owner; - } - - /** - * Returns the name of the field or method designated by this handle. - * - * @return the name of the field or method designated by this handle. - */ - public String getName() { - return name; - } - - /** - * Returns the descriptor of the field or method designated by this handle. - * - * @return the descriptor of the field or method designated by this handle. - */ - public String getDesc() { - return desc; - } - - /** - * Returns true if the owner of the field or method designated by this handle is an interface. - * - * @return true if the owner of the field or method designated by this handle is an interface. - */ - public boolean isInterface() { - return itf; - } - - @Override - public boolean equals(Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof Handle)) { - return false; - } - Handle h = (Handle) obj; - return tag == h.tag && itf == h.itf && owner.equals(h.owner) && name.equals(h.name) && desc.equals(h.desc); - } - - @Override - public int hashCode() { - return tag + (itf ? 64 : 0) + owner.hashCode() * name.hashCode() * desc.hashCode(); - } - - /** - * Returns the textual representation of this handle. The textual representation is: - * - *

-     * for a reference to a class:
-     * owner '.' name desc ' ' '(' tag ')'
-     * for a reference to an interface:
-     * owner '.' name desc ' ' '(' tag ' ' itf ')'
-     * 
- * - * . As this format is unambiguous, it can be parsed if necessary. - */ - @Override - public String toString() { - return owner + '.' + name + desc + " (" + tag + (itf ? " itf" : "") + ')'; - } -} +/* + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ + +/* + * + * + * + * + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.redkale.asm; + +/** + * A reference to a field or a method. + * + * @author Remi Forax + * @author Eric Bruneton + */ +public final class Handle { + + /** + * The kind of field or method designated by this Handle. Should be {@link Opcodes#H_GETFIELD}, + * {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, + * {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, + * {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}. + */ + final int tag; + + /** The internal name of the class that owns the field or method designated by this handle. */ + final String owner; + + /** The name of the field or method designated by this handle. */ + final String name; + + /** The descriptor of the field or method designated by this handle. */ + final String desc; + + /** Indicate if the owner is an interface or not. */ + final boolean itf; + + /** + * Constructs a new field or method handle. + * + * @param tag the kind of field or method designated by this Handle. Must be {@link Opcodes#H_GETFIELD}, + * {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, + * {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, + * {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}. + * @param owner the internal name of the class that owns the field or method designated by this handle. + * @param name the name of the field or method designated by this handle. + * @param desc the descriptor of the field or method designated by this handle. + * @param itf true if the owner is an interface. + */ + public Handle(int tag, String owner, String name, String desc, boolean itf) { + this.tag = tag; + this.owner = owner; + this.name = name; + this.desc = desc; + this.itf = itf; + } + + /** + * Returns the kind of field or method designated by this handle. + * + * @return {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, + * {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, + * {@link Opcodes#H_INVOKESPECIAL}, {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}. + */ + public int getTag() { + return tag; + } + + /** + * Returns the internal name of the class that owns the field or method designated by this handle. + * + * @return the internal name of the class that owns the field or method designated by this handle. + */ + public String getOwner() { + return owner; + } + + /** + * Returns the name of the field or method designated by this handle. + * + * @return the name of the field or method designated by this handle. + */ + public String getName() { + return name; + } + + /** + * Returns the descriptor of the field or method designated by this handle. + * + * @return the descriptor of the field or method designated by this handle. + */ + public String getDesc() { + return desc; + } + + /** + * Returns true if the owner of the field or method designated by this handle is an interface. + * + * @return true if the owner of the field or method designated by this handle is an interface. + */ + public boolean isInterface() { + return itf; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof Handle)) { + return false; + } + Handle h = (Handle) obj; + return tag == h.tag && itf == h.itf && owner.equals(h.owner) && name.equals(h.name) && desc.equals(h.desc); + } + + @Override + public int hashCode() { + return tag + (itf ? 64 : 0) + owner.hashCode() * name.hashCode() * desc.hashCode(); + } + + /** + * Returns the textual representation of this handle. The textual representation is: + * + *
+     * for a reference to a class:
+     * owner '.' name desc ' ' '(' tag ')'
+     * for a reference to an interface:
+     * owner '.' name desc ' ' '(' tag ' ' itf ')'
+     * 
+ * + * . As this format is unambiguous, it can be parsed if necessary. + */ + @Override + public String toString() { + return owner + '.' + name + desc + " (" + tag + (itf ? " itf" : "") + ')'; + } +} diff --git a/src/main/java/org/redkale/asm/Handler.java b/src/main/java/org/redkale/asm/Handler.java index b99109332..fb9f47dcd 100644 --- a/src/main/java/org/redkale/asm/Handler.java +++ b/src/main/java/org/redkale/asm/Handler.java @@ -1,138 +1,138 @@ -/* - * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */ - -/* - * - * - * - * - * - * ASM: a very small and fast Java bytecode manipulation framework - * Copyright (c) 2000-2011 INRIA, France Telecom - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.redkale.asm; - -/** - * Information about an exception handler block. - * - * @author Eric Bruneton - */ -class Handler { - - /** Beginning of the exception handler's scope (inclusive). */ - Label start; - - /** End of the exception handler's scope (exclusive). */ - Label end; - - /** Beginning of the exception handler's code. */ - Label handler; - - /** - * Internal name of the type of exceptions handled by this handler, or <tt>null</tt> to catch any - * exceptions. - */ - String desc; - - /** - * Constant pool index of the internal name of the type of exceptions handled by this handler, or 0 to catch any - * exceptions. - */ - int type; - - /** Next exception handler block info. */ - Handler next; - - /** - * Removes the range between start and end from the given exception handlers. - * - * @param h an exception handler list. - * @param start the start of the range to be removed. - * @param end the end of the range to be removed. Maybe null. - * @return the exception handler list with the start-end range removed. - */ - static Handler remove(Handler h, Label start, Label end) { - if (h == null) { - return null; - } else { - h.next = remove(h.next, start, end); - } - int hstart = h.start.position; - int hend = h.end.position; - int s = start.position; - int e = end == null ? Integer.MAX_VALUE : end.position; - // if [hstart,hend[ and [s,e[ intervals intersect... - if (s < hend && e > hstart) { - if (s <= hstart) { - if (e >= hend) { - // [hstart,hend[ fully included in [s,e[, h removed - h = h.next; - } else { - // [hstart,hend[ minus [s,e[ = [e,hend[ - h.start = end; - } - } else if (e >= hend) { - // [hstart,hend[ minus [s,e[ = [hstart,s[ - h.end = start; - } else { - // [hstart,hend[ minus [s,e[ = [hstart,s[ + [e,hend[ - Handler g = new Handler(); - g.start = end; - g.end = h.end; - g.handler = h.handler; - g.desc = h.desc; - g.type = h.type; - g.next = h.next; - h.end = start; - h.next = g; - } - } - return h; - } -} +/* + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ + +/* + * + * + * + * + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.redkale.asm; + +/** + * Information about an exception handler block. + * + * @author Eric Bruneton + */ +class Handler { + + /** Beginning of the exception handler's scope (inclusive). */ + Label start; + + /** End of the exception handler's scope (exclusive). */ + Label end; + + /** Beginning of the exception handler's code. */ + Label handler; + + /** + * Internal name of the type of exceptions handled by this handler, or <tt>null</tt> to catch any + * exceptions. + */ + String desc; + + /** + * Constant pool index of the internal name of the type of exceptions handled by this handler, or 0 to catch any + * exceptions. + */ + int type; + + /** Next exception handler block info. */ + Handler next; + + /** + * Removes the range between start and end from the given exception handlers. + * + * @param h an exception handler list. + * @param start the start of the range to be removed. + * @param end the end of the range to be removed. Maybe null. + * @return the exception handler list with the start-end range removed. + */ + static Handler remove(Handler h, Label start, Label end) { + if (h == null) { + return null; + } else { + h.next = remove(h.next, start, end); + } + int hstart = h.start.position; + int hend = h.end.position; + int s = start.position; + int e = end == null ? Integer.MAX_VALUE : end.position; + // if [hstart,hend[ and [s,e[ intervals intersect... + if (s < hend && e > hstart) { + if (s <= hstart) { + if (e >= hend) { + // [hstart,hend[ fully included in [s,e[, h removed + h = h.next; + } else { + // [hstart,hend[ minus [s,e[ = [e,hend[ + h.start = end; + } + } else if (e >= hend) { + // [hstart,hend[ minus [s,e[ = [hstart,s[ + h.end = start; + } else { + // [hstart,hend[ minus [s,e[ = [hstart,s[ + [e,hend[ + Handler g = new Handler(); + g.start = end; + g.end = h.end; + g.handler = h.handler; + g.desc = h.desc; + g.type = h.type; + g.next = h.next; + h.end = start; + h.next = g; + } + } + return h; + } +} diff --git a/src/main/java/org/redkale/asm/Item.java b/src/main/java/org/redkale/asm/Item.java index 453c71ca9..39a624a11 100644 --- a/src/main/java/org/redkale/asm/Item.java +++ b/src/main/java/org/redkale/asm/Item.java @@ -1,289 +1,289 @@ -/* - * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */ - -/* - * - * - * - * - * - * ASM: a very small and fast Java bytecode manipulation framework - * Copyright (c) 2000-2011 INRIA, France Telecom - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.redkale.asm; - -/** - * A constant pool item. Constant pool items can be created with the 'newXXX' methods in the {@link ClassWriter} class. - * - * @author Eric Bruneton - */ -final class Item { - - /** Index of this item in the constant pool. */ - int index; - - /** - * Type of this constant pool item. A single class is used to represent all constant pool item types, in order to - * minimize the bytecode size of this package. The value of this field is one of {@link ClassWriter#INT}, - * {@link ClassWriter#LONG}, {@link ClassWriter#FLOAT}, {@link ClassWriter#DOUBLE}, {@link ClassWriter#UTF8}, - * {@link ClassWriter#STR}, {@link ClassWriter#CLASS}, {@link ClassWriter#NAME_TYPE}, {@link ClassWriter#FIELD}, - * {@link ClassWriter#METH}, {@link ClassWriter#IMETH}, {@link ClassWriter#MODULE}, {@link ClassWriter#PACKAGE}, - * {@link ClassWriter#MTYPE}, {@link ClassWriter#INDY}. - * - *

MethodHandle constant 9 variations are stored using a range of 9 values from {@link ClassWriter#HANDLE_BASE} + - * 1 to {@link ClassWriter#HANDLE_BASE} + 9. - * - *

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

MethodHandle constant 9 variations are stored using a range of 9 values from {@link ClassWriter#HANDLE_BASE} + + * 1 to {@link ClassWriter#HANDLE_BASE} + 9. + * + *

Special Item types are used for Items that are stored in the ClassWriter {@link ClassWriter#typeTable}, + * instead of the constant pool, in order to avoid clashes with normal constant pool items in the ClassWriter + * constant pool's hash table. These special item types are {@link ClassWriter#TYPE_NORMAL}, + * {@link ClassWriter#TYPE_UNINIT} and {@link ClassWriter#TYPE_MERGED}. + */ + int type; + + /** Value of this item, for an integer item. */ + int intVal; + + /** Value of this item, for a long item. */ + long longVal; + + /** First part of the value of this item, for items that do not hold a primitive value. */ + String strVal1; + + /** Second part of the value of this item, for items that do not hold a primitive value. */ + String strVal2; + + /** Third part of the value of this item, for items that do not hold a primitive value. */ + String strVal3; + + /** The hash code value of this constant pool item. */ + int hashCode; + + /** Link to another constant pool item, used for collision lists in the constant pool's hash table. */ + Item next; + + /** Constructs an uninitialized {@link Item}. */ + Item() {} + + /** + * Constructs an uninitialized {@link Item} for constant pool element at given position. + * + * @param index index of the item to be constructed. + */ + Item(final int index) { + this.index = index; + } + + /** + * Constructs a copy of the given item. + * + * @param index index of the item to be constructed. + * @param i the item that must be copied into the item to be constructed. + */ + Item(final int index, final Item i) { + this.index = index; + type = i.type; + intVal = i.intVal; + longVal = i.longVal; + strVal1 = i.strVal1; + strVal2 = i.strVal2; + strVal3 = i.strVal3; + hashCode = i.hashCode; + } + + /** + * Sets this item to an integer item. + * + * @param intVal the value of this item. + */ + void set(final int intVal) { + this.type = ClassWriter.INT; + this.intVal = intVal; + this.hashCode = 0x7FFFFFFF & (type + intVal); + } + + /** + * Sets this item to a long item. + * + * @param longVal the value of this item. + */ + void set(final long longVal) { + this.type = ClassWriter.LONG; + this.longVal = longVal; + this.hashCode = 0x7FFFFFFF & (type + (int) longVal); + } + + /** + * Sets this item to a float item. + * + * @param floatVal the value of this item. + */ + void set(final float floatVal) { + this.type = ClassWriter.FLOAT; + this.intVal = Float.floatToRawIntBits(floatVal); + this.hashCode = 0x7FFFFFFF & (type + (int) floatVal); + } + + /** + * Sets this item to a double item. + * + * @param doubleVal the value of this item. + */ + void set(final double doubleVal) { + this.type = ClassWriter.DOUBLE; + this.longVal = Double.doubleToRawLongBits(doubleVal); + this.hashCode = 0x7FFFFFFF & (type + (int) doubleVal); + } + + /** + * Sets this item to an item that do not hold a primitive value. + * + * @param type the type of this item. + * @param strVal1 first part of the value of this item. + * @param strVal2 second part of the value of this item. + * @param strVal3 third part of the value of this item. + */ + @SuppressWarnings("fallthrough") + void set(final int type, final String strVal1, final String strVal2, final String strVal3) { + this.type = type; + this.strVal1 = strVal1; + this.strVal2 = strVal2; + this.strVal3 = strVal3; + switch (type) { + case ClassWriter.CLASS: + this.intVal = 0; // intVal of a class must be zero, see visitInnerClass + case ClassWriter.UTF8: + case ClassWriter.STR: + case ClassWriter.MTYPE: + case ClassWriter.MODULE: + case ClassWriter.PACKAGE: + case ClassWriter.TYPE_NORMAL: + hashCode = 0x7FFFFFFF & (type + strVal1.hashCode()); + return; + case ClassWriter.NAME_TYPE: { + hashCode = 0x7FFFFFFF & (type + strVal1.hashCode() * strVal2.hashCode()); + return; + } + // ClassWriter.FIELD: + // ClassWriter.METH: + // ClassWriter.IMETH: + // ClassWriter.HANDLE_BASE + 1..9 + default: + hashCode = 0x7FFFFFFF & (type + strVal1.hashCode() * strVal2.hashCode() * strVal3.hashCode()); + } + } + + /** + * Sets the item to an InvokeDynamic item. + * + * @param name invokedynamic's name. + * @param desc invokedynamic's desc. + * @param bsmIndex zero based index into the class attribute BootrapMethods. + */ + void set(String name, String desc, int bsmIndex) { + this.type = ClassWriter.INDY; + this.longVal = bsmIndex; + this.strVal1 = name; + this.strVal2 = desc; + this.hashCode = 0x7FFFFFFF & (ClassWriter.INDY + bsmIndex * strVal1.hashCode() * strVal2.hashCode()); + } + + /** + * Sets the item to a BootstrapMethod item. + * + * @param position position in byte in the class attribute BootrapMethods. + * @param hashCode hashcode of the item. This hashcode is processed from the hashcode of the bootstrap method and + * the hashcode of all bootstrap arguments. + */ + void set(int position, int hashCode) { + this.type = ClassWriter.BSM; + this.intVal = position; + this.hashCode = hashCode; + } + + /** + * Indicates if the given item is equal to this one. This method assumes that the two items have the same + * {@link #type}. + * + * @param i the item to be compared to this one. Both items must have the same {@link #type}. + * @return <tt>true</tt> if the given item if equal to this one, <tt>false</tt> + * otherwise. + */ + boolean isEqualTo(final Item i) { + switch (type) { + case ClassWriter.UTF8: + case ClassWriter.STR: + case ClassWriter.CLASS: + case ClassWriter.MODULE: + case ClassWriter.PACKAGE: + case ClassWriter.MTYPE: + case ClassWriter.TYPE_NORMAL: + return i.strVal1.equals(strVal1); + case ClassWriter.TYPE_MERGED: + case ClassWriter.LONG: + case ClassWriter.DOUBLE: + return i.longVal == longVal; + case ClassWriter.INT: + case ClassWriter.FLOAT: + return i.intVal == intVal; + case ClassWriter.TYPE_UNINIT: + return i.intVal == intVal && i.strVal1.equals(strVal1); + case ClassWriter.NAME_TYPE: + return i.strVal1.equals(strVal1) && i.strVal2.equals(strVal2); + case ClassWriter.INDY: { + return i.longVal == longVal && i.strVal1.equals(strVal1) && i.strVal2.equals(strVal2); + } + // case ClassWriter.FIELD: + // case ClassWriter.METH: + // case ClassWriter.IMETH: + // case ClassWriter.HANDLE_BASE + 1..9 + default: + return i.strVal1.equals(strVal1) && i.strVal2.equals(strVal2) && i.strVal3.equals(strVal3); + } + } +} diff --git a/src/main/java/org/redkale/asm/Label.java b/src/main/java/org/redkale/asm/Label.java index 04cc983ea..f2baeb3d0 100644 --- a/src/main/java/org/redkale/asm/Label.java +++ b/src/main/java/org/redkale/asm/Label.java @@ -1,509 +1,509 @@ -/* - * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */ - -/* - * - * - * - * - * - * ASM: a very small and fast Java bytecode manipulation framework - * Copyright (c) 2000-2011 INRIA, France Telecom - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.redkale.asm; - -/** - * A label represents a position in the bytecode of a method. Labels are used for jump, goto, and switch instructions, - * and for try catch blocks. A label designates the instruction that is just after. Note however that there can - * be other elements between a label and the instruction it designates (such as other labels, stack map frames, line - * numbers, etc.). - * - * @author Eric Bruneton - */ -public class Label { - - /** - * Indicates if this label is only used for debug attributes. Such a label is not the start of a basic block, the - * target of a jump instruction, or an exception handler. It can be safely ignored in control flow graph analysis - * algorithms (for optimization purposes). - */ - static final int DEBUG = 1; - - /** Indicates if the position of this label is known. */ - static final int RESOLVED = 2; - - /** Indicates if this label has been updated, after instruction resizing. */ - static final int RESIZED = 4; - - /** - * Indicates if this basic block has been pushed in the basic block stack. See {@link MethodWriter#visitMaxs - * visitMaxs}. - */ - static final int PUSHED = 8; - - /** Indicates if this label is the target of a jump instruction, or the start of an exception handler. */ - static final int TARGET = 16; - - /** Indicates if a stack map frame must be stored for this label. */ - static final int STORE = 32; - - /** Indicates if this label corresponds to a reachable basic block. */ - static final int REACHABLE = 64; - - /** Indicates if this basic block ends with a JSR instruction. */ - static final int JSR = 128; - - /** Indicates if this basic block ends with a RET instruction. */ - static final int RET = 256; - - /** Indicates if this basic block is the start of a subroutine. */ - static final int SUBROUTINE = 512; - - /** Indicates if this subroutine basic block has been visited by a visitSubroutine(null, ...) call. */ - static final int VISITED = 1024; - - /** Indicates if this subroutine basic block has been visited by a visitSubroutine(!null, ...) call. */ - static final int VISITED2 = 2048; - - /** - * Field used to associate user information to a label. Warning: this field is used by the ASM tree package. In - * order to use it with the ASM tree package you must override the - */ - public Object info; - - /** - * Flags that indicate the status of this label. - * - * @see #DEBUG - * @see #RESOLVED - * @see #RESIZED - * @see #PUSHED - * @see #TARGET - * @see #STORE - * @see #REACHABLE - * @see #JSR - * @see #RET - */ - int status; - - /** - * The line number corresponding to this label, if known. If there are several lines, each line is stored in a - * separate label, all linked via their next field (these links are created in ClassReader and removed just before - * visitLabel is called, so that this does not impact the rest of the code). - */ - int line; - - /** The position of this label in the code, if known. */ - int position; - - /** Number of forward references to this label, times two. */ - private int referenceCount; - - /** - * Informations about forward references. Each forward reference is described by two consecutive integers in this - * array: the first one is the position of the first byte of the bytecode instruction that contains the forward - * reference, while the second is the position of the first byte of the forward reference itself. In fact the sign - * of the first integer indicates if this reference uses 2 or 4 bytes, and its absolute value gives the position of - * the bytecode instruction. This array is also used as a bitset to store the subroutines to which a basic block - * belongs. This information is needed in {@linked MethodWriter#visitMaxs}, after all forward references have been - * resolved. Hence the same array can be used for both purposes without problems. - */ - private int[] srcAndRefPositions; - - // ------------------------------------------------------------------------ - - /* - * Fields for the control flow and data flow graph analysis algorithms (used - * to compute the maximum stack size or the stack map frames). A control - * flow graph contains one node per "basic block", and one edge per "jump" - * from one basic block to another. Each node (i.e., each basic block) is - * represented by the Label object that corresponds to the first instruction - * of this basic block. Each node also stores the list of its successors in - * the graph, as a linked list of Edge objects. - * - * The control flow analysis algorithms used to compute the maximum stack - * size or the stack map frames are similar and use two steps. The first - * step, during the visit of each instruction, builds information about the - * state of the local variables and the operand stack at the end of each - * basic block, called the "output frame", relatively to the frame - * state at the beginning of the basic block, which is called the "input - * frame", and which is unknown during this step. The second step, in - * {@link MethodWriter#visitMaxs}, is a fix point algorithm that computes - * information about the input frame of each basic block, from the input - * state of the first basic block (known from the method signature), and by - * the using the previously computed relative output frames. - * - * The algorithm used to compute the maximum stack size only computes the - * relative output and absolute input stack heights, while the algorithm - * used to compute stack map frames computes relative output frames and - * absolute input frames. - */ - - /** - * Start of the output stack relatively to the input stack. The exact semantics of this field depends on the - * algorithm that is used. - * - *

When only the maximum stack size is computed, this field is the number of elements in the input stack. - * - *

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

When only the maximum stack size is computed, this field is the number of elements in the input stack. + * + *

When the stack map frames are completely computed, this field is the offset of the first output stack element + * relatively to the top of the input stack. This offset is always negative or null. A null offset means that the + * output stack must be appended to the input stack. A -n offset means that the first n output stack elements must + * replace the top n input stack elements, and that the other elements must be appended to the input stack. + */ + int inputStackTop; + + /** + * Maximum height reached by the output stack, relatively to the top of the input stack. This maximum is always + * positive or null. + */ + int outputStackMax; + + /** + * Information about the input and output stack map frames of this basic block. This field is only used when + * {@link ClassWriter#COMPUTE_FRAMES} option is used. + */ + Frame frame; + + /** + * The successor of this label, in the order they are visited. This linked list does not include labels used for + * debug info only. If {@link ClassWriter#COMPUTE_FRAMES} option is used then, in addition, it does not contain + * successive labels that denote the same bytecode position (in this case only the first label appears in this + * list). + */ + Label successor; + + /** + * The successors of this node in the control flow graph. These successors are stored in a linked list of + * {@link Edge Edge} objects, linked to each other by their {@link Edge#next} field. + */ + Edge successors; + + /** + * The next basic block in the basic block stack. This stack is used in the main loop of the fix point algorithm + * used in the second step of the control flow analysis algorithms. It is also used in {@link #visitSubroutine} to + * avoid using a recursive method, and in ClassReader to temporarily store multiple source lines for a label. + * + * @see MethodWriter#visitMaxs + */ + Label next; + + // ------------------------------------------------------------------------ + // Constructor + // ------------------------------------------------------------------------ + + /** Constructs a new label. */ + public Label() { + // do nothing + } + + // ------------------------------------------------------------------------ + // Methods to compute offsets and to manage forward references + // ------------------------------------------------------------------------ + + /** + * Returns the offset corresponding to this label. This offset is computed from the start of the method's bytecode. + * This method is intended for {@link Attribute} sub classes, and is normally not needed by class generators or + * adapters. + * + * @return the offset corresponding to this label. + * @throws IllegalStateException if this label is not resolved yet. + */ + public int getOffset() { + if ((status & RESOLVED) == 0) { + throw new IllegalStateException("Label offset position has not been resolved yet"); + } + return position; + } + + /** + * Puts a reference to this label in the bytecode of a method. If the position of the label is known, the offset is + * computed and written directly. Otherwise, a null offset is written and a new forward reference is declared for + * this label. + * + * @param owner the code writer that calls this method. + * @param out the bytecode of the method. + * @param source the position of first byte of the bytecode instruction that contains this label. + * @param wideOffset <tt>true</tt> if the reference must be stored in 4 bytes, or + * <tt>false</tt> if it must be stored with 2 bytes. + * @throws IllegalArgumentException if this label has not been created by the given code writer. + */ + void put(final MethodWriter owner, final ByteVector out, final int source, final boolean wideOffset) { + if ((status & RESOLVED) == 0) { + if (wideOffset) { + addReference(-1 - source, out.length); + out.putInt(-1); + } else { + addReference(source, out.length); + out.putShort(-1); + } + } else { + if (wideOffset) { + out.putInt(position - source); + } else { + out.putShort(position - source); + } + } + } + + /** + * Adds a forward reference to this label. This method must be called only for a true forward reference, i.e. only + * if this label is not resolved yet. For backward references, the offset of the reference can be, and must be, + * computed and stored directly. + * + * @param sourcePosition the position of the referencing instruction. This position will be used to compute the + * offset of this forward reference. + * @param referencePosition the position where the offset for this forward reference must be stored. + */ + private void addReference(final int sourcePosition, final int referencePosition) { + if (srcAndRefPositions == null) { + srcAndRefPositions = new int[6]; + } + if (referenceCount >= srcAndRefPositions.length) { + int[] a = new int[srcAndRefPositions.length + 6]; + System.arraycopy(srcAndRefPositions, 0, a, 0, srcAndRefPositions.length); + srcAndRefPositions = a; + } + srcAndRefPositions[referenceCount++] = sourcePosition; + srcAndRefPositions[referenceCount++] = referencePosition; + } + + /** + * Resolves all forward references to this label. This method must be called when this label is added to the + * bytecode of the method, i.e. when its position becomes known. This method fills in the blanks that where left in + * the bytecode by each forward reference previously added to this label. + * + * @param owner the code writer that calls this method. + * @param position the position of this label in the bytecode. + * @param data the bytecode of the method. + * @return <tt>true</tt> if a blank that was left for this label was too small to store the offset. + * In such a case the corresponding jump instruction is replaced with a pseudo instruction (using unused + * opcodes) using an unsigned two bytes offset. These pseudo instructions will be replaced with standard + * bytecode instructions with wider offsets (4 bytes instead of 2), in ClassReader. + * @throws IllegalArgumentException if this label has already been resolved, or if it has not been created by the + * given code writer. + */ + boolean resolve(final MethodWriter owner, final int position, final byte[] data) { + boolean needUpdate = false; + this.status |= RESOLVED; + this.position = position; + int i = 0; + while (i < referenceCount) { + int source = srcAndRefPositions[i++]; + int reference = srcAndRefPositions[i++]; + int offset; + if (source >= 0) { + offset = position - source; + if (offset < Short.MIN_VALUE || offset > Short.MAX_VALUE) { + /* + * changes the opcode of the jump instruction, in order to + * be able to find it later (see resizeInstructions in + * MethodWriter). These temporary opcodes are similar to + * jump instruction opcodes, except that the 2 bytes offset + * is unsigned (and can therefore represent values from 0 to + * 65535, which is sufficient since the size of a method is + * limited to 65535 bytes). + */ + int opcode = data[reference - 1] & 0xFF; + if (opcode <= Opcodes.JSR) { + // changes IFEQ ... JSR to opcodes 202 to 217 + data[reference - 1] = (byte) (opcode + 49); + } else { + // changes IFNULL and IFNONNULL to opcodes 218 and 219 + data[reference - 1] = (byte) (opcode + 20); + } + needUpdate = true; + } + data[reference++] = (byte) (offset >>> 8); + data[reference] = (byte) offset; + } else { + offset = position + source + 1; + data[reference++] = (byte) (offset >>> 24); + data[reference++] = (byte) (offset >>> 16); + data[reference++] = (byte) (offset >>> 8); + data[reference] = (byte) offset; + } + } + return needUpdate; + } + + /** + * Returns the first label of the series to which this label belongs. For an isolated label or for the first label + * in a series of successive labels, this method returns the label itself. For other labels it returns the first + * label of the series. + * + * @return the first label of the series to which this label belongs. + */ + Label getFirst() { + return frame == null ? this : frame.owner; + } + + // ------------------------------------------------------------------------ + // Methods related to subroutines + // ------------------------------------------------------------------------ + + /** + * Returns true is this basic block belongs to the given subroutine. + * + * @param id a subroutine id. + * @return true is this basic block belongs to the given subroutine. + */ + boolean inSubroutine(final long id) { + if ((status & Label.VISITED) != 0) { + return (srcAndRefPositions[(int) (id >>> 32)] & (int) id) != 0; + } + return false; + } + + /** + * Returns true if this basic block and the given one belong to a common subroutine. + * + * @param block another basic block. + * @return true if this basic block and the given one belong to a common subroutine. + */ + boolean inSameSubroutine(final Label block) { + if ((status & VISITED) == 0 || (block.status & VISITED) == 0) { + return false; + } + for (int i = 0; i < srcAndRefPositions.length; ++i) { + if ((srcAndRefPositions[i] & block.srcAndRefPositions[i]) != 0) { + return true; + } + } + return false; + } + + /** + * Marks this basic block as belonging to the given subroutine. + * + * @param id a subroutine id. + * @param nbSubroutines the total number of subroutines in the method. + */ + void addToSubroutine(final long id, final int nbSubroutines) { + if ((status & VISITED) == 0) { + status |= VISITED; + srcAndRefPositions = new int[nbSubroutines / 32 + 1]; + } + srcAndRefPositions[(int) (id >>> 32)] |= (int) id; + } + + /** + * Finds the basic blocks that belong to a given subroutine, and marks these blocks as belonging to this subroutine. + * This method follows the control flow graph to find all the blocks that are reachable from the current block + * WITHOUT following any JSR target. + * + * @param JSR a JSR block that jumps to this subroutine. If this JSR is not null it is added to the successor of the + * RET blocks found in the subroutine. + * @param id the id of this subroutine. + * @param nbSubroutines the total number of subroutines in the method. + */ + void visitSubroutine(final Label JSR, final long id, final int nbSubroutines) { + // user managed stack of labels, to avoid using a recursive method + // (recursivity can lead to stack overflow with very large methods) + Label stack = this; + while (stack != null) { + // removes a label l from the stack + Label l = stack; + stack = l.next; + l.next = null; + + if (JSR != null) { + if ((l.status & VISITED2) != 0) { + continue; + } + l.status |= VISITED2; + // adds JSR to the successors of l, if it is a RET block + if ((l.status & RET) != 0) { + if (!l.inSameSubroutine(JSR)) { + Edge e = new Edge(); + e.info = l.inputStackTop; + e.successor = JSR.successors.successor; + e.next = l.successors; + l.successors = e; + } + } + } else { + // if the l block already belongs to subroutine 'id', continue + if (l.inSubroutine(id)) { + continue; + } + // marks the l block as belonging to subroutine 'id' + l.addToSubroutine(id, nbSubroutines); + } + // pushes each successor of l on the stack, except JSR targets + Edge e = l.successors; + while (e != null) { + // if the l block is a JSR block, then 'l.successors.next' leads + // to the JSR target (see {@link #visitJumpInsn}) and must + // therefore not be followed + if ((l.status & Label.JSR) == 0 || e != l.successors.next) { + // pushes e.successor on the stack if it not already added + if (e.successor.next == null) { + e.successor.next = stack; + stack = e.successor; + } + } + e = e.next; + } + } + } + + // ------------------------------------------------------------------------ + // Overriden Object methods + // ------------------------------------------------------------------------ + + /** + * Returns a string representation of this label. + * + * @return a string representation of this label. + */ + @Override + public String toString() { + return "L" + System.identityHashCode(this); + } +} diff --git a/src/main/java/org/redkale/asm/MethodVisitor.java b/src/main/java/org/redkale/asm/MethodVisitor.java index 4e2ccd310..b16206bd0 100644 --- a/src/main/java/org/redkale/asm/MethodVisitor.java +++ b/src/main/java/org/redkale/asm/MethodVisitor.java @@ -1,670 +1,670 @@ -/* - * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */ - -/* - * - * - * - * - * - * ASM: a very small and fast Java bytecode manipulation framework - * Copyright (c) 2000-2011 INRIA, France Telecom - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.redkale.asm; - -/** - * A visitor to visit a Java method. The methods of this class must be called in the following order: ( - * <tt>visitParameter</tt> )* [ <tt>visitAnnotationDefault</tt> ] ( - * <tt>visitAnnotation</tt> | <tt>visitParameterAnnotation</tt> - * <tt>visitTypeAnnotation</tt> | <tt>visitAttribute</tt> )* [ - * <tt>visitCode</tt> ( <tt>visitFrame</tt> | <tt>visitXInsn</tt> - * | <tt>visitLabel</tt> | <tt>visitInsnAnnotation</tt> | - * <tt>visitTryCatchBlock</tt> | <tt>visitTryCatchAnnotation</tt> | - * <tt>visitLocalVariable</tt> | <tt>visitLocalVariableAnnotation</tt> | - * <tt>visitLineNumber</tt> )* <tt>visitMaxs</tt> ] <tt>visitEnd</tt>. - * In addition, the <tt>visitXInsn</tt> and <tt>visitLabel</tt> methods must be - * called in the sequential order of the bytecode instructions of the visited code, - * <tt>visitInsnAnnotation</tt> must be called after the annotated instruction, - * <tt>visitTryCatchBlock</tt> must be called before the labels passed as arguments have been - * visited, <tt>visitTryCatchBlockAnnotation</tt> must be called after the corresponding try - * catch block has been visited, and the <tt>visitLocalVariable</tt>, - * <tt>visitLocalVariableAnnotation</tt> and <tt>visitLineNumber</tt> methods must be - * called after the labels passed as arguments have been visited. - * - * @author Eric Bruneton - */ -public abstract class MethodVisitor { - - /** - * The ASM API version implemented by this visitor. The value of this field must be one of {@link Opcodes#ASM4}, - * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. - */ - protected final int api; - - /** The method visitor to which this visitor must delegate method calls. May be null. */ - protected MethodVisitor mv; - - /** - * Constructs a new {@link MethodVisitor}. - * - * @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4}, - * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. - */ - public MethodVisitor(final int api) { - this(api, null); - } - - /** - * Constructs a new {@link MethodVisitor}. - * - * @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4}, - * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. - * @param mv the method visitor to which this visitor must delegate method calls. May be null. - */ - public MethodVisitor(final int api, final MethodVisitor mv) { - this.api = api; - this.mv = mv; - } - - // ------------------------------------------------------------------------- - // Parameters, annotations and non standard attributes - // ------------------------------------------------------------------------- - - /** - * Visits a parameter of this method. - * - * @param name parameter name or null if none is provided. - * @param access the parameter's access flags, only <tt>ACC_FINAL</tt>, - * <tt>ACC_SYNTHETIC</tt> or/and <tt>ACC_MANDATED</tt> are allowed (see - * {@link Opcodes}). - */ - public void visitParameter(String name, int access) { - if (mv != null) { - mv.visitParameter(name, access); - } - } - - /** - * Visits the default value of this annotation interface method. - * - * @return a visitor to the visit the actual default value of this annotation interface method, or - * <tt>null</tt> if this visitor is not interested in visiting this default value. The 'name' - * parameters passed to the methods of this annotation visitor are ignored. Moreover, exacly one visit method - * must be called on this annotation visitor, followed by visitEnd. - */ - public AnnotationVisitor visitAnnotationDefault() { - if (mv != null) { - return mv.visitAnnotationDefault(); - } - return null; - } - - /** - * Visits an annotation of this method. - * - * @param desc the class descriptor of the annotation class. - * @param visible <tt>true</tt> if the annotation is visible at runtime. - * @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not - * interested in visiting this annotation. - */ - public AnnotationVisitor visitAnnotation(String desc, boolean visible) { - if (mv != null) { - return mv.visitAnnotation(desc, visible); - } - return null; - } - - /** - * Visits an annotation on a type in the method signature. - * - * @param typeRef a reference to the annotated type. The sort of this type reference must be - * {@link TypeReference#METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER}, - * {@link TypeReference#METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND}, - * {@link TypeReference#METHOD_RETURN METHOD_RETURN}, {@link TypeReference#METHOD_RECEIVER METHOD_RECEIVER}, - * {@link TypeReference#METHOD_FORMAL_PARAMETER METHOD_FORMAL_PARAMETER} or {@link TypeReference#THROWS THROWS}. - * See {@link TypeReference}. - * @param typePath the path to the annotated type argument, wildcard bound, array element type, or static inner type - * within 'typeRef'. May be <tt>null</tt> if the annotation targets 'typeRef' as a whole. - * @param desc the class descriptor of the annotation class. - * @param visible <tt>true</tt> if the annotation is visible at runtime. - * @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not - * interested in visiting this annotation. - */ - public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) { - if (mv != null) { - return mv.visitTypeAnnotation(typeRef, typePath, desc, visible); - } - return null; - } - - /** - * Visits an annotation of a parameter this method. - * - * @param parameter the parameter index. - * @param desc the class descriptor of the annotation class. - * @param visible <tt>true</tt> if the annotation is visible at runtime. - * @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not - * interested in visiting this annotation. - */ - public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) { - if (mv != null) { - return mv.visitParameterAnnotation(parameter, desc, visible); - } - return null; - } - - /** - * Visits a non standard attribute of this method. - * - * @param attr an attribute. - */ - public void visitAttribute(Attribute attr) { - if (mv != null) { - mv.visitAttribute(attr); - } - } - - /** Starts the visit of the method's code, if any (i.e. non abstract method). */ - public void visitCode() { - if (mv != null) { - mv.visitCode(); - } - } - - /** - * Visits the current state of the local variables and operand stack elements. This method must(*) be called just - * before any instruction i that follows an unconditional branch instruction such as GOTO or THROW, that - * is the target of a jump instruction, or that starts an exception handler block. The visited types must describe - * the values of the local variables and of the operand stack elements just before i is executed.
- *
- * (*) this is mandatory only for classes whose version is greater than or equal to {@link Opcodes#V1_6 V1_6}.
- *
- * The frames of a method must be given either in expanded form, or in compressed form (all frames must use the same - * format, i.e. you must not mix expanded and compressed frames within a single method): - * - *

- * - *
- * In both cases the first frame, corresponding to the method's parameters and access flags, is implicit and must - * not be visited. Also, it is illegal to visit two or more frames for the same code location (i.e., at least one - * instruction must be visited between two calls to visitFrame). - * - * @param type the type of this stack map frame. Must be {@link Opcodes#F_NEW} for expanded frames, or - * {@link Opcodes#F_FULL}, {@link Opcodes#F_APPEND}, {@link Opcodes#F_CHOP}, {@link Opcodes#F_SAME} or - * {@link Opcodes#F_APPEND}, {@link Opcodes#F_SAME1} for compressed frames. - * @param nLocal the number of local variables in the visited frame. - * @param local the local variable types in this frame. This array must not be modified. Primitive types are - * represented by {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, {@link Opcodes#FLOAT}, {@link Opcodes#LONG}, - * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or {@link Opcodes#UNINITIALIZED_THIS} (long and double are - * represented by a single element). Reference types are represented by String objects (representing internal - * names), and uninitialized types by Label objects (this label designates the NEW instruction that created this - * uninitialized value). - * @param nStack the number of operand stack elements in the visited frame. - * @param stack the operand stack types in this frame. This array must not be modified. Its content has the same - * format as the "local" array. - * @throws IllegalStateException if a frame is visited just after another one, without any instruction between the - * two (unless this frame is a Opcodes#F_SAME frame, in which case it is silently ignored). - */ - public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) { - if (mv != null) { - mv.visitFrame(type, nLocal, local, nStack, stack); - } - } - - // ------------------------------------------------------------------------- - // Normal instructions - // ------------------------------------------------------------------------- - - /** - * Visits a zero operand instruction. - * - * @param opcode the opcode of the instruction to be visited. This opcode is either NOP, ACONST_NULL, ICONST_M1, - * ICONST_0, ICONST_1, ICONST_2, ICONST_3, ICONST_4, ICONST_5, LCONST_0, LCONST_1, FCONST_0, FCONST_1, FCONST_2, - * DCONST_0, DCONST_1, IALOAD, LALOAD, FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD, IASTORE, LASTORE, - * FASTORE, DASTORE, AASTORE, BASTORE, CASTORE, SASTORE, POP, POP2, DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1, DUP2_X2, - * SWAP, IADD, LADD, FADD, DADD, ISUB, LSUB, FSUB, DSUB, IMUL, LMUL, FMUL, DMUL, IDIV, LDIV, FDIV, DDIV, IREM, - * LREM, FREM, DREM, INEG, LNEG, FNEG, DNEG, ISHL, LSHL, ISHR, LSHR, IUSHR, LUSHR, IAND, LAND, IOR, LOR, IXOR, - * LXOR, I2L, I2F, I2D, L2I, L2F, L2D, F2I, F2L, F2D, D2I, D2L, D2F, I2B, I2C, I2S, LCMP, FCMPL, FCMPG, DCMPL, - * DCMPG, IRETURN, LRETURN, FRETURN, DRETURN, ARETURN, RETURN, ARRAYLENGTH, ATHROW, MONITORENTER, or - * MONITOREXIT. - */ - public void visitInsn(int opcode) { - if (mv != null) { - mv.visitInsn(opcode); - } - } - - /** - * Visits an instruction with a single int operand. - * - * @param opcode the opcode of the instruction to be visited. This opcode is either BIPUSH, SIPUSH or NEWARRAY. - * @param operand the operand of the instruction to be visited.
- * When opcode is BIPUSH, operand value should be between Byte.MIN_VALUE and Byte.MAX_VALUE.
- * When opcode is SIPUSH, operand value should be between Short.MIN_VALUE and Short.MAX_VALUE.
- * When opcode is NEWARRAY, operand value should be one of {@link Opcodes#T_BOOLEAN}, {@link Opcodes#T_CHAR}, - * {@link Opcodes#T_FLOAT}, {@link Opcodes#T_DOUBLE}, {@link Opcodes#T_BYTE}, {@link Opcodes#T_SHORT}, - * {@link Opcodes#T_INT} or {@link Opcodes#T_LONG}. - */ - public void visitIntInsn(int opcode, int operand) { - if (mv != null) { - mv.visitIntInsn(opcode, operand); - } - } - - /** - * Visits a local variable instruction. A local variable instruction is an instruction that loads or stores the - * value of a local variable. - * - * @param opcode the opcode of the local variable instruction to be visited. This opcode is either ILOAD, LLOAD, - * FLOAD, DLOAD, ALOAD, ISTORE, LSTORE, FSTORE, DSTORE, ASTORE or RET. - * @param var the operand of the instruction to be visited. This operand is the index of a local variable. - */ - public void visitVarInsn(int opcode, int var) { - if (mv != null) { - mv.visitVarInsn(opcode, var); - } - } - - /** - * Visits a type instruction. A type instruction is an instruction that takes the internal name of a class as - * parameter. - * - * @param opcode the opcode of the type instruction to be visited. This opcode is either NEW, ANEWARRAY, CHECKCAST - * or INSTANCEOF. - * @param type the operand of the instruction to be visited. This operand must be the internal name of an object or - * array class (see {@link Type#getInternalName() getInternalName}). - */ - public void visitTypeInsn(int opcode, String type) { - if (mv != null) { - mv.visitTypeInsn(opcode, type); - } - } - - /** - * Visits a field instruction. A field instruction is an instruction that loads or stores the value of a field of an - * object. - * - * @param opcode the opcode of the type instruction to be visited. This opcode is either GETSTATIC, PUTSTATIC, - * GETFIELD or PUTFIELD. - * @param owner the internal name of the field's owner class (see {@link Type#getInternalName() getInternalName}). - * @param name the field's name. - * @param desc the field's descriptor (see {@link Type Type}). - */ - public void visitFieldInsn(int opcode, String owner, String name, String desc) { - if (mv != null) { - mv.visitFieldInsn(opcode, owner, name, desc); - } - } - - /** - * Visits a method instruction. A method instruction is an instruction that invokes a method. - * - * @param opcode the opcode of the type instruction to be visited. This opcode is either INVOKEVIRTUAL, - * INVOKESPECIAL, INVOKESTATIC or INVOKEINTERFACE. - * @param owner the internal name of the method's owner class (see {@link Type#getInternalName() getInternalName}). - * @param name the method's name. - * @param desc the method's descriptor (see {@link Type Type}). - * @param itf if the method's owner class is an interface. - */ - public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { - if (mv != null) { - mv.visitMethodInsn(opcode, owner, name, desc, itf); - } - } - - /** - * Visits an invokedynamic instruction. - * - * @param name the method's name. - * @param desc the method's descriptor (see {@link Type Type}). - * @param bsm the bootstrap method. - * @param bsmArgs the bootstrap method constant arguments. Each argument must be an {@link Integer}, {@link Float}, - * {@link Long}, {@link Double}, {@link String}, {@link Type} or {@link Handle} value. This method is allowed to - * modify the content of the array so a caller should expect that this array may change. - */ - public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) { - if (mv != null) { - mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs); - } - } - - /** - * Visits a jump instruction. A jump instruction is an instruction that may jump to another instruction. - * - * @param opcode the opcode of the type instruction to be visited. This opcode is either IFEQ, IFNE, IFLT, IFGE, - * IFGT, IFLE, IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ACMPEQ, IF_ACMPNE, GOTO, - * JSR, IFNULL or IFNONNULL. - * @param label the operand of the instruction to be visited. This operand is a label that designates the - * instruction to which the jump instruction may jump. - */ - public void visitJumpInsn(int opcode, Label label) { - if (mv != null) { - mv.visitJumpInsn(opcode, label); - } - } - - /** - * Visits a label. A label designates the instruction that will be visited just after it. - * - * @param label a {@link Label Label} object. - */ - public void visitLabel(Label label) { - if (mv != null) { - mv.visitLabel(label); - } - } - - // ------------------------------------------------------------------------- - // Special instructions - // ------------------------------------------------------------------------- - - /** - * Visits a LDC instruction. Note that new constant types may be added in future versions of the Java Virtual - * Machine. To easily detect new constant types, implementations of this method should check for unexpected constant - * types, like this: - * - *
-     * if (cst instanceof Integer) {
-     *     // ...
-     * } else if (cst instanceof Float) {
-     *     // ...
-     * } else if (cst instanceof Long) {
-     *     // ...
-     * } else if (cst instanceof Double) {
-     *     // ...
-     * } else if (cst instanceof String) {
-     *     // ...
-     * } else if (cst instanceof Type) {
-     *     int sort = ((Type) cst).getSort();
-     *     if (sort == Type.OBJECT) {
-     *         // ...
-     *     } else if (sort == Type.ARRAY) {
-     *         // ...
-     *     } else if (sort == Type.METHOD) {
-     *         // ...
-     *     } else {
-     *         // throw an exception
-     *     }
-     * } else if (cst instanceof Handle) {
-     *     // ...
-     * } else {
-     *     // throw an exception
-     * }
-     * 
- * - * @param cst the constant to be loaded on the stack. This parameter must be a non null {@link Integer}, a - * {@link Float}, a {@link Long}, a {@link Double}, a {@link String}, a {@link Type} of OBJECT or ARRAY sort for - * <tt>.class</tt> constants, for classes whose version is 49.0, a {@link Type} of METHOD sort - * or a {@link Handle} for MethodType and MethodHandle constants, for classes whose version is 51.0. - */ - public void visitLdcInsn(Object cst) { - if (mv != null) { - mv.visitLdcInsn(cst); - } - } - - /** - * Visits an IINC instruction. - * - * @param var index of the local variable to be incremented. - * @param increment amount to increment the local variable by. - */ - public void visitIincInsn(int var, int increment) { - if (mv != null) { - mv.visitIincInsn(var, increment); - } - } - - /** - * Visits a TABLESWITCH instruction. - * - * @param min the minimum key value. - * @param max the maximum key value. - * @param dflt beginning of the default handler block. - * @param labels beginnings of the handler blocks. <tt>labels[i]</tt> is the beginning of the - * handler block for the <tt>min + i</tt> key. - */ - public void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels) { - if (mv != null) { - mv.visitTableSwitchInsn(min, max, dflt, labels); - } - } - - /** - * Visits a LOOKUPSWITCH instruction. - * - * @param dflt beginning of the default handler block. - * @param keys the values of the keys. - * @param labels beginnings of the handler blocks. <tt>labels[i]</tt> is the beginning of the - * handler block for the <tt>keys[i]</tt> key. - */ - public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) { - if (mv != null) { - mv.visitLookupSwitchInsn(dflt, keys, labels); - } - } - - /** - * Visits a MULTIANEWARRAY instruction. - * - * @param desc an array type descriptor (see {@link Type Type}). - * @param dims number of dimensions of the array to allocate. - */ - public void visitMultiANewArrayInsn(String desc, int dims) { - if (mv != null) { - mv.visitMultiANewArrayInsn(desc, dims); - } - } - - /** - * Visits an annotation on an instruction. This method must be called just after the annotated instruction. - * It can be called several times for the same instruction. - * - * @param typeRef a reference to the annotated type. The sort of this type reference must be - * {@link TypeReference#INSTANCEOF INSTANCEOF}, {@link TypeReference#NEW NEW}, - * {@link TypeReference#CONSTRUCTOR_REFERENCE CONSTRUCTOR_REFERENCE}, {@link TypeReference#METHOD_REFERENCE - * METHOD_REFERENCE}, {@link TypeReference#CAST CAST}, {@link TypeReference#CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT - * CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link TypeReference#METHOD_INVOCATION_TYPE_ARGUMENT - * METHOD_INVOCATION_TYPE_ARGUMENT}, {@link TypeReference#CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT - * CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or {@link TypeReference#METHOD_REFERENCE_TYPE_ARGUMENT - * METHOD_REFERENCE_TYPE_ARGUMENT}. See {@link TypeReference}. - * @param typePath the path to the annotated type argument, wildcard bound, array element type, or static inner type - * within 'typeRef'. May be <tt>null</tt> if the annotation targets 'typeRef' as a whole. - * @param desc the class descriptor of the annotation class. - * @param visible <tt>true</tt> if the annotation is visible at runtime. - * @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not - * interested in visiting this annotation. - */ - public AnnotationVisitor visitInsnAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) { - if (mv != null) { - return mv.visitInsnAnnotation(typeRef, typePath, desc, visible); - } - return null; - } - - // ------------------------------------------------------------------------- - // Exceptions table entries, debug information, max stack and max locals - // ------------------------------------------------------------------------- - - /** - * Visits a try catch block. - * - * @param start beginning of the exception handler's scope (inclusive). - * @param end end of the exception handler's scope (exclusive). - * @param handler beginning of the exception handler's code. - * @param type internal name of the type of exceptions handled by the handler, or <tt>null</tt> to - * catch any exceptions (for "finally" blocks). - * @throws IllegalArgumentException if one of the labels has already been visited by this visitor (by the - * {@link #visitLabel visitLabel} method). - */ - public void visitTryCatchBlock(Label start, Label end, Label handler, String type) { - if (mv != null) { - mv.visitTryCatchBlock(start, end, handler, type); - } - } - - /** - * Visits an annotation on an exception handler type. This method must be called after the - * {@link #visitTryCatchBlock} for the annotated exception handler. It can be called several times for the same - * exception handler. - * - * @param typeRef a reference to the annotated type. The sort of this type reference must be - * {@link TypeReference#EXCEPTION_PARAMETER EXCEPTION_PARAMETER}. See {@link TypeReference}. - * @param typePath the path to the annotated type argument, wildcard bound, array element type, or static inner type - * within 'typeRef'. May be <tt>null</tt> if the annotation targets 'typeRef' as a whole. - * @param desc the class descriptor of the annotation class. - * @param visible <tt>true</tt> if the annotation is visible at runtime. - * @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not - * interested in visiting this annotation. - */ - public AnnotationVisitor visitTryCatchAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) { - if (mv != null) { - return mv.visitTryCatchAnnotation(typeRef, typePath, desc, visible); - } - return null; - } - - /** - * Visits a local variable declaration. - * - * @param name the name of a local variable. - * @param desc the type descriptor of this local variable. - * @param signature the type signature of this local variable. May be <tt>null</tt> if the local - * variable type does not use generic types. - * @param start the first instruction corresponding to the scope of this local variable (inclusive). - * @param end the last instruction corresponding to the scope of this local variable (exclusive). - * @param index the local variable's index. - * @throws IllegalArgumentException if one of the labels has not already been visited by this visitor (by the - * {@link #visitLabel visitLabel} method). - */ - public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) { - if (mv != null) { - mv.visitLocalVariable(name, desc, signature, start, end, index); - } - } - - /** - * Visits an annotation on a local variable type. - * - * @param typeRef a reference to the annotated type. The sort of this type reference must be - * {@link TypeReference#LOCAL_VARIABLE LOCAL_VARIABLE} or {@link TypeReference#RESOURCE_VARIABLE - * RESOURCE_VARIABLE}. See {@link TypeReference}. - * @param typePath the path to the annotated type argument, wildcard bound, array element type, or static inner type - * within 'typeRef'. May be <tt>null</tt> if the annotation targets 'typeRef' as a whole. - * @param start the fist instructions corresponding to the continuous ranges that make the scope of this local - * variable (inclusive). - * @param end the last instructions corresponding to the continuous ranges that make the scope of this local - * variable (exclusive). This array must have the same size as the 'start' array. - * @param index the local variable's index in each range. This array must have the same size as the 'start' array. - * @param desc the class descriptor of the annotation class. - * @param visible <tt>true</tt> if the annotation is visible at runtime. - * @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not - * interested in visiting this annotation. - */ - public AnnotationVisitor visitLocalVariableAnnotation( - int typeRef, TypePath typePath, Label[] start, Label[] end, int[] index, String desc, boolean visible) { - if (mv != null) { - return mv.visitLocalVariableAnnotation(typeRef, typePath, start, end, index, desc, visible); - } - return null; - } - - /** - * Visits a line number declaration. - * - * @param line a line number. This number refers to the source file from which the class was compiled. - * @param start the first instruction corresponding to this line number. - * @throws IllegalArgumentException if <tt>start</tt> has not already been visited by this visitor - * (by the {@link #visitLabel visitLabel} method). - */ - public void visitLineNumber(int line, Label start) { - if (mv != null) { - mv.visitLineNumber(line, start); - } - } - - /** - * Visits the maximum stack size and the maximum number of local variables of the method. - * - * @param maxStack maximum stack size of the method. - * @param maxLocals maximum number of local variables for the method. - */ - public void visitMaxs(int maxStack, int maxLocals) { - if (mv != null) { - mv.visitMaxs(maxStack, maxLocals); - } - } - - /** - * Visits the end of the method. This method, which is the last one to be called, is used to inform the visitor that - * all the annotations and attributes of the method have been visited. - */ - public void visitEnd() { - if (mv != null) { - mv.visitEnd(); - } - } -} +/* + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ + +/* + * + * + * + * + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.redkale.asm; + +/** + * A visitor to visit a Java method. The methods of this class must be called in the following order: ( + * <tt>visitParameter</tt> )* [ <tt>visitAnnotationDefault</tt> ] ( + * <tt>visitAnnotation</tt> | <tt>visitParameterAnnotation</tt> + * <tt>visitTypeAnnotation</tt> | <tt>visitAttribute</tt> )* [ + * <tt>visitCode</tt> ( <tt>visitFrame</tt> | <tt>visitXInsn</tt> + * | <tt>visitLabel</tt> | <tt>visitInsnAnnotation</tt> | + * <tt>visitTryCatchBlock</tt> | <tt>visitTryCatchAnnotation</tt> | + * <tt>visitLocalVariable</tt> | <tt>visitLocalVariableAnnotation</tt> | + * <tt>visitLineNumber</tt> )* <tt>visitMaxs</tt> ] <tt>visitEnd</tt>. + * In addition, the <tt>visitXInsn</tt> and <tt>visitLabel</tt> methods must be + * called in the sequential order of the bytecode instructions of the visited code, + * <tt>visitInsnAnnotation</tt> must be called after the annotated instruction, + * <tt>visitTryCatchBlock</tt> must be called before the labels passed as arguments have been + * visited, <tt>visitTryCatchBlockAnnotation</tt> must be called after the corresponding try + * catch block has been visited, and the <tt>visitLocalVariable</tt>, + * <tt>visitLocalVariableAnnotation</tt> and <tt>visitLineNumber</tt> methods must be + * called after the labels passed as arguments have been visited. + * + * @author Eric Bruneton + */ +public abstract class MethodVisitor { + + /** + * The ASM API version implemented by this visitor. The value of this field must be one of {@link Opcodes#ASM4}, + * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. + */ + protected final int api; + + /** The method visitor to which this visitor must delegate method calls. May be null. */ + protected MethodVisitor mv; + + /** + * Constructs a new {@link MethodVisitor}. + * + * @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4}, + * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. + */ + public MethodVisitor(final int api) { + this(api, null); + } + + /** + * Constructs a new {@link MethodVisitor}. + * + * @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4}, + * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. + * @param mv the method visitor to which this visitor must delegate method calls. May be null. + */ + public MethodVisitor(final int api, final MethodVisitor mv) { + this.api = api; + this.mv = mv; + } + + // ------------------------------------------------------------------------- + // Parameters, annotations and non standard attributes + // ------------------------------------------------------------------------- + + /** + * Visits a parameter of this method. + * + * @param name parameter name or null if none is provided. + * @param access the parameter's access flags, only <tt>ACC_FINAL</tt>, + * <tt>ACC_SYNTHETIC</tt> or/and <tt>ACC_MANDATED</tt> are allowed (see + * {@link Opcodes}). + */ + public void visitParameter(String name, int access) { + if (mv != null) { + mv.visitParameter(name, access); + } + } + + /** + * Visits the default value of this annotation interface method. + * + * @return a visitor to the visit the actual default value of this annotation interface method, or + * <tt>null</tt> if this visitor is not interested in visiting this default value. The 'name' + * parameters passed to the methods of this annotation visitor are ignored. Moreover, exacly one visit method + * must be called on this annotation visitor, followed by visitEnd. + */ + public AnnotationVisitor visitAnnotationDefault() { + if (mv != null) { + return mv.visitAnnotationDefault(); + } + return null; + } + + /** + * Visits an annotation of this method. + * + * @param desc the class descriptor of the annotation class. + * @param visible <tt>true</tt> if the annotation is visible at runtime. + * @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not + * interested in visiting this annotation. + */ + public AnnotationVisitor visitAnnotation(String desc, boolean visible) { + if (mv != null) { + return mv.visitAnnotation(desc, visible); + } + return null; + } + + /** + * Visits an annotation on a type in the method signature. + * + * @param typeRef a reference to the annotated type. The sort of this type reference must be + * {@link TypeReference#METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER}, + * {@link TypeReference#METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND}, + * {@link TypeReference#METHOD_RETURN METHOD_RETURN}, {@link TypeReference#METHOD_RECEIVER METHOD_RECEIVER}, + * {@link TypeReference#METHOD_FORMAL_PARAMETER METHOD_FORMAL_PARAMETER} or {@link TypeReference#THROWS THROWS}. + * See {@link TypeReference}. + * @param typePath the path to the annotated type argument, wildcard bound, array element type, or static inner type + * within 'typeRef'. May be <tt>null</tt> if the annotation targets 'typeRef' as a whole. + * @param desc the class descriptor of the annotation class. + * @param visible <tt>true</tt> if the annotation is visible at runtime. + * @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not + * interested in visiting this annotation. + */ + public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) { + if (mv != null) { + return mv.visitTypeAnnotation(typeRef, typePath, desc, visible); + } + return null; + } + + /** + * Visits an annotation of a parameter this method. + * + * @param parameter the parameter index. + * @param desc the class descriptor of the annotation class. + * @param visible <tt>true</tt> if the annotation is visible at runtime. + * @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not + * interested in visiting this annotation. + */ + public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) { + if (mv != null) { + return mv.visitParameterAnnotation(parameter, desc, visible); + } + return null; + } + + /** + * Visits a non standard attribute of this method. + * + * @param attr an attribute. + */ + public void visitAttribute(Attribute attr) { + if (mv != null) { + mv.visitAttribute(attr); + } + } + + /** Starts the visit of the method's code, if any (i.e. non abstract method). */ + public void visitCode() { + if (mv != null) { + mv.visitCode(); + } + } + + /** + * Visits the current state of the local variables and operand stack elements. This method must(*) be called just + * before any instruction i that follows an unconditional branch instruction such as GOTO or THROW, that + * is the target of a jump instruction, or that starts an exception handler block. The visited types must describe + * the values of the local variables and of the operand stack elements just before i is executed.
+ *
+ * (*) this is mandatory only for classes whose version is greater than or equal to {@link Opcodes#V1_6 V1_6}.
+ *
+ * The frames of a method must be given either in expanded form, or in compressed form (all frames must use the same + * format, i.e. you must not mix expanded and compressed frames within a single method): + * + * + * + *
+ * In both cases the first frame, corresponding to the method's parameters and access flags, is implicit and must + * not be visited. Also, it is illegal to visit two or more frames for the same code location (i.e., at least one + * instruction must be visited between two calls to visitFrame). + * + * @param type the type of this stack map frame. Must be {@link Opcodes#F_NEW} for expanded frames, or + * {@link Opcodes#F_FULL}, {@link Opcodes#F_APPEND}, {@link Opcodes#F_CHOP}, {@link Opcodes#F_SAME} or + * {@link Opcodes#F_APPEND}, {@link Opcodes#F_SAME1} for compressed frames. + * @param nLocal the number of local variables in the visited frame. + * @param local the local variable types in this frame. This array must not be modified. Primitive types are + * represented by {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, {@link Opcodes#FLOAT}, {@link Opcodes#LONG}, + * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or {@link Opcodes#UNINITIALIZED_THIS} (long and double are + * represented by a single element). Reference types are represented by String objects (representing internal + * names), and uninitialized types by Label objects (this label designates the NEW instruction that created this + * uninitialized value). + * @param nStack the number of operand stack elements in the visited frame. + * @param stack the operand stack types in this frame. This array must not be modified. Its content has the same + * format as the "local" array. + * @throws IllegalStateException if a frame is visited just after another one, without any instruction between the + * two (unless this frame is a Opcodes#F_SAME frame, in which case it is silently ignored). + */ + public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) { + if (mv != null) { + mv.visitFrame(type, nLocal, local, nStack, stack); + } + } + + // ------------------------------------------------------------------------- + // Normal instructions + // ------------------------------------------------------------------------- + + /** + * Visits a zero operand instruction. + * + * @param opcode the opcode of the instruction to be visited. This opcode is either NOP, ACONST_NULL, ICONST_M1, + * ICONST_0, ICONST_1, ICONST_2, ICONST_3, ICONST_4, ICONST_5, LCONST_0, LCONST_1, FCONST_0, FCONST_1, FCONST_2, + * DCONST_0, DCONST_1, IALOAD, LALOAD, FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD, IASTORE, LASTORE, + * FASTORE, DASTORE, AASTORE, BASTORE, CASTORE, SASTORE, POP, POP2, DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1, DUP2_X2, + * SWAP, IADD, LADD, FADD, DADD, ISUB, LSUB, FSUB, DSUB, IMUL, LMUL, FMUL, DMUL, IDIV, LDIV, FDIV, DDIV, IREM, + * LREM, FREM, DREM, INEG, LNEG, FNEG, DNEG, ISHL, LSHL, ISHR, LSHR, IUSHR, LUSHR, IAND, LAND, IOR, LOR, IXOR, + * LXOR, I2L, I2F, I2D, L2I, L2F, L2D, F2I, F2L, F2D, D2I, D2L, D2F, I2B, I2C, I2S, LCMP, FCMPL, FCMPG, DCMPL, + * DCMPG, IRETURN, LRETURN, FRETURN, DRETURN, ARETURN, RETURN, ARRAYLENGTH, ATHROW, MONITORENTER, or + * MONITOREXIT. + */ + public void visitInsn(int opcode) { + if (mv != null) { + mv.visitInsn(opcode); + } + } + + /** + * Visits an instruction with a single int operand. + * + * @param opcode the opcode of the instruction to be visited. This opcode is either BIPUSH, SIPUSH or NEWARRAY. + * @param operand the operand of the instruction to be visited.
+ * When opcode is BIPUSH, operand value should be between Byte.MIN_VALUE and Byte.MAX_VALUE.
+ * When opcode is SIPUSH, operand value should be between Short.MIN_VALUE and Short.MAX_VALUE.
+ * When opcode is NEWARRAY, operand value should be one of {@link Opcodes#T_BOOLEAN}, {@link Opcodes#T_CHAR}, + * {@link Opcodes#T_FLOAT}, {@link Opcodes#T_DOUBLE}, {@link Opcodes#T_BYTE}, {@link Opcodes#T_SHORT}, + * {@link Opcodes#T_INT} or {@link Opcodes#T_LONG}. + */ + public void visitIntInsn(int opcode, int operand) { + if (mv != null) { + mv.visitIntInsn(opcode, operand); + } + } + + /** + * Visits a local variable instruction. A local variable instruction is an instruction that loads or stores the + * value of a local variable. + * + * @param opcode the opcode of the local variable instruction to be visited. This opcode is either ILOAD, LLOAD, + * FLOAD, DLOAD, ALOAD, ISTORE, LSTORE, FSTORE, DSTORE, ASTORE or RET. + * @param var the operand of the instruction to be visited. This operand is the index of a local variable. + */ + public void visitVarInsn(int opcode, int var) { + if (mv != null) { + mv.visitVarInsn(opcode, var); + } + } + + /** + * Visits a type instruction. A type instruction is an instruction that takes the internal name of a class as + * parameter. + * + * @param opcode the opcode of the type instruction to be visited. This opcode is either NEW, ANEWARRAY, CHECKCAST + * or INSTANCEOF. + * @param type the operand of the instruction to be visited. This operand must be the internal name of an object or + * array class (see {@link Type#getInternalName() getInternalName}). + */ + public void visitTypeInsn(int opcode, String type) { + if (mv != null) { + mv.visitTypeInsn(opcode, type); + } + } + + /** + * Visits a field instruction. A field instruction is an instruction that loads or stores the value of a field of an + * object. + * + * @param opcode the opcode of the type instruction to be visited. This opcode is either GETSTATIC, PUTSTATIC, + * GETFIELD or PUTFIELD. + * @param owner the internal name of the field's owner class (see {@link Type#getInternalName() getInternalName}). + * @param name the field's name. + * @param desc the field's descriptor (see {@link Type Type}). + */ + public void visitFieldInsn(int opcode, String owner, String name, String desc) { + if (mv != null) { + mv.visitFieldInsn(opcode, owner, name, desc); + } + } + + /** + * Visits a method instruction. A method instruction is an instruction that invokes a method. + * + * @param opcode the opcode of the type instruction to be visited. This opcode is either INVOKEVIRTUAL, + * INVOKESPECIAL, INVOKESTATIC or INVOKEINTERFACE. + * @param owner the internal name of the method's owner class (see {@link Type#getInternalName() getInternalName}). + * @param name the method's name. + * @param desc the method's descriptor (see {@link Type Type}). + * @param itf if the method's owner class is an interface. + */ + public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { + if (mv != null) { + mv.visitMethodInsn(opcode, owner, name, desc, itf); + } + } + + /** + * Visits an invokedynamic instruction. + * + * @param name the method's name. + * @param desc the method's descriptor (see {@link Type Type}). + * @param bsm the bootstrap method. + * @param bsmArgs the bootstrap method constant arguments. Each argument must be an {@link Integer}, {@link Float}, + * {@link Long}, {@link Double}, {@link String}, {@link Type} or {@link Handle} value. This method is allowed to + * modify the content of the array so a caller should expect that this array may change. + */ + public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) { + if (mv != null) { + mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs); + } + } + + /** + * Visits a jump instruction. A jump instruction is an instruction that may jump to another instruction. + * + * @param opcode the opcode of the type instruction to be visited. This opcode is either IFEQ, IFNE, IFLT, IFGE, + * IFGT, IFLE, IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ACMPEQ, IF_ACMPNE, GOTO, + * JSR, IFNULL or IFNONNULL. + * @param label the operand of the instruction to be visited. This operand is a label that designates the + * instruction to which the jump instruction may jump. + */ + public void visitJumpInsn(int opcode, Label label) { + if (mv != null) { + mv.visitJumpInsn(opcode, label); + } + } + + /** + * Visits a label. A label designates the instruction that will be visited just after it. + * + * @param label a {@link Label Label} object. + */ + public void visitLabel(Label label) { + if (mv != null) { + mv.visitLabel(label); + } + } + + // ------------------------------------------------------------------------- + // Special instructions + // ------------------------------------------------------------------------- + + /** + * Visits a LDC instruction. Note that new constant types may be added in future versions of the Java Virtual + * Machine. To easily detect new constant types, implementations of this method should check for unexpected constant + * types, like this: + * + *
+     * if (cst instanceof Integer) {
+     *     // ...
+     * } else if (cst instanceof Float) {
+     *     // ...
+     * } else if (cst instanceof Long) {
+     *     // ...
+     * } else if (cst instanceof Double) {
+     *     // ...
+     * } else if (cst instanceof String) {
+     *     // ...
+     * } else if (cst instanceof Type) {
+     *     int sort = ((Type) cst).getSort();
+     *     if (sort == Type.OBJECT) {
+     *         // ...
+     *     } else if (sort == Type.ARRAY) {
+     *         // ...
+     *     } else if (sort == Type.METHOD) {
+     *         // ...
+     *     } else {
+     *         // throw an exception
+     *     }
+     * } else if (cst instanceof Handle) {
+     *     // ...
+     * } else {
+     *     // throw an exception
+     * }
+     * 
+ * + * @param cst the constant to be loaded on the stack. This parameter must be a non null {@link Integer}, a + * {@link Float}, a {@link Long}, a {@link Double}, a {@link String}, a {@link Type} of OBJECT or ARRAY sort for + * <tt>.class</tt> constants, for classes whose version is 49.0, a {@link Type} of METHOD sort + * or a {@link Handle} for MethodType and MethodHandle constants, for classes whose version is 51.0. + */ + public void visitLdcInsn(Object cst) { + if (mv != null) { + mv.visitLdcInsn(cst); + } + } + + /** + * Visits an IINC instruction. + * + * @param var index of the local variable to be incremented. + * @param increment amount to increment the local variable by. + */ + public void visitIincInsn(int var, int increment) { + if (mv != null) { + mv.visitIincInsn(var, increment); + } + } + + /** + * Visits a TABLESWITCH instruction. + * + * @param min the minimum key value. + * @param max the maximum key value. + * @param dflt beginning of the default handler block. + * @param labels beginnings of the handler blocks. <tt>labels[i]</tt> is the beginning of the + * handler block for the <tt>min + i</tt> key. + */ + public void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels) { + if (mv != null) { + mv.visitTableSwitchInsn(min, max, dflt, labels); + } + } + + /** + * Visits a LOOKUPSWITCH instruction. + * + * @param dflt beginning of the default handler block. + * @param keys the values of the keys. + * @param labels beginnings of the handler blocks. <tt>labels[i]</tt> is the beginning of the + * handler block for the <tt>keys[i]</tt> key. + */ + public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) { + if (mv != null) { + mv.visitLookupSwitchInsn(dflt, keys, labels); + } + } + + /** + * Visits a MULTIANEWARRAY instruction. + * + * @param desc an array type descriptor (see {@link Type Type}). + * @param dims number of dimensions of the array to allocate. + */ + public void visitMultiANewArrayInsn(String desc, int dims) { + if (mv != null) { + mv.visitMultiANewArrayInsn(desc, dims); + } + } + + /** + * Visits an annotation on an instruction. This method must be called just after the annotated instruction. + * It can be called several times for the same instruction. + * + * @param typeRef a reference to the annotated type. The sort of this type reference must be + * {@link TypeReference#INSTANCEOF INSTANCEOF}, {@link TypeReference#NEW NEW}, + * {@link TypeReference#CONSTRUCTOR_REFERENCE CONSTRUCTOR_REFERENCE}, {@link TypeReference#METHOD_REFERENCE + * METHOD_REFERENCE}, {@link TypeReference#CAST CAST}, {@link TypeReference#CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT + * CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link TypeReference#METHOD_INVOCATION_TYPE_ARGUMENT + * METHOD_INVOCATION_TYPE_ARGUMENT}, {@link TypeReference#CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT + * CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or {@link TypeReference#METHOD_REFERENCE_TYPE_ARGUMENT + * METHOD_REFERENCE_TYPE_ARGUMENT}. See {@link TypeReference}. + * @param typePath the path to the annotated type argument, wildcard bound, array element type, or static inner type + * within 'typeRef'. May be <tt>null</tt> if the annotation targets 'typeRef' as a whole. + * @param desc the class descriptor of the annotation class. + * @param visible <tt>true</tt> if the annotation is visible at runtime. + * @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not + * interested in visiting this annotation. + */ + public AnnotationVisitor visitInsnAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) { + if (mv != null) { + return mv.visitInsnAnnotation(typeRef, typePath, desc, visible); + } + return null; + } + + // ------------------------------------------------------------------------- + // Exceptions table entries, debug information, max stack and max locals + // ------------------------------------------------------------------------- + + /** + * Visits a try catch block. + * + * @param start beginning of the exception handler's scope (inclusive). + * @param end end of the exception handler's scope (exclusive). + * @param handler beginning of the exception handler's code. + * @param type internal name of the type of exceptions handled by the handler, or <tt>null</tt> to + * catch any exceptions (for "finally" blocks). + * @throws IllegalArgumentException if one of the labels has already been visited by this visitor (by the + * {@link #visitLabel visitLabel} method). + */ + public void visitTryCatchBlock(Label start, Label end, Label handler, String type) { + if (mv != null) { + mv.visitTryCatchBlock(start, end, handler, type); + } + } + + /** + * Visits an annotation on an exception handler type. This method must be called after the + * {@link #visitTryCatchBlock} for the annotated exception handler. It can be called several times for the same + * exception handler. + * + * @param typeRef a reference to the annotated type. The sort of this type reference must be + * {@link TypeReference#EXCEPTION_PARAMETER EXCEPTION_PARAMETER}. See {@link TypeReference}. + * @param typePath the path to the annotated type argument, wildcard bound, array element type, or static inner type + * within 'typeRef'. May be <tt>null</tt> if the annotation targets 'typeRef' as a whole. + * @param desc the class descriptor of the annotation class. + * @param visible <tt>true</tt> if the annotation is visible at runtime. + * @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not + * interested in visiting this annotation. + */ + public AnnotationVisitor visitTryCatchAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) { + if (mv != null) { + return mv.visitTryCatchAnnotation(typeRef, typePath, desc, visible); + } + return null; + } + + /** + * Visits a local variable declaration. + * + * @param name the name of a local variable. + * @param desc the type descriptor of this local variable. + * @param signature the type signature of this local variable. May be <tt>null</tt> if the local + * variable type does not use generic types. + * @param start the first instruction corresponding to the scope of this local variable (inclusive). + * @param end the last instruction corresponding to the scope of this local variable (exclusive). + * @param index the local variable's index. + * @throws IllegalArgumentException if one of the labels has not already been visited by this visitor (by the + * {@link #visitLabel visitLabel} method). + */ + public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) { + if (mv != null) { + mv.visitLocalVariable(name, desc, signature, start, end, index); + } + } + + /** + * Visits an annotation on a local variable type. + * + * @param typeRef a reference to the annotated type. The sort of this type reference must be + * {@link TypeReference#LOCAL_VARIABLE LOCAL_VARIABLE} or {@link TypeReference#RESOURCE_VARIABLE + * RESOURCE_VARIABLE}. See {@link TypeReference}. + * @param typePath the path to the annotated type argument, wildcard bound, array element type, or static inner type + * within 'typeRef'. May be <tt>null</tt> if the annotation targets 'typeRef' as a whole. + * @param start the fist instructions corresponding to the continuous ranges that make the scope of this local + * variable (inclusive). + * @param end the last instructions corresponding to the continuous ranges that make the scope of this local + * variable (exclusive). This array must have the same size as the 'start' array. + * @param index the local variable's index in each range. This array must have the same size as the 'start' array. + * @param desc the class descriptor of the annotation class. + * @param visible <tt>true</tt> if the annotation is visible at runtime. + * @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not + * interested in visiting this annotation. + */ + public AnnotationVisitor visitLocalVariableAnnotation( + int typeRef, TypePath typePath, Label[] start, Label[] end, int[] index, String desc, boolean visible) { + if (mv != null) { + return mv.visitLocalVariableAnnotation(typeRef, typePath, start, end, index, desc, visible); + } + return null; + } + + /** + * Visits a line number declaration. + * + * @param line a line number. This number refers to the source file from which the class was compiled. + * @param start the first instruction corresponding to this line number. + * @throws IllegalArgumentException if <tt>start</tt> has not already been visited by this visitor + * (by the {@link #visitLabel visitLabel} method). + */ + public void visitLineNumber(int line, Label start) { + if (mv != null) { + mv.visitLineNumber(line, start); + } + } + + /** + * Visits the maximum stack size and the maximum number of local variables of the method. + * + * @param maxStack maximum stack size of the method. + * @param maxLocals maximum number of local variables for the method. + */ + public void visitMaxs(int maxStack, int maxLocals) { + if (mv != null) { + mv.visitMaxs(maxStack, maxLocals); + } + } + + /** + * Visits the end of the method. This method, which is the last one to be called, is used to inform the visitor that + * all the annotations and attributes of the method have been visited. + */ + public void visitEnd() { + if (mv != null) { + mv.visitEnd(); + } + } +} diff --git a/src/main/java/org/redkale/asm/MethodWriter.java b/src/main/java/org/redkale/asm/MethodWriter.java index b106d10a5..702094a90 100644 --- a/src/main/java/org/redkale/asm/MethodWriter.java +++ b/src/main/java/org/redkale/asm/MethodWriter.java @@ -1,2240 +1,2240 @@ -/* - * 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 {@link MethodVisitor} that generates methods in bytecode form. Each visit method of this class appends the bytecode - * corresponding to the visited instruction to a byte vector, in the order these methods are called. - * - * @author Eric Bruneton - * @author Eugene Kuleshov - */ -class MethodWriter extends MethodVisitor { - - /** Pseudo access flag used to denote constructors. */ - static final int ACC_CONSTRUCTOR = 0x80000; - - /** Frame has exactly the same locals as the previous stack map frame and number of stack items is zero. */ - static final int SAME_FRAME = 0; // to 63 (0-3f) - - /** Frame has exactly the same locals as the previous stack map frame and number of stack items is 1 */ - static final int SAME_LOCALS_1_STACK_ITEM_FRAME = 64; // to 127 (40-7f) - - /** Reserved for future use */ - static final int RESERVED = 128; - - /** - * Frame has exactly the same locals as the previous stack map frame and number of stack items is 1. Offset is - * bigger then 63; - */ - static final int SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED = 247; // f7 - - /** - * Frame where current locals are the same as the locals in the previous frame, except that the k last locals are - * absent. The value of k is given by the formula 251-frame_type. - */ - static final int CHOP_FRAME = 248; // to 250 (f8-fA) - - /** - * Frame has exactly the same locals as the previous stack map frame and number of stack items is zero. Offset is - * bigger then 63; - */ - static final int SAME_FRAME_EXTENDED = 251; // fb - - /** - * Frame where current locals are the same as the locals in the previous frame, except that k additional locals are - * defined. The value of k is given by the formula frame_type-251. - */ - static final int APPEND_FRAME = 252; // to 254 // fc-fe - - /** Full frame */ - static final int FULL_FRAME = 255; // ff - - /** - * Indicates that the stack map frames must be recomputed from scratch. In this case the maximum stack size and - * number of local variables is also recomputed from scratch. - * - * @see #compute - */ - static final int FRAMES = 0; - - /** - * Indicates that the stack map frames of type F_INSERT must be computed. The other frames are not (re)computed. - * They should all be of type F_NEW and should be sufficient to compute the content of the F_INSERT frames, together - * with the bytecode instructions between a F_NEW and a F_INSERT frame - and without any knowledge of the type - * hierarchy (by definition of F_INSERT). - * - * @see #compute - */ - static final int INSERTED_FRAMES = 1; - - /** - * Indicates that the maximum stack size and number of local variables must be automatically computed. - * - * @see #compute - */ - static final int MAXS = 2; - - /** - * Indicates that nothing must be automatically computed. - * - * @see #compute - */ - static final int NOTHING = 3; - - /** The class writer to which this method must be added. */ - final ClassWriter cw; - - /** Access flags of this method. */ - private int access; - - /** The index of the constant pool item that contains the name of this method. */ - private final int name; - - /** The index of the constant pool item that contains the descriptor of this method. */ - private final int desc; - - /** The descriptor of this method. */ - private final String descriptor; - - /** The signature of this method. */ - String signature; - - /** - * If not zero, indicates that the code of this method must be copied from the ClassReader associated to this writer - * in cw.cr. More precisely, this field gives the index of the first byte to copied from cw.cr.b - * . - */ - int classReaderOffset; - - /** - * If not zero, indicates that the code of this method must be copied from the ClassReader associated to this writer - * in cw.cr. More precisely, this field gives the number of bytes to copied from cw.cr.b. - */ - int classReaderLength; - - /** Number of exceptions that can be thrown by this method. */ - int exceptionCount; - - /** - * The exceptions that can be thrown by this method. More precisely, this array contains the indexes of the constant - * pool items that contain the internal names of these exception classes. - */ - int[] exceptions; - - /** The annotation default attribute of this method. May be <tt>null</tt>. */ - private ByteVector annd; - - /** The runtime visible annotations of this method. May be <tt>null</tt>. */ - private AnnotationWriter anns; - - /** The runtime invisible annotations of this method. May be <tt>null</tt>. */ - private AnnotationWriter ianns; - - /** The runtime visible type annotations of this method. May be <tt>null</tt> . */ - private AnnotationWriter tanns; - - /** The runtime invisible type annotations of this method. May be <tt>null</tt>. */ - private AnnotationWriter itanns; - - /** The runtime visible parameter annotations of this method. May be <tt>null</tt>. */ - private AnnotationWriter[] panns; - - /** The runtime invisible parameter annotations of this method. May be <tt>null</tt>. */ - private AnnotationWriter[] ipanns; - - /** The number of synthetic parameters of this method. */ - private int synthetics; - - /** The non standard attributes of the method. */ - private Attribute attrs; - - /** The bytecode of this method. */ - private ByteVector code = new ByteVector(); - - /** Maximum stack size of this method. */ - private int maxStack; - - /** Maximum number of local variables for this method. */ - private int maxLocals; - - /** Number of local variables in the current stack map frame. */ - private int currentLocals; - - /** Number of stack map frames in the StackMapTable attribute. */ - int frameCount; - - /** The StackMapTable attribute. */ - private ByteVector stackMap; - - /** The offset of the last frame that was written in the StackMapTable attribute. */ - private int previousFrameOffset; - - /** - * The last frame that was written in the StackMapTable attribute. - * - * @see #frame - */ - private int[] previousFrame; - - /** - * The current stack map frame. The first element contains the offset of the instruction to which the frame - * corresponds, the second element is the number of locals and the third one is the number of stack elements. The - * local variables start at index 3 and are followed by the operand stack values. In summary frame[0] = offset, - * frame[1] = nLocal, frame[2] = nStack, frame[3] = nLocal. All types are encoded as integers, with the same format - * as the one used in {@link Label}, but limited to BASE types. - */ - private int[] frame; - - /** Number of elements in the exception handler list. */ - private int handlerCount; - - /** The first element in the exception handler list. */ - private Handler firstHandler; - - /** The last element in the exception handler list. */ - private Handler lastHandler; - - /** Number of entries in the MethodParameters attribute. */ - private int methodParametersCount; - - /** The MethodParameters attribute. */ - private ByteVector methodParameters; - - /** Number of entries in the LocalVariableTable attribute. */ - private int localVarCount; - - /** The LocalVariableTable attribute. */ - private ByteVector localVar; - - /** Number of entries in the LocalVariableTypeTable attribute. */ - private int localVarTypeCount; - - /** The LocalVariableTypeTable attribute. */ - private ByteVector localVarType; - - /** Number of entries in the LineNumberTable attribute. */ - private int lineNumberCount; - - /** The LineNumberTable attribute. */ - private ByteVector lineNumber; - - /** The start offset of the last visited instruction. */ - private int lastCodeOffset; - - /** The runtime visible type annotations of the code. May be <tt>null</tt>. */ - private AnnotationWriter ctanns; - - /** The runtime invisible type annotations of the code. May be <tt>null</tt>. */ - private AnnotationWriter ictanns; - - /** The non standard attributes of the method's code. */ - private Attribute cattrs; - - /** The number of subroutines in this method. */ - private int subroutines; - - // ------------------------------------------------------------------------ - - /* - * Fields for the control flow graph analysis algorithm (used to compute the - * maximum stack size). A control flow graph contains one node per "basic - * block", and one edge per "jump" from one basic block to another. Each - * node (i.e., each basic block) is represented by the Label object that - * corresponds to the first instruction of this basic block. Each node also - * stores the list of its successors in the graph, as a linked list of Edge - * objects. - */ - - /** - * Indicates what must be automatically computed. - * - * @see #FRAMES - * @see #INSERTED_FRAMES - * @see #MAXS - * @see #NOTHING - */ - private final int compute; - - /** - * A list of labels. This list is the list of basic blocks in the method, i.e. a list of Label objects linked to - * each other by their {@link Label#successor} field, in the order they are visited by - * {@link MethodVisitor#visitLabel}, and starting with the first basic block. - */ - private Label labels; - - /** The previous basic block. */ - private Label previousBlock; - - /** The current basic block. */ - private Label currentBlock; - - /** - * The (relative) stack size after the last visited instruction. This size is relative to the beginning of the - * current basic block, i.e., the true stack size after the last visited instruction is equal to the - * {@link Label#inputStackTop beginStackSize} of the current basic block plus <tt>stackSize</tt>. - */ - private int stackSize; - - /** - * The (relative) maximum stack size after the last visited instruction. This size is relative to the beginning of - * the current basic block, i.e., the true maximum stack size after the last visited instruction is equal to the - * {@link Label#inputStackTop beginStackSize} of the current basic block plus <tt>stackSize</tt>. - */ - private int maxStackSize; - - // ------------------------------------------------------------------------ - // Constructor - // ------------------------------------------------------------------------ - - /** - * Constructs a new {@link MethodWriter}. - * - * @param cw the class writer in which the method must be added. - * @param access the method's access flags (see {@link Opcodes}). - * @param name the method's name. - * @param desc the method's descriptor (see {@link Type}). - * @param signature the method's signature. May be <tt>null</tt>. - * @param exceptions the internal names of the method's exceptions. May be <tt>null</tt>. - * @param compute Indicates what must be automatically computed (see #compute). - */ - MethodWriter( - final ClassWriter cw, - final int access, - final String name, - final String desc, - final String signature, - final String[] exceptions, - final int compute) { - super(Opcodes.ASM6); - if (cw.firstMethod == null) { - cw.firstMethod = this; - } else { - cw.lastMethod.mv = this; - } - cw.lastMethod = this; - this.cw = cw; - this.access = access; - if ("".equals(name)) { - this.access |= ACC_CONSTRUCTOR; - } - this.name = cw.newUTF8(name); - this.desc = cw.newUTF8(desc); - this.descriptor = desc; - this.signature = signature; - if (exceptions != null && exceptions.length > 0) { - exceptionCount = exceptions.length; - this.exceptions = new int[exceptionCount]; - for (int i = 0; i < exceptionCount; ++i) { - this.exceptions[i] = cw.newClass(exceptions[i]); - } - } - this.compute = compute; - if (compute != NOTHING) { - // updates maxLocals - int size = Type.getArgumentsAndReturnSizes(descriptor) >> 2; - if ((access & Opcodes.ACC_STATIC) != 0) { - --size; - } - maxLocals = size; - currentLocals = size; - // creates and visits the label for the first basic block - labels = new Label(); - labels.status |= Label.PUSHED; - visitLabel(labels); - } - } - - // ------------------------------------------------------------------------ - // Implementation of the MethodVisitor abstract class - // ------------------------------------------------------------------------ - - @Override - public void visitParameter(String name, int access) { - if (methodParameters == null) { - methodParameters = new ByteVector(); - } - ++methodParametersCount; - methodParameters.putShort((name == null) ? 0 : cw.newUTF8(name)).putShort(access); - } - - @Override - public AnnotationVisitor visitAnnotationDefault() { - annd = new ByteVector(); - return new AnnotationWriter(cw, false, annd, null, 0); - } - - @Override - public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) { - ByteVector bv = new ByteVector(); - // write type, and reserve space for values count - bv.putShort(cw.newUTF8(desc)).putShort(0); - AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2); - if (visible) { - aw.next = anns; - anns = aw; - } else { - aw.next = ianns; - ianns = aw; - } - return aw; - } - - @Override - public AnnotationVisitor visitTypeAnnotation( - final int typeRef, final TypePath typePath, final String desc, final boolean visible) { - ByteVector bv = new ByteVector(); - // write target_type and target_info - AnnotationWriter.putTarget(typeRef, typePath, bv); - // write type, and reserve space for values count - bv.putShort(cw.newUTF8(desc)).putShort(0); - AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, bv.length - 2); - if (visible) { - aw.next = tanns; - tanns = aw; - } else { - aw.next = itanns; - itanns = aw; - } - return aw; - } - - @Override - public AnnotationVisitor visitParameterAnnotation(final int parameter, final String desc, final boolean visible) { - ByteVector bv = new ByteVector(); - if ("Ljava/lang/Synthetic;".equals(desc)) { - // workaround for a bug in javac with synthetic parameters - // see ClassReader.readParameterAnnotations - synthetics = Math.max(synthetics, parameter + 1); - return new AnnotationWriter(cw, false, bv, null, 0); - } - // write type, and reserve space for values count - bv.putShort(cw.newUTF8(desc)).putShort(0); - AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2); - if (visible) { - if (panns == null) { - panns = new AnnotationWriter[Type.getArgumentTypes(descriptor).length]; - } - aw.next = panns[parameter]; - panns[parameter] = aw; - } else { - if (ipanns == null) { - ipanns = new AnnotationWriter[Type.getArgumentTypes(descriptor).length]; - } - aw.next = ipanns[parameter]; - ipanns[parameter] = aw; - } - return aw; - } - - @Override - public void visitAttribute(final Attribute attr) { - if (attr.isCodeAttribute()) { - attr.next = cattrs; - cattrs = attr; - } else { - attr.next = attrs; - attrs = attr; - } - } - - @Override - public void visitCode() { - // do nothing - } - - @Override - public void visitFrame( - final int type, final int nLocal, final Object[] local, final int nStack, final Object[] stack) { - if (compute == FRAMES) { - return; - } - - if (compute == INSERTED_FRAMES) { - if (currentBlock.frame == null) { - // This should happen only once, for the implicit first frame - // (which is explicitly visited in ClassReader if the - // EXPAND_ASM_INSNS option is used). - currentBlock.frame = new CurrentFrame(); - currentBlock.frame.owner = currentBlock; - currentBlock.frame.initInputFrame(cw, access, Type.getArgumentTypes(descriptor), nLocal); - visitImplicitFirstFrame(); - } else { - if (type == Opcodes.F_NEW) { - currentBlock.frame.set(cw, nLocal, local, nStack, stack); - } else { - // In this case type is equal to F_INSERT by hypothesis, and - // currentBlock.frame contains the stack map frame at the - // current instruction, computed from the last F_NEW frame - // and the bytecode instructions in between (via calls to - // CurrentFrame#execute). - } - visitFrame(currentBlock.frame); - } - } else if (type == Opcodes.F_NEW) { - if (previousFrame == null) { - visitImplicitFirstFrame(); - } - currentLocals = nLocal; - int frameIndex = startFrame(code.length, nLocal, nStack); - for (int i = 0; i < nLocal; ++i) { - if (local[i] instanceof String) { - String desc = Type.getObjectType((String) local[i]).getDescriptor(); - frame[frameIndex++] = Frame.type(cw, desc); - } else if (local[i] instanceof Integer) { - frame[frameIndex++] = Frame.BASE | ((Integer) local[i]).intValue(); - } else { - frame[frameIndex++] = - Frame.UNINITIALIZED | cw.addUninitializedType("", ((Label) local[i]).position); - } - } - for (int i = 0; i < nStack; ++i) { - if (stack[i] instanceof String) { - String desc = Type.getObjectType((String) stack[i]).getDescriptor(); - frame[frameIndex++] = Frame.type(cw, desc); - } else if (stack[i] instanceof Integer) { - frame[frameIndex++] = Frame.BASE | ((Integer) stack[i]).intValue(); - } else { - frame[frameIndex++] = - Frame.UNINITIALIZED | cw.addUninitializedType("", ((Label) stack[i]).position); - } - } - endFrame(); - } else { - int delta; - if (stackMap == null) { - stackMap = new ByteVector(); - delta = code.length; - } else { - delta = code.length - previousFrameOffset - 1; - if (delta < 0) { - if (type == Opcodes.F_SAME) { - return; - } else { - throw new IllegalStateException(); - } - } - } - - switch (type) { - case Opcodes.F_FULL: - currentLocals = nLocal; - stackMap.putByte(FULL_FRAME).putShort(delta).putShort(nLocal); - for (int i = 0; i < nLocal; ++i) { - writeFrameType(local[i]); - } - stackMap.putShort(nStack); - for (int i = 0; i < nStack; ++i) { - writeFrameType(stack[i]); - } - break; - case Opcodes.F_APPEND: - currentLocals += nLocal; - stackMap.putByte(SAME_FRAME_EXTENDED + nLocal).putShort(delta); - for (int i = 0; i < nLocal; ++i) { - writeFrameType(local[i]); - } - break; - case Opcodes.F_CHOP: - currentLocals -= nLocal; - stackMap.putByte(SAME_FRAME_EXTENDED - nLocal).putShort(delta); - break; - case Opcodes.F_SAME: - if (delta < 64) { - stackMap.putByte(delta); - } else { - stackMap.putByte(SAME_FRAME_EXTENDED).putShort(delta); - } - break; - case Opcodes.F_SAME1: - if (delta < 64) { - stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME + delta); - } else { - stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) - .putShort(delta); - } - writeFrameType(stack[0]); - break; - } - - previousFrameOffset = code.length; - ++frameCount; - } - - maxStack = Math.max(maxStack, nStack); - maxLocals = Math.max(maxLocals, currentLocals); - } - - @Override - public void visitInsn(final int opcode) { - lastCodeOffset = code.length; - // adds the instruction to the bytecode of the method - code.putByte(opcode); - // update currentBlock - // Label currentBlock = this.currentBlock; - if (currentBlock != null) { - if (compute == FRAMES || compute == INSERTED_FRAMES) { - currentBlock.frame.execute(opcode, 0, null, null); - } else { - // updates current and max stack sizes - int size = stackSize + Frame.SIZE[opcode]; - if (size > maxStackSize) { - maxStackSize = size; - } - stackSize = size; - } - // if opcode == ATHROW or xRETURN, ends current block (no successor) - if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN) || opcode == Opcodes.ATHROW) { - noSuccessor(); - } - } - } - - @Override - public void visitIntInsn(final int opcode, final int operand) { - lastCodeOffset = code.length; - // Label currentBlock = this.currentBlock; - if (currentBlock != null) { - if (compute == FRAMES || compute == INSERTED_FRAMES) { - currentBlock.frame.execute(opcode, operand, null, null); - } else if (opcode != Opcodes.NEWARRAY) { - // updates current and max stack sizes only for NEWARRAY - // (stack size variation = 0 for BIPUSH or SIPUSH) - int size = stackSize + 1; - if (size > maxStackSize) { - maxStackSize = size; - } - stackSize = size; - } - } - // adds the instruction to the bytecode of the method - if (opcode == Opcodes.SIPUSH) { - code.put12(opcode, operand); - } else { // BIPUSH or NEWARRAY - code.put11(opcode, operand); - } - } - - @Override - public void visitVarInsn(final int opcode, final int var) { - lastCodeOffset = code.length; - // Label currentBlock = this.currentBlock; - if (currentBlock != null) { - if (compute == FRAMES || compute == INSERTED_FRAMES) { - currentBlock.frame.execute(opcode, var, null, null); - } else { - // updates current and max stack sizes - if (opcode == Opcodes.RET) { - // no stack change, but end of current block (no successor) - currentBlock.status |= Label.RET; - // save 'stackSize' here for future use - // (see {@link #findSubroutineSuccessors}) - currentBlock.inputStackTop = stackSize; - noSuccessor(); - } else { // xLOAD or xSTORE - int size = stackSize + Frame.SIZE[opcode]; - if (size > maxStackSize) { - maxStackSize = size; - } - stackSize = size; - } - } - } - if (compute != NOTHING) { - // updates max locals - int n; - if (opcode == Opcodes.LLOAD - || opcode == Opcodes.DLOAD - || opcode == Opcodes.LSTORE - || opcode == Opcodes.DSTORE) { - n = var + 2; - } else { - n = var + 1; - } - if (n > maxLocals) { - maxLocals = n; - } - } - // adds the instruction to the bytecode of the method - if (var < 4 && opcode != Opcodes.RET) { - int opt; - if (opcode < Opcodes.ISTORE) { - /* ILOAD_0 */ - opt = 26 + ((opcode - Opcodes.ILOAD) << 2) + var; - } else { - /* ISTORE_0 */ - opt = 59 + ((opcode - Opcodes.ISTORE) << 2) + var; - } - code.putByte(opt); - } else if (var >= 256) { - code.putByte(196 /* WIDE */).put12(opcode, var); - } else { - code.put11(opcode, var); - } - if (opcode >= Opcodes.ISTORE && compute == FRAMES && handlerCount > 0) { - visitLabel(new Label()); - } - } - - @Override - public void visitTypeInsn(final int opcode, final String type) { - lastCodeOffset = code.length; - Item i = cw.newStringishItem(ClassWriter.CLASS, type); - // Label currentBlock = this.currentBlock; - if (currentBlock != null) { - if (compute == FRAMES || compute == INSERTED_FRAMES) { - currentBlock.frame.execute(opcode, code.length, cw, i); - } else if (opcode == Opcodes.NEW) { - // updates current and max stack sizes only if opcode == NEW - // (no stack change for ANEWARRAY, CHECKCAST, INSTANCEOF) - int size = stackSize + 1; - if (size > maxStackSize) { - maxStackSize = size; - } - stackSize = size; - } - } - // adds the instruction to the bytecode of the method - code.put12(opcode, i.index); - } - - @Override - public void visitFieldInsn(final int opcode, final String owner, final String name, final String desc) { - lastCodeOffset = code.length; - Item i = cw.newFieldItem(owner, name, desc); - // Label currentBlock = this.currentBlock; - if (currentBlock != null) { - if (compute == FRAMES || compute == INSERTED_FRAMES) { - currentBlock.frame.execute(opcode, 0, cw, i); - } else { - int size; - // computes the stack size variation - char c = desc.charAt(0); - switch (opcode) { - case Opcodes.GETSTATIC: - size = stackSize + (c == 'D' || c == 'J' ? 2 : 1); - break; - case Opcodes.PUTSTATIC: - size = stackSize + (c == 'D' || c == 'J' ? -2 : -1); - break; - case Opcodes.GETFIELD: - size = stackSize + (c == 'D' || c == 'J' ? 1 : 0); - break; - // case Constants.PUTFIELD: - default: - size = stackSize + (c == 'D' || c == 'J' ? -3 : -2); - break; - } - // updates current and max stack sizes - if (size > maxStackSize) { - maxStackSize = size; - } - stackSize = size; - } - } - // adds the instruction to the bytecode of the method - code.put12(opcode, i.index); - } - - @Override - public void visitMethodInsn( - final int opcode, final String owner, final String name, final String desc, final boolean itf) { - lastCodeOffset = code.length; - Item i = cw.newMethodItem(owner, name, desc, itf); - int argSize = i.intVal; - // Label currentBlock = this.currentBlock; - if (currentBlock != null) { - if (compute == FRAMES || compute == INSERTED_FRAMES) { - currentBlock.frame.execute(opcode, 0, cw, i); - } else { - /* - * computes the stack size variation. In order not to recompute - * several times this variation for the same Item, we use the - * intVal field of this item to store this variation, once it - * has been computed. More precisely this intVal field stores - * the sizes of the arguments and of the return value - * corresponding to desc. - */ - if (argSize == 0) { - // the above sizes have not been computed yet, - // so we compute them... - argSize = Type.getArgumentsAndReturnSizes(desc); - // ... and we save them in order - // not to recompute them in the future - i.intVal = argSize; - } - int size; - if (opcode == Opcodes.INVOKESTATIC) { - size = stackSize - (argSize >> 2) + (argSize & 0x03) + 1; - } else { - size = stackSize - (argSize >> 2) + (argSize & 0x03); - } - // updates current and max stack sizes - if (size > maxStackSize) { - maxStackSize = size; - } - stackSize = size; - } - } - // adds the instruction to the bytecode of the method - if (opcode == Opcodes.INVOKEINTERFACE) { - if (argSize == 0) { - argSize = Type.getArgumentsAndReturnSizes(desc); - i.intVal = argSize; - } - code.put12(Opcodes.INVOKEINTERFACE, i.index).put11(argSize >> 2, 0); - } else { - code.put12(opcode, i.index); - } - } - - @Override - public void visitInvokeDynamicInsn( - final String name, final String desc, final Handle bsm, final Object... bsmArgs) { - lastCodeOffset = code.length; - Item i = cw.newInvokeDynamicItem(name, desc, bsm, bsmArgs); - int argSize = i.intVal; - // Label currentBlock = this.currentBlock; - if (currentBlock != null) { - if (compute == FRAMES || compute == INSERTED_FRAMES) { - currentBlock.frame.execute(Opcodes.INVOKEDYNAMIC, 0, cw, i); - } else { - /* - * computes the stack size variation. In order not to recompute - * several times this variation for the same Item, we use the - * intVal field of this item to store this variation, once it - * has been computed. More precisely this intVal field stores - * the sizes of the arguments and of the return value - * corresponding to desc. - */ - if (argSize == 0) { - // the above sizes have not been computed yet, - // so we compute them... - argSize = Type.getArgumentsAndReturnSizes(desc); - // ... and we save them in order - // not to recompute them in the future - i.intVal = argSize; - } - int size = stackSize - (argSize >> 2) + (argSize & 0x03) + 1; - - // updates current and max stack sizes - if (size > maxStackSize) { - maxStackSize = size; - } - stackSize = size; - } - } - // adds the instruction to the bytecode of the method - code.put12(Opcodes.INVOKEDYNAMIC, i.index); - code.putShort(0); - } - - @Override - public void visitJumpInsn(int opcode, final Label label) { - boolean isWide = opcode >= 200; // GOTO_W - opcode = isWide ? opcode - 33 : opcode; - lastCodeOffset = code.length; - Label nextInsn = null; - // Label currentBlock = this.currentBlock; - if (currentBlock != null) { - if (compute == FRAMES) { - currentBlock.frame.execute(opcode, 0, null, null); - // 'label' is the target of a jump instruction - label.getFirst().status |= Label.TARGET; - // adds 'label' as a successor of this basic block - addSuccessor(Edge.NORMAL, label); - if (opcode != Opcodes.GOTO) { - // creates a Label for the next basic block - nextInsn = new Label(); - } - } else if (compute == INSERTED_FRAMES) { - currentBlock.frame.execute(opcode, 0, null, null); - } else { - if (opcode == Opcodes.JSR) { - if ((label.status & Label.SUBROUTINE) == 0) { - label.status |= Label.SUBROUTINE; - ++subroutines; - } - currentBlock.status |= Label.JSR; - addSuccessor(stackSize + 1, label); - // creates a Label for the next basic block - nextInsn = new Label(); - /* - * note that, by construction in this method, a JSR block - * has at least two successors in the control flow graph: - * the first one leads the next instruction after the JSR, - * while the second one leads to the JSR target. - */ - } else { - // updates current stack size (max stack size unchanged - // because stack size variation always negative in this - // case) - stackSize += Frame.SIZE[opcode]; - addSuccessor(stackSize, label); - } - } - } - // adds the instruction to the bytecode of the method - if ((label.status & Label.RESOLVED) != 0 && label.position - code.length < Short.MIN_VALUE) { - /* - * case of a backward jump with an offset < -32768. In this case we - * automatically replace GOTO with GOTO_W, JSR with JSR_W and IFxxx - * with IFNOTxxx GOTO_W L:..., where IFNOTxxx is the - * "opposite" opcode of IFxxx (i.e., IFNE for IFEQ) and where - * designates the instruction just after the GOTO_W. - */ - if (opcode == Opcodes.GOTO) { - code.putByte(200); // GOTO_W - } else if (opcode == Opcodes.JSR) { - code.putByte(201); // JSR_W - } else { - // if the IF instruction is transformed into IFNOT GOTO_W the - // next instruction becomes the target of the IFNOT instruction - if (nextInsn != null) { - nextInsn.status |= Label.TARGET; - } - code.putByte(opcode <= 166 ? ((opcode + 1) ^ 1) - 1 : opcode ^ 1); - code.putShort(8); // jump offset - // ASM pseudo GOTO_W insn, see ClassReader. We don't use a real - // GOTO_W because we might need to insert a frame just after (as - // the target of the IFNOTxxx jump instruction). - code.putByte(220); - cw.hasAsmInsns = true; - } - label.put(this, code, code.length - 1, true); - } else if (isWide) { - /* - * case of a GOTO_W or JSR_W specified by the user (normally - * ClassReader when used to resize instructions). In this case we - * keep the original instruction. - */ - code.putByte(opcode + 33); - label.put(this, code, code.length - 1, true); - } else { - /* - * case of a backward jump with an offset >= -32768, or of a forward - * jump with, of course, an unknown offset. In these cases we store - * the offset in 2 bytes (which will be increased in - * resizeInstructions, if needed). - */ - code.putByte(opcode); - label.put(this, code, code.length - 1, false); - } - if (currentBlock != null) { - if (nextInsn != null) { - // if the jump instruction is not a GOTO, the next instruction - // is also a successor of this instruction. Calling visitLabel - // adds the label of this next instruction as a successor of the - // current block, and starts a new basic block - visitLabel(nextInsn); - } - if (opcode == Opcodes.GOTO) { - noSuccessor(); - } - } - } - - @Override - public void visitLabel(final Label label) { - // resolves previous forward references to label, if any - cw.hasAsmInsns |= label.resolve(this, code.length, code.data); - // updates currentBlock - if ((label.status & Label.DEBUG) != 0) { - return; - } - if (compute == FRAMES) { - if (currentBlock != null) { - if (label.position == currentBlock.position) { - // successive labels, do not start a new basic block - currentBlock.status |= (label.status & Label.TARGET); - label.frame = currentBlock.frame; - return; - } - // ends current block (with one new successor) - addSuccessor(Edge.NORMAL, label); - } - // begins a new current block - currentBlock = label; - if (label.frame == null) { - label.frame = new Frame(); - label.frame.owner = label; - } - // updates the basic block list - if (previousBlock != null) { - if (label.position == previousBlock.position) { - previousBlock.status |= (label.status & Label.TARGET); - label.frame = previousBlock.frame; - currentBlock = previousBlock; - return; - } - previousBlock.successor = label; - } - previousBlock = label; - } else if (compute == INSERTED_FRAMES) { - if (currentBlock == null) { - // This case should happen only once, for the visitLabel call in - // the constructor. Indeed, if compute is equal to - // INSERTED_FRAMES currentBlock can not be set back to null (see - // #noSuccessor). - currentBlock = label; - } else { - // Updates the frame owner so that a correct frame offset is - // computed in visitFrame(Frame). - currentBlock.frame.owner = label; - } - } else if (compute == MAXS) { - if (currentBlock != null) { - // ends current block (with one new successor) - currentBlock.outputStackMax = maxStackSize; - addSuccessor(stackSize, label); - } - // begins a new current block - currentBlock = label; - // resets the relative current and max stack sizes - stackSize = 0; - maxStackSize = 0; - // updates the basic block list - if (previousBlock != null) { - previousBlock.successor = label; - } - previousBlock = label; - } - } - - @Override - public void visitLdcInsn(final Object cst) { - lastCodeOffset = code.length; - Item i = cw.newConstItem(cst); - // Label currentBlock = this.currentBlock; - if (currentBlock != null) { - if (compute == FRAMES || compute == INSERTED_FRAMES) { - currentBlock.frame.execute(Opcodes.LDC, 0, cw, i); - } else { - int size; - // computes the stack size variation - if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) { - size = stackSize + 2; - } else { - size = stackSize + 1; - } - // updates current and max stack sizes - if (size > maxStackSize) { - maxStackSize = size; - } - stackSize = size; - } - } - // adds the instruction to the bytecode of the method - int index = i.index; - if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) { - code.put12(20 /* LDC2_W */, index); - } else if (index >= 256) { - code.put12(19 /* LDC_W */, index); - } else { - code.put11(Opcodes.LDC, index); - } - } - - @Override - public void visitIincInsn(final int var, final int increment) { - lastCodeOffset = code.length; - if (currentBlock != null) { - if (compute == FRAMES || compute == INSERTED_FRAMES) { - currentBlock.frame.execute(Opcodes.IINC, var, null, null); - } - } - if (compute != NOTHING) { - // updates max locals - int n = var + 1; - if (n > maxLocals) { - maxLocals = n; - } - } - // adds the instruction to the bytecode of the method - if ((var > 255) || (increment > 127) || (increment < -128)) { - code.putByte(196 /* WIDE */).put12(Opcodes.IINC, var).putShort(increment); - } else { - code.putByte(Opcodes.IINC).put11(var, increment); - } - } - - @Override - public void visitTableSwitchInsn(final int min, final int max, final Label dflt, final Label... labels) { - lastCodeOffset = code.length; - // adds the instruction to the bytecode of the method - int source = code.length; - code.putByte(Opcodes.TABLESWITCH); - code.putByteArray(null, 0, (4 - code.length % 4) % 4); - dflt.put(this, code, source, true); - code.putInt(min).putInt(max); - for (int i = 0; i < labels.length; ++i) { - labels[i].put(this, code, source, true); - } - // updates currentBlock - visitSwitchInsn(dflt, labels); - } - - @Override - public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) { - lastCodeOffset = code.length; - // adds the instruction to the bytecode of the method - int source = code.length; - code.putByte(Opcodes.LOOKUPSWITCH); - code.putByteArray(null, 0, (4 - code.length % 4) % 4); - dflt.put(this, code, source, true); - code.putInt(labels.length); - for (int i = 0; i < labels.length; ++i) { - code.putInt(keys[i]); - labels[i].put(this, code, source, true); - } - // updates currentBlock - visitSwitchInsn(dflt, labels); - } - - private void visitSwitchInsn(final Label dflt, final Label[] labels) { - // Label currentBlock = this.currentBlock; - if (currentBlock != null) { - if (compute == FRAMES) { - currentBlock.frame.execute(Opcodes.LOOKUPSWITCH, 0, null, null); - // adds current block successors - addSuccessor(Edge.NORMAL, dflt); - dflt.getFirst().status |= Label.TARGET; - for (int i = 0; i < labels.length; ++i) { - addSuccessor(Edge.NORMAL, labels[i]); - labels[i].getFirst().status |= Label.TARGET; - } - } else { - // updates current stack size (max stack size unchanged) - --stackSize; - // adds current block successors - addSuccessor(stackSize, dflt); - for (int i = 0; i < labels.length; ++i) { - addSuccessor(stackSize, labels[i]); - } - } - // ends current block - noSuccessor(); - } - } - - @Override - public void visitMultiANewArrayInsn(final String desc, final int dims) { - lastCodeOffset = code.length; - Item i = cw.newStringishItem(ClassWriter.CLASS, desc); - // Label currentBlock = this.currentBlock; - if (currentBlock != null) { - if (compute == FRAMES || compute == INSERTED_FRAMES) { - currentBlock.frame.execute(Opcodes.MULTIANEWARRAY, dims, cw, i); - } else { - // updates current stack size (max stack size unchanged because - // stack size variation always negative or null) - stackSize += 1 - dims; - } - } - // adds the instruction to the bytecode of the method - code.put12(Opcodes.MULTIANEWARRAY, i.index).putByte(dims); - } - - @Override - public AnnotationVisitor visitInsnAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) { - ByteVector bv = new ByteVector(); - // write target_type and target_info - typeRef = (typeRef & 0xFF0000FF) | (lastCodeOffset << 8); - AnnotationWriter.putTarget(typeRef, typePath, bv); - // write type, and reserve space for values count - bv.putShort(cw.newUTF8(desc)).putShort(0); - AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, bv.length - 2); - if (visible) { - aw.next = ctanns; - ctanns = aw; - } else { - aw.next = ictanns; - ictanns = aw; - } - return aw; - } - - @Override - public void visitTryCatchBlock(final Label start, final Label end, final Label handler, final String type) { - ++handlerCount; - Handler h = new Handler(); - h.start = start; - h.end = end; - h.handler = handler; - h.desc = type; - h.type = type != null ? cw.newClass(type) : 0; - if (lastHandler == null) { - firstHandler = h; - } else { - lastHandler.next = h; - } - lastHandler = h; - } - - @Override - public AnnotationVisitor visitTryCatchAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) { - ByteVector bv = new ByteVector(); - // write target_type and target_info - AnnotationWriter.putTarget(typeRef, typePath, bv); - // write type, and reserve space for values count - bv.putShort(cw.newUTF8(desc)).putShort(0); - AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, bv.length - 2); - if (visible) { - aw.next = ctanns; - ctanns = aw; - } else { - aw.next = ictanns; - ictanns = aw; - } - return aw; - } - - @Override - public void visitLocalVariable( - final String name, - final String desc, - final String signature, - final Label start, - final Label end, - final int index) { - if (signature != null) { - if (localVarType == null) { - localVarType = new ByteVector(); - } - ++localVarTypeCount; - localVarType - .putShort(start.position) - .putShort(end.position - start.position) - .putShort(cw.newUTF8(name)) - .putShort(cw.newUTF8(signature)) - .putShort(index); - } - if (localVar == null) { - localVar = new ByteVector(); - } - ++localVarCount; - localVar.putShort(start.position) - .putShort(end.position - start.position) - .putShort(cw.newUTF8(name)) - .putShort(cw.newUTF8(desc)) - .putShort(index); - if (compute != NOTHING) { - // updates max locals - char c = desc.charAt(0); - int n = index + (c == 'J' || c == 'D' ? 2 : 1); - if (n > maxLocals) { - maxLocals = n; - } - } - } - - @Override - public AnnotationVisitor visitLocalVariableAnnotation( - int typeRef, TypePath typePath, Label[] start, Label[] end, int[] index, String desc, boolean visible) { - ByteVector bv = new ByteVector(); - // write target_type and target_info - bv.putByte(typeRef >>> 24).putShort(start.length); - for (int i = 0; i < start.length; ++i) { - bv.putShort(start[i].position) - .putShort(end[i].position - start[i].position) - .putShort(index[i]); - } - if (typePath == null) { - bv.putByte(0); - } else { - int length = typePath.b[typePath.offset] * 2 + 1; - bv.putByteArray(typePath.b, typePath.offset, length); - } - // write type, and reserve space for values count - bv.putShort(cw.newUTF8(desc)).putShort(0); - AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, bv.length - 2); - if (visible) { - aw.next = ctanns; - ctanns = aw; - } else { - aw.next = ictanns; - ictanns = aw; - } - return aw; - } - - @Override - public void visitLineNumber(final int line, final Label start) { - if (lineNumber == null) { - lineNumber = new ByteVector(); - } - ++lineNumberCount; - lineNumber.putShort(start.position); - lineNumber.putShort(line); - } - - @Override - public void visitMaxs(final int maxStack, final int maxLocals) { - if (compute == FRAMES) { - // completes the control flow graph with exception handler blocks - Handler handler = firstHandler; - while (handler != null) { - Label l = handler.start.getFirst(); - Label h = handler.handler.getFirst(); - Label e = handler.end.getFirst(); - // computes the kind of the edges to 'h' - String t = handler.desc == null ? "java/lang/Throwable" : handler.desc; - int kind = Frame.OBJECT | cw.addType(t); - // h is an exception handler - h.status |= Label.TARGET; - // adds 'h' as a successor of labels between 'start' and 'end' - while (l != e) { - // creates an edge to 'h' - Edge b = new Edge(); - b.info = kind; - b.successor = h; - // adds it to the successors of 'l' - b.next = l.successors; - l.successors = b; - // goes to the next label - l = l.successor; - } - handler = handler.next; - } - - // creates and visits the first (implicit) frame - Frame f = labels.frame; - f.initInputFrame(cw, access, Type.getArgumentTypes(descriptor), this.maxLocals); - visitFrame(f); - - /* - * fix point algorithm: mark the first basic block as 'changed' - * (i.e. put it in the 'changed' list) and, while there are changed - * basic blocks, choose one, mark it as unchanged, and update its - * successors (which can be changed in the process). - */ - int max = 0; - Label changed = labels; - while (changed != null) { - // removes a basic block from the list of changed basic blocks - Label l = changed; - changed = changed.next; - l.next = null; - f = l.frame; - // a reachable jump target must be stored in the stack map - if ((l.status & Label.TARGET) != 0) { - l.status |= Label.STORE; - } - // all visited labels are reachable, by definition - l.status |= Label.REACHABLE; - // updates the (absolute) maximum stack size - int blockMax = f.inputStack.length + l.outputStackMax; - if (blockMax > max) { - max = blockMax; - } - // updates the successors of the current basic block - Edge e = l.successors; - while (e != null) { - Label n = e.successor.getFirst(); - boolean change = f.merge(cw, n.frame, e.info); - if (change && n.next == null) { - // if n has changed and is not already in the 'changed' - // list, adds it to this list - n.next = changed; - changed = n; - } - e = e.next; - } - } - - // visits all the frames that must be stored in the stack map - Label l = labels; - while (l != null) { - f = l.frame; - if ((l.status & Label.STORE) != 0) { - visitFrame(f); - } - if ((l.status & Label.REACHABLE) == 0) { - // finds start and end of dead basic block - Label k = l.successor; - int start = l.position; - int end = (k == null ? code.length : k.position) - 1; - // if non empty basic block - if (end >= start) { - max = Math.max(max, 1); - // replaces instructions with NOP ... NOP ATHROW - for (int i = start; i < end; ++i) { - code.data[i] = Opcodes.NOP; - } - code.data[end] = (byte) Opcodes.ATHROW; - // emits a frame for this unreachable block - int frameIndex = startFrame(start, 0, 1); - frame[frameIndex] = Frame.OBJECT | cw.addType("java/lang/Throwable"); - endFrame(); - // removes the start-end range from the exception - // handlers - firstHandler = Handler.remove(firstHandler, l, k); - } - } - l = l.successor; - } - - handler = firstHandler; - handlerCount = 0; - while (handler != null) { - handlerCount += 1; - handler = handler.next; - } - - this.maxStack = max; - } else if (compute == MAXS) { - // completes the control flow graph with exception handler blocks - Handler handler = firstHandler; - while (handler != null) { - Label l = handler.start; - Label h = handler.handler; - Label e = handler.end; - // adds 'h' as a successor of labels between 'start' and 'end' - while (l != e) { - // creates an edge to 'h' - Edge b = new Edge(); - b.info = Edge.EXCEPTION; - b.successor = h; - // adds it to the successors of 'l' - if ((l.status & Label.JSR) == 0) { - b.next = l.successors; - l.successors = b; - } else { - // if l is a JSR block, adds b after the first two edges - // to preserve the hypothesis about JSR block successors - // order (see {@link #visitJumpInsn}) - b.next = l.successors.next.next; - l.successors.next.next = b; - } - // goes to the next label - l = l.successor; - } - handler = handler.next; - } - - if (subroutines > 0) { - // completes the control flow graph with the RET successors - /* - * first step: finds the subroutines. This step determines, for - * each basic block, to which subroutine(s) it belongs. - */ - // finds the basic blocks that belong to the "main" subroutine - int id = 0; - labels.visitSubroutine(null, 1, subroutines); - // finds the basic blocks that belong to the real subroutines - Label l = labels; - while (l != null) { - if ((l.status & Label.JSR) != 0) { - // the subroutine is defined by l's TARGET, not by l - Label subroutine = l.successors.next.successor; - // if this subroutine has not been visited yet... - if ((subroutine.status & Label.VISITED) == 0) { - // ...assigns it a new id and finds its basic blocks - id += 1; - subroutine.visitSubroutine(null, (id / 32L) << 32 | (1L << (id % 32)), subroutines); - } - } - l = l.successor; - } - // second step: finds the successors of RET blocks - l = labels; - while (l != null) { - if ((l.status & Label.JSR) != 0) { - Label L = labels; - while (L != null) { - L.status &= ~Label.VISITED2; - L = L.successor; - } - // the subroutine is defined by l's TARGET, not by l - Label subroutine = l.successors.next.successor; - subroutine.visitSubroutine(l, 0, subroutines); - } - l = l.successor; - } - } - - /* - * control flow analysis algorithm: while the block stack is not - * empty, pop a block from this stack, update the max stack size, - * compute the true (non relative) begin stack size of the - * successors of this block, and push these successors onto the - * stack (unless they have already been pushed onto the stack). - * Note: by hypothesis, the {@link Label#inputStackTop} of the - * blocks in the block stack are the true (non relative) beginning - * stack sizes of these blocks. - */ - int max = 0; - Label stack = labels; - while (stack != null) { - // pops a block from the stack - Label l = stack; - stack = stack.next; - // computes the true (non relative) max stack size of this block - int start = l.inputStackTop; - int blockMax = start + l.outputStackMax; - // updates the global max stack size - if (blockMax > max) { - max = blockMax; - } - // analyzes the successors of the block - Edge b = l.successors; - if ((l.status & Label.JSR) != 0) { - // ignores the first edge of JSR blocks (virtual successor) - b = b.next; - } - while (b != null) { - l = b.successor; - // if this successor has not already been pushed... - if ((l.status & Label.PUSHED) == 0) { - // computes its true beginning stack size... - l.inputStackTop = b.info == Edge.EXCEPTION ? 1 : start + b.info; - // ...and pushes it onto the stack - l.status |= Label.PUSHED; - l.next = stack; - stack = l; - } - b = b.next; - } - } - this.maxStack = Math.max(maxStack, max); - } else { - this.maxStack = maxStack; - this.maxLocals = maxLocals; - } - } - - @Override - public void visitEnd() { - // do nothing - } - - // ------------------------------------------------------------------------ - // Utility methods: control flow analysis algorithm - // ------------------------------------------------------------------------ - - /** - * Adds a successor to the {@link #currentBlock currentBlock} block. - * - * @param info information about the control flow edge to be added. - * @param successor the successor block to be added to the current block. - */ - private void addSuccessor(final int info, final Label successor) { - // creates and initializes an Edge object... - Edge b = new Edge(); - b.info = info; - b.successor = successor; - // ...and adds it to the successor list of the currentBlock block - b.next = currentBlock.successors; - currentBlock.successors = b; - } - - /** - * Ends the current basic block. This method must be used in the case where the current basic block does not have - * any successor. - */ - private void noSuccessor() { - if (compute == FRAMES) { - Label l = new Label(); - l.frame = new Frame(); - l.frame.owner = l; - l.resolve(this, code.length, code.data); - previousBlock.successor = l; - previousBlock = l; - } else { - currentBlock.outputStackMax = maxStackSize; - } - if (compute != INSERTED_FRAMES) { - currentBlock = null; - } - } - - // ------------------------------------------------------------------------ - // Utility methods: stack map frames - // ------------------------------------------------------------------------ - - /** - * Visits a frame that has been computed from scratch. - * - * @param f the frame that must be visited. - */ - private void visitFrame(final Frame f) { - int i, t; - int nTop = 0; - int nLocal = 0; - int nStack = 0; - int[] locals = f.inputLocals; - int[] stacks = f.inputStack; - // computes the number of locals (ignores TOP types that are just after - // a LONG or a DOUBLE, and all trailing TOP types) - for (i = 0; i < locals.length; ++i) { - t = locals[i]; - if (t == Frame.TOP) { - ++nTop; - } else { - nLocal += nTop + 1; - nTop = 0; - } - if (t == Frame.LONG || t == Frame.DOUBLE) { - ++i; - } - } - // computes the stack size (ignores TOP types that are just after - // a LONG or a DOUBLE) - for (i = 0; i < stacks.length; ++i) { - t = stacks[i]; - ++nStack; - if (t == Frame.LONG || t == Frame.DOUBLE) { - ++i; - } - } - // visits the frame and its content - int frameIndex = startFrame(f.owner.position, nLocal, nStack); - for (i = 0; nLocal > 0; ++i, --nLocal) { - t = locals[i]; - frame[frameIndex++] = t; - if (t == Frame.LONG || t == Frame.DOUBLE) { - ++i; - } - } - for (i = 0; i < stacks.length; ++i) { - t = stacks[i]; - frame[frameIndex++] = t; - if (t == Frame.LONG || t == Frame.DOUBLE) { - ++i; - } - } - endFrame(); - } - - /** Visit the implicit first frame of this method. */ - private void visitImplicitFirstFrame() { - // There can be at most descriptor.length() + 1 locals - int frameIndex = startFrame(0, descriptor.length() + 1, 0); - if ((access & Opcodes.ACC_STATIC) == 0) { - if ((access & ACC_CONSTRUCTOR) == 0) { - frame[frameIndex++] = Frame.OBJECT | cw.addType(cw.thisName); - } else { - frame[frameIndex++] = Frame.UNINITIALIZED_THIS; - } - } - int i = 1; - loop: - while (true) { - int j = i; - switch (descriptor.charAt(i++)) { - case 'Z': - case 'C': - case 'B': - case 'S': - case 'I': - frame[frameIndex++] = Frame.INTEGER; - break; - case 'F': - frame[frameIndex++] = Frame.FLOAT; - break; - case 'J': - frame[frameIndex++] = Frame.LONG; - break; - case 'D': - frame[frameIndex++] = Frame.DOUBLE; - break; - case '[': - while (descriptor.charAt(i) == '[') { - ++i; - } - if (descriptor.charAt(i) == 'L') { - ++i; - while (descriptor.charAt(i) != ';') { - ++i; - } - } - frame[frameIndex++] = Frame.type(cw, descriptor.substring(j, ++i)); - break; - case 'L': - while (descriptor.charAt(i) != ';') { - ++i; - } - frame[frameIndex++] = Frame.OBJECT | cw.addType(descriptor.substring(j + 1, i++)); - break; - default: - break loop; - } - } - frame[1] = frameIndex - 3; - endFrame(); - } - - /** - * Starts the visit of a stack map frame. - * - * @param offset the offset of the instruction to which the frame corresponds. - * @param nLocal the number of local variables in the frame. - * @param nStack the number of stack elements in the frame. - * @return the index of the next element to be written in this frame. - */ - private int startFrame(final int offset, final int nLocal, final int nStack) { - int n = 3 + nLocal + nStack; - if (frame == null || frame.length < n) { - frame = new int[n]; - } - frame[0] = offset; - frame[1] = nLocal; - frame[2] = nStack; - return 3; - } - - /** - * Checks if the visit of the current frame {@link #frame} is finished, and if yes, write it in the StackMapTable - * attribute. - */ - private void endFrame() { - if (previousFrame != null) { // do not write the first frame - if (stackMap == null) { - stackMap = new ByteVector(); - } - writeFrame(); - ++frameCount; - } - previousFrame = frame; - frame = null; - } - - /** Compress and writes the current frame {@link #frame} in the StackMapTable attribute. */ - private void writeFrame() { - int clocalsSize = frame[1]; - int cstackSize = frame[2]; - if ((cw.version & 0xFFFF) < Opcodes.V1_6) { - stackMap.putShort(frame[0]).putShort(clocalsSize); - writeFrameTypes(3, 3 + clocalsSize); - stackMap.putShort(cstackSize); - writeFrameTypes(3 + clocalsSize, 3 + clocalsSize + cstackSize); - return; - } - int localsSize = previousFrame[1]; - int type = FULL_FRAME; - int k = 0; - int delta; - if (frameCount == 0) { - delta = frame[0]; - } else { - delta = frame[0] - previousFrame[0] - 1; - } - if (cstackSize == 0) { - k = clocalsSize - localsSize; - switch (k) { - case -3: - case -2: - case -1: - type = CHOP_FRAME; - localsSize = clocalsSize; - break; - case 0: - type = delta < 64 ? SAME_FRAME : SAME_FRAME_EXTENDED; - break; - case 1: - case 2: - case 3: - type = APPEND_FRAME; - break; - } - } else if (clocalsSize == localsSize && cstackSize == 1) { - type = delta < 63 ? SAME_LOCALS_1_STACK_ITEM_FRAME : SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED; - } - if (type != FULL_FRAME) { - // verify if locals are the same - int l = 3; - for (int j = 0; j < localsSize; j++) { - if (frame[l] != previousFrame[l]) { - type = FULL_FRAME; - break; - } - l++; - } - } - switch (type) { - case SAME_FRAME: - stackMap.putByte(delta); - break; - case SAME_LOCALS_1_STACK_ITEM_FRAME: - stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME + delta); - writeFrameTypes(3 + clocalsSize, 4 + clocalsSize); - break; - case SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED: - stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED).putShort(delta); - writeFrameTypes(3 + clocalsSize, 4 + clocalsSize); - break; - case SAME_FRAME_EXTENDED: - stackMap.putByte(SAME_FRAME_EXTENDED).putShort(delta); - break; - case CHOP_FRAME: - stackMap.putByte(SAME_FRAME_EXTENDED + k).putShort(delta); - break; - case APPEND_FRAME: - stackMap.putByte(SAME_FRAME_EXTENDED + k).putShort(delta); - writeFrameTypes(3 + localsSize, 3 + clocalsSize); - break; - // case FULL_FRAME: - default: - stackMap.putByte(FULL_FRAME).putShort(delta).putShort(clocalsSize); - writeFrameTypes(3, 3 + clocalsSize); - stackMap.putShort(cstackSize); - writeFrameTypes(3 + clocalsSize, 3 + clocalsSize + cstackSize); - } - } - - /** - * Writes some types of the current frame {@link #frame} into the StackMapTableAttribute. This method converts types - * from the format used in {@link Label} to the format used in StackMapTable attributes. In particular, it converts - * type table indexes to constant pool indexes. - * - * @param start index of the first type in {@link #frame} to write. - * @param end index of last type in {@link #frame} to write (exclusive). - */ - private void writeFrameTypes(final int start, final int end) { - for (int i = start; i < end; ++i) { - int t = frame[i]; - int d = t & Frame.DIM; - if (d == 0) { - int v = t & Frame.BASE_VALUE; - switch (t & Frame.BASE_KIND) { - case Frame.OBJECT: - stackMap.putByte(7).putShort(cw.newClass(cw.typeTable[v].strVal1)); - break; - case Frame.UNINITIALIZED: - stackMap.putByte(8).putShort(cw.typeTable[v].intVal); - break; - default: - stackMap.putByte(v); - } - } else { - StringBuilder sb = new StringBuilder(); - d >>= 28; - while (d-- > 0) { - sb.append('['); - } - if ((t & Frame.BASE_KIND) == Frame.OBJECT) { - sb.append('L'); - sb.append(cw.typeTable[t & Frame.BASE_VALUE].strVal1); - sb.append(';'); - } else { - switch (t & 0xF) { - case 1: - sb.append('I'); - break; - case 2: - sb.append('F'); - break; - case 3: - sb.append('D'); - break; - case 9: - sb.append('Z'); - break; - case 10: - sb.append('B'); - break; - case 11: - sb.append('C'); - break; - case 12: - sb.append('S'); - break; - default: - sb.append('J'); - } - } - stackMap.putByte(7).putShort(cw.newClass(sb.toString())); - } - } - } - - private void writeFrameType(final Object type) { - if (type instanceof String) { - stackMap.putByte(7).putShort(cw.newClass((String) type)); - } else if (type instanceof Integer) { - stackMap.putByte(((Integer) type).intValue()); - } else { - stackMap.putByte(8).putShort(((Label) type).position); - } - } - - // ------------------------------------------------------------------------ - // Utility methods: dump bytecode array - // ------------------------------------------------------------------------ - - /** - * Returns the size of the bytecode of this method. - * - * @return the size of the bytecode of this method. - */ - final int getSize() { - if (classReaderOffset != 0) { - return 6 + classReaderLength; - } - int size = 8; - if (code.length > 0) { - if (code.length > 65535) { - throw new RuntimeException("Method code too large!"); - } - cw.newUTF8("Code"); - size += 18 + code.length + 8 * handlerCount; - if (localVar != null) { - cw.newUTF8("LocalVariableTable"); - size += 8 + localVar.length; - } - if (localVarType != null) { - cw.newUTF8("LocalVariableTypeTable"); - size += 8 + localVarType.length; - } - if (lineNumber != null) { - cw.newUTF8("LineNumberTable"); - size += 8 + lineNumber.length; - } - if (stackMap != null) { - boolean zip = (cw.version & 0xFFFF) >= Opcodes.V1_6; - cw.newUTF8(zip ? "StackMapTable" : "StackMap"); - size += 8 + stackMap.length; - } - if (ctanns != null) { - cw.newUTF8("RuntimeVisibleTypeAnnotations"); - size += 8 + ctanns.getSize(); - } - if (ictanns != null) { - cw.newUTF8("RuntimeInvisibleTypeAnnotations"); - size += 8 + ictanns.getSize(); - } - if (cattrs != null) { - size += cattrs.getSize(cw, code.data, code.length, maxStack, maxLocals); - } - } - if (exceptionCount > 0) { - cw.newUTF8("Exceptions"); - size += 8 + 2 * exceptionCount; - } - if ((access & Opcodes.ACC_SYNTHETIC) != 0) { - if ((cw.version & 0xFFFF) < Opcodes.V1_5 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) { - cw.newUTF8("Synthetic"); - size += 6; - } - } - if ((access & Opcodes.ACC_DEPRECATED) != 0) { - cw.newUTF8("Deprecated"); - size += 6; - } - if (signature != null) { - cw.newUTF8("Signature"); - cw.newUTF8(signature); - size += 8; - } - if (methodParameters != null) { - cw.newUTF8("MethodParameters"); - size += 7 + methodParameters.length; - } - if (annd != null) { - cw.newUTF8("AnnotationDefault"); - size += 6 + annd.length; - } - if (anns != null) { - cw.newUTF8("RuntimeVisibleAnnotations"); - size += 8 + anns.getSize(); - } - if (ianns != null) { - cw.newUTF8("RuntimeInvisibleAnnotations"); - size += 8 + ianns.getSize(); - } - if (tanns != null) { - cw.newUTF8("RuntimeVisibleTypeAnnotations"); - size += 8 + tanns.getSize(); - } - if (itanns != null) { - cw.newUTF8("RuntimeInvisibleTypeAnnotations"); - size += 8 + itanns.getSize(); - } - if (panns != null) { - cw.newUTF8("RuntimeVisibleParameterAnnotations"); - size += 7 + 2 * (panns.length - synthetics); - for (int i = panns.length - 1; i >= synthetics; --i) { - size += panns[i] == null ? 0 : panns[i].getSize(); - } - } - if (ipanns != null) { - cw.newUTF8("RuntimeInvisibleParameterAnnotations"); - size += 7 + 2 * (ipanns.length - synthetics); - for (int i = ipanns.length - 1; i >= synthetics; --i) { - size += ipanns[i] == null ? 0 : ipanns[i].getSize(); - } - } - if (attrs != null) { - size += attrs.getSize(cw, null, 0, -1, -1); - } - return size; - } - - /** - * Puts the bytecode of this method in the given byte vector. - * - * @param out the byte vector into which the bytecode of this method must be copied. - */ - final void put(final ByteVector out) { - final int FACTOR = ClassWriter.TO_ACC_SYNTHETIC; - int mask = ACC_CONSTRUCTOR - | Opcodes.ACC_DEPRECATED - | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE - | ((access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) / FACTOR); - out.putShort(access & ~mask).putShort(name).putShort(desc); - if (classReaderOffset != 0) { - out.putByteArray(cw.cr.b, classReaderOffset, classReaderLength); - return; - } - int attributeCount = 0; - if (code.length > 0) { - ++attributeCount; - } - if (exceptionCount > 0) { - ++attributeCount; - } - if ((access & Opcodes.ACC_SYNTHETIC) != 0) { - if ((cw.version & 0xFFFF) < Opcodes.V1_5 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) { - ++attributeCount; - } - } - if ((access & Opcodes.ACC_DEPRECATED) != 0) { - ++attributeCount; - } - if (signature != null) { - ++attributeCount; - } - if (methodParameters != null) { - ++attributeCount; - } - if (annd != null) { - ++attributeCount; - } - if (anns != null) { - ++attributeCount; - } - if (ianns != null) { - ++attributeCount; - } - if (tanns != null) { - ++attributeCount; - } - if (itanns != null) { - ++attributeCount; - } - if (panns != null) { - ++attributeCount; - } - if (ipanns != null) { - ++attributeCount; - } - if (attrs != null) { - attributeCount += attrs.getCount(); - } - out.putShort(attributeCount); - if (code.length > 0) { - int size = 12 + code.length + 8 * handlerCount; - if (localVar != null) { - size += 8 + localVar.length; - } - if (localVarType != null) { - size += 8 + localVarType.length; - } - if (lineNumber != null) { - size += 8 + lineNumber.length; - } - if (stackMap != null) { - size += 8 + stackMap.length; - } - if (ctanns != null) { - size += 8 + ctanns.getSize(); - } - if (ictanns != null) { - size += 8 + ictanns.getSize(); - } - if (cattrs != null) { - size += cattrs.getSize(cw, code.data, code.length, maxStack, maxLocals); - } - out.putShort(cw.newUTF8("Code")).putInt(size); - out.putShort(maxStack).putShort(maxLocals); - out.putInt(code.length).putByteArray(code.data, 0, code.length); - out.putShort(handlerCount); - if (handlerCount > 0) { - Handler h = firstHandler; - while (h != null) { - out.putShort(h.start.position) - .putShort(h.end.position) - .putShort(h.handler.position) - .putShort(h.type); - h = h.next; - } - } - attributeCount = 0; - if (localVar != null) { - ++attributeCount; - } - if (localVarType != null) { - ++attributeCount; - } - if (lineNumber != null) { - ++attributeCount; - } - if (stackMap != null) { - ++attributeCount; - } - if (ctanns != null) { - ++attributeCount; - } - if (ictanns != null) { - ++attributeCount; - } - if (cattrs != null) { - attributeCount += cattrs.getCount(); - } - out.putShort(attributeCount); - if (localVar != null) { - out.putShort(cw.newUTF8("LocalVariableTable")); - out.putInt(localVar.length + 2).putShort(localVarCount); - out.putByteArray(localVar.data, 0, localVar.length); - } - if (localVarType != null) { - out.putShort(cw.newUTF8("LocalVariableTypeTable")); - out.putInt(localVarType.length + 2).putShort(localVarTypeCount); - out.putByteArray(localVarType.data, 0, localVarType.length); - } - if (lineNumber != null) { - out.putShort(cw.newUTF8("LineNumberTable")); - out.putInt(lineNumber.length + 2).putShort(lineNumberCount); - out.putByteArray(lineNumber.data, 0, lineNumber.length); - } - if (stackMap != null) { - boolean zip = (cw.version & 0xFFFF) >= Opcodes.V1_6; - out.putShort(cw.newUTF8(zip ? "StackMapTable" : "StackMap")); - out.putInt(stackMap.length + 2).putShort(frameCount); - out.putByteArray(stackMap.data, 0, stackMap.length); - } - if (ctanns != null) { - out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations")); - ctanns.put(out); - } - if (ictanns != null) { - out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations")); - ictanns.put(out); - } - if (cattrs != null) { - cattrs.put(cw, code.data, code.length, maxLocals, maxStack, out); - } - } - if (exceptionCount > 0) { - out.putShort(cw.newUTF8("Exceptions")).putInt(2 * exceptionCount + 2); - out.putShort(exceptionCount); - for (int i = 0; i < exceptionCount; ++i) { - out.putShort(exceptions[i]); - } - } - if ((access & Opcodes.ACC_SYNTHETIC) != 0) { - if ((cw.version & 0xFFFF) < Opcodes.V1_5 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) { - out.putShort(cw.newUTF8("Synthetic")).putInt(0); - } - } - if ((access & Opcodes.ACC_DEPRECATED) != 0) { - out.putShort(cw.newUTF8("Deprecated")).putInt(0); - } - if (signature != null) { - out.putShort(cw.newUTF8("Signature")).putInt(2).putShort(cw.newUTF8(signature)); - } - if (methodParameters != null) { - out.putShort(cw.newUTF8("MethodParameters")); - out.putInt(methodParameters.length + 1).putByte(methodParametersCount); - out.putByteArray(methodParameters.data, 0, methodParameters.length); - } - if (annd != null) { - out.putShort(cw.newUTF8("AnnotationDefault")); - out.putInt(annd.length); - out.putByteArray(annd.data, 0, annd.length); - } - if (anns != null) { - out.putShort(cw.newUTF8("RuntimeVisibleAnnotations")); - anns.put(out); - } - if (ianns != null) { - out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations")); - ianns.put(out); - } - if (tanns != null) { - out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations")); - tanns.put(out); - } - if (itanns != null) { - out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations")); - itanns.put(out); - } - if (panns != null) { - out.putShort(cw.newUTF8("RuntimeVisibleParameterAnnotations")); - AnnotationWriter.put(panns, synthetics, out); - } - if (ipanns != null) { - out.putShort(cw.newUTF8("RuntimeInvisibleParameterAnnotations")); - AnnotationWriter.put(ipanns, synthetics, out); - } - if (attrs != null) { - attrs.put(cw, null, 0, -1, -1, out); - } - } -} +/* + * 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 {@link MethodVisitor} that generates methods in bytecode form. Each visit method of this class appends the bytecode + * corresponding to the visited instruction to a byte vector, in the order these methods are called. + * + * @author Eric Bruneton + * @author Eugene Kuleshov + */ +class MethodWriter extends MethodVisitor { + + /** Pseudo access flag used to denote constructors. */ + static final int ACC_CONSTRUCTOR = 0x80000; + + /** Frame has exactly the same locals as the previous stack map frame and number of stack items is zero. */ + static final int SAME_FRAME = 0; // to 63 (0-3f) + + /** Frame has exactly the same locals as the previous stack map frame and number of stack items is 1 */ + static final int SAME_LOCALS_1_STACK_ITEM_FRAME = 64; // to 127 (40-7f) + + /** Reserved for future use */ + static final int RESERVED = 128; + + /** + * Frame has exactly the same locals as the previous stack map frame and number of stack items is 1. Offset is + * bigger then 63; + */ + static final int SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED = 247; // f7 + + /** + * Frame where current locals are the same as the locals in the previous frame, except that the k last locals are + * absent. The value of k is given by the formula 251-frame_type. + */ + static final int CHOP_FRAME = 248; // to 250 (f8-fA) + + /** + * Frame has exactly the same locals as the previous stack map frame and number of stack items is zero. Offset is + * bigger then 63; + */ + static final int SAME_FRAME_EXTENDED = 251; // fb + + /** + * Frame where current locals are the same as the locals in the previous frame, except that k additional locals are + * defined. The value of k is given by the formula frame_type-251. + */ + static final int APPEND_FRAME = 252; // to 254 // fc-fe + + /** Full frame */ + static final int FULL_FRAME = 255; // ff + + /** + * Indicates that the stack map frames must be recomputed from scratch. In this case the maximum stack size and + * number of local variables is also recomputed from scratch. + * + * @see #compute + */ + static final int FRAMES = 0; + + /** + * Indicates that the stack map frames of type F_INSERT must be computed. The other frames are not (re)computed. + * They should all be of type F_NEW and should be sufficient to compute the content of the F_INSERT frames, together + * with the bytecode instructions between a F_NEW and a F_INSERT frame - and without any knowledge of the type + * hierarchy (by definition of F_INSERT). + * + * @see #compute + */ + static final int INSERTED_FRAMES = 1; + + /** + * Indicates that the maximum stack size and number of local variables must be automatically computed. + * + * @see #compute + */ + static final int MAXS = 2; + + /** + * Indicates that nothing must be automatically computed. + * + * @see #compute + */ + static final int NOTHING = 3; + + /** The class writer to which this method must be added. */ + final ClassWriter cw; + + /** Access flags of this method. */ + private int access; + + /** The index of the constant pool item that contains the name of this method. */ + private final int name; + + /** The index of the constant pool item that contains the descriptor of this method. */ + private final int desc; + + /** The descriptor of this method. */ + private final String descriptor; + + /** The signature of this method. */ + String signature; + + /** + * If not zero, indicates that the code of this method must be copied from the ClassReader associated to this writer + * in cw.cr. More precisely, this field gives the index of the first byte to copied from cw.cr.b + * . + */ + int classReaderOffset; + + /** + * If not zero, indicates that the code of this method must be copied from the ClassReader associated to this writer + * in cw.cr. More precisely, this field gives the number of bytes to copied from cw.cr.b. + */ + int classReaderLength; + + /** Number of exceptions that can be thrown by this method. */ + int exceptionCount; + + /** + * The exceptions that can be thrown by this method. More precisely, this array contains the indexes of the constant + * pool items that contain the internal names of these exception classes. + */ + int[] exceptions; + + /** The annotation default attribute of this method. May be <tt>null</tt>. */ + private ByteVector annd; + + /** The runtime visible annotations of this method. May be <tt>null</tt>. */ + private AnnotationWriter anns; + + /** The runtime invisible annotations of this method. May be <tt>null</tt>. */ + private AnnotationWriter ianns; + + /** The runtime visible type annotations of this method. May be <tt>null</tt> . */ + private AnnotationWriter tanns; + + /** The runtime invisible type annotations of this method. May be <tt>null</tt>. */ + private AnnotationWriter itanns; + + /** The runtime visible parameter annotations of this method. May be <tt>null</tt>. */ + private AnnotationWriter[] panns; + + /** The runtime invisible parameter annotations of this method. May be <tt>null</tt>. */ + private AnnotationWriter[] ipanns; + + /** The number of synthetic parameters of this method. */ + private int synthetics; + + /** The non standard attributes of the method. */ + private Attribute attrs; + + /** The bytecode of this method. */ + private ByteVector code = new ByteVector(); + + /** Maximum stack size of this method. */ + private int maxStack; + + /** Maximum number of local variables for this method. */ + private int maxLocals; + + /** Number of local variables in the current stack map frame. */ + private int currentLocals; + + /** Number of stack map frames in the StackMapTable attribute. */ + int frameCount; + + /** The StackMapTable attribute. */ + private ByteVector stackMap; + + /** The offset of the last frame that was written in the StackMapTable attribute. */ + private int previousFrameOffset; + + /** + * The last frame that was written in the StackMapTable attribute. + * + * @see #frame + */ + private int[] previousFrame; + + /** + * The current stack map frame. The first element contains the offset of the instruction to which the frame + * corresponds, the second element is the number of locals and the third one is the number of stack elements. The + * local variables start at index 3 and are followed by the operand stack values. In summary frame[0] = offset, + * frame[1] = nLocal, frame[2] = nStack, frame[3] = nLocal. All types are encoded as integers, with the same format + * as the one used in {@link Label}, but limited to BASE types. + */ + private int[] frame; + + /** Number of elements in the exception handler list. */ + private int handlerCount; + + /** The first element in the exception handler list. */ + private Handler firstHandler; + + /** The last element in the exception handler list. */ + private Handler lastHandler; + + /** Number of entries in the MethodParameters attribute. */ + private int methodParametersCount; + + /** The MethodParameters attribute. */ + private ByteVector methodParameters; + + /** Number of entries in the LocalVariableTable attribute. */ + private int localVarCount; + + /** The LocalVariableTable attribute. */ + private ByteVector localVar; + + /** Number of entries in the LocalVariableTypeTable attribute. */ + private int localVarTypeCount; + + /** The LocalVariableTypeTable attribute. */ + private ByteVector localVarType; + + /** Number of entries in the LineNumberTable attribute. */ + private int lineNumberCount; + + /** The LineNumberTable attribute. */ + private ByteVector lineNumber; + + /** The start offset of the last visited instruction. */ + private int lastCodeOffset; + + /** The runtime visible type annotations of the code. May be <tt>null</tt>. */ + private AnnotationWriter ctanns; + + /** The runtime invisible type annotations of the code. May be <tt>null</tt>. */ + private AnnotationWriter ictanns; + + /** The non standard attributes of the method's code. */ + private Attribute cattrs; + + /** The number of subroutines in this method. */ + private int subroutines; + + // ------------------------------------------------------------------------ + + /* + * Fields for the control flow graph analysis algorithm (used to compute the + * maximum stack size). A control flow graph contains one node per "basic + * block", and one edge per "jump" from one basic block to another. Each + * node (i.e., each basic block) is represented by the Label object that + * corresponds to the first instruction of this basic block. Each node also + * stores the list of its successors in the graph, as a linked list of Edge + * objects. + */ + + /** + * Indicates what must be automatically computed. + * + * @see #FRAMES + * @see #INSERTED_FRAMES + * @see #MAXS + * @see #NOTHING + */ + private final int compute; + + /** + * A list of labels. This list is the list of basic blocks in the method, i.e. a list of Label objects linked to + * each other by their {@link Label#successor} field, in the order they are visited by + * {@link MethodVisitor#visitLabel}, and starting with the first basic block. + */ + private Label labels; + + /** The previous basic block. */ + private Label previousBlock; + + /** The current basic block. */ + private Label currentBlock; + + /** + * The (relative) stack size after the last visited instruction. This size is relative to the beginning of the + * current basic block, i.e., the true stack size after the last visited instruction is equal to the + * {@link Label#inputStackTop beginStackSize} of the current basic block plus <tt>stackSize</tt>. + */ + private int stackSize; + + /** + * The (relative) maximum stack size after the last visited instruction. This size is relative to the beginning of + * the current basic block, i.e., the true maximum stack size after the last visited instruction is equal to the + * {@link Label#inputStackTop beginStackSize} of the current basic block plus <tt>stackSize</tt>. + */ + private int maxStackSize; + + // ------------------------------------------------------------------------ + // Constructor + // ------------------------------------------------------------------------ + + /** + * Constructs a new {@link MethodWriter}. + * + * @param cw the class writer in which the method must be added. + * @param access the method's access flags (see {@link Opcodes}). + * @param name the method's name. + * @param desc the method's descriptor (see {@link Type}). + * @param signature the method's signature. May be <tt>null</tt>. + * @param exceptions the internal names of the method's exceptions. May be <tt>null</tt>. + * @param compute Indicates what must be automatically computed (see #compute). + */ + MethodWriter( + final ClassWriter cw, + final int access, + final String name, + final String desc, + final String signature, + final String[] exceptions, + final int compute) { + super(Opcodes.ASM6); + if (cw.firstMethod == null) { + cw.firstMethod = this; + } else { + cw.lastMethod.mv = this; + } + cw.lastMethod = this; + this.cw = cw; + this.access = access; + if ("".equals(name)) { + this.access |= ACC_CONSTRUCTOR; + } + this.name = cw.newUTF8(name); + this.desc = cw.newUTF8(desc); + this.descriptor = desc; + this.signature = signature; + if (exceptions != null && exceptions.length > 0) { + exceptionCount = exceptions.length; + this.exceptions = new int[exceptionCount]; + for (int i = 0; i < exceptionCount; ++i) { + this.exceptions[i] = cw.newClass(exceptions[i]); + } + } + this.compute = compute; + if (compute != NOTHING) { + // updates maxLocals + int size = Type.getArgumentsAndReturnSizes(descriptor) >> 2; + if ((access & Opcodes.ACC_STATIC) != 0) { + --size; + } + maxLocals = size; + currentLocals = size; + // creates and visits the label for the first basic block + labels = new Label(); + labels.status |= Label.PUSHED; + visitLabel(labels); + } + } + + // ------------------------------------------------------------------------ + // Implementation of the MethodVisitor abstract class + // ------------------------------------------------------------------------ + + @Override + public void visitParameter(String name, int access) { + if (methodParameters == null) { + methodParameters = new ByteVector(); + } + ++methodParametersCount; + methodParameters.putShort((name == null) ? 0 : cw.newUTF8(name)).putShort(access); + } + + @Override + public AnnotationVisitor visitAnnotationDefault() { + annd = new ByteVector(); + return new AnnotationWriter(cw, false, annd, null, 0); + } + + @Override + public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) { + ByteVector bv = new ByteVector(); + // write type, and reserve space for values count + bv.putShort(cw.newUTF8(desc)).putShort(0); + AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2); + if (visible) { + aw.next = anns; + anns = aw; + } else { + aw.next = ianns; + ianns = aw; + } + return aw; + } + + @Override + public AnnotationVisitor visitTypeAnnotation( + final int typeRef, final TypePath typePath, final String desc, final boolean visible) { + ByteVector bv = new ByteVector(); + // write target_type and target_info + AnnotationWriter.putTarget(typeRef, typePath, bv); + // write type, and reserve space for values count + bv.putShort(cw.newUTF8(desc)).putShort(0); + AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, bv.length - 2); + if (visible) { + aw.next = tanns; + tanns = aw; + } else { + aw.next = itanns; + itanns = aw; + } + return aw; + } + + @Override + public AnnotationVisitor visitParameterAnnotation(final int parameter, final String desc, final boolean visible) { + ByteVector bv = new ByteVector(); + if ("Ljava/lang/Synthetic;".equals(desc)) { + // workaround for a bug in javac with synthetic parameters + // see ClassReader.readParameterAnnotations + synthetics = Math.max(synthetics, parameter + 1); + return new AnnotationWriter(cw, false, bv, null, 0); + } + // write type, and reserve space for values count + bv.putShort(cw.newUTF8(desc)).putShort(0); + AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2); + if (visible) { + if (panns == null) { + panns = new AnnotationWriter[Type.getArgumentTypes(descriptor).length]; + } + aw.next = panns[parameter]; + panns[parameter] = aw; + } else { + if (ipanns == null) { + ipanns = new AnnotationWriter[Type.getArgumentTypes(descriptor).length]; + } + aw.next = ipanns[parameter]; + ipanns[parameter] = aw; + } + return aw; + } + + @Override + public void visitAttribute(final Attribute attr) { + if (attr.isCodeAttribute()) { + attr.next = cattrs; + cattrs = attr; + } else { + attr.next = attrs; + attrs = attr; + } + } + + @Override + public void visitCode() { + // do nothing + } + + @Override + public void visitFrame( + final int type, final int nLocal, final Object[] local, final int nStack, final Object[] stack) { + if (compute == FRAMES) { + return; + } + + if (compute == INSERTED_FRAMES) { + if (currentBlock.frame == null) { + // This should happen only once, for the implicit first frame + // (which is explicitly visited in ClassReader if the + // EXPAND_ASM_INSNS option is used). + currentBlock.frame = new CurrentFrame(); + currentBlock.frame.owner = currentBlock; + currentBlock.frame.initInputFrame(cw, access, Type.getArgumentTypes(descriptor), nLocal); + visitImplicitFirstFrame(); + } else { + if (type == Opcodes.F_NEW) { + currentBlock.frame.set(cw, nLocal, local, nStack, stack); + } else { + // In this case type is equal to F_INSERT by hypothesis, and + // currentBlock.frame contains the stack map frame at the + // current instruction, computed from the last F_NEW frame + // and the bytecode instructions in between (via calls to + // CurrentFrame#execute). + } + visitFrame(currentBlock.frame); + } + } else if (type == Opcodes.F_NEW) { + if (previousFrame == null) { + visitImplicitFirstFrame(); + } + currentLocals = nLocal; + int frameIndex = startFrame(code.length, nLocal, nStack); + for (int i = 0; i < nLocal; ++i) { + if (local[i] instanceof String) { + String desc = Type.getObjectType((String) local[i]).getDescriptor(); + frame[frameIndex++] = Frame.type(cw, desc); + } else if (local[i] instanceof Integer) { + frame[frameIndex++] = Frame.BASE | ((Integer) local[i]).intValue(); + } else { + frame[frameIndex++] = + Frame.UNINITIALIZED | cw.addUninitializedType("", ((Label) local[i]).position); + } + } + for (int i = 0; i < nStack; ++i) { + if (stack[i] instanceof String) { + String desc = Type.getObjectType((String) stack[i]).getDescriptor(); + frame[frameIndex++] = Frame.type(cw, desc); + } else if (stack[i] instanceof Integer) { + frame[frameIndex++] = Frame.BASE | ((Integer) stack[i]).intValue(); + } else { + frame[frameIndex++] = + Frame.UNINITIALIZED | cw.addUninitializedType("", ((Label) stack[i]).position); + } + } + endFrame(); + } else { + int delta; + if (stackMap == null) { + stackMap = new ByteVector(); + delta = code.length; + } else { + delta = code.length - previousFrameOffset - 1; + if (delta < 0) { + if (type == Opcodes.F_SAME) { + return; + } else { + throw new IllegalStateException(); + } + } + } + + switch (type) { + case Opcodes.F_FULL: + currentLocals = nLocal; + stackMap.putByte(FULL_FRAME).putShort(delta).putShort(nLocal); + for (int i = 0; i < nLocal; ++i) { + writeFrameType(local[i]); + } + stackMap.putShort(nStack); + for (int i = 0; i < nStack; ++i) { + writeFrameType(stack[i]); + } + break; + case Opcodes.F_APPEND: + currentLocals += nLocal; + stackMap.putByte(SAME_FRAME_EXTENDED + nLocal).putShort(delta); + for (int i = 0; i < nLocal; ++i) { + writeFrameType(local[i]); + } + break; + case Opcodes.F_CHOP: + currentLocals -= nLocal; + stackMap.putByte(SAME_FRAME_EXTENDED - nLocal).putShort(delta); + break; + case Opcodes.F_SAME: + if (delta < 64) { + stackMap.putByte(delta); + } else { + stackMap.putByte(SAME_FRAME_EXTENDED).putShort(delta); + } + break; + case Opcodes.F_SAME1: + if (delta < 64) { + stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME + delta); + } else { + stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) + .putShort(delta); + } + writeFrameType(stack[0]); + break; + } + + previousFrameOffset = code.length; + ++frameCount; + } + + maxStack = Math.max(maxStack, nStack); + maxLocals = Math.max(maxLocals, currentLocals); + } + + @Override + public void visitInsn(final int opcode) { + lastCodeOffset = code.length; + // adds the instruction to the bytecode of the method + code.putByte(opcode); + // update currentBlock + // Label currentBlock = this.currentBlock; + if (currentBlock != null) { + if (compute == FRAMES || compute == INSERTED_FRAMES) { + currentBlock.frame.execute(opcode, 0, null, null); + } else { + // updates current and max stack sizes + int size = stackSize + Frame.SIZE[opcode]; + if (size > maxStackSize) { + maxStackSize = size; + } + stackSize = size; + } + // if opcode == ATHROW or xRETURN, ends current block (no successor) + if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN) || opcode == Opcodes.ATHROW) { + noSuccessor(); + } + } + } + + @Override + public void visitIntInsn(final int opcode, final int operand) { + lastCodeOffset = code.length; + // Label currentBlock = this.currentBlock; + if (currentBlock != null) { + if (compute == FRAMES || compute == INSERTED_FRAMES) { + currentBlock.frame.execute(opcode, operand, null, null); + } else if (opcode != Opcodes.NEWARRAY) { + // updates current and max stack sizes only for NEWARRAY + // (stack size variation = 0 for BIPUSH or SIPUSH) + int size = stackSize + 1; + if (size > maxStackSize) { + maxStackSize = size; + } + stackSize = size; + } + } + // adds the instruction to the bytecode of the method + if (opcode == Opcodes.SIPUSH) { + code.put12(opcode, operand); + } else { // BIPUSH or NEWARRAY + code.put11(opcode, operand); + } + } + + @Override + public void visitVarInsn(final int opcode, final int var) { + lastCodeOffset = code.length; + // Label currentBlock = this.currentBlock; + if (currentBlock != null) { + if (compute == FRAMES || compute == INSERTED_FRAMES) { + currentBlock.frame.execute(opcode, var, null, null); + } else { + // updates current and max stack sizes + if (opcode == Opcodes.RET) { + // no stack change, but end of current block (no successor) + currentBlock.status |= Label.RET; + // save 'stackSize' here for future use + // (see {@link #findSubroutineSuccessors}) + currentBlock.inputStackTop = stackSize; + noSuccessor(); + } else { // xLOAD or xSTORE + int size = stackSize + Frame.SIZE[opcode]; + if (size > maxStackSize) { + maxStackSize = size; + } + stackSize = size; + } + } + } + if (compute != NOTHING) { + // updates max locals + int n; + if (opcode == Opcodes.LLOAD + || opcode == Opcodes.DLOAD + || opcode == Opcodes.LSTORE + || opcode == Opcodes.DSTORE) { + n = var + 2; + } else { + n = var + 1; + } + if (n > maxLocals) { + maxLocals = n; + } + } + // adds the instruction to the bytecode of the method + if (var < 4 && opcode != Opcodes.RET) { + int opt; + if (opcode < Opcodes.ISTORE) { + /* ILOAD_0 */ + opt = 26 + ((opcode - Opcodes.ILOAD) << 2) + var; + } else { + /* ISTORE_0 */ + opt = 59 + ((opcode - Opcodes.ISTORE) << 2) + var; + } + code.putByte(opt); + } else if (var >= 256) { + code.putByte(196 /* WIDE */).put12(opcode, var); + } else { + code.put11(opcode, var); + } + if (opcode >= Opcodes.ISTORE && compute == FRAMES && handlerCount > 0) { + visitLabel(new Label()); + } + } + + @Override + public void visitTypeInsn(final int opcode, final String type) { + lastCodeOffset = code.length; + Item i = cw.newStringishItem(ClassWriter.CLASS, type); + // Label currentBlock = this.currentBlock; + if (currentBlock != null) { + if (compute == FRAMES || compute == INSERTED_FRAMES) { + currentBlock.frame.execute(opcode, code.length, cw, i); + } else if (opcode == Opcodes.NEW) { + // updates current and max stack sizes only if opcode == NEW + // (no stack change for ANEWARRAY, CHECKCAST, INSTANCEOF) + int size = stackSize + 1; + if (size > maxStackSize) { + maxStackSize = size; + } + stackSize = size; + } + } + // adds the instruction to the bytecode of the method + code.put12(opcode, i.index); + } + + @Override + public void visitFieldInsn(final int opcode, final String owner, final String name, final String desc) { + lastCodeOffset = code.length; + Item i = cw.newFieldItem(owner, name, desc); + // Label currentBlock = this.currentBlock; + if (currentBlock != null) { + if (compute == FRAMES || compute == INSERTED_FRAMES) { + currentBlock.frame.execute(opcode, 0, cw, i); + } else { + int size; + // computes the stack size variation + char c = desc.charAt(0); + switch (opcode) { + case Opcodes.GETSTATIC: + size = stackSize + (c == 'D' || c == 'J' ? 2 : 1); + break; + case Opcodes.PUTSTATIC: + size = stackSize + (c == 'D' || c == 'J' ? -2 : -1); + break; + case Opcodes.GETFIELD: + size = stackSize + (c == 'D' || c == 'J' ? 1 : 0); + break; + // case Constants.PUTFIELD: + default: + size = stackSize + (c == 'D' || c == 'J' ? -3 : -2); + break; + } + // updates current and max stack sizes + if (size > maxStackSize) { + maxStackSize = size; + } + stackSize = size; + } + } + // adds the instruction to the bytecode of the method + code.put12(opcode, i.index); + } + + @Override + public void visitMethodInsn( + final int opcode, final String owner, final String name, final String desc, final boolean itf) { + lastCodeOffset = code.length; + Item i = cw.newMethodItem(owner, name, desc, itf); + int argSize = i.intVal; + // Label currentBlock = this.currentBlock; + if (currentBlock != null) { + if (compute == FRAMES || compute == INSERTED_FRAMES) { + currentBlock.frame.execute(opcode, 0, cw, i); + } else { + /* + * computes the stack size variation. In order not to recompute + * several times this variation for the same Item, we use the + * intVal field of this item to store this variation, once it + * has been computed. More precisely this intVal field stores + * the sizes of the arguments and of the return value + * corresponding to desc. + */ + if (argSize == 0) { + // the above sizes have not been computed yet, + // so we compute them... + argSize = Type.getArgumentsAndReturnSizes(desc); + // ... and we save them in order + // not to recompute them in the future + i.intVal = argSize; + } + int size; + if (opcode == Opcodes.INVOKESTATIC) { + size = stackSize - (argSize >> 2) + (argSize & 0x03) + 1; + } else { + size = stackSize - (argSize >> 2) + (argSize & 0x03); + } + // updates current and max stack sizes + if (size > maxStackSize) { + maxStackSize = size; + } + stackSize = size; + } + } + // adds the instruction to the bytecode of the method + if (opcode == Opcodes.INVOKEINTERFACE) { + if (argSize == 0) { + argSize = Type.getArgumentsAndReturnSizes(desc); + i.intVal = argSize; + } + code.put12(Opcodes.INVOKEINTERFACE, i.index).put11(argSize >> 2, 0); + } else { + code.put12(opcode, i.index); + } + } + + @Override + public void visitInvokeDynamicInsn( + final String name, final String desc, final Handle bsm, final Object... bsmArgs) { + lastCodeOffset = code.length; + Item i = cw.newInvokeDynamicItem(name, desc, bsm, bsmArgs); + int argSize = i.intVal; + // Label currentBlock = this.currentBlock; + if (currentBlock != null) { + if (compute == FRAMES || compute == INSERTED_FRAMES) { + currentBlock.frame.execute(Opcodes.INVOKEDYNAMIC, 0, cw, i); + } else { + /* + * computes the stack size variation. In order not to recompute + * several times this variation for the same Item, we use the + * intVal field of this item to store this variation, once it + * has been computed. More precisely this intVal field stores + * the sizes of the arguments and of the return value + * corresponding to desc. + */ + if (argSize == 0) { + // the above sizes have not been computed yet, + // so we compute them... + argSize = Type.getArgumentsAndReturnSizes(desc); + // ... and we save them in order + // not to recompute them in the future + i.intVal = argSize; + } + int size = stackSize - (argSize >> 2) + (argSize & 0x03) + 1; + + // updates current and max stack sizes + if (size > maxStackSize) { + maxStackSize = size; + } + stackSize = size; + } + } + // adds the instruction to the bytecode of the method + code.put12(Opcodes.INVOKEDYNAMIC, i.index); + code.putShort(0); + } + + @Override + public void visitJumpInsn(int opcode, final Label label) { + boolean isWide = opcode >= 200; // GOTO_W + opcode = isWide ? opcode - 33 : opcode; + lastCodeOffset = code.length; + Label nextInsn = null; + // Label currentBlock = this.currentBlock; + if (currentBlock != null) { + if (compute == FRAMES) { + currentBlock.frame.execute(opcode, 0, null, null); + // 'label' is the target of a jump instruction + label.getFirst().status |= Label.TARGET; + // adds 'label' as a successor of this basic block + addSuccessor(Edge.NORMAL, label); + if (opcode != Opcodes.GOTO) { + // creates a Label for the next basic block + nextInsn = new Label(); + } + } else if (compute == INSERTED_FRAMES) { + currentBlock.frame.execute(opcode, 0, null, null); + } else { + if (opcode == Opcodes.JSR) { + if ((label.status & Label.SUBROUTINE) == 0) { + label.status |= Label.SUBROUTINE; + ++subroutines; + } + currentBlock.status |= Label.JSR; + addSuccessor(stackSize + 1, label); + // creates a Label for the next basic block + nextInsn = new Label(); + /* + * note that, by construction in this method, a JSR block + * has at least two successors in the control flow graph: + * the first one leads the next instruction after the JSR, + * while the second one leads to the JSR target. + */ + } else { + // updates current stack size (max stack size unchanged + // because stack size variation always negative in this + // case) + stackSize += Frame.SIZE[opcode]; + addSuccessor(stackSize, label); + } + } + } + // adds the instruction to the bytecode of the method + if ((label.status & Label.RESOLVED) != 0 && label.position - code.length < Short.MIN_VALUE) { + /* + * case of a backward jump with an offset < -32768. In this case we + * automatically replace GOTO with GOTO_W, JSR with JSR_W and IFxxx + * with IFNOTxxx GOTO_W L:..., where IFNOTxxx is the + * "opposite" opcode of IFxxx (i.e., IFNE for IFEQ) and where + * designates the instruction just after the GOTO_W. + */ + if (opcode == Opcodes.GOTO) { + code.putByte(200); // GOTO_W + } else if (opcode == Opcodes.JSR) { + code.putByte(201); // JSR_W + } else { + // if the IF instruction is transformed into IFNOT GOTO_W the + // next instruction becomes the target of the IFNOT instruction + if (nextInsn != null) { + nextInsn.status |= Label.TARGET; + } + code.putByte(opcode <= 166 ? ((opcode + 1) ^ 1) - 1 : opcode ^ 1); + code.putShort(8); // jump offset + // ASM pseudo GOTO_W insn, see ClassReader. We don't use a real + // GOTO_W because we might need to insert a frame just after (as + // the target of the IFNOTxxx jump instruction). + code.putByte(220); + cw.hasAsmInsns = true; + } + label.put(this, code, code.length - 1, true); + } else if (isWide) { + /* + * case of a GOTO_W or JSR_W specified by the user (normally + * ClassReader when used to resize instructions). In this case we + * keep the original instruction. + */ + code.putByte(opcode + 33); + label.put(this, code, code.length - 1, true); + } else { + /* + * case of a backward jump with an offset >= -32768, or of a forward + * jump with, of course, an unknown offset. In these cases we store + * the offset in 2 bytes (which will be increased in + * resizeInstructions, if needed). + */ + code.putByte(opcode); + label.put(this, code, code.length - 1, false); + } + if (currentBlock != null) { + if (nextInsn != null) { + // if the jump instruction is not a GOTO, the next instruction + // is also a successor of this instruction. Calling visitLabel + // adds the label of this next instruction as a successor of the + // current block, and starts a new basic block + visitLabel(nextInsn); + } + if (opcode == Opcodes.GOTO) { + noSuccessor(); + } + } + } + + @Override + public void visitLabel(final Label label) { + // resolves previous forward references to label, if any + cw.hasAsmInsns |= label.resolve(this, code.length, code.data); + // updates currentBlock + if ((label.status & Label.DEBUG) != 0) { + return; + } + if (compute == FRAMES) { + if (currentBlock != null) { + if (label.position == currentBlock.position) { + // successive labels, do not start a new basic block + currentBlock.status |= (label.status & Label.TARGET); + label.frame = currentBlock.frame; + return; + } + // ends current block (with one new successor) + addSuccessor(Edge.NORMAL, label); + } + // begins a new current block + currentBlock = label; + if (label.frame == null) { + label.frame = new Frame(); + label.frame.owner = label; + } + // updates the basic block list + if (previousBlock != null) { + if (label.position == previousBlock.position) { + previousBlock.status |= (label.status & Label.TARGET); + label.frame = previousBlock.frame; + currentBlock = previousBlock; + return; + } + previousBlock.successor = label; + } + previousBlock = label; + } else if (compute == INSERTED_FRAMES) { + if (currentBlock == null) { + // This case should happen only once, for the visitLabel call in + // the constructor. Indeed, if compute is equal to + // INSERTED_FRAMES currentBlock can not be set back to null (see + // #noSuccessor). + currentBlock = label; + } else { + // Updates the frame owner so that a correct frame offset is + // computed in visitFrame(Frame). + currentBlock.frame.owner = label; + } + } else if (compute == MAXS) { + if (currentBlock != null) { + // ends current block (with one new successor) + currentBlock.outputStackMax = maxStackSize; + addSuccessor(stackSize, label); + } + // begins a new current block + currentBlock = label; + // resets the relative current and max stack sizes + stackSize = 0; + maxStackSize = 0; + // updates the basic block list + if (previousBlock != null) { + previousBlock.successor = label; + } + previousBlock = label; + } + } + + @Override + public void visitLdcInsn(final Object cst) { + lastCodeOffset = code.length; + Item i = cw.newConstItem(cst); + // Label currentBlock = this.currentBlock; + if (currentBlock != null) { + if (compute == FRAMES || compute == INSERTED_FRAMES) { + currentBlock.frame.execute(Opcodes.LDC, 0, cw, i); + } else { + int size; + // computes the stack size variation + if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) { + size = stackSize + 2; + } else { + size = stackSize + 1; + } + // updates current and max stack sizes + if (size > maxStackSize) { + maxStackSize = size; + } + stackSize = size; + } + } + // adds the instruction to the bytecode of the method + int index = i.index; + if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) { + code.put12(20 /* LDC2_W */, index); + } else if (index >= 256) { + code.put12(19 /* LDC_W */, index); + } else { + code.put11(Opcodes.LDC, index); + } + } + + @Override + public void visitIincInsn(final int var, final int increment) { + lastCodeOffset = code.length; + if (currentBlock != null) { + if (compute == FRAMES || compute == INSERTED_FRAMES) { + currentBlock.frame.execute(Opcodes.IINC, var, null, null); + } + } + if (compute != NOTHING) { + // updates max locals + int n = var + 1; + if (n > maxLocals) { + maxLocals = n; + } + } + // adds the instruction to the bytecode of the method + if ((var > 255) || (increment > 127) || (increment < -128)) { + code.putByte(196 /* WIDE */).put12(Opcodes.IINC, var).putShort(increment); + } else { + code.putByte(Opcodes.IINC).put11(var, increment); + } + } + + @Override + public void visitTableSwitchInsn(final int min, final int max, final Label dflt, final Label... labels) { + lastCodeOffset = code.length; + // adds the instruction to the bytecode of the method + int source = code.length; + code.putByte(Opcodes.TABLESWITCH); + code.putByteArray(null, 0, (4 - code.length % 4) % 4); + dflt.put(this, code, source, true); + code.putInt(min).putInt(max); + for (int i = 0; i < labels.length; ++i) { + labels[i].put(this, code, source, true); + } + // updates currentBlock + visitSwitchInsn(dflt, labels); + } + + @Override + public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) { + lastCodeOffset = code.length; + // adds the instruction to the bytecode of the method + int source = code.length; + code.putByte(Opcodes.LOOKUPSWITCH); + code.putByteArray(null, 0, (4 - code.length % 4) % 4); + dflt.put(this, code, source, true); + code.putInt(labels.length); + for (int i = 0; i < labels.length; ++i) { + code.putInt(keys[i]); + labels[i].put(this, code, source, true); + } + // updates currentBlock + visitSwitchInsn(dflt, labels); + } + + private void visitSwitchInsn(final Label dflt, final Label[] labels) { + // Label currentBlock = this.currentBlock; + if (currentBlock != null) { + if (compute == FRAMES) { + currentBlock.frame.execute(Opcodes.LOOKUPSWITCH, 0, null, null); + // adds current block successors + addSuccessor(Edge.NORMAL, dflt); + dflt.getFirst().status |= Label.TARGET; + for (int i = 0; i < labels.length; ++i) { + addSuccessor(Edge.NORMAL, labels[i]); + labels[i].getFirst().status |= Label.TARGET; + } + } else { + // updates current stack size (max stack size unchanged) + --stackSize; + // adds current block successors + addSuccessor(stackSize, dflt); + for (int i = 0; i < labels.length; ++i) { + addSuccessor(stackSize, labels[i]); + } + } + // ends current block + noSuccessor(); + } + } + + @Override + public void visitMultiANewArrayInsn(final String desc, final int dims) { + lastCodeOffset = code.length; + Item i = cw.newStringishItem(ClassWriter.CLASS, desc); + // Label currentBlock = this.currentBlock; + if (currentBlock != null) { + if (compute == FRAMES || compute == INSERTED_FRAMES) { + currentBlock.frame.execute(Opcodes.MULTIANEWARRAY, dims, cw, i); + } else { + // updates current stack size (max stack size unchanged because + // stack size variation always negative or null) + stackSize += 1 - dims; + } + } + // adds the instruction to the bytecode of the method + code.put12(Opcodes.MULTIANEWARRAY, i.index).putByte(dims); + } + + @Override + public AnnotationVisitor visitInsnAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) { + ByteVector bv = new ByteVector(); + // write target_type and target_info + typeRef = (typeRef & 0xFF0000FF) | (lastCodeOffset << 8); + AnnotationWriter.putTarget(typeRef, typePath, bv); + // write type, and reserve space for values count + bv.putShort(cw.newUTF8(desc)).putShort(0); + AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, bv.length - 2); + if (visible) { + aw.next = ctanns; + ctanns = aw; + } else { + aw.next = ictanns; + ictanns = aw; + } + return aw; + } + + @Override + public void visitTryCatchBlock(final Label start, final Label end, final Label handler, final String type) { + ++handlerCount; + Handler h = new Handler(); + h.start = start; + h.end = end; + h.handler = handler; + h.desc = type; + h.type = type != null ? cw.newClass(type) : 0; + if (lastHandler == null) { + firstHandler = h; + } else { + lastHandler.next = h; + } + lastHandler = h; + } + + @Override + public AnnotationVisitor visitTryCatchAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) { + ByteVector bv = new ByteVector(); + // write target_type and target_info + AnnotationWriter.putTarget(typeRef, typePath, bv); + // write type, and reserve space for values count + bv.putShort(cw.newUTF8(desc)).putShort(0); + AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, bv.length - 2); + if (visible) { + aw.next = ctanns; + ctanns = aw; + } else { + aw.next = ictanns; + ictanns = aw; + } + return aw; + } + + @Override + public void visitLocalVariable( + final String name, + final String desc, + final String signature, + final Label start, + final Label end, + final int index) { + if (signature != null) { + if (localVarType == null) { + localVarType = new ByteVector(); + } + ++localVarTypeCount; + localVarType + .putShort(start.position) + .putShort(end.position - start.position) + .putShort(cw.newUTF8(name)) + .putShort(cw.newUTF8(signature)) + .putShort(index); + } + if (localVar == null) { + localVar = new ByteVector(); + } + ++localVarCount; + localVar.putShort(start.position) + .putShort(end.position - start.position) + .putShort(cw.newUTF8(name)) + .putShort(cw.newUTF8(desc)) + .putShort(index); + if (compute != NOTHING) { + // updates max locals + char c = desc.charAt(0); + int n = index + (c == 'J' || c == 'D' ? 2 : 1); + if (n > maxLocals) { + maxLocals = n; + } + } + } + + @Override + public AnnotationVisitor visitLocalVariableAnnotation( + int typeRef, TypePath typePath, Label[] start, Label[] end, int[] index, String desc, boolean visible) { + ByteVector bv = new ByteVector(); + // write target_type and target_info + bv.putByte(typeRef >>> 24).putShort(start.length); + for (int i = 0; i < start.length; ++i) { + bv.putShort(start[i].position) + .putShort(end[i].position - start[i].position) + .putShort(index[i]); + } + if (typePath == null) { + bv.putByte(0); + } else { + int length = typePath.b[typePath.offset] * 2 + 1; + bv.putByteArray(typePath.b, typePath.offset, length); + } + // write type, and reserve space for values count + bv.putShort(cw.newUTF8(desc)).putShort(0); + AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, bv.length - 2); + if (visible) { + aw.next = ctanns; + ctanns = aw; + } else { + aw.next = ictanns; + ictanns = aw; + } + return aw; + } + + @Override + public void visitLineNumber(final int line, final Label start) { + if (lineNumber == null) { + lineNumber = new ByteVector(); + } + ++lineNumberCount; + lineNumber.putShort(start.position); + lineNumber.putShort(line); + } + + @Override + public void visitMaxs(final int maxStack, final int maxLocals) { + if (compute == FRAMES) { + // completes the control flow graph with exception handler blocks + Handler handler = firstHandler; + while (handler != null) { + Label l = handler.start.getFirst(); + Label h = handler.handler.getFirst(); + Label e = handler.end.getFirst(); + // computes the kind of the edges to 'h' + String t = handler.desc == null ? "java/lang/Throwable" : handler.desc; + int kind = Frame.OBJECT | cw.addType(t); + // h is an exception handler + h.status |= Label.TARGET; + // adds 'h' as a successor of labels between 'start' and 'end' + while (l != e) { + // creates an edge to 'h' + Edge b = new Edge(); + b.info = kind; + b.successor = h; + // adds it to the successors of 'l' + b.next = l.successors; + l.successors = b; + // goes to the next label + l = l.successor; + } + handler = handler.next; + } + + // creates and visits the first (implicit) frame + Frame f = labels.frame; + f.initInputFrame(cw, access, Type.getArgumentTypes(descriptor), this.maxLocals); + visitFrame(f); + + /* + * fix point algorithm: mark the first basic block as 'changed' + * (i.e. put it in the 'changed' list) and, while there are changed + * basic blocks, choose one, mark it as unchanged, and update its + * successors (which can be changed in the process). + */ + int max = 0; + Label changed = labels; + while (changed != null) { + // removes a basic block from the list of changed basic blocks + Label l = changed; + changed = changed.next; + l.next = null; + f = l.frame; + // a reachable jump target must be stored in the stack map + if ((l.status & Label.TARGET) != 0) { + l.status |= Label.STORE; + } + // all visited labels are reachable, by definition + l.status |= Label.REACHABLE; + // updates the (absolute) maximum stack size + int blockMax = f.inputStack.length + l.outputStackMax; + if (blockMax > max) { + max = blockMax; + } + // updates the successors of the current basic block + Edge e = l.successors; + while (e != null) { + Label n = e.successor.getFirst(); + boolean change = f.merge(cw, n.frame, e.info); + if (change && n.next == null) { + // if n has changed and is not already in the 'changed' + // list, adds it to this list + n.next = changed; + changed = n; + } + e = e.next; + } + } + + // visits all the frames that must be stored in the stack map + Label l = labels; + while (l != null) { + f = l.frame; + if ((l.status & Label.STORE) != 0) { + visitFrame(f); + } + if ((l.status & Label.REACHABLE) == 0) { + // finds start and end of dead basic block + Label k = l.successor; + int start = l.position; + int end = (k == null ? code.length : k.position) - 1; + // if non empty basic block + if (end >= start) { + max = Math.max(max, 1); + // replaces instructions with NOP ... NOP ATHROW + for (int i = start; i < end; ++i) { + code.data[i] = Opcodes.NOP; + } + code.data[end] = (byte) Opcodes.ATHROW; + // emits a frame for this unreachable block + int frameIndex = startFrame(start, 0, 1); + frame[frameIndex] = Frame.OBJECT | cw.addType("java/lang/Throwable"); + endFrame(); + // removes the start-end range from the exception + // handlers + firstHandler = Handler.remove(firstHandler, l, k); + } + } + l = l.successor; + } + + handler = firstHandler; + handlerCount = 0; + while (handler != null) { + handlerCount += 1; + handler = handler.next; + } + + this.maxStack = max; + } else if (compute == MAXS) { + // completes the control flow graph with exception handler blocks + Handler handler = firstHandler; + while (handler != null) { + Label l = handler.start; + Label h = handler.handler; + Label e = handler.end; + // adds 'h' as a successor of labels between 'start' and 'end' + while (l != e) { + // creates an edge to 'h' + Edge b = new Edge(); + b.info = Edge.EXCEPTION; + b.successor = h; + // adds it to the successors of 'l' + if ((l.status & Label.JSR) == 0) { + b.next = l.successors; + l.successors = b; + } else { + // if l is a JSR block, adds b after the first two edges + // to preserve the hypothesis about JSR block successors + // order (see {@link #visitJumpInsn}) + b.next = l.successors.next.next; + l.successors.next.next = b; + } + // goes to the next label + l = l.successor; + } + handler = handler.next; + } + + if (subroutines > 0) { + // completes the control flow graph with the RET successors + /* + * first step: finds the subroutines. This step determines, for + * each basic block, to which subroutine(s) it belongs. + */ + // finds the basic blocks that belong to the "main" subroutine + int id = 0; + labels.visitSubroutine(null, 1, subroutines); + // finds the basic blocks that belong to the real subroutines + Label l = labels; + while (l != null) { + if ((l.status & Label.JSR) != 0) { + // the subroutine is defined by l's TARGET, not by l + Label subroutine = l.successors.next.successor; + // if this subroutine has not been visited yet... + if ((subroutine.status & Label.VISITED) == 0) { + // ...assigns it a new id and finds its basic blocks + id += 1; + subroutine.visitSubroutine(null, (id / 32L) << 32 | (1L << (id % 32)), subroutines); + } + } + l = l.successor; + } + // second step: finds the successors of RET blocks + l = labels; + while (l != null) { + if ((l.status & Label.JSR) != 0) { + Label L = labels; + while (L != null) { + L.status &= ~Label.VISITED2; + L = L.successor; + } + // the subroutine is defined by l's TARGET, not by l + Label subroutine = l.successors.next.successor; + subroutine.visitSubroutine(l, 0, subroutines); + } + l = l.successor; + } + } + + /* + * control flow analysis algorithm: while the block stack is not + * empty, pop a block from this stack, update the max stack size, + * compute the true (non relative) begin stack size of the + * successors of this block, and push these successors onto the + * stack (unless they have already been pushed onto the stack). + * Note: by hypothesis, the {@link Label#inputStackTop} of the + * blocks in the block stack are the true (non relative) beginning + * stack sizes of these blocks. + */ + int max = 0; + Label stack = labels; + while (stack != null) { + // pops a block from the stack + Label l = stack; + stack = stack.next; + // computes the true (non relative) max stack size of this block + int start = l.inputStackTop; + int blockMax = start + l.outputStackMax; + // updates the global max stack size + if (blockMax > max) { + max = blockMax; + } + // analyzes the successors of the block + Edge b = l.successors; + if ((l.status & Label.JSR) != 0) { + // ignores the first edge of JSR blocks (virtual successor) + b = b.next; + } + while (b != null) { + l = b.successor; + // if this successor has not already been pushed... + if ((l.status & Label.PUSHED) == 0) { + // computes its true beginning stack size... + l.inputStackTop = b.info == Edge.EXCEPTION ? 1 : start + b.info; + // ...and pushes it onto the stack + l.status |= Label.PUSHED; + l.next = stack; + stack = l; + } + b = b.next; + } + } + this.maxStack = Math.max(maxStack, max); + } else { + this.maxStack = maxStack; + this.maxLocals = maxLocals; + } + } + + @Override + public void visitEnd() { + // do nothing + } + + // ------------------------------------------------------------------------ + // Utility methods: control flow analysis algorithm + // ------------------------------------------------------------------------ + + /** + * Adds a successor to the {@link #currentBlock currentBlock} block. + * + * @param info information about the control flow edge to be added. + * @param successor the successor block to be added to the current block. + */ + private void addSuccessor(final int info, final Label successor) { + // creates and initializes an Edge object... + Edge b = new Edge(); + b.info = info; + b.successor = successor; + // ...and adds it to the successor list of the currentBlock block + b.next = currentBlock.successors; + currentBlock.successors = b; + } + + /** + * Ends the current basic block. This method must be used in the case where the current basic block does not have + * any successor. + */ + private void noSuccessor() { + if (compute == FRAMES) { + Label l = new Label(); + l.frame = new Frame(); + l.frame.owner = l; + l.resolve(this, code.length, code.data); + previousBlock.successor = l; + previousBlock = l; + } else { + currentBlock.outputStackMax = maxStackSize; + } + if (compute != INSERTED_FRAMES) { + currentBlock = null; + } + } + + // ------------------------------------------------------------------------ + // Utility methods: stack map frames + // ------------------------------------------------------------------------ + + /** + * Visits a frame that has been computed from scratch. + * + * @param f the frame that must be visited. + */ + private void visitFrame(final Frame f) { + int i, t; + int nTop = 0; + int nLocal = 0; + int nStack = 0; + int[] locals = f.inputLocals; + int[] stacks = f.inputStack; + // computes the number of locals (ignores TOP types that are just after + // a LONG or a DOUBLE, and all trailing TOP types) + for (i = 0; i < locals.length; ++i) { + t = locals[i]; + if (t == Frame.TOP) { + ++nTop; + } else { + nLocal += nTop + 1; + nTop = 0; + } + if (t == Frame.LONG || t == Frame.DOUBLE) { + ++i; + } + } + // computes the stack size (ignores TOP types that are just after + // a LONG or a DOUBLE) + for (i = 0; i < stacks.length; ++i) { + t = stacks[i]; + ++nStack; + if (t == Frame.LONG || t == Frame.DOUBLE) { + ++i; + } + } + // visits the frame and its content + int frameIndex = startFrame(f.owner.position, nLocal, nStack); + for (i = 0; nLocal > 0; ++i, --nLocal) { + t = locals[i]; + frame[frameIndex++] = t; + if (t == Frame.LONG || t == Frame.DOUBLE) { + ++i; + } + } + for (i = 0; i < stacks.length; ++i) { + t = stacks[i]; + frame[frameIndex++] = t; + if (t == Frame.LONG || t == Frame.DOUBLE) { + ++i; + } + } + endFrame(); + } + + /** Visit the implicit first frame of this method. */ + private void visitImplicitFirstFrame() { + // There can be at most descriptor.length() + 1 locals + int frameIndex = startFrame(0, descriptor.length() + 1, 0); + if ((access & Opcodes.ACC_STATIC) == 0) { + if ((access & ACC_CONSTRUCTOR) == 0) { + frame[frameIndex++] = Frame.OBJECT | cw.addType(cw.thisName); + } else { + frame[frameIndex++] = Frame.UNINITIALIZED_THIS; + } + } + int i = 1; + loop: + while (true) { + int j = i; + switch (descriptor.charAt(i++)) { + case 'Z': + case 'C': + case 'B': + case 'S': + case 'I': + frame[frameIndex++] = Frame.INTEGER; + break; + case 'F': + frame[frameIndex++] = Frame.FLOAT; + break; + case 'J': + frame[frameIndex++] = Frame.LONG; + break; + case 'D': + frame[frameIndex++] = Frame.DOUBLE; + break; + case '[': + while (descriptor.charAt(i) == '[') { + ++i; + } + if (descriptor.charAt(i) == 'L') { + ++i; + while (descriptor.charAt(i) != ';') { + ++i; + } + } + frame[frameIndex++] = Frame.type(cw, descriptor.substring(j, ++i)); + break; + case 'L': + while (descriptor.charAt(i) != ';') { + ++i; + } + frame[frameIndex++] = Frame.OBJECT | cw.addType(descriptor.substring(j + 1, i++)); + break; + default: + break loop; + } + } + frame[1] = frameIndex - 3; + endFrame(); + } + + /** + * Starts the visit of a stack map frame. + * + * @param offset the offset of the instruction to which the frame corresponds. + * @param nLocal the number of local variables in the frame. + * @param nStack the number of stack elements in the frame. + * @return the index of the next element to be written in this frame. + */ + private int startFrame(final int offset, final int nLocal, final int nStack) { + int n = 3 + nLocal + nStack; + if (frame == null || frame.length < n) { + frame = new int[n]; + } + frame[0] = offset; + frame[1] = nLocal; + frame[2] = nStack; + return 3; + } + + /** + * Checks if the visit of the current frame {@link #frame} is finished, and if yes, write it in the StackMapTable + * attribute. + */ + private void endFrame() { + if (previousFrame != null) { // do not write the first frame + if (stackMap == null) { + stackMap = new ByteVector(); + } + writeFrame(); + ++frameCount; + } + previousFrame = frame; + frame = null; + } + + /** Compress and writes the current frame {@link #frame} in the StackMapTable attribute. */ + private void writeFrame() { + int clocalsSize = frame[1]; + int cstackSize = frame[2]; + if ((cw.version & 0xFFFF) < Opcodes.V1_6) { + stackMap.putShort(frame[0]).putShort(clocalsSize); + writeFrameTypes(3, 3 + clocalsSize); + stackMap.putShort(cstackSize); + writeFrameTypes(3 + clocalsSize, 3 + clocalsSize + cstackSize); + return; + } + int localsSize = previousFrame[1]; + int type = FULL_FRAME; + int k = 0; + int delta; + if (frameCount == 0) { + delta = frame[0]; + } else { + delta = frame[0] - previousFrame[0] - 1; + } + if (cstackSize == 0) { + k = clocalsSize - localsSize; + switch (k) { + case -3: + case -2: + case -1: + type = CHOP_FRAME; + localsSize = clocalsSize; + break; + case 0: + type = delta < 64 ? SAME_FRAME : SAME_FRAME_EXTENDED; + break; + case 1: + case 2: + case 3: + type = APPEND_FRAME; + break; + } + } else if (clocalsSize == localsSize && cstackSize == 1) { + type = delta < 63 ? SAME_LOCALS_1_STACK_ITEM_FRAME : SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED; + } + if (type != FULL_FRAME) { + // verify if locals are the same + int l = 3; + for (int j = 0; j < localsSize; j++) { + if (frame[l] != previousFrame[l]) { + type = FULL_FRAME; + break; + } + l++; + } + } + switch (type) { + case SAME_FRAME: + stackMap.putByte(delta); + break; + case SAME_LOCALS_1_STACK_ITEM_FRAME: + stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME + delta); + writeFrameTypes(3 + clocalsSize, 4 + clocalsSize); + break; + case SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED: + stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED).putShort(delta); + writeFrameTypes(3 + clocalsSize, 4 + clocalsSize); + break; + case SAME_FRAME_EXTENDED: + stackMap.putByte(SAME_FRAME_EXTENDED).putShort(delta); + break; + case CHOP_FRAME: + stackMap.putByte(SAME_FRAME_EXTENDED + k).putShort(delta); + break; + case APPEND_FRAME: + stackMap.putByte(SAME_FRAME_EXTENDED + k).putShort(delta); + writeFrameTypes(3 + localsSize, 3 + clocalsSize); + break; + // case FULL_FRAME: + default: + stackMap.putByte(FULL_FRAME).putShort(delta).putShort(clocalsSize); + writeFrameTypes(3, 3 + clocalsSize); + stackMap.putShort(cstackSize); + writeFrameTypes(3 + clocalsSize, 3 + clocalsSize + cstackSize); + } + } + + /** + * Writes some types of the current frame {@link #frame} into the StackMapTableAttribute. This method converts types + * from the format used in {@link Label} to the format used in StackMapTable attributes. In particular, it converts + * type table indexes to constant pool indexes. + * + * @param start index of the first type in {@link #frame} to write. + * @param end index of last type in {@link #frame} to write (exclusive). + */ + private void writeFrameTypes(final int start, final int end) { + for (int i = start; i < end; ++i) { + int t = frame[i]; + int d = t & Frame.DIM; + if (d == 0) { + int v = t & Frame.BASE_VALUE; + switch (t & Frame.BASE_KIND) { + case Frame.OBJECT: + stackMap.putByte(7).putShort(cw.newClass(cw.typeTable[v].strVal1)); + break; + case Frame.UNINITIALIZED: + stackMap.putByte(8).putShort(cw.typeTable[v].intVal); + break; + default: + stackMap.putByte(v); + } + } else { + StringBuilder sb = new StringBuilder(); + d >>= 28; + while (d-- > 0) { + sb.append('['); + } + if ((t & Frame.BASE_KIND) == Frame.OBJECT) { + sb.append('L'); + sb.append(cw.typeTable[t & Frame.BASE_VALUE].strVal1); + sb.append(';'); + } else { + switch (t & 0xF) { + case 1: + sb.append('I'); + break; + case 2: + sb.append('F'); + break; + case 3: + sb.append('D'); + break; + case 9: + sb.append('Z'); + break; + case 10: + sb.append('B'); + break; + case 11: + sb.append('C'); + break; + case 12: + sb.append('S'); + break; + default: + sb.append('J'); + } + } + stackMap.putByte(7).putShort(cw.newClass(sb.toString())); + } + } + } + + private void writeFrameType(final Object type) { + if (type instanceof String) { + stackMap.putByte(7).putShort(cw.newClass((String) type)); + } else if (type instanceof Integer) { + stackMap.putByte(((Integer) type).intValue()); + } else { + stackMap.putByte(8).putShort(((Label) type).position); + } + } + + // ------------------------------------------------------------------------ + // Utility methods: dump bytecode array + // ------------------------------------------------------------------------ + + /** + * Returns the size of the bytecode of this method. + * + * @return the size of the bytecode of this method. + */ + final int getSize() { + if (classReaderOffset != 0) { + return 6 + classReaderLength; + } + int size = 8; + if (code.length > 0) { + if (code.length > 65535) { + throw new RuntimeException("Method code too large!"); + } + cw.newUTF8("Code"); + size += 18 + code.length + 8 * handlerCount; + if (localVar != null) { + cw.newUTF8("LocalVariableTable"); + size += 8 + localVar.length; + } + if (localVarType != null) { + cw.newUTF8("LocalVariableTypeTable"); + size += 8 + localVarType.length; + } + if (lineNumber != null) { + cw.newUTF8("LineNumberTable"); + size += 8 + lineNumber.length; + } + if (stackMap != null) { + boolean zip = (cw.version & 0xFFFF) >= Opcodes.V1_6; + cw.newUTF8(zip ? "StackMapTable" : "StackMap"); + size += 8 + stackMap.length; + } + if (ctanns != null) { + cw.newUTF8("RuntimeVisibleTypeAnnotations"); + size += 8 + ctanns.getSize(); + } + if (ictanns != null) { + cw.newUTF8("RuntimeInvisibleTypeAnnotations"); + size += 8 + ictanns.getSize(); + } + if (cattrs != null) { + size += cattrs.getSize(cw, code.data, code.length, maxStack, maxLocals); + } + } + if (exceptionCount > 0) { + cw.newUTF8("Exceptions"); + size += 8 + 2 * exceptionCount; + } + if ((access & Opcodes.ACC_SYNTHETIC) != 0) { + if ((cw.version & 0xFFFF) < Opcodes.V1_5 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) { + cw.newUTF8("Synthetic"); + size += 6; + } + } + if ((access & Opcodes.ACC_DEPRECATED) != 0) { + cw.newUTF8("Deprecated"); + size += 6; + } + if (signature != null) { + cw.newUTF8("Signature"); + cw.newUTF8(signature); + size += 8; + } + if (methodParameters != null) { + cw.newUTF8("MethodParameters"); + size += 7 + methodParameters.length; + } + if (annd != null) { + cw.newUTF8("AnnotationDefault"); + size += 6 + annd.length; + } + if (anns != null) { + cw.newUTF8("RuntimeVisibleAnnotations"); + size += 8 + anns.getSize(); + } + if (ianns != null) { + cw.newUTF8("RuntimeInvisibleAnnotations"); + size += 8 + ianns.getSize(); + } + if (tanns != null) { + cw.newUTF8("RuntimeVisibleTypeAnnotations"); + size += 8 + tanns.getSize(); + } + if (itanns != null) { + cw.newUTF8("RuntimeInvisibleTypeAnnotations"); + size += 8 + itanns.getSize(); + } + if (panns != null) { + cw.newUTF8("RuntimeVisibleParameterAnnotations"); + size += 7 + 2 * (panns.length - synthetics); + for (int i = panns.length - 1; i >= synthetics; --i) { + size += panns[i] == null ? 0 : panns[i].getSize(); + } + } + if (ipanns != null) { + cw.newUTF8("RuntimeInvisibleParameterAnnotations"); + size += 7 + 2 * (ipanns.length - synthetics); + for (int i = ipanns.length - 1; i >= synthetics; --i) { + size += ipanns[i] == null ? 0 : ipanns[i].getSize(); + } + } + if (attrs != null) { + size += attrs.getSize(cw, null, 0, -1, -1); + } + return size; + } + + /** + * Puts the bytecode of this method in the given byte vector. + * + * @param out the byte vector into which the bytecode of this method must be copied. + */ + final void put(final ByteVector out) { + final int FACTOR = ClassWriter.TO_ACC_SYNTHETIC; + int mask = ACC_CONSTRUCTOR + | Opcodes.ACC_DEPRECATED + | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE + | ((access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) / FACTOR); + out.putShort(access & ~mask).putShort(name).putShort(desc); + if (classReaderOffset != 0) { + out.putByteArray(cw.cr.b, classReaderOffset, classReaderLength); + return; + } + int attributeCount = 0; + if (code.length > 0) { + ++attributeCount; + } + if (exceptionCount > 0) { + ++attributeCount; + } + if ((access & Opcodes.ACC_SYNTHETIC) != 0) { + if ((cw.version & 0xFFFF) < Opcodes.V1_5 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) { + ++attributeCount; + } + } + if ((access & Opcodes.ACC_DEPRECATED) != 0) { + ++attributeCount; + } + if (signature != null) { + ++attributeCount; + } + if (methodParameters != null) { + ++attributeCount; + } + if (annd != null) { + ++attributeCount; + } + if (anns != null) { + ++attributeCount; + } + if (ianns != null) { + ++attributeCount; + } + if (tanns != null) { + ++attributeCount; + } + if (itanns != null) { + ++attributeCount; + } + if (panns != null) { + ++attributeCount; + } + if (ipanns != null) { + ++attributeCount; + } + if (attrs != null) { + attributeCount += attrs.getCount(); + } + out.putShort(attributeCount); + if (code.length > 0) { + int size = 12 + code.length + 8 * handlerCount; + if (localVar != null) { + size += 8 + localVar.length; + } + if (localVarType != null) { + size += 8 + localVarType.length; + } + if (lineNumber != null) { + size += 8 + lineNumber.length; + } + if (stackMap != null) { + size += 8 + stackMap.length; + } + if (ctanns != null) { + size += 8 + ctanns.getSize(); + } + if (ictanns != null) { + size += 8 + ictanns.getSize(); + } + if (cattrs != null) { + size += cattrs.getSize(cw, code.data, code.length, maxStack, maxLocals); + } + out.putShort(cw.newUTF8("Code")).putInt(size); + out.putShort(maxStack).putShort(maxLocals); + out.putInt(code.length).putByteArray(code.data, 0, code.length); + out.putShort(handlerCount); + if (handlerCount > 0) { + Handler h = firstHandler; + while (h != null) { + out.putShort(h.start.position) + .putShort(h.end.position) + .putShort(h.handler.position) + .putShort(h.type); + h = h.next; + } + } + attributeCount = 0; + if (localVar != null) { + ++attributeCount; + } + if (localVarType != null) { + ++attributeCount; + } + if (lineNumber != null) { + ++attributeCount; + } + if (stackMap != null) { + ++attributeCount; + } + if (ctanns != null) { + ++attributeCount; + } + if (ictanns != null) { + ++attributeCount; + } + if (cattrs != null) { + attributeCount += cattrs.getCount(); + } + out.putShort(attributeCount); + if (localVar != null) { + out.putShort(cw.newUTF8("LocalVariableTable")); + out.putInt(localVar.length + 2).putShort(localVarCount); + out.putByteArray(localVar.data, 0, localVar.length); + } + if (localVarType != null) { + out.putShort(cw.newUTF8("LocalVariableTypeTable")); + out.putInt(localVarType.length + 2).putShort(localVarTypeCount); + out.putByteArray(localVarType.data, 0, localVarType.length); + } + if (lineNumber != null) { + out.putShort(cw.newUTF8("LineNumberTable")); + out.putInt(lineNumber.length + 2).putShort(lineNumberCount); + out.putByteArray(lineNumber.data, 0, lineNumber.length); + } + if (stackMap != null) { + boolean zip = (cw.version & 0xFFFF) >= Opcodes.V1_6; + out.putShort(cw.newUTF8(zip ? "StackMapTable" : "StackMap")); + out.putInt(stackMap.length + 2).putShort(frameCount); + out.putByteArray(stackMap.data, 0, stackMap.length); + } + if (ctanns != null) { + out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations")); + ctanns.put(out); + } + if (ictanns != null) { + out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations")); + ictanns.put(out); + } + if (cattrs != null) { + cattrs.put(cw, code.data, code.length, maxLocals, maxStack, out); + } + } + if (exceptionCount > 0) { + out.putShort(cw.newUTF8("Exceptions")).putInt(2 * exceptionCount + 2); + out.putShort(exceptionCount); + for (int i = 0; i < exceptionCount; ++i) { + out.putShort(exceptions[i]); + } + } + if ((access & Opcodes.ACC_SYNTHETIC) != 0) { + if ((cw.version & 0xFFFF) < Opcodes.V1_5 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) { + out.putShort(cw.newUTF8("Synthetic")).putInt(0); + } + } + if ((access & Opcodes.ACC_DEPRECATED) != 0) { + out.putShort(cw.newUTF8("Deprecated")).putInt(0); + } + if (signature != null) { + out.putShort(cw.newUTF8("Signature")).putInt(2).putShort(cw.newUTF8(signature)); + } + if (methodParameters != null) { + out.putShort(cw.newUTF8("MethodParameters")); + out.putInt(methodParameters.length + 1).putByte(methodParametersCount); + out.putByteArray(methodParameters.data, 0, methodParameters.length); + } + if (annd != null) { + out.putShort(cw.newUTF8("AnnotationDefault")); + out.putInt(annd.length); + out.putByteArray(annd.data, 0, annd.length); + } + if (anns != null) { + out.putShort(cw.newUTF8("RuntimeVisibleAnnotations")); + anns.put(out); + } + if (ianns != null) { + out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations")); + ianns.put(out); + } + if (tanns != null) { + out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations")); + tanns.put(out); + } + if (itanns != null) { + out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations")); + itanns.put(out); + } + if (panns != null) { + out.putShort(cw.newUTF8("RuntimeVisibleParameterAnnotations")); + AnnotationWriter.put(panns, synthetics, out); + } + if (ipanns != null) { + out.putShort(cw.newUTF8("RuntimeInvisibleParameterAnnotations")); + AnnotationWriter.put(ipanns, synthetics, out); + } + if (attrs != null) { + attrs.put(cw, null, 0, -1, -1, out); + } + } +} diff --git a/src/main/java/org/redkale/asm/ModuleVisitor.java b/src/main/java/org/redkale/asm/ModuleVisitor.java index a14c214fa..33e21aa13 100644 --- a/src/main/java/org/redkale/asm/ModuleVisitor.java +++ b/src/main/java/org/redkale/asm/ModuleVisitor.java @@ -1,202 +1,202 @@ -/* - * 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(); - } - } -} +/* + * 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(); + } + } +} diff --git a/src/main/java/org/redkale/asm/ModuleWriter.java b/src/main/java/org/redkale/asm/ModuleWriter.java index dbbdacd28..2e2659fd6 100644 --- a/src/main/java/org/redkale/asm/ModuleWriter.java +++ b/src/main/java/org/redkale/asm/ModuleWriter.java @@ -1,288 +1,288 @@ -/* - * 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); - } - } -} +/* + * 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); + } + } +} diff --git a/src/main/java/org/redkale/asm/Opcodes.java b/src/main/java/org/redkale/asm/Opcodes.java index 8bec065f3..03981ef29 100644 --- a/src/main/java/org/redkale/asm/Opcodes.java +++ b/src/main/java/org/redkale/asm/Opcodes.java @@ -1,402 +1,402 @@ -/* - * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */ - -/* - * - * - * - * - * - * ASM: a very small and fast Java bytecode manipulation framework - * Copyright (c) 2000-2011 INRIA, France Telecom - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.redkale.asm; - -/** - * Defines the JVM opcodes, access flags and array type codes. This interface does not define all the JVM opcodes - * because some opcodes are automatically handled. For example, the xLOAD and xSTORE opcodes are automatically replaced - * by xLOAD_n and xSTORE_n opcodes when possible. The xLOAD_n and xSTORE_n opcodes are therefore not defined in this - * interface. Likewise for LDC, automatically replaced by LDC_W or LDC2_W when necessary, WIDE, GOTO_W and JSR_W. - * - * @author Eric Bruneton - * @author Eugene Kuleshov - */ -public interface Opcodes { - - // ASM API versions - int ASM4 = 4 << 16 | 0 << 8; - int ASM5 = 5 << 16 | 0 << 8; - int ASM6 = 6 << 16 | 0 << 8; - - // 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 V9 = 0 << 16 | 53; - int V10 = 0 << 16 | 54; - int V11 = 0 << 16 | 55; - - // access flags - - int ACC_PUBLIC = 0x0001; // class, field, method - int ACC_PRIVATE = 0x0002; // class, field, method - int ACC_PROTECTED = 0x0004; // class, field, method - int ACC_STATIC = 0x0008; // field, method - int ACC_FINAL = 0x0010; // class, field, method, parameter - int ACC_SUPER = 0x0020; // class - int ACC_SYNCHRONIZED = 0x0020; // method - int ACC_OPEN = 0x0020; // module - int ACC_TRANSITIVE = 0x0020; // module requires - int ACC_VOLATILE = 0x0040; // field - int ACC_BRIDGE = 0x0040; // method - int ACC_STATIC_PHASE = 0x0040; // module requires - int ACC_VARARGS = 0x0080; // method - int ACC_TRANSIENT = 0x0080; // field - int ACC_NATIVE = 0x0100; // method - int ACC_INTERFACE = 0x0200; // class - int ACC_ABSTRACT = 0x0400; // class, method - int ACC_STRICT = 0x0800; // method - int ACC_SYNTHETIC = 0x1000; // class, field, method, parameter, module * - int ACC_ANNOTATION = 0x2000; // class - int ACC_ENUM = 0x4000; // class(?) field inner - int ACC_MANDATED = 0x8000; // parameter, module, module * - int ACC_MODULE = 0x8000; // class - - // ASM specific pseudo access flags - - int ACC_DEPRECATED = 0x20000; // class, field, method - - // types for NEWARRAY - - int T_BOOLEAN = 4; - int T_CHAR = 5; - int T_FLOAT = 6; - int T_DOUBLE = 7; - int T_BYTE = 8; - int T_SHORT = 9; - int T_INT = 10; - int T_LONG = 11; - - // tags for Handle - - int H_GETFIELD = 1; - int H_GETSTATIC = 2; - int H_PUTFIELD = 3; - int H_PUTSTATIC = 4; - int H_INVOKEVIRTUAL = 5; - int H_INVOKESTATIC = 6; - int H_INVOKESPECIAL = 7; - int H_NEWINVOKESPECIAL = 8; - int H_INVOKEINTERFACE = 9; - - // stack map frame types - - /** Represents an expanded frame. See {@link ClassReader#EXPAND_FRAMES}. */ - int F_NEW = -1; - - /** Represents a compressed frame with complete frame data. */ - int F_FULL = 0; - - /** - * Represents a compressed frame where locals are the same as the locals in the previous frame, except that - * additional 1-3 locals are defined, and with an empty stack. - */ - int F_APPEND = 1; - - /** - * Represents a compressed frame where locals are the same as the locals in the previous frame, except that the last - * 1-3 locals are absent and with an empty stack. - */ - int F_CHOP = 2; - - /** Represents a compressed frame with exactly the same locals as the previous frame and with an empty stack. */ - int F_SAME = 3; - - /** - * Represents a compressed frame with exactly the same locals as the previous frame and with a single value on the - * stack. - */ - int F_SAME1 = 4; - - // Do not try to change the following code to use auto-boxing, - // these values are compared by reference and not by value - // The constructor of Integer was deprecated in 9 - // but we are stuck with it by backward compatibility - @SuppressWarnings("deprecation") - Integer TOP = new Integer(0); - - @SuppressWarnings("deprecation") - Integer INTEGER = new Integer(1); - - @SuppressWarnings("deprecation") - Integer FLOAT = new Integer(2); - - @SuppressWarnings("deprecation") - Integer DOUBLE = new Integer(3); - - @SuppressWarnings("deprecation") - Integer LONG = new Integer(4); - - @SuppressWarnings("deprecation") - Integer NULL = new Integer(5); - - @SuppressWarnings("deprecation") - Integer UNINITIALIZED_THIS = new Integer(6); - - // opcodes // visit method (- = idem) - - int NOP = 0; // visitInsn - int ACONST_NULL = 1; // - - int ICONST_M1 = 2; // - - int ICONST_0 = 3; // - - int ICONST_1 = 4; // - - int ICONST_2 = 5; // - - int ICONST_3 = 6; // - - int ICONST_4 = 7; // - - int ICONST_5 = 8; // - - int LCONST_0 = 9; // - - int LCONST_1 = 10; // - - int FCONST_0 = 11; // - - int FCONST_1 = 12; // - - int FCONST_2 = 13; // - - int DCONST_0 = 14; // - - int DCONST_1 = 15; // - - int BIPUSH = 16; // visitIntInsn - int SIPUSH = 17; // - - int LDC = 18; // visitLdcInsn - // int LDC_W = 19; // - - // int LDC2_W = 20; // - - int ILOAD = 21; // visitVarInsn - int LLOAD = 22; // - - int FLOAD = 23; // - - int DLOAD = 24; // - - int ALOAD = 25; // - - // int ILOAD_0 = 26; // - - // int ILOAD_1 = 27; // - - // int ILOAD_2 = 28; // - - // int ILOAD_3 = 29; // - - // int LLOAD_0 = 30; // - - // int LLOAD_1 = 31; // - - // int LLOAD_2 = 32; // - - // int LLOAD_3 = 33; // - - // int FLOAD_0 = 34; // - - // int FLOAD_1 = 35; // - - // int FLOAD_2 = 36; // - - // int FLOAD_3 = 37; // - - // int DLOAD_0 = 38; // - - // int DLOAD_1 = 39; // - - // int DLOAD_2 = 40; // - - // int DLOAD_3 = 41; // - - // int ALOAD_0 = 42; // - - // int ALOAD_1 = 43; // - - // int ALOAD_2 = 44; // - - // int ALOAD_3 = 45; // - - int IALOAD = 46; // visitInsn - int LALOAD = 47; // - - int FALOAD = 48; // - - int DALOAD = 49; // - - int AALOAD = 50; // - - int BALOAD = 51; // - - int CALOAD = 52; // - - int SALOAD = 53; // - - int ISTORE = 54; // visitVarInsn - int LSTORE = 55; // - - int FSTORE = 56; // - - int DSTORE = 57; // - - int ASTORE = 58; // - - // int ISTORE_0 = 59; // - - // int ISTORE_1 = 60; // - - // int ISTORE_2 = 61; // - - // int ISTORE_3 = 62; // - - // int LSTORE_0 = 63; // - - // int LSTORE_1 = 64; // - - // int LSTORE_2 = 65; // - - // int LSTORE_3 = 66; // - - // int FSTORE_0 = 67; // - - // int FSTORE_1 = 68; // - - // int FSTORE_2 = 69; // - - // int FSTORE_3 = 70; // - - // int DSTORE_0 = 71; // - - // int DSTORE_1 = 72; // - - // int DSTORE_2 = 73; // - - // int DSTORE_3 = 74; // - - // int ASTORE_0 = 75; // - - // int ASTORE_1 = 76; // - - // int ASTORE_2 = 77; // - - // int ASTORE_3 = 78; // - - int IASTORE = 79; // visitInsn - int LASTORE = 80; // - - int FASTORE = 81; // - - int DASTORE = 82; // - - int AASTORE = 83; // - - int BASTORE = 84; // - - int CASTORE = 85; // - - int SASTORE = 86; // - - int POP = 87; // - - int POP2 = 88; // - - int DUP = 89; // - - int DUP_X1 = 90; // - - int DUP_X2 = 91; // - - int DUP2 = 92; // - - int DUP2_X1 = 93; // - - int DUP2_X2 = 94; // - - int SWAP = 95; // - - int IADD = 96; // - - int LADD = 97; // - - int FADD = 98; // - - int DADD = 99; // - - int ISUB = 100; // - - int LSUB = 101; // - - int FSUB = 102; // - - int DSUB = 103; // - - int IMUL = 104; // - - int LMUL = 105; // - - int FMUL = 106; // - - int DMUL = 107; // - - int IDIV = 108; // - - int LDIV = 109; // - - int FDIV = 110; // - - int DDIV = 111; // - - int IREM = 112; // - - int LREM = 113; // - - int FREM = 114; // - - int DREM = 115; // - - int INEG = 116; // - - int LNEG = 117; // - - int FNEG = 118; // - - int DNEG = 119; // - - int ISHL = 120; // - - int LSHL = 121; // - - int ISHR = 122; // - - int LSHR = 123; // - - int IUSHR = 124; // - - int LUSHR = 125; // - - int IAND = 126; // - - int LAND = 127; // - - int IOR = 128; // - - int LOR = 129; // - - int IXOR = 130; // - - int LXOR = 131; // - - int IINC = 132; // visitIincInsn - int I2L = 133; // visitInsn - int I2F = 134; // - - int I2D = 135; // - - int L2I = 136; // - - int L2F = 137; // - - int L2D = 138; // - - int F2I = 139; // - - int F2L = 140; // - - int F2D = 141; // - - int D2I = 142; // - - int D2L = 143; // - - int D2F = 144; // - - int I2B = 145; // - - int I2C = 146; // - - int I2S = 147; // - - int LCMP = 148; // - - int FCMPL = 149; // - - int FCMPG = 150; // - - int DCMPL = 151; // - - int DCMPG = 152; // - - int IFEQ = 153; // visitJumpInsn - int IFNE = 154; // - - int IFLT = 155; // - - int IFGE = 156; // - - int IFGT = 157; // - - int IFLE = 158; // - - int IF_ICMPEQ = 159; // - - int IF_ICMPNE = 160; // - - int IF_ICMPLT = 161; // - - int IF_ICMPGE = 162; // - - int IF_ICMPGT = 163; // - - int IF_ICMPLE = 164; // - - int IF_ACMPEQ = 165; // - - int IF_ACMPNE = 166; // - - int GOTO = 167; // - - int JSR = 168; // - - int RET = 169; // visitVarInsn - int TABLESWITCH = 170; // visiTableSwitchInsn - int LOOKUPSWITCH = 171; // visitLookupSwitch - int IRETURN = 172; // visitInsn - int LRETURN = 173; // - - int FRETURN = 174; // - - int DRETURN = 175; // - - int ARETURN = 176; // - - int RETURN = 177; // - - int GETSTATIC = 178; // visitFieldInsn - int PUTSTATIC = 179; // - - int GETFIELD = 180; // - - int PUTFIELD = 181; // - - int INVOKEVIRTUAL = 182; // visitMethodInsn - int INVOKESPECIAL = 183; // - - int INVOKESTATIC = 184; // - - int INVOKEINTERFACE = 185; // - - int INVOKEDYNAMIC = 186; // visitInvokeDynamicInsn - int NEW = 187; // visitTypeInsn - int NEWARRAY = 188; // visitIntInsn - int ANEWARRAY = 189; // visitTypeInsn - int ARRAYLENGTH = 190; // visitInsn - int ATHROW = 191; // - - int CHECKCAST = 192; // visitTypeInsn - int INSTANCEOF = 193; // - - int MONITORENTER = 194; // visitInsn - int MONITOREXIT = 195; // - - // int WIDE = 196; // NOT VISITED - int MULTIANEWARRAY = 197; // visitMultiANewArrayInsn - int IFNULL = 198; // visitJumpInsn - int IFNONNULL = 199; // - - // int GOTO_W = 200; // - - // int JSR_W = 201; // - -} +/* + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ + +/* + * + * + * + * + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.redkale.asm; + +/** + * Defines the JVM opcodes, access flags and array type codes. This interface does not define all the JVM opcodes + * because some opcodes are automatically handled. For example, the xLOAD and xSTORE opcodes are automatically replaced + * by xLOAD_n and xSTORE_n opcodes when possible. The xLOAD_n and xSTORE_n opcodes are therefore not defined in this + * interface. Likewise for LDC, automatically replaced by LDC_W or LDC2_W when necessary, WIDE, GOTO_W and JSR_W. + * + * @author Eric Bruneton + * @author Eugene Kuleshov + */ +public interface Opcodes { + + // ASM API versions + int ASM4 = 4 << 16 | 0 << 8; + int ASM5 = 5 << 16 | 0 << 8; + int ASM6 = 6 << 16 | 0 << 8; + + // 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 V9 = 0 << 16 | 53; + int V10 = 0 << 16 | 54; + int V11 = 0 << 16 | 55; + + // access flags + + int ACC_PUBLIC = 0x0001; // class, field, method + int ACC_PRIVATE = 0x0002; // class, field, method + int ACC_PROTECTED = 0x0004; // class, field, method + int ACC_STATIC = 0x0008; // field, method + int ACC_FINAL = 0x0010; // class, field, method, parameter + int ACC_SUPER = 0x0020; // class + int ACC_SYNCHRONIZED = 0x0020; // method + int ACC_OPEN = 0x0020; // module + int ACC_TRANSITIVE = 0x0020; // module requires + int ACC_VOLATILE = 0x0040; // field + int ACC_BRIDGE = 0x0040; // method + int ACC_STATIC_PHASE = 0x0040; // module requires + int ACC_VARARGS = 0x0080; // method + int ACC_TRANSIENT = 0x0080; // field + int ACC_NATIVE = 0x0100; // method + int ACC_INTERFACE = 0x0200; // class + int ACC_ABSTRACT = 0x0400; // class, method + int ACC_STRICT = 0x0800; // method + int ACC_SYNTHETIC = 0x1000; // class, field, method, parameter, module * + int ACC_ANNOTATION = 0x2000; // class + int ACC_ENUM = 0x4000; // class(?) field inner + int ACC_MANDATED = 0x8000; // parameter, module, module * + int ACC_MODULE = 0x8000; // class + + // ASM specific pseudo access flags + + int ACC_DEPRECATED = 0x20000; // class, field, method + + // types for NEWARRAY + + int T_BOOLEAN = 4; + int T_CHAR = 5; + int T_FLOAT = 6; + int T_DOUBLE = 7; + int T_BYTE = 8; + int T_SHORT = 9; + int T_INT = 10; + int T_LONG = 11; + + // tags for Handle + + int H_GETFIELD = 1; + int H_GETSTATIC = 2; + int H_PUTFIELD = 3; + int H_PUTSTATIC = 4; + int H_INVOKEVIRTUAL = 5; + int H_INVOKESTATIC = 6; + int H_INVOKESPECIAL = 7; + int H_NEWINVOKESPECIAL = 8; + int H_INVOKEINTERFACE = 9; + + // stack map frame types + + /** Represents an expanded frame. See {@link ClassReader#EXPAND_FRAMES}. */ + int F_NEW = -1; + + /** Represents a compressed frame with complete frame data. */ + int F_FULL = 0; + + /** + * Represents a compressed frame where locals are the same as the locals in the previous frame, except that + * additional 1-3 locals are defined, and with an empty stack. + */ + int F_APPEND = 1; + + /** + * Represents a compressed frame where locals are the same as the locals in the previous frame, except that the last + * 1-3 locals are absent and with an empty stack. + */ + int F_CHOP = 2; + + /** Represents a compressed frame with exactly the same locals as the previous frame and with an empty stack. */ + int F_SAME = 3; + + /** + * Represents a compressed frame with exactly the same locals as the previous frame and with a single value on the + * stack. + */ + int F_SAME1 = 4; + + // Do not try to change the following code to use auto-boxing, + // these values are compared by reference and not by value + // The constructor of Integer was deprecated in 9 + // but we are stuck with it by backward compatibility + @SuppressWarnings("deprecation") + Integer TOP = new Integer(0); + + @SuppressWarnings("deprecation") + Integer INTEGER = new Integer(1); + + @SuppressWarnings("deprecation") + Integer FLOAT = new Integer(2); + + @SuppressWarnings("deprecation") + Integer DOUBLE = new Integer(3); + + @SuppressWarnings("deprecation") + Integer LONG = new Integer(4); + + @SuppressWarnings("deprecation") + Integer NULL = new Integer(5); + + @SuppressWarnings("deprecation") + Integer UNINITIALIZED_THIS = new Integer(6); + + // opcodes // visit method (- = idem) + + int NOP = 0; // visitInsn + int ACONST_NULL = 1; // - + int ICONST_M1 = 2; // - + int ICONST_0 = 3; // - + int ICONST_1 = 4; // - + int ICONST_2 = 5; // - + int ICONST_3 = 6; // - + int ICONST_4 = 7; // - + int ICONST_5 = 8; // - + int LCONST_0 = 9; // - + int LCONST_1 = 10; // - + int FCONST_0 = 11; // - + int FCONST_1 = 12; // - + int FCONST_2 = 13; // - + int DCONST_0 = 14; // - + int DCONST_1 = 15; // - + int BIPUSH = 16; // visitIntInsn + int SIPUSH = 17; // - + int LDC = 18; // visitLdcInsn + // int LDC_W = 19; // - + // int LDC2_W = 20; // - + int ILOAD = 21; // visitVarInsn + int LLOAD = 22; // - + int FLOAD = 23; // - + int DLOAD = 24; // - + int ALOAD = 25; // - + // int ILOAD_0 = 26; // - + // int ILOAD_1 = 27; // - + // int ILOAD_2 = 28; // - + // int ILOAD_3 = 29; // - + // int LLOAD_0 = 30; // - + // int LLOAD_1 = 31; // - + // int LLOAD_2 = 32; // - + // int LLOAD_3 = 33; // - + // int FLOAD_0 = 34; // - + // int FLOAD_1 = 35; // - + // int FLOAD_2 = 36; // - + // int FLOAD_3 = 37; // - + // int DLOAD_0 = 38; // - + // int DLOAD_1 = 39; // - + // int DLOAD_2 = 40; // - + // int DLOAD_3 = 41; // - + // int ALOAD_0 = 42; // - + // int ALOAD_1 = 43; // - + // int ALOAD_2 = 44; // - + // int ALOAD_3 = 45; // - + int IALOAD = 46; // visitInsn + int LALOAD = 47; // - + int FALOAD = 48; // - + int DALOAD = 49; // - + int AALOAD = 50; // - + int BALOAD = 51; // - + int CALOAD = 52; // - + int SALOAD = 53; // - + int ISTORE = 54; // visitVarInsn + int LSTORE = 55; // - + int FSTORE = 56; // - + int DSTORE = 57; // - + int ASTORE = 58; // - + // int ISTORE_0 = 59; // - + // int ISTORE_1 = 60; // - + // int ISTORE_2 = 61; // - + // int ISTORE_3 = 62; // - + // int LSTORE_0 = 63; // - + // int LSTORE_1 = 64; // - + // int LSTORE_2 = 65; // - + // int LSTORE_3 = 66; // - + // int FSTORE_0 = 67; // - + // int FSTORE_1 = 68; // - + // int FSTORE_2 = 69; // - + // int FSTORE_3 = 70; // - + // int DSTORE_0 = 71; // - + // int DSTORE_1 = 72; // - + // int DSTORE_2 = 73; // - + // int DSTORE_3 = 74; // - + // int ASTORE_0 = 75; // - + // int ASTORE_1 = 76; // - + // int ASTORE_2 = 77; // - + // int ASTORE_3 = 78; // - + int IASTORE = 79; // visitInsn + int LASTORE = 80; // - + int FASTORE = 81; // - + int DASTORE = 82; // - + int AASTORE = 83; // - + int BASTORE = 84; // - + int CASTORE = 85; // - + int SASTORE = 86; // - + int POP = 87; // - + int POP2 = 88; // - + int DUP = 89; // - + int DUP_X1 = 90; // - + int DUP_X2 = 91; // - + int DUP2 = 92; // - + int DUP2_X1 = 93; // - + int DUP2_X2 = 94; // - + int SWAP = 95; // - + int IADD = 96; // - + int LADD = 97; // - + int FADD = 98; // - + int DADD = 99; // - + int ISUB = 100; // - + int LSUB = 101; // - + int FSUB = 102; // - + int DSUB = 103; // - + int IMUL = 104; // - + int LMUL = 105; // - + int FMUL = 106; // - + int DMUL = 107; // - + int IDIV = 108; // - + int LDIV = 109; // - + int FDIV = 110; // - + int DDIV = 111; // - + int IREM = 112; // - + int LREM = 113; // - + int FREM = 114; // - + int DREM = 115; // - + int INEG = 116; // - + int LNEG = 117; // - + int FNEG = 118; // - + int DNEG = 119; // - + int ISHL = 120; // - + int LSHL = 121; // - + int ISHR = 122; // - + int LSHR = 123; // - + int IUSHR = 124; // - + int LUSHR = 125; // - + int IAND = 126; // - + int LAND = 127; // - + int IOR = 128; // - + int LOR = 129; // - + int IXOR = 130; // - + int LXOR = 131; // - + int IINC = 132; // visitIincInsn + int I2L = 133; // visitInsn + int I2F = 134; // - + int I2D = 135; // - + int L2I = 136; // - + int L2F = 137; // - + int L2D = 138; // - + int F2I = 139; // - + int F2L = 140; // - + int F2D = 141; // - + int D2I = 142; // - + int D2L = 143; // - + int D2F = 144; // - + int I2B = 145; // - + int I2C = 146; // - + int I2S = 147; // - + int LCMP = 148; // - + int FCMPL = 149; // - + int FCMPG = 150; // - + int DCMPL = 151; // - + int DCMPG = 152; // - + int IFEQ = 153; // visitJumpInsn + int IFNE = 154; // - + int IFLT = 155; // - + int IFGE = 156; // - + int IFGT = 157; // - + int IFLE = 158; // - + int IF_ICMPEQ = 159; // - + int IF_ICMPNE = 160; // - + int IF_ICMPLT = 161; // - + int IF_ICMPGE = 162; // - + int IF_ICMPGT = 163; // - + int IF_ICMPLE = 164; // - + int IF_ACMPEQ = 165; // - + int IF_ACMPNE = 166; // - + int GOTO = 167; // - + int JSR = 168; // - + int RET = 169; // visitVarInsn + int TABLESWITCH = 170; // visiTableSwitchInsn + int LOOKUPSWITCH = 171; // visitLookupSwitch + int IRETURN = 172; // visitInsn + int LRETURN = 173; // - + int FRETURN = 174; // - + int DRETURN = 175; // - + int ARETURN = 176; // - + int RETURN = 177; // - + int GETSTATIC = 178; // visitFieldInsn + int PUTSTATIC = 179; // - + int GETFIELD = 180; // - + int PUTFIELD = 181; // - + int INVOKEVIRTUAL = 182; // visitMethodInsn + int INVOKESPECIAL = 183; // - + int INVOKESTATIC = 184; // - + int INVOKEINTERFACE = 185; // - + int INVOKEDYNAMIC = 186; // visitInvokeDynamicInsn + int NEW = 187; // visitTypeInsn + int NEWARRAY = 188; // visitIntInsn + int ANEWARRAY = 189; // visitTypeInsn + int ARRAYLENGTH = 190; // visitInsn + int ATHROW = 191; // - + int CHECKCAST = 192; // visitTypeInsn + int INSTANCEOF = 193; // - + int MONITORENTER = 194; // visitInsn + int MONITOREXIT = 195; // - + // int WIDE = 196; // NOT VISITED + int MULTIANEWARRAY = 197; // visitMultiANewArrayInsn + int IFNULL = 198; // visitJumpInsn + int IFNONNULL = 199; // - + // int GOTO_W = 200; // - + // int JSR_W = 201; // - +} diff --git a/src/main/java/org/redkale/asm/Type.java b/src/main/java/org/redkale/asm/Type.java index 24ff609a4..ea9e82612 100644 --- a/src/main/java/org/redkale/asm/Type.java +++ b/src/main/java/org/redkale/asm/Type.java @@ -1,815 +1,815 @@ -/* - * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */ - -/* - * - * - * - * - * - * ASM: a very small and fast Java bytecode manipulation framework - * Copyright (c) 2000-2011 INRIA, France Telecom - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.redkale.asm; - -import java.lang.reflect.Constructor; -import java.lang.reflect.Method; - -/** - * A Java field or method type. This class can be used to make it easier to manipulate type and method descriptors. - * - * @author Eric Bruneton - * @author Chris Nokleberg - */ -public class Type { - - /** The sort of the <tt>void</tt> type. See {@link #getSort getSort}. */ - public static final int VOID = 0; - - /** The sort of the <tt>boolean</tt> type. See {@link #getSort getSort}. */ - public static final int BOOLEAN = 1; - - /** The sort of the <tt>char</tt> type. See {@link #getSort getSort}. */ - public static final int CHAR = 2; - - /** The sort of the <tt>byte</tt> type. See {@link #getSort getSort}. */ - public static final int BYTE = 3; - - /** The sort of the <tt>short</tt> type. See {@link #getSort getSort}. */ - public static final int SHORT = 4; - - /** The sort of the <tt>int</tt> type. See {@link #getSort getSort}. */ - public static final int INT = 5; - - /** The sort of the <tt>float</tt> type. See {@link #getSort getSort}. */ - public static final int FLOAT = 6; - - /** The sort of the <tt>long</tt> type. See {@link #getSort getSort}. */ - public static final int LONG = 7; - - /** The sort of the <tt>double</tt> type. See {@link #getSort getSort}. */ - public static final int DOUBLE = 8; - - /** The sort of array reference types. See {@link #getSort getSort}. */ - public static final int ARRAY = 9; - - /** The sort of object reference types. See {@link #getSort getSort}. */ - public static final int OBJECT = 10; - - /** The sort of method types. See {@link #getSort getSort}. */ - public static final int METHOD = 11; - - /** The <tt>void</tt> type. */ - public static final Type VOID_TYPE = new Type(VOID, null, ('V' << 24) | (5 << 16) | (0 << 8) | 0, 1); - - /** The <tt>boolean</tt> type. */ - public static final Type BOOLEAN_TYPE = new Type(BOOLEAN, null, ('Z' << 24) | (0 << 16) | (5 << 8) | 1, 1); - - /** The <tt>char</tt> type. */ - public static final Type CHAR_TYPE = new Type(CHAR, null, ('C' << 24) | (0 << 16) | (6 << 8) | 1, 1); - - /** The <tt>byte</tt> type. */ - public static final Type BYTE_TYPE = new Type(BYTE, null, ('B' << 24) | (0 << 16) | (5 << 8) | 1, 1); - - /** The <tt>short</tt> type. */ - public static final Type SHORT_TYPE = new Type(SHORT, null, ('S' << 24) | (0 << 16) | (7 << 8) | 1, 1); - - /** The <tt>int</tt> type. */ - public static final Type INT_TYPE = new Type(INT, null, ('I' << 24) | (0 << 16) | (0 << 8) | 1, 1); - - /** The <tt>float</tt> type. */ - public static final Type FLOAT_TYPE = new Type(FLOAT, null, ('F' << 24) | (2 << 16) | (2 << 8) | 1, 1); - - /** The <tt>long</tt> type. */ - public static final Type LONG_TYPE = new Type(LONG, null, ('J' << 24) | (1 << 16) | (1 << 8) | 2, 1); - - /** The <tt>double</tt> type. */ - public static final Type DOUBLE_TYPE = new Type(DOUBLE, null, ('D' << 24) | (3 << 16) | (3 << 8) | 2, 1); - - // ------------------------------------------------------------------------ - // Fields - // ------------------------------------------------------------------------ - - /** The sort of this Java type. */ - private final int sort; - - /** A buffer containing the internal name of this Java type. This field is only used for reference types. */ - private final char[] buf; - - /** - * The offset of the internal name of this Java type in {@link #buf buf} or, for primitive types, the size, - * descriptor and getOpcode offsets for this type (byte 0 contains the size, byte 1 the descriptor, byte 2 the - * offset for IALOAD or IASTORE, byte 3 the offset for all other instructions). - */ - private final int off; - - /** The length of the internal name of this Java type. */ - private final int len; - - // ------------------------------------------------------------------------ - // Constructors - // ------------------------------------------------------------------------ - - /** - * Constructs a reference type. - * - * @param sort the sort of the reference type to be constructed. - * @param buf a buffer containing the descriptor of the previous type. - * @param off the offset of this descriptor in the previous buffer. - * @param len the length of this descriptor. - */ - private Type(final int sort, final char[] buf, final int off, final int len) { - this.sort = sort; - this.buf = buf; - this.off = off; - this.len = len; - } - - /** - * Returns the Java type corresponding to the given type descriptor. - * - * @param typeDescriptor a field or method type descriptor. - * @return the Java type corresponding to the given type descriptor. - */ - public static Type getType(final String typeDescriptor) { - return getType(typeDescriptor.toCharArray(), 0); - } - - /** - * Returns the Java type corresponding to the given internal name. - * - * @param internalName an internal name. - * @return the Java type corresponding to the given internal name. - */ - public static Type getObjectType(final String internalName) { - char[] buf = internalName.toCharArray(); - return new Type(buf[0] == '[' ? ARRAY : OBJECT, buf, 0, buf.length); - } - - /** - * Returns the Java type corresponding to the given method descriptor. Equivalent to - * Type.getType(methodDescriptor). - * - * @param methodDescriptor a method descriptor. - * @return the Java type corresponding to the given method descriptor. - */ - public static Type getMethodType(final String methodDescriptor) { - return getType(methodDescriptor.toCharArray(), 0); - } - - /** - * Returns the Java method type corresponding to the given argument and return types. - * - * @param returnType the return type of the method. - * @param argumentTypes the argument types of the method. - * @return the Java type corresponding to the given argument and return types. - */ - public static Type getMethodType(final Type returnType, final Type... argumentTypes) { - return getType(getMethodDescriptor(returnType, argumentTypes)); - } - - /** - * Returns the Java type corresponding to the given class. - * - * @param c a class. - * @return the Java type corresponding to the given class. - */ - public static Type getType(final Class c) { - if (c.isPrimitive()) { - if (c == Integer.TYPE) { - return INT_TYPE; - } else if (c == Void.TYPE) { - return VOID_TYPE; - } else if (c == Boolean.TYPE) { - return BOOLEAN_TYPE; - } else if (c == Byte.TYPE) { - return BYTE_TYPE; - } else if (c == Character.TYPE) { - return CHAR_TYPE; - } else if (c == Short.TYPE) { - return SHORT_TYPE; - } else if (c == Double.TYPE) { - return DOUBLE_TYPE; - } else if (c == Float.TYPE) { - return FLOAT_TYPE; - } else /* if (c == Long.TYPE) */ { - return LONG_TYPE; - } - } else { - return getType(getDescriptor(c)); - } - } - - /** - * Returns the Java method type corresponding to the given constructor. - * - * @param c a {@link Constructor Constructor} object. - * @return the Java method type corresponding to the given constructor. - */ - public static Type getType(final Constructor c) { - return getType(getConstructorDescriptor(c)); - } - - /** - * Returns the Java method type corresponding to the given method. - * - * @param m a {@link Method Method} object. - * @return the Java method type corresponding to the given method. - */ - public static Type getType(final Method m) { - return getType(getMethodDescriptor(m)); - } - - /** - * Returns the Java types corresponding to the argument types of the given method descriptor. - * - * @param methodDescriptor a method descriptor. - * @return the Java types corresponding to the argument types of the given method descriptor. - */ - public static Type[] getArgumentTypes(final String methodDescriptor) { - char[] buf = methodDescriptor.toCharArray(); - int off = 1; - int size = 0; - while (true) { - char car = buf[off++]; - if (car == ')') { - break; - } else if (car == 'L') { - while (buf[off++] != ';') { - // do nothing - } - ++size; - } else if (car != '[') { - ++size; - } - } - Type[] args = new Type[size]; - off = 1; - size = 0; - while (buf[off] != ')') { - args[size] = getType(buf, off); - off += args[size].len + (args[size].sort == OBJECT ? 2 : 0); - size += 1; - } - return args; - } - - /** - * Returns the Java types corresponding to the argument types of the given method. - * - * @param method a method. - * @return the Java types corresponding to the argument types of the given method. - */ - public static Type[] getArgumentTypes(final Method method) { - Class[] classes = method.getParameterTypes(); - Type[] types = new Type[classes.length]; - for (int i = classes.length - 1; i >= 0; --i) { - types[i] = getType(classes[i]); - } - return types; - } - - /** - * Returns the Java type corresponding to the return type of the given method descriptor. - * - * @param methodDescriptor a method descriptor. - * @return the Java type corresponding to the return type of the given method descriptor. - */ - public static Type getReturnType(final String methodDescriptor) { - char[] buf = methodDescriptor.toCharArray(); - int off = 1; - while (true) { - char car = buf[off++]; - if (car == ')') { - return getType(buf, off); - } else if (car == 'L') { - while (buf[off++] != ';') { - // do nothing - } - } - } - } - - /** - * Returns the Java type corresponding to the return type of the given method. - * - * @param method a method. - * @return the Java type corresponding to the return type of the given method. - */ - public static Type getReturnType(final Method method) { - return getType(method.getReturnType()); - } - - /** - * Computes the size of the arguments and of the return value of a method. - * - * @param desc the descriptor of a method. - * @return the size of the arguments of the method (plus one for the implicit this argument), argSize, and the size - * of its return value, retSize, packed into a single int i = <tt>(argSize << 2) | - * retSize</tt> (argSize is therefore equal to <tt>i >> 2</tt>, and retSize to - * <tt>i & 0x03</tt>). - */ - public static int getArgumentsAndReturnSizes(final String desc) { - int n = 1; - int c = 1; - while (true) { - char car = desc.charAt(c++); - if (car == ')') { - car = desc.charAt(c); - return n << 2 | (car == 'V' ? 0 : (car == 'D' || car == 'J' ? 2 : 1)); - } else if (car == 'L') { - while (desc.charAt(c++) != ';') { - // do nothing - } - n += 1; - } else if (car == '[') { - while ((car = desc.charAt(c)) == '[') { - ++c; - } - if (car == 'D' || car == 'J') { - n -= 1; - } - } else if (car == 'D' || car == 'J') { - n += 2; - } else { - n += 1; - } - } - } - - /** - * Returns the Java type corresponding to the given type descriptor. For method descriptors, buf is supposed to - * contain nothing more than the descriptor itself. - * - * @param buf a buffer containing a type descriptor. - * @param off the offset of this descriptor in the previous buffer. - * @return the Java type corresponding to the given type descriptor. - */ - private static Type getType(final char[] buf, final int off) { - int len; - switch (buf[off]) { - case 'V': - return VOID_TYPE; - case 'Z': - return BOOLEAN_TYPE; - case 'C': - return CHAR_TYPE; - case 'B': - return BYTE_TYPE; - case 'S': - return SHORT_TYPE; - case 'I': - return INT_TYPE; - case 'F': - return FLOAT_TYPE; - case 'J': - return LONG_TYPE; - case 'D': - return DOUBLE_TYPE; - case '[': - len = 1; - while (buf[off + len] == '[') { - ++len; - } - if (buf[off + len] == 'L') { - ++len; - while (buf[off + len] != ';') { - ++len; - } - } - return new Type(ARRAY, buf, off, len + 1); - case 'L': - len = 1; - while (buf[off + len] != ';') { - ++len; - } - return new Type(OBJECT, buf, off + 1, len - 1); - // case '(': - default: - return new Type(METHOD, buf, off, buf.length - off); - } - } - - // ------------------------------------------------------------------------ - // Accessors - // ------------------------------------------------------------------------ - - /** - * Returns the sort of this Java type. - * - * @return {@link #VOID VOID}, {@link #BOOLEAN BOOLEAN}, {@link #CHAR CHAR}, {@link #BYTE BYTE}, {@link #SHORT - * SHORT}, {@link #INT INT}, {@link #FLOAT FLOAT}, {@link #LONG LONG}, {@link #DOUBLE DOUBLE}, {@link #ARRAY - * ARRAY}, {@link #OBJECT OBJECT} or {@link #METHOD METHOD}. - */ - public int getSort() { - return sort; - } - - /** - * Returns the number of dimensions of this array type. This method should only be used for an array type. - * - * @return the number of dimensions of this array type. - */ - public int getDimensions() { - int i = 1; - while (buf[off + i] == '[') { - ++i; - } - return i; - } - - /** - * Returns the type of the elements of this array type. This method should only be used for an array type. - * - * @return Returns the type of the elements of this array type. - */ - public Type getElementType() { - return getType(buf, off + getDimensions()); - } - - /** - * Returns the binary name of the class corresponding to this type. This method must not be used on method types. - * - * @return the binary name of the class corresponding to this type. - */ - public String getClassName() { - switch (sort) { - case VOID: - return "void"; - case BOOLEAN: - return "boolean"; - case CHAR: - return "char"; - case BYTE: - return "byte"; - case SHORT: - return "short"; - case INT: - return "int"; - case FLOAT: - return "float"; - case LONG: - return "long"; - case DOUBLE: - return "double"; - case ARRAY: - StringBuilder sb = new StringBuilder(getElementType().getClassName()); - for (int i = getDimensions(); i > 0; --i) { - sb.append("[]"); - } - return sb.toString(); - case OBJECT: - return new String(buf, off, len).replace('/', '.'); - default: - return null; - } - } - - /** - * Returns the internal name of the class corresponding to this object or array type. The internal name of a class - * is its fully qualified name (as returned by Class.getName(), where '.' are replaced by '/'. This method should - * only be used for an object or array type. - * - * @return the internal name of the class corresponding to this object type. - */ - public String getInternalName() { - return new String(buf, off, len); - } - - /** - * Returns the argument types of methods of this type. This method should only be used for method types. - * - * @return the argument types of methods of this type. - */ - public Type[] getArgumentTypes() { - return getArgumentTypes(getDescriptor()); - } - - /** - * Returns the return type of methods of this type. This method should only be used for method types. - * - * @return the return type of methods of this type. - */ - public Type getReturnType() { - return getReturnType(getDescriptor()); - } - - /** - * Returns the size of the arguments and of the return value of methods of this type. This method should only be - * used for method types. - * - * @return the size of the arguments (plus one for the implicit this argument), argSize, and the size of the return - * value, retSize, packed into a single int i = <tt>(argSize << 2) | retSize</tt> (argSize - * is therefore equal to <tt>i >> 2</tt>, and retSize to <tt>i & - * 0x03</tt>). - */ - public int getArgumentsAndReturnSizes() { - return getArgumentsAndReturnSizes(getDescriptor()); - } - - // ------------------------------------------------------------------------ - // Conversion to type descriptors - // ------------------------------------------------------------------------ - - /** - * Returns the descriptor corresponding to this Java type. - * - * @return the descriptor corresponding to this Java type. - */ - public String getDescriptor() { - StringBuilder buf = new StringBuilder(); - getDescriptor(buf); - return buf.toString(); - } - - /** - * Returns the descriptor corresponding to the given argument and return types. - * - * @param returnType the return type of the method. - * @param argumentTypes the argument types of the method. - * @return the descriptor corresponding to the given argument and return types. - */ - public static String getMethodDescriptor(final Type returnType, final Type... argumentTypes) { - StringBuilder buf = new StringBuilder(); - buf.append('('); - for (int i = 0; i < argumentTypes.length; ++i) { - argumentTypes[i].getDescriptor(buf); - } - buf.append(')'); - returnType.getDescriptor(buf); - return buf.toString(); - } - - /** - * Appends the descriptor corresponding to this Java type to the given string buffer. - * - * @param buf the string buffer to which the descriptor must be appended. - */ - private void getDescriptor(final StringBuilder buf) { - if (this.buf == null) { - // descriptor is in byte 3 of 'off' for primitive types (buf == - // null) - buf.append((char) ((off & 0xFF000000) >>> 24)); - } else if (sort == OBJECT) { - buf.append('L'); - buf.append(this.buf, off, len); - buf.append(';'); - } else { // sort == ARRAY || sort == METHOD - buf.append(this.buf, off, len); - } - } - - // ------------------------------------------------------------------------ - // Direct conversion from classes to type descriptors, - // without intermediate Type objects - // ------------------------------------------------------------------------ - - /** - * Returns the internal name of the given class. The internal name of a class is its fully qualified name, as - * returned by Class.getName(), where '.' are replaced by '/'. - * - * @param c an object or array class. - * @return the internal name of the given class. - */ - public static String getInternalName(final Class c) { - return c.getName().replace('.', '/'); - } - - /** - * Returns the descriptor corresponding to the given Java type. - * - * @param c an object class, a primitive class or an array class. - * @return the descriptor corresponding to the given class. - */ - public static String getDescriptor(final Class c) { - StringBuilder buf = new StringBuilder(); - getDescriptor(buf, c); - return buf.toString(); - } - - /** - * Returns the descriptor corresponding to the given constructor. - * - * @param c a {@link Constructor Constructor} object. - * @return the descriptor of the given constructor. - */ - public static String getConstructorDescriptor(final Constructor c) { - Class[] parameters = c.getParameterTypes(); - StringBuilder buf = new StringBuilder(); - buf.append('('); - for (int i = 0; i < parameters.length; ++i) { - getDescriptor(buf, parameters[i]); - } - return buf.append(")V").toString(); - } - - /** - * Returns the descriptor corresponding to the given method. - * - * @param m a {@link Method Method} object. - * @return the descriptor of the given method. - */ - public static String getMethodDescriptor(final Method m) { - Class[] parameters = m.getParameterTypes(); - StringBuilder buf = new StringBuilder(); - buf.append('('); - for (int i = 0; i < parameters.length; ++i) { - getDescriptor(buf, parameters[i]); - } - buf.append(')'); - getDescriptor(buf, m.getReturnType()); - return buf.toString(); - } - - /** - * Appends the descriptor of the given class to the given string buffer. - * - * @param buf the string buffer to which the descriptor must be appended. - * @param c the class whose descriptor must be computed. - */ - private static void getDescriptor(final StringBuilder buf, final Class c) { - Class d = c; - while (true) { - if (d.isPrimitive()) { - char car; - if (d == Integer.TYPE) { - car = 'I'; - } else if (d == Void.TYPE) { - car = 'V'; - } else if (d == Boolean.TYPE) { - car = 'Z'; - } else if (d == Byte.TYPE) { - car = 'B'; - } else if (d == Character.TYPE) { - car = 'C'; - } else if (d == Short.TYPE) { - car = 'S'; - } else if (d == Double.TYPE) { - car = 'D'; - } else if (d == Float.TYPE) { - car = 'F'; - } else /* if (d == Long.TYPE) */ { - car = 'J'; - } - buf.append(car); - return; - } else if (d.isArray()) { - buf.append('['); - d = d.getComponentType(); - } else { - buf.append('L'); - String name = d.getName(); - int len = name.length(); - for (int i = 0; i < len; ++i) { - char car = name.charAt(i); - buf.append(car == '.' ? '/' : car); - } - buf.append(';'); - return; - } - } - } - - // ------------------------------------------------------------------------ - // Corresponding size and opcodes - // ------------------------------------------------------------------------ - - /** - * Returns the size of values of this type. This method must not be used for method types. - * - * @return the size of values of this type, i.e., 2 for <tt>long</tt> and - * <tt>double</tt>, 0 for <tt>void</tt> and 1 otherwise. - */ - public int getSize() { - // the size is in byte 0 of 'off' for primitive types (buf == null) - return buf == null ? (off & 0xFF) : 1; - } - - /** - * Returns a JVM instruction opcode adapted to this Java type. This method must not be used for method types. - * - * @param opcode a JVM instruction opcode. This opcode must be one of ILOAD, ISTORE, IALOAD, IASTORE, IADD, ISUB, - * IMUL, IDIV, IREM, INEG, ISHL, ISHR, IUSHR, IAND, IOR, IXOR and IRETURN. - * @return an opcode that is similar to the given opcode, but adapted to this Java type. For example, if this type - * is <tt>float</tt> and <tt>opcode</tt> is IRETURN, this method returns - * FRETURN. - */ - public int getOpcode(final int opcode) { - if (opcode == Opcodes.IALOAD || opcode == Opcodes.IASTORE) { - // the offset for IALOAD or IASTORE is in byte 1 of 'off' for - // primitive types (buf == null) - return opcode + (buf == null ? (off & 0xFF00) >> 8 : 4); - } else { - // the offset for other instructions is in byte 2 of 'off' for - // primitive types (buf == null) - return opcode + (buf == null ? (off & 0xFF0000) >> 16 : 4); - } - } - - // ------------------------------------------------------------------------ - // Equals, hashCode and toString - // ------------------------------------------------------------------------ - - /** - * Tests if the given object is equal to this type. - * - * @param o the object to be compared to this type. - * @return <tt>true</tt> if the given object is equal to this type. - */ - @Override - public boolean equals(final Object o) { - if (this == o) { - return true; - } - if (!(o instanceof Type)) { - return false; - } - Type t = (Type) o; - if (sort != t.sort) { - return false; - } - if (sort >= ARRAY) { - if (len != t.len) { - return false; - } - for (int i = off, j = t.off, end = i + len; i < end; i++, j++) { - if (buf[i] != t.buf[j]) { - return false; - } - } - } - return true; - } - - /** - * Returns a hash code value for this type. - * - * @return a hash code value for this type. - */ - @Override - public int hashCode() { - int hc = 13 * sort; - if (sort >= ARRAY) { - for (int i = off, end = i + len; i < end; i++) { - hc = 17 * (hc + buf[i]); - } - } - return hc; - } - - /** - * Returns a string representation of this type. - * - * @return the descriptor of this type. - */ - @Override - public String toString() { - return getDescriptor(); - } -} +/* + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ + +/* + * + * + * + * + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.redkale.asm; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; + +/** + * A Java field or method type. This class can be used to make it easier to manipulate type and method descriptors. + * + * @author Eric Bruneton + * @author Chris Nokleberg + */ +public class Type { + + /** The sort of the <tt>void</tt> type. See {@link #getSort getSort}. */ + public static final int VOID = 0; + + /** The sort of the <tt>boolean</tt> type. See {@link #getSort getSort}. */ + public static final int BOOLEAN = 1; + + /** The sort of the <tt>char</tt> type. See {@link #getSort getSort}. */ + public static final int CHAR = 2; + + /** The sort of the <tt>byte</tt> type. See {@link #getSort getSort}. */ + public static final int BYTE = 3; + + /** The sort of the <tt>short</tt> type. See {@link #getSort getSort}. */ + public static final int SHORT = 4; + + /** The sort of the <tt>int</tt> type. See {@link #getSort getSort}. */ + public static final int INT = 5; + + /** The sort of the <tt>float</tt> type. See {@link #getSort getSort}. */ + public static final int FLOAT = 6; + + /** The sort of the <tt>long</tt> type. See {@link #getSort getSort}. */ + public static final int LONG = 7; + + /** The sort of the <tt>double</tt> type. See {@link #getSort getSort}. */ + public static final int DOUBLE = 8; + + /** The sort of array reference types. See {@link #getSort getSort}. */ + public static final int ARRAY = 9; + + /** The sort of object reference types. See {@link #getSort getSort}. */ + public static final int OBJECT = 10; + + /** The sort of method types. See {@link #getSort getSort}. */ + public static final int METHOD = 11; + + /** The <tt>void</tt> type. */ + public static final Type VOID_TYPE = new Type(VOID, null, ('V' << 24) | (5 << 16) | (0 << 8) | 0, 1); + + /** The <tt>boolean</tt> type. */ + public static final Type BOOLEAN_TYPE = new Type(BOOLEAN, null, ('Z' << 24) | (0 << 16) | (5 << 8) | 1, 1); + + /** The <tt>char</tt> type. */ + public static final Type CHAR_TYPE = new Type(CHAR, null, ('C' << 24) | (0 << 16) | (6 << 8) | 1, 1); + + /** The <tt>byte</tt> type. */ + public static final Type BYTE_TYPE = new Type(BYTE, null, ('B' << 24) | (0 << 16) | (5 << 8) | 1, 1); + + /** The <tt>short</tt> type. */ + public static final Type SHORT_TYPE = new Type(SHORT, null, ('S' << 24) | (0 << 16) | (7 << 8) | 1, 1); + + /** The <tt>int</tt> type. */ + public static final Type INT_TYPE = new Type(INT, null, ('I' << 24) | (0 << 16) | (0 << 8) | 1, 1); + + /** The <tt>float</tt> type. */ + public static final Type FLOAT_TYPE = new Type(FLOAT, null, ('F' << 24) | (2 << 16) | (2 << 8) | 1, 1); + + /** The <tt>long</tt> type. */ + public static final Type LONG_TYPE = new Type(LONG, null, ('J' << 24) | (1 << 16) | (1 << 8) | 2, 1); + + /** The <tt>double</tt> type. */ + public static final Type DOUBLE_TYPE = new Type(DOUBLE, null, ('D' << 24) | (3 << 16) | (3 << 8) | 2, 1); + + // ------------------------------------------------------------------------ + // Fields + // ------------------------------------------------------------------------ + + /** The sort of this Java type. */ + private final int sort; + + /** A buffer containing the internal name of this Java type. This field is only used for reference types. */ + private final char[] buf; + + /** + * The offset of the internal name of this Java type in {@link #buf buf} or, for primitive types, the size, + * descriptor and getOpcode offsets for this type (byte 0 contains the size, byte 1 the descriptor, byte 2 the + * offset for IALOAD or IASTORE, byte 3 the offset for all other instructions). + */ + private final int off; + + /** The length of the internal name of this Java type. */ + private final int len; + + // ------------------------------------------------------------------------ + // Constructors + // ------------------------------------------------------------------------ + + /** + * Constructs a reference type. + * + * @param sort the sort of the reference type to be constructed. + * @param buf a buffer containing the descriptor of the previous type. + * @param off the offset of this descriptor in the previous buffer. + * @param len the length of this descriptor. + */ + private Type(final int sort, final char[] buf, final int off, final int len) { + this.sort = sort; + this.buf = buf; + this.off = off; + this.len = len; + } + + /** + * Returns the Java type corresponding to the given type descriptor. + * + * @param typeDescriptor a field or method type descriptor. + * @return the Java type corresponding to the given type descriptor. + */ + public static Type getType(final String typeDescriptor) { + return getType(typeDescriptor.toCharArray(), 0); + } + + /** + * Returns the Java type corresponding to the given internal name. + * + * @param internalName an internal name. + * @return the Java type corresponding to the given internal name. + */ + public static Type getObjectType(final String internalName) { + char[] buf = internalName.toCharArray(); + return new Type(buf[0] == '[' ? ARRAY : OBJECT, buf, 0, buf.length); + } + + /** + * Returns the Java type corresponding to the given method descriptor. Equivalent to + * Type.getType(methodDescriptor). + * + * @param methodDescriptor a method descriptor. + * @return the Java type corresponding to the given method descriptor. + */ + public static Type getMethodType(final String methodDescriptor) { + return getType(methodDescriptor.toCharArray(), 0); + } + + /** + * Returns the Java method type corresponding to the given argument and return types. + * + * @param returnType the return type of the method. + * @param argumentTypes the argument types of the method. + * @return the Java type corresponding to the given argument and return types. + */ + public static Type getMethodType(final Type returnType, final Type... argumentTypes) { + return getType(getMethodDescriptor(returnType, argumentTypes)); + } + + /** + * Returns the Java type corresponding to the given class. + * + * @param c a class. + * @return the Java type corresponding to the given class. + */ + public static Type getType(final Class c) { + if (c.isPrimitive()) { + if (c == Integer.TYPE) { + return INT_TYPE; + } else if (c == Void.TYPE) { + return VOID_TYPE; + } else if (c == Boolean.TYPE) { + return BOOLEAN_TYPE; + } else if (c == Byte.TYPE) { + return BYTE_TYPE; + } else if (c == Character.TYPE) { + return CHAR_TYPE; + } else if (c == Short.TYPE) { + return SHORT_TYPE; + } else if (c == Double.TYPE) { + return DOUBLE_TYPE; + } else if (c == Float.TYPE) { + return FLOAT_TYPE; + } else /* if (c == Long.TYPE) */ { + return LONG_TYPE; + } + } else { + return getType(getDescriptor(c)); + } + } + + /** + * Returns the Java method type corresponding to the given constructor. + * + * @param c a {@link Constructor Constructor} object. + * @return the Java method type corresponding to the given constructor. + */ + public static Type getType(final Constructor c) { + return getType(getConstructorDescriptor(c)); + } + + /** + * Returns the Java method type corresponding to the given method. + * + * @param m a {@link Method Method} object. + * @return the Java method type corresponding to the given method. + */ + public static Type getType(final Method m) { + return getType(getMethodDescriptor(m)); + } + + /** + * Returns the Java types corresponding to the argument types of the given method descriptor. + * + * @param methodDescriptor a method descriptor. + * @return the Java types corresponding to the argument types of the given method descriptor. + */ + public static Type[] getArgumentTypes(final String methodDescriptor) { + char[] buf = methodDescriptor.toCharArray(); + int off = 1; + int size = 0; + while (true) { + char car = buf[off++]; + if (car == ')') { + break; + } else if (car == 'L') { + while (buf[off++] != ';') { + // do nothing + } + ++size; + } else if (car != '[') { + ++size; + } + } + Type[] args = new Type[size]; + off = 1; + size = 0; + while (buf[off] != ')') { + args[size] = getType(buf, off); + off += args[size].len + (args[size].sort == OBJECT ? 2 : 0); + size += 1; + } + return args; + } + + /** + * Returns the Java types corresponding to the argument types of the given method. + * + * @param method a method. + * @return the Java types corresponding to the argument types of the given method. + */ + public static Type[] getArgumentTypes(final Method method) { + Class[] classes = method.getParameterTypes(); + Type[] types = new Type[classes.length]; + for (int i = classes.length - 1; i >= 0; --i) { + types[i] = getType(classes[i]); + } + return types; + } + + /** + * Returns the Java type corresponding to the return type of the given method descriptor. + * + * @param methodDescriptor a method descriptor. + * @return the Java type corresponding to the return type of the given method descriptor. + */ + public static Type getReturnType(final String methodDescriptor) { + char[] buf = methodDescriptor.toCharArray(); + int off = 1; + while (true) { + char car = buf[off++]; + if (car == ')') { + return getType(buf, off); + } else if (car == 'L') { + while (buf[off++] != ';') { + // do nothing + } + } + } + } + + /** + * Returns the Java type corresponding to the return type of the given method. + * + * @param method a method. + * @return the Java type corresponding to the return type of the given method. + */ + public static Type getReturnType(final Method method) { + return getType(method.getReturnType()); + } + + /** + * Computes the size of the arguments and of the return value of a method. + * + * @param desc the descriptor of a method. + * @return the size of the arguments of the method (plus one for the implicit this argument), argSize, and the size + * of its return value, retSize, packed into a single int i = <tt>(argSize << 2) | + * retSize</tt> (argSize is therefore equal to <tt>i >> 2</tt>, and retSize to + * <tt>i & 0x03</tt>). + */ + public static int getArgumentsAndReturnSizes(final String desc) { + int n = 1; + int c = 1; + while (true) { + char car = desc.charAt(c++); + if (car == ')') { + car = desc.charAt(c); + return n << 2 | (car == 'V' ? 0 : (car == 'D' || car == 'J' ? 2 : 1)); + } else if (car == 'L') { + while (desc.charAt(c++) != ';') { + // do nothing + } + n += 1; + } else if (car == '[') { + while ((car = desc.charAt(c)) == '[') { + ++c; + } + if (car == 'D' || car == 'J') { + n -= 1; + } + } else if (car == 'D' || car == 'J') { + n += 2; + } else { + n += 1; + } + } + } + + /** + * Returns the Java type corresponding to the given type descriptor. For method descriptors, buf is supposed to + * contain nothing more than the descriptor itself. + * + * @param buf a buffer containing a type descriptor. + * @param off the offset of this descriptor in the previous buffer. + * @return the Java type corresponding to the given type descriptor. + */ + private static Type getType(final char[] buf, final int off) { + int len; + switch (buf[off]) { + case 'V': + return VOID_TYPE; + case 'Z': + return BOOLEAN_TYPE; + case 'C': + return CHAR_TYPE; + case 'B': + return BYTE_TYPE; + case 'S': + return SHORT_TYPE; + case 'I': + return INT_TYPE; + case 'F': + return FLOAT_TYPE; + case 'J': + return LONG_TYPE; + case 'D': + return DOUBLE_TYPE; + case '[': + len = 1; + while (buf[off + len] == '[') { + ++len; + } + if (buf[off + len] == 'L') { + ++len; + while (buf[off + len] != ';') { + ++len; + } + } + return new Type(ARRAY, buf, off, len + 1); + case 'L': + len = 1; + while (buf[off + len] != ';') { + ++len; + } + return new Type(OBJECT, buf, off + 1, len - 1); + // case '(': + default: + return new Type(METHOD, buf, off, buf.length - off); + } + } + + // ------------------------------------------------------------------------ + // Accessors + // ------------------------------------------------------------------------ + + /** + * Returns the sort of this Java type. + * + * @return {@link #VOID VOID}, {@link #BOOLEAN BOOLEAN}, {@link #CHAR CHAR}, {@link #BYTE BYTE}, {@link #SHORT + * SHORT}, {@link #INT INT}, {@link #FLOAT FLOAT}, {@link #LONG LONG}, {@link #DOUBLE DOUBLE}, {@link #ARRAY + * ARRAY}, {@link #OBJECT OBJECT} or {@link #METHOD METHOD}. + */ + public int getSort() { + return sort; + } + + /** + * Returns the number of dimensions of this array type. This method should only be used for an array type. + * + * @return the number of dimensions of this array type. + */ + public int getDimensions() { + int i = 1; + while (buf[off + i] == '[') { + ++i; + } + return i; + } + + /** + * Returns the type of the elements of this array type. This method should only be used for an array type. + * + * @return Returns the type of the elements of this array type. + */ + public Type getElementType() { + return getType(buf, off + getDimensions()); + } + + /** + * Returns the binary name of the class corresponding to this type. This method must not be used on method types. + * + * @return the binary name of the class corresponding to this type. + */ + public String getClassName() { + switch (sort) { + case VOID: + return "void"; + case BOOLEAN: + return "boolean"; + case CHAR: + return "char"; + case BYTE: + return "byte"; + case SHORT: + return "short"; + case INT: + return "int"; + case FLOAT: + return "float"; + case LONG: + return "long"; + case DOUBLE: + return "double"; + case ARRAY: + StringBuilder sb = new StringBuilder(getElementType().getClassName()); + for (int i = getDimensions(); i > 0; --i) { + sb.append("[]"); + } + return sb.toString(); + case OBJECT: + return new String(buf, off, len).replace('/', '.'); + default: + return null; + } + } + + /** + * Returns the internal name of the class corresponding to this object or array type. The internal name of a class + * is its fully qualified name (as returned by Class.getName(), where '.' are replaced by '/'. This method should + * only be used for an object or array type. + * + * @return the internal name of the class corresponding to this object type. + */ + public String getInternalName() { + return new String(buf, off, len); + } + + /** + * Returns the argument types of methods of this type. This method should only be used for method types. + * + * @return the argument types of methods of this type. + */ + public Type[] getArgumentTypes() { + return getArgumentTypes(getDescriptor()); + } + + /** + * Returns the return type of methods of this type. This method should only be used for method types. + * + * @return the return type of methods of this type. + */ + public Type getReturnType() { + return getReturnType(getDescriptor()); + } + + /** + * Returns the size of the arguments and of the return value of methods of this type. This method should only be + * used for method types. + * + * @return the size of the arguments (plus one for the implicit this argument), argSize, and the size of the return + * value, retSize, packed into a single int i = <tt>(argSize << 2) | retSize</tt> (argSize + * is therefore equal to <tt>i >> 2</tt>, and retSize to <tt>i & + * 0x03</tt>). + */ + public int getArgumentsAndReturnSizes() { + return getArgumentsAndReturnSizes(getDescriptor()); + } + + // ------------------------------------------------------------------------ + // Conversion to type descriptors + // ------------------------------------------------------------------------ + + /** + * Returns the descriptor corresponding to this Java type. + * + * @return the descriptor corresponding to this Java type. + */ + public String getDescriptor() { + StringBuilder buf = new StringBuilder(); + getDescriptor(buf); + return buf.toString(); + } + + /** + * Returns the descriptor corresponding to the given argument and return types. + * + * @param returnType the return type of the method. + * @param argumentTypes the argument types of the method. + * @return the descriptor corresponding to the given argument and return types. + */ + public static String getMethodDescriptor(final Type returnType, final Type... argumentTypes) { + StringBuilder buf = new StringBuilder(); + buf.append('('); + for (int i = 0; i < argumentTypes.length; ++i) { + argumentTypes[i].getDescriptor(buf); + } + buf.append(')'); + returnType.getDescriptor(buf); + return buf.toString(); + } + + /** + * Appends the descriptor corresponding to this Java type to the given string buffer. + * + * @param buf the string buffer to which the descriptor must be appended. + */ + private void getDescriptor(final StringBuilder buf) { + if (this.buf == null) { + // descriptor is in byte 3 of 'off' for primitive types (buf == + // null) + buf.append((char) ((off & 0xFF000000) >>> 24)); + } else if (sort == OBJECT) { + buf.append('L'); + buf.append(this.buf, off, len); + buf.append(';'); + } else { // sort == ARRAY || sort == METHOD + buf.append(this.buf, off, len); + } + } + + // ------------------------------------------------------------------------ + // Direct conversion from classes to type descriptors, + // without intermediate Type objects + // ------------------------------------------------------------------------ + + /** + * Returns the internal name of the given class. The internal name of a class is its fully qualified name, as + * returned by Class.getName(), where '.' are replaced by '/'. + * + * @param c an object or array class. + * @return the internal name of the given class. + */ + public static String getInternalName(final Class c) { + return c.getName().replace('.', '/'); + } + + /** + * Returns the descriptor corresponding to the given Java type. + * + * @param c an object class, a primitive class or an array class. + * @return the descriptor corresponding to the given class. + */ + public static String getDescriptor(final Class c) { + StringBuilder buf = new StringBuilder(); + getDescriptor(buf, c); + return buf.toString(); + } + + /** + * Returns the descriptor corresponding to the given constructor. + * + * @param c a {@link Constructor Constructor} object. + * @return the descriptor of the given constructor. + */ + public static String getConstructorDescriptor(final Constructor c) { + Class[] parameters = c.getParameterTypes(); + StringBuilder buf = new StringBuilder(); + buf.append('('); + for (int i = 0; i < parameters.length; ++i) { + getDescriptor(buf, parameters[i]); + } + return buf.append(")V").toString(); + } + + /** + * Returns the descriptor corresponding to the given method. + * + * @param m a {@link Method Method} object. + * @return the descriptor of the given method. + */ + public static String getMethodDescriptor(final Method m) { + Class[] parameters = m.getParameterTypes(); + StringBuilder buf = new StringBuilder(); + buf.append('('); + for (int i = 0; i < parameters.length; ++i) { + getDescriptor(buf, parameters[i]); + } + buf.append(')'); + getDescriptor(buf, m.getReturnType()); + return buf.toString(); + } + + /** + * Appends the descriptor of the given class to the given string buffer. + * + * @param buf the string buffer to which the descriptor must be appended. + * @param c the class whose descriptor must be computed. + */ + private static void getDescriptor(final StringBuilder buf, final Class c) { + Class d = c; + while (true) { + if (d.isPrimitive()) { + char car; + if (d == Integer.TYPE) { + car = 'I'; + } else if (d == Void.TYPE) { + car = 'V'; + } else if (d == Boolean.TYPE) { + car = 'Z'; + } else if (d == Byte.TYPE) { + car = 'B'; + } else if (d == Character.TYPE) { + car = 'C'; + } else if (d == Short.TYPE) { + car = 'S'; + } else if (d == Double.TYPE) { + car = 'D'; + } else if (d == Float.TYPE) { + car = 'F'; + } else /* if (d == Long.TYPE) */ { + car = 'J'; + } + buf.append(car); + return; + } else if (d.isArray()) { + buf.append('['); + d = d.getComponentType(); + } else { + buf.append('L'); + String name = d.getName(); + int len = name.length(); + for (int i = 0; i < len; ++i) { + char car = name.charAt(i); + buf.append(car == '.' ? '/' : car); + } + buf.append(';'); + return; + } + } + } + + // ------------------------------------------------------------------------ + // Corresponding size and opcodes + // ------------------------------------------------------------------------ + + /** + * Returns the size of values of this type. This method must not be used for method types. + * + * @return the size of values of this type, i.e., 2 for <tt>long</tt> and + * <tt>double</tt>, 0 for <tt>void</tt> and 1 otherwise. + */ + public int getSize() { + // the size is in byte 0 of 'off' for primitive types (buf == null) + return buf == null ? (off & 0xFF) : 1; + } + + /** + * Returns a JVM instruction opcode adapted to this Java type. This method must not be used for method types. + * + * @param opcode a JVM instruction opcode. This opcode must be one of ILOAD, ISTORE, IALOAD, IASTORE, IADD, ISUB, + * IMUL, IDIV, IREM, INEG, ISHL, ISHR, IUSHR, IAND, IOR, IXOR and IRETURN. + * @return an opcode that is similar to the given opcode, but adapted to this Java type. For example, if this type + * is <tt>float</tt> and <tt>opcode</tt> is IRETURN, this method returns + * FRETURN. + */ + public int getOpcode(final int opcode) { + if (opcode == Opcodes.IALOAD || opcode == Opcodes.IASTORE) { + // the offset for IALOAD or IASTORE is in byte 1 of 'off' for + // primitive types (buf == null) + return opcode + (buf == null ? (off & 0xFF00) >> 8 : 4); + } else { + // the offset for other instructions is in byte 2 of 'off' for + // primitive types (buf == null) + return opcode + (buf == null ? (off & 0xFF0000) >> 16 : 4); + } + } + + // ------------------------------------------------------------------------ + // Equals, hashCode and toString + // ------------------------------------------------------------------------ + + /** + * Tests if the given object is equal to this type. + * + * @param o the object to be compared to this type. + * @return <tt>true</tt> if the given object is equal to this type. + */ + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (!(o instanceof Type)) { + return false; + } + Type t = (Type) o; + if (sort != t.sort) { + return false; + } + if (sort >= ARRAY) { + if (len != t.len) { + return false; + } + for (int i = off, j = t.off, end = i + len; i < end; i++, j++) { + if (buf[i] != t.buf[j]) { + return false; + } + } + } + return true; + } + + /** + * Returns a hash code value for this type. + * + * @return a hash code value for this type. + */ + @Override + public int hashCode() { + int hc = 13 * sort; + if (sort >= ARRAY) { + for (int i = off, end = i + len; i < end; i++) { + hc = 17 * (hc + buf[i]); + } + } + return hc; + } + + /** + * Returns a string representation of this type. + * + * @return the descriptor of this type. + */ + @Override + public String toString() { + return getDescriptor(); + } +} diff --git a/src/main/java/org/redkale/asm/TypePath.java b/src/main/java/org/redkale/asm/TypePath.java index 39964a78a..b32c0fa26 100644 --- a/src/main/java/org/redkale/asm/TypePath.java +++ b/src/main/java/org/redkale/asm/TypePath.java @@ -1,195 +1,195 @@ -/* - * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */ - -/* - * - * - * - * - * - * ASM: a very small and fast Java bytecode manipulation framework - * Copyright (c) 2000-2013 INRIA, France Telecom - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -package org.redkale.asm; - -/** - * The path to a type argument, wildcard bound, array element type, or static inner type within an enclosing type. - * - * @author Eric Bruneton - */ -public class TypePath { - - /** A type path step that steps into the element type of an array type. See {@link #getStep getStep}. */ - public static final int ARRAY_ELEMENT = 0; - - /** A type path step that steps into the nested type of a class type. See {@link #getStep getStep}. */ - public static final int INNER_TYPE = 1; - - /** A type path step that steps into the bound of a wildcard type. See {@link #getStep getStep}. */ - public static final int WILDCARD_BOUND = 2; - - /** A type path step that steps into a type argument of a generic type. See {@link #getStep getStep}. */ - public static final int TYPE_ARGUMENT = 3; - - /** The byte array where the path is stored, in Java class file format. */ - byte[] b; - - /** The offset of the first byte of the type path in 'b'. */ - int offset; - - /** - * Creates a new type path. - * - * @param b the byte array containing the type path in Java class file format. - * @param offset the offset of the first byte of the type path in 'b'. - */ - TypePath(byte[] b, int offset) { - this.b = b; - this.offset = offset; - } - - /** - * Returns the length of this path. - * - * @return the length of this path. - */ - public int getLength() { - return b[offset]; - } - - /** - * Returns the value of the given step of this path. - * - * @param index an index between 0 and {@link #getLength()}, exclusive. - * @return {@link #ARRAY_ELEMENT ARRAY_ELEMENT}, {@link #INNER_TYPE INNER_TYPE}, {@link #WILDCARD_BOUND - * WILDCARD_BOUND}, or {@link #TYPE_ARGUMENT TYPE_ARGUMENT}. - */ - public int getStep(int index) { - return b[offset + 2 * index + 1]; - } - - /** - * Returns the index of the type argument that the given step is stepping into. This method should only be used for - * steps whose value is {@link #TYPE_ARGUMENT TYPE_ARGUMENT}. - * - * @param index an index between 0 and {@link #getLength()}, exclusive. - * @return the index of the type argument that the given step is stepping into. - */ - public int getStepArgument(int index) { - return b[offset + 2 * index + 2]; - } - - /** - * Converts a type path in string form, in the format used by {@link #toString()}, into a TypePath object. - * - * @param typePath a type path in string form, in the format used by {@link #toString()}. May be null or empty. - * @return the corresponding TypePath object, or null if the path is empty. - */ - public static TypePath fromString(final String typePath) { - if (typePath == null || typePath.isEmpty()) { - return null; - } - int n = typePath.length(); - ByteVector out = new ByteVector(n); - out.putByte(0); - for (int i = 0; i < n; ) { - char c = typePath.charAt(i++); - if (c == '[') { - out.put11(ARRAY_ELEMENT, 0); - } else if (c == '.') { - out.put11(INNER_TYPE, 0); - } else if (c == '*') { - out.put11(WILDCARD_BOUND, 0); - } else if (c >= '0' && c <= '9') { - int typeArg = c - '0'; - while (i < n && (c = typePath.charAt(i)) >= '0' && c <= '9') { - typeArg = typeArg * 10 + c - '0'; - i += 1; - } - if (i < n && typePath.charAt(i) == ';') { - i += 1; - } - out.put11(TYPE_ARGUMENT, typeArg); - } - } - out.data[0] = (byte) (out.length / 2); - return new TypePath(out.data, 0); - } - - /** - * Returns a string representation of this type path. {@link #ARRAY_ELEMENT ARRAY_ELEMENT} steps are represented - * with '[', {@link #INNER_TYPE INNER_TYPE} steps with '.', {@link #WILDCARD_BOUND WILDCARD_BOUND} steps with '*' - * and {@link #TYPE_ARGUMENT TYPE_ARGUMENT} steps with their type argument index in decimal form followed by ';'. - */ - @Override - public String toString() { - int length = getLength(); - StringBuilder result = new StringBuilder(length * 2); - for (int i = 0; i < length; ++i) { - switch (getStep(i)) { - case ARRAY_ELEMENT: - result.append('['); - break; - case INNER_TYPE: - result.append('.'); - break; - case WILDCARD_BOUND: - result.append('*'); - break; - case TYPE_ARGUMENT: - result.append(getStepArgument(i)).append(';'); - break; - default: - result.append('_'); - } - } - return result.toString(); - } -} +/* + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ + +/* + * + * + * + * + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2013 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.redkale.asm; + +/** + * The path to a type argument, wildcard bound, array element type, or static inner type within an enclosing type. + * + * @author Eric Bruneton + */ +public class TypePath { + + /** A type path step that steps into the element type of an array type. See {@link #getStep getStep}. */ + public static final int ARRAY_ELEMENT = 0; + + /** A type path step that steps into the nested type of a class type. See {@link #getStep getStep}. */ + public static final int INNER_TYPE = 1; + + /** A type path step that steps into the bound of a wildcard type. See {@link #getStep getStep}. */ + public static final int WILDCARD_BOUND = 2; + + /** A type path step that steps into a type argument of a generic type. See {@link #getStep getStep}. */ + public static final int TYPE_ARGUMENT = 3; + + /** The byte array where the path is stored, in Java class file format. */ + byte[] b; + + /** The offset of the first byte of the type path in 'b'. */ + int offset; + + /** + * Creates a new type path. + * + * @param b the byte array containing the type path in Java class file format. + * @param offset the offset of the first byte of the type path in 'b'. + */ + TypePath(byte[] b, int offset) { + this.b = b; + this.offset = offset; + } + + /** + * Returns the length of this path. + * + * @return the length of this path. + */ + public int getLength() { + return b[offset]; + } + + /** + * Returns the value of the given step of this path. + * + * @param index an index between 0 and {@link #getLength()}, exclusive. + * @return {@link #ARRAY_ELEMENT ARRAY_ELEMENT}, {@link #INNER_TYPE INNER_TYPE}, {@link #WILDCARD_BOUND + * WILDCARD_BOUND}, or {@link #TYPE_ARGUMENT TYPE_ARGUMENT}. + */ + public int getStep(int index) { + return b[offset + 2 * index + 1]; + } + + /** + * Returns the index of the type argument that the given step is stepping into. This method should only be used for + * steps whose value is {@link #TYPE_ARGUMENT TYPE_ARGUMENT}. + * + * @param index an index between 0 and {@link #getLength()}, exclusive. + * @return the index of the type argument that the given step is stepping into. + */ + public int getStepArgument(int index) { + return b[offset + 2 * index + 2]; + } + + /** + * Converts a type path in string form, in the format used by {@link #toString()}, into a TypePath object. + * + * @param typePath a type path in string form, in the format used by {@link #toString()}. May be null or empty. + * @return the corresponding TypePath object, or null if the path is empty. + */ + public static TypePath fromString(final String typePath) { + if (typePath == null || typePath.isEmpty()) { + return null; + } + int n = typePath.length(); + ByteVector out = new ByteVector(n); + out.putByte(0); + for (int i = 0; i < n; ) { + char c = typePath.charAt(i++); + if (c == '[') { + out.put11(ARRAY_ELEMENT, 0); + } else if (c == '.') { + out.put11(INNER_TYPE, 0); + } else if (c == '*') { + out.put11(WILDCARD_BOUND, 0); + } else if (c >= '0' && c <= '9') { + int typeArg = c - '0'; + while (i < n && (c = typePath.charAt(i)) >= '0' && c <= '9') { + typeArg = typeArg * 10 + c - '0'; + i += 1; + } + if (i < n && typePath.charAt(i) == ';') { + i += 1; + } + out.put11(TYPE_ARGUMENT, typeArg); + } + } + out.data[0] = (byte) (out.length / 2); + return new TypePath(out.data, 0); + } + + /** + * Returns a string representation of this type path. {@link #ARRAY_ELEMENT ARRAY_ELEMENT} steps are represented + * with '[', {@link #INNER_TYPE INNER_TYPE} steps with '.', {@link #WILDCARD_BOUND WILDCARD_BOUND} steps with '*' + * and {@link #TYPE_ARGUMENT TYPE_ARGUMENT} steps with their type argument index in decimal form followed by ';'. + */ + @Override + public String toString() { + int length = getLength(); + StringBuilder result = new StringBuilder(length * 2); + for (int i = 0; i < length; ++i) { + switch (getStep(i)) { + case ARRAY_ELEMENT: + result.append('['); + break; + case INNER_TYPE: + result.append('.'); + break; + case WILDCARD_BOUND: + result.append('*'); + break; + case TYPE_ARGUMENT: + result.append(getStepArgument(i)).append(';'); + break; + default: + result.append('_'); + } + } + return result.toString(); + } +} diff --git a/src/main/java/org/redkale/asm/TypeReference.java b/src/main/java/org/redkale/asm/TypeReference.java index 2ec9ae0f4..4dd59f9df 100644 --- a/src/main/java/org/redkale/asm/TypeReference.java +++ b/src/main/java/org/redkale/asm/TypeReference.java @@ -1,402 +1,402 @@ -/* - * 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 static final int CLASS_TYPE_PARAMETER = 0x00; - - /** The sort of type references that target a type parameter of a generic method. See {@link #getSort getSort}. */ - public static final 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 static final 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 static final 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 static final int METHOD_TYPE_PARAMETER_BOUND = 0x12; - - /** The sort of type references that target the type of a field. See {@link #getSort getSort}. */ - public static final int FIELD = 0x13; - - /** The sort of type references that target the return type of a method. See {@link #getSort getSort}. */ - public static final int METHOD_RETURN = 0x14; - - /** The sort of type references that target the receiver type of a method. See {@link #getSort getSort}. */ - public static final 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 static final 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 static final int THROWS = 0x17; - - /** - * The sort of type references that target the type of a local variable in a method. See {@link #getSort getSort}. - */ - public static final 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 static final 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 static final int EXCEPTION_PARAMETER = 0x42; - - /** - * The sort of type references that target the type declared in an 'instanceof' instruction. See {@link #getSort - * getSort}. - */ - public static final 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 static final int NEW = 0x44; - - /** - * The sort of type references that target the receiver type of a constructor reference. See {@link #getSort - * getSort}. - */ - public static final int CONSTRUCTOR_REFERENCE = 0x45; - - /** - * The sort of type references that target the receiver type of a method reference. See {@link #getSort getSort}. - */ - public static final 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 static final 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 static final 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 static final 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 static final 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 static final 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 static final int CLASS_TYPE_PARAMETER = 0x00; + + /** The sort of type references that target a type parameter of a generic method. See {@link #getSort getSort}. */ + public static final 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 static final 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 static final 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 static final int METHOD_TYPE_PARAMETER_BOUND = 0x12; + + /** The sort of type references that target the type of a field. See {@link #getSort getSort}. */ + public static final int FIELD = 0x13; + + /** The sort of type references that target the return type of a method. See {@link #getSort getSort}. */ + public static final int METHOD_RETURN = 0x14; + + /** The sort of type references that target the receiver type of a method. See {@link #getSort getSort}. */ + public static final 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 static final 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 static final int THROWS = 0x17; + + /** + * The sort of type references that target the type of a local variable in a method. See {@link #getSort getSort}. + */ + public static final 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 static final 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 static final int EXCEPTION_PARAMETER = 0x42; + + /** + * The sort of type references that target the type declared in an 'instanceof' instruction. See {@link #getSort + * getSort}. + */ + public static final 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 static final int NEW = 0x44; + + /** + * The sort of type references that target the receiver type of a constructor reference. See {@link #getSort + * getSort}. + */ + public static final int CONSTRUCTOR_REFERENCE = 0x45; + + /** + * The sort of type references that target the receiver type of a method reference. See {@link #getSort getSort}. + */ + public static final 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 static final 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 static final 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 static final 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 static final 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 static final 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; + } +} diff --git a/src/main/java/org/redkale/boot/AppConfig.java b/src/main/java/org/redkale/boot/AppConfig.java index bbe098afd..ef35b170e 100644 --- a/src/main/java/org/redkale/boot/AppConfig.java +++ b/src/main/java/org/redkale/boot/AppConfig.java @@ -1,494 +1,494 @@ -/* - * - */ -package org.redkale.boot; - -import static org.redkale.boot.Application.*; -import static org.redkale.util.RedkaleClassLoader.putReflectionClass; -import static org.redkale.util.RedkaleClassLoader.putReflectionPublicConstructors; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.URI; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Collections; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Properties; -import java.util.Set; -import java.util.logging.SimpleFormatter; -import org.redkale.source.DataSources; -import org.redkale.util.AnyValue; -import org.redkale.util.AnyValueWriter; -import org.redkale.util.RedkaleClassLoader; -import org.redkale.util.RedkaleException; -import org.redkale.util.Utility; - -/** - * 加载系统参数配置 - * - * @author zhangjx - */ -class AppConfig { - - /** - * 当前进程的配置文件, 类型:String、URI、File、Path
- * 一般命名为: application.xml、application.onlyLogProps, 若配置文件不是本地文件, 则File、Path类型的值为null - */ - static final String PARAM_APP_CONF_FILE = "APP_CONF_FILE"; - - // 是否用于main方法运行 - final boolean singletonMode; - - // 是否用于编译模式运行 - final boolean compileMode; - - // application.xml原始配置信息 - AnyValue config; - - // 是否从/META-INF中读取配置 - boolean configFromCache; - - // 本进程节点ID - String nodeid; - - // 本进程节点ID - String name; - - // 本地IP地址 - InetSocketAddress localAddress; - - // 进程根目录 - File home; - - // 配置文件目录 - File confFile; - - // 配置文件目录 - URI confDir; - - // 根ClassLoader - RedkaleClassLoader classLoader; - - // Server根ClassLoader - RedkaleClassLoader serverClassLoader; - - // 本地文件日志配置项 - final Properties locaLogProperties = new Properties(); - - // 本地文件除logging配置之外的所有的配置项, 包含system.property.、mimetype.property.开头的 - final Properties localEnvProperties = new Properties(); - - public AppConfig(boolean singletonMode, boolean compileMode) { - this.singletonMode = singletonMode; - this.compileMode = compileMode; - } - - public static AppConfig create(boolean singletonMode, boolean compileMode) throws IOException { - AppConfig rs = new AppConfig(singletonMode, compileMode); - rs.init(loadAppConfig()); - return rs; - } - - private void init(AnyValue conf) { - this.config = conf; - this.name = checkName(config.getValue("name", "")); - this.nodeid = checkNodeid(config.getValue("nodeid", String.valueOf(Math.abs(System.nanoTime())))); - this.configFromCache = "true".equals(config.getValue("[config-from-cache]")); - // 初始化classLoader、serverClassLoader - this.initClassLoader(); - // 初始化home、confDir、localAddress等信息 - this.initAppHome(); - // 读取本地参数配置 - this.initLocalProperties(); - // 读取本地日志配置 - this.initLogProperties(); - // 读取本地数据库配置 - this.initSourceProperties(); - } - - /** 初始化classLoader、serverClassLoader */ - private void initClassLoader() { - ClassLoader currClassLoader = Thread.currentThread().getContextClassLoader(); - if (currClassLoader instanceof RedkaleClassLoader) { - this.classLoader = (RedkaleClassLoader) currClassLoader; - } else { - Set cacheClasses = null; - if (!singletonMode && !compileMode) { - try { - InputStream in = - Application.class.getResourceAsStream(RedkaleClassLoader.RESOURCE_CACHE_CLASSES_PATH); - if (in != null) { - BufferedReader reader = - new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8), 1024); - List list = new ArrayList<>(); - reader.lines().forEach(list::add); - Collections.sort(list); - if (!list.isEmpty()) { - cacheClasses = new LinkedHashSet<>(list); - } - in.close(); - } - } catch (Exception e) { - // do nothing - } - } - if (cacheClasses == null) { - this.classLoader = new RedkaleClassLoader(currClassLoader); - } else { - this.classLoader = new RedkaleClassLoader.RedkaleCacheClassLoader(currClassLoader, cacheClasses); - } - Thread.currentThread().setContextClassLoader(this.classLoader); - } - if (compileMode || this.classLoader instanceof RedkaleClassLoader.RedkaleCacheClassLoader) { - this.serverClassLoader = this.classLoader; - } else { - this.serverClassLoader = new RedkaleClassLoader(this.classLoader); - } - } - - /** 初始化home、confDir、localAddress等信息 */ - private void initAppHome() { - final File root = new File(System.getProperty(RESNAME_APP_HOME, "")); - final String rootPath = getCanonicalPath(root); - this.home = new File(rootPath); - String confDir = System.getProperty(RESNAME_APP_CONF_DIR, "conf"); - if (confDir.contains("://") - || confDir.startsWith("file:") - || confDir.startsWith("resource:") - || confDir.contains("!")) { // graalvm native-image startwith resource:META-INF - this.confDir = URI.create(confDir); - if (confDir.startsWith("file:")) { - this.confFile = getCanonicalFile(new File(this.confDir.getPath())); - } - } else if (confDir.charAt(0) == '/' || confDir.indexOf(':') > -1) { - this.confFile = getCanonicalFile(new File(confDir)); - this.confDir = confFile.toURI(); - } else { - this.confFile = new File(getCanonicalPath(new File(this.home, confDir))); - this.confDir = confFile.toURI(); - } - String localaddr = config.getValue("address", "").trim(); - InetAddress addr = localaddr.isEmpty() - ? Utility.localInetAddress() - : new InetSocketAddress(localaddr, config.getIntValue("port")).getAddress(); - this.localAddress = new InetSocketAddress(addr, config.getIntValue("port")); - } - - /** 读取本地参数配置 */ - private void initLocalProperties() { - // 环境变量的优先级最高 - System.getProperties().forEach((k, v) -> { - if (k.toString().startsWith("redkale.")) { - localEnvProperties.put(k, v); - } - }); - AnyValue propsConf = this.config.getAnyValue("properties"); - if (propsConf == null) { - final AnyValue resources = config.getAnyValue("resources"); - if (resources != null) { - System.err.println(" in application config file is deprecated"); - propsConf = resources.getAnyValue("properties"); - } - } - if (propsConf != null) { // 设置配置文件中的系统变量 - for (AnyValue prop : propsConf.getAnyValues("property")) { - String key = prop.getValue("name", ""); - String value = prop.getValue("value"); - if (value != null) { - localEnvProperties.put(key, value); - } - } - if (propsConf.getValue("load") != null) { // 加载本地配置项文件 - for (String dfload : - propsConf.getValue("load").replace(',', ';').split(";")) { - if (dfload.trim().isEmpty()) { - continue; - } - final URI df = RedkaleClassLoader.getConfResourceAsURI( - configFromCache ? null : this.confDir.toString(), dfload.trim()); - if (df == null) { - continue; - } - if (!"file".equals(df.getScheme()) || df.toString().contains("!") || new File(df).isFile()) { - Properties props = new Properties(); - try { - InputStream in = df.toURL().openStream(); - props.load(in); - in.close(); - localEnvProperties.putAll(props); - } catch (Exception e) { - throw new RedkaleException(e); - } - } - } - } - } - // 设置Convert默认配置项 - if (System.getProperty("redkale.convert.pool.size") == null - && localEnvProperties.getProperty("system.property.redkale.convert.pool.size") == null) { - localEnvProperties.put("system.property.redkale.convert.pool.size", "128"); - } - if (System.getProperty("redkale.convert.writer.buffer.defsize") == null - && localEnvProperties.getProperty("system.property.redkale.convert.writer.buffer.defsize") == null) { - localEnvProperties.put("system.property.redkale.convert.writer.buffer.defsize", "4096"); - } - } - - /** 读取本地DataSource、CacheSource配置 */ - private void initSourceProperties() { - if ("file".equals(this.confDir.getScheme())) { - File sourceFile = new File(new File(confDir), "source.properties"); - if (sourceFile.isFile() && sourceFile.canRead()) { - Properties props = new Properties(); - try { - InputStream in = new FileInputStream(sourceFile); - props.load(in); - in.close(); - } catch (IOException e) { - throw new RedkaleException(e); - } - this.localEnvProperties.putAll(props); - } else { - // 兼容 persistence.xml 【已废弃】 - File persist = new File(new File(confDir), "persistence.xml"); - if (persist.isFile() && persist.canRead()) { - System.err.println("persistence.xml is deprecated, replaced by source.properties"); - try { - InputStream in = new FileInputStream(persist); - this.localEnvProperties.putAll(DataSources.loadSourceProperties(in)); - in.close(); - } catch (IOException e) { - throw new RedkaleException(e); - } - } - } - } else { // 从url或jar文件中resources读取 - try { - final URI sourceURI = RedkaleClassLoader.getConfResourceAsURI( - configFromCache ? null : this.confDir.toString(), "source.properties"); - InputStream in = sourceURI.toURL().openStream(); - Properties props = new Properties(); - props.load(in); - in.close(); - this.localEnvProperties.putAll(props); - } catch (Exception e) { - // 没有文件 跳过 - } - } - } - - /** 读取本地日志配置 */ - private void initLogProperties() { - URI logConfURI; - File logConfFile = null; - if (configFromCache) { - logConfURI = RedkaleClassLoader.getConfResourceAsURI(null, "logging.properties"); - } else if ("file".equals(confDir.getScheme())) { - logConfFile = new File(confDir.getPath(), "logging.properties"); - logConfURI = logConfFile.toURI(); - if (!logConfFile.isFile() || !logConfFile.canRead()) { - logConfFile = null; - } - } else { - logConfURI = URI.create(confDir + (confDir.toString().endsWith("/") ? "" : "/") + "logging.properties"); - } - if (!"file".equals(confDir.getScheme()) || logConfFile != null) { - try { - InputStream fin = logConfURI.toURL().openStream(); - Properties properties0 = new Properties(); - properties0.load(fin); - fin.close(); - properties0.forEach(locaLogProperties::put); - } catch (IOException e) { - throw new RedkaleException("read logging.properties error", e); - } - } - if (compileMode) { - putReflectionClass(java.lang.Class.class.getName()); - putReflectionPublicConstructors(SimpleFormatter.class, SimpleFormatter.class.getName()); - putReflectionPublicConstructors(LoggingSearchHandler.class, LoggingSearchHandler.class.getName()); - putReflectionPublicConstructors(LoggingFileHandler.class, LoggingFileHandler.class.getName()); - putReflectionPublicConstructors( - LoggingFileHandler.LoggingFormater.class, LoggingFileHandler.LoggingFormater.class.getName()); - putReflectionPublicConstructors( - LoggingFileHandler.LoggingConsoleHandler.class, - LoggingFileHandler.LoggingConsoleHandler.class.getName()); - putReflectionPublicConstructors( - LoggingFileHandler.LoggingSncpFileHandler.class, - LoggingFileHandler.LoggingSncpFileHandler.class.getName()); - } - } - - /** - * 从本地application.xml或application.properties文件加载配置信息 - * - * @return 配置信息 - * @throws IOException - */ - static AnyValue loadAppConfig() throws IOException { - final String home = new File(System.getProperty(RESNAME_APP_HOME, "")) - .getCanonicalPath() - .replace('\\', '/'); - String sysConfFile = System.getProperty(PARAM_APP_CONF_FILE); - if (sysConfFile != null) { - String text; - if (sysConfFile.contains("://")) { - text = Utility.readThenClose(URI.create(sysConfFile).toURL().openStream()); - } else { - File f = new File(sysConfFile); - if (f.isFile() && f.canRead()) { - text = Utility.readThenClose(new FileInputStream(f)); - } else { - throw new IOException("Read application conf file (" + sysConfFile + ") error "); - } - } - return text.trim().startsWith("<") - ? AnyValue.loadFromXml(text, (k, v) -> v.replace("${" + RESNAME_APP_HOME + "}", home)) - .getAnyValue("application") - : AnyValue.loadFromProperties(text).getAnyValue("redkale"); - } - String confDir = System.getProperty(RESNAME_APP_CONF_DIR, "conf"); - URI appConfFile; - boolean fromCache = false; - if (confDir.contains("://")) { // jar内部资源 - appConfFile = URI.create(confDir + (confDir.endsWith("/") ? "" : "/") + "application.xml"); - try { - appConfFile.toURL().openStream().close(); - } catch (IOException e) { // 没有application.xml就尝试读application.properties - appConfFile = URI.create(confDir + (confDir.endsWith("/") ? "" : "/") + "application.properties"); - } - } else if (confDir.charAt(0) == '/' || confDir.indexOf(':') > 0) { // 绝对路径 - File f = new File(confDir, "application.xml"); - if (f.isFile() && f.canRead()) { - appConfFile = f.toURI(); - confDir = f.getParentFile().getCanonicalPath(); - } else { - f = new File(confDir, "application.properties"); - if (f.isFile() && f.canRead()) { - appConfFile = f.toURI(); - confDir = f.getParentFile().getCanonicalPath(); - } else { - appConfFile = RedkaleClassLoader.getConfResourceAsURI(null, "application.xml"); // 不能传confDir - try { - appConfFile.toURL().openStream().close(); - } catch (IOException e) { // 没有application.xml就尝试读application.properties - appConfFile = RedkaleClassLoader.getConfResourceAsURI(null, "application.properties"); - } - confDir = appConfFile - .toString() - .replace("/application.xml", "") - .replace("/application.properties", ""); - fromCache = true; - } - } - } else { // 相对路径 - File f = new File(new File(home, confDir), "application.xml"); - if (f.isFile() && f.canRead()) { - appConfFile = f.toURI(); - confDir = f.getParentFile().getCanonicalPath(); - } else { - f = new File(new File(home, confDir), "application.properties"); - if (f.isFile() && f.canRead()) { - appConfFile = f.toURI(); - confDir = f.getParentFile().getCanonicalPath(); - } else { - appConfFile = RedkaleClassLoader.getConfResourceAsURI(null, "application.xml"); // 不能传confDir - try { - appConfFile.toURL().openStream().close(); - } catch (IOException e) { // 没有application.xml就尝试读application.properties - appConfFile = RedkaleClassLoader.getConfResourceAsURI(null, "application.properties"); - } - confDir = appConfFile - .toString() - .replace("/application.xml", "") - .replace("/application.properties", ""); - fromCache = true; - } - } - } - System.setProperty(RESNAME_APP_CONF_DIR, confDir); - String text = Utility.readThenClose(appConfFile.toURL().openStream()); - AnyValue conf; - if (text.trim().startsWith("<")) { - conf = AnyValue.loadFromXml(text, (k, v) -> v.replace("${APP_HOME}", home)) - .getAnyValue("application"); - } else { - conf = AnyValue.loadFromProperties(text).getAnyValue("redkale"); - } - if (fromCache) { - ((AnyValueWriter) conf).addValue("[config-from-cache]", "true"); - } - - return conf; - } - - /** - * 检查name是否含特殊字符 - * - * @param name - * @return - */ - private static String checkName(String name) { - if (name == null || name.isEmpty()) { - return name; - } - for (char ch : name.toCharArray()) { - if (!((ch >= '0' && ch <= '9') - || (ch >= 'a' && ch <= 'z') - || (ch >= 'A' && ch <= 'Z') - || ch == '_' - || ch == '.' - || ch == '-')) { // 不能含特殊字符 - throw new RedkaleException("name only 0-9 a-z A-Z _ - ."); - } - } - return name; - } - - /** - * 检查node是否含特殊字符 - * - * @param name - * @return - */ - private static String checkNodeid(String nodeid) { - if (nodeid == null || nodeid.isEmpty()) { - return nodeid; - } - for (char ch : nodeid.toCharArray()) { - if (!((ch >= '0' && ch <= '9') - || (ch >= 'a' && ch <= 'z') - || (ch >= 'A' && ch <= 'Z') - || ch == '_' - || ch == '.' - || ch == '-')) { // 不能含特殊字符 - throw new RedkaleException("nodeid only 0-9 a-z A-Z _ - ."); - } - } - return nodeid; - } - - private String getCanonicalPath(File file) { - try { - return file.getCanonicalPath(); - } catch (IOException e) { - return file.getAbsolutePath(); - } - } - - private File getCanonicalFile(File file) { - try { - return file.getCanonicalFile(); - } catch (IOException e) { - return file; - } - } -} +/* + * + */ +package org.redkale.boot; + +import static org.redkale.boot.Application.*; +import static org.redkale.util.RedkaleClassLoader.putReflectionClass; +import static org.redkale.util.RedkaleClassLoader.putReflectionPublicConstructors; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Properties; +import java.util.Set; +import java.util.logging.SimpleFormatter; +import org.redkale.source.DataSources; +import org.redkale.util.AnyValue; +import org.redkale.util.AnyValueWriter; +import org.redkale.util.RedkaleClassLoader; +import org.redkale.util.RedkaleException; +import org.redkale.util.Utility; + +/** + * 加载系统参数配置 + * + * @author zhangjx + */ +class AppConfig { + + /** + * 当前进程的配置文件, 类型:String、URI、File、Path
+ * 一般命名为: application.xml、application.onlyLogProps, 若配置文件不是本地文件, 则File、Path类型的值为null + */ + static final String PARAM_APP_CONF_FILE = "APP_CONF_FILE"; + + // 是否用于main方法运行 + final boolean singletonMode; + + // 是否用于编译模式运行 + final boolean compileMode; + + // application.xml原始配置信息 + AnyValue config; + + // 是否从/META-INF中读取配置 + boolean configFromCache; + + // 本进程节点ID + String nodeid; + + // 本进程节点ID + String name; + + // 本地IP地址 + InetSocketAddress localAddress; + + // 进程根目录 + File home; + + // 配置文件目录 + File confFile; + + // 配置文件目录 + URI confDir; + + // 根ClassLoader + RedkaleClassLoader classLoader; + + // Server根ClassLoader + RedkaleClassLoader serverClassLoader; + + // 本地文件日志配置项 + final Properties locaLogProperties = new Properties(); + + // 本地文件除logging配置之外的所有的配置项, 包含system.property.、mimetype.property.开头的 + final Properties localEnvProperties = new Properties(); + + public AppConfig(boolean singletonMode, boolean compileMode) { + this.singletonMode = singletonMode; + this.compileMode = compileMode; + } + + public static AppConfig create(boolean singletonMode, boolean compileMode) throws IOException { + AppConfig rs = new AppConfig(singletonMode, compileMode); + rs.init(loadAppConfig()); + return rs; + } + + private void init(AnyValue conf) { + this.config = conf; + this.name = checkName(config.getValue("name", "")); + this.nodeid = checkNodeid(config.getValue("nodeid", String.valueOf(Math.abs(System.nanoTime())))); + this.configFromCache = "true".equals(config.getValue("[config-from-cache]")); + // 初始化classLoader、serverClassLoader + this.initClassLoader(); + // 初始化home、confDir、localAddress等信息 + this.initAppHome(); + // 读取本地参数配置 + this.initLocalProperties(); + // 读取本地日志配置 + this.initLogProperties(); + // 读取本地数据库配置 + this.initSourceProperties(); + } + + /** 初始化classLoader、serverClassLoader */ + private void initClassLoader() { + ClassLoader currClassLoader = Thread.currentThread().getContextClassLoader(); + if (currClassLoader instanceof RedkaleClassLoader) { + this.classLoader = (RedkaleClassLoader) currClassLoader; + } else { + Set cacheClasses = null; + if (!singletonMode && !compileMode) { + try { + InputStream in = + Application.class.getResourceAsStream(RedkaleClassLoader.RESOURCE_CACHE_CLASSES_PATH); + if (in != null) { + BufferedReader reader = + new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8), 1024); + List list = new ArrayList<>(); + reader.lines().forEach(list::add); + Collections.sort(list); + if (!list.isEmpty()) { + cacheClasses = new LinkedHashSet<>(list); + } + in.close(); + } + } catch (Exception e) { + // do nothing + } + } + if (cacheClasses == null) { + this.classLoader = new RedkaleClassLoader(currClassLoader); + } else { + this.classLoader = new RedkaleClassLoader.RedkaleCacheClassLoader(currClassLoader, cacheClasses); + } + Thread.currentThread().setContextClassLoader(this.classLoader); + } + if (compileMode || this.classLoader instanceof RedkaleClassLoader.RedkaleCacheClassLoader) { + this.serverClassLoader = this.classLoader; + } else { + this.serverClassLoader = new RedkaleClassLoader(this.classLoader); + } + } + + /** 初始化home、confDir、localAddress等信息 */ + private void initAppHome() { + final File root = new File(System.getProperty(RESNAME_APP_HOME, "")); + final String rootPath = getCanonicalPath(root); + this.home = new File(rootPath); + String confDir = System.getProperty(RESNAME_APP_CONF_DIR, "conf"); + if (confDir.contains("://") + || confDir.startsWith("file:") + || confDir.startsWith("resource:") + || confDir.contains("!")) { // graalvm native-image startwith resource:META-INF + this.confDir = URI.create(confDir); + if (confDir.startsWith("file:")) { + this.confFile = getCanonicalFile(new File(this.confDir.getPath())); + } + } else if (confDir.charAt(0) == '/' || confDir.indexOf(':') > -1) { + this.confFile = getCanonicalFile(new File(confDir)); + this.confDir = confFile.toURI(); + } else { + this.confFile = new File(getCanonicalPath(new File(this.home, confDir))); + this.confDir = confFile.toURI(); + } + String localaddr = config.getValue("address", "").trim(); + InetAddress addr = localaddr.isEmpty() + ? Utility.localInetAddress() + : new InetSocketAddress(localaddr, config.getIntValue("port")).getAddress(); + this.localAddress = new InetSocketAddress(addr, config.getIntValue("port")); + } + + /** 读取本地参数配置 */ + private void initLocalProperties() { + // 环境变量的优先级最高 + System.getProperties().forEach((k, v) -> { + if (k.toString().startsWith("redkale.")) { + localEnvProperties.put(k, v); + } + }); + AnyValue propsConf = this.config.getAnyValue("properties"); + if (propsConf == null) { + final AnyValue resources = config.getAnyValue("resources"); + if (resources != null) { + System.err.println(" in application config file is deprecated"); + propsConf = resources.getAnyValue("properties"); + } + } + if (propsConf != null) { // 设置配置文件中的系统变量 + for (AnyValue prop : propsConf.getAnyValues("property")) { + String key = prop.getValue("name", ""); + String value = prop.getValue("value"); + if (value != null) { + localEnvProperties.put(key, value); + } + } + if (propsConf.getValue("load") != null) { // 加载本地配置项文件 + for (String dfload : + propsConf.getValue("load").replace(',', ';').split(";")) { + if (dfload.trim().isEmpty()) { + continue; + } + final URI df = RedkaleClassLoader.getConfResourceAsURI( + configFromCache ? null : this.confDir.toString(), dfload.trim()); + if (df == null) { + continue; + } + if (!"file".equals(df.getScheme()) || df.toString().contains("!") || new File(df).isFile()) { + Properties props = new Properties(); + try { + InputStream in = df.toURL().openStream(); + props.load(in); + in.close(); + localEnvProperties.putAll(props); + } catch (Exception e) { + throw new RedkaleException(e); + } + } + } + } + } + // 设置Convert默认配置项 + if (System.getProperty("redkale.convert.pool.size") == null + && localEnvProperties.getProperty("system.property.redkale.convert.pool.size") == null) { + localEnvProperties.put("system.property.redkale.convert.pool.size", "128"); + } + if (System.getProperty("redkale.convert.writer.buffer.defsize") == null + && localEnvProperties.getProperty("system.property.redkale.convert.writer.buffer.defsize") == null) { + localEnvProperties.put("system.property.redkale.convert.writer.buffer.defsize", "4096"); + } + } + + /** 读取本地DataSource、CacheSource配置 */ + private void initSourceProperties() { + if ("file".equals(this.confDir.getScheme())) { + File sourceFile = new File(new File(confDir), "source.properties"); + if (sourceFile.isFile() && sourceFile.canRead()) { + Properties props = new Properties(); + try { + InputStream in = new FileInputStream(sourceFile); + props.load(in); + in.close(); + } catch (IOException e) { + throw new RedkaleException(e); + } + this.localEnvProperties.putAll(props); + } else { + // 兼容 persistence.xml 【已废弃】 + File persist = new File(new File(confDir), "persistence.xml"); + if (persist.isFile() && persist.canRead()) { + System.err.println("persistence.xml is deprecated, replaced by source.properties"); + try { + InputStream in = new FileInputStream(persist); + this.localEnvProperties.putAll(DataSources.loadSourceProperties(in)); + in.close(); + } catch (IOException e) { + throw new RedkaleException(e); + } + } + } + } else { // 从url或jar文件中resources读取 + try { + final URI sourceURI = RedkaleClassLoader.getConfResourceAsURI( + configFromCache ? null : this.confDir.toString(), "source.properties"); + InputStream in = sourceURI.toURL().openStream(); + Properties props = new Properties(); + props.load(in); + in.close(); + this.localEnvProperties.putAll(props); + } catch (Exception e) { + // 没有文件 跳过 + } + } + } + + /** 读取本地日志配置 */ + private void initLogProperties() { + URI logConfURI; + File logConfFile = null; + if (configFromCache) { + logConfURI = RedkaleClassLoader.getConfResourceAsURI(null, "logging.properties"); + } else if ("file".equals(confDir.getScheme())) { + logConfFile = new File(confDir.getPath(), "logging.properties"); + logConfURI = logConfFile.toURI(); + if (!logConfFile.isFile() || !logConfFile.canRead()) { + logConfFile = null; + } + } else { + logConfURI = URI.create(confDir + (confDir.toString().endsWith("/") ? "" : "/") + "logging.properties"); + } + if (!"file".equals(confDir.getScheme()) || logConfFile != null) { + try { + InputStream fin = logConfURI.toURL().openStream(); + Properties properties0 = new Properties(); + properties0.load(fin); + fin.close(); + properties0.forEach(locaLogProperties::put); + } catch (IOException e) { + throw new RedkaleException("read logging.properties error", e); + } + } + if (compileMode) { + putReflectionClass(java.lang.Class.class.getName()); + putReflectionPublicConstructors(SimpleFormatter.class, SimpleFormatter.class.getName()); + putReflectionPublicConstructors(LoggingSearchHandler.class, LoggingSearchHandler.class.getName()); + putReflectionPublicConstructors(LoggingFileHandler.class, LoggingFileHandler.class.getName()); + putReflectionPublicConstructors( + LoggingFileHandler.LoggingFormater.class, LoggingFileHandler.LoggingFormater.class.getName()); + putReflectionPublicConstructors( + LoggingFileHandler.LoggingConsoleHandler.class, + LoggingFileHandler.LoggingConsoleHandler.class.getName()); + putReflectionPublicConstructors( + LoggingFileHandler.LoggingSncpFileHandler.class, + LoggingFileHandler.LoggingSncpFileHandler.class.getName()); + } + } + + /** + * 从本地application.xml或application.properties文件加载配置信息 + * + * @return 配置信息 + * @throws IOException + */ + static AnyValue loadAppConfig() throws IOException { + final String home = new File(System.getProperty(RESNAME_APP_HOME, "")) + .getCanonicalPath() + .replace('\\', '/'); + String sysConfFile = System.getProperty(PARAM_APP_CONF_FILE); + if (sysConfFile != null) { + String text; + if (sysConfFile.contains("://")) { + text = Utility.readThenClose(URI.create(sysConfFile).toURL().openStream()); + } else { + File f = new File(sysConfFile); + if (f.isFile() && f.canRead()) { + text = Utility.readThenClose(new FileInputStream(f)); + } else { + throw new IOException("Read application conf file (" + sysConfFile + ") error "); + } + } + return text.trim().startsWith("<") + ? AnyValue.loadFromXml(text, (k, v) -> v.replace("${" + RESNAME_APP_HOME + "}", home)) + .getAnyValue("application") + : AnyValue.loadFromProperties(text).getAnyValue("redkale"); + } + String confDir = System.getProperty(RESNAME_APP_CONF_DIR, "conf"); + URI appConfFile; + boolean fromCache = false; + if (confDir.contains("://")) { // jar内部资源 + appConfFile = URI.create(confDir + (confDir.endsWith("/") ? "" : "/") + "application.xml"); + try { + appConfFile.toURL().openStream().close(); + } catch (IOException e) { // 没有application.xml就尝试读application.properties + appConfFile = URI.create(confDir + (confDir.endsWith("/") ? "" : "/") + "application.properties"); + } + } else if (confDir.charAt(0) == '/' || confDir.indexOf(':') > 0) { // 绝对路径 + File f = new File(confDir, "application.xml"); + if (f.isFile() && f.canRead()) { + appConfFile = f.toURI(); + confDir = f.getParentFile().getCanonicalPath(); + } else { + f = new File(confDir, "application.properties"); + if (f.isFile() && f.canRead()) { + appConfFile = f.toURI(); + confDir = f.getParentFile().getCanonicalPath(); + } else { + appConfFile = RedkaleClassLoader.getConfResourceAsURI(null, "application.xml"); // 不能传confDir + try { + appConfFile.toURL().openStream().close(); + } catch (IOException e) { // 没有application.xml就尝试读application.properties + appConfFile = RedkaleClassLoader.getConfResourceAsURI(null, "application.properties"); + } + confDir = appConfFile + .toString() + .replace("/application.xml", "") + .replace("/application.properties", ""); + fromCache = true; + } + } + } else { // 相对路径 + File f = new File(new File(home, confDir), "application.xml"); + if (f.isFile() && f.canRead()) { + appConfFile = f.toURI(); + confDir = f.getParentFile().getCanonicalPath(); + } else { + f = new File(new File(home, confDir), "application.properties"); + if (f.isFile() && f.canRead()) { + appConfFile = f.toURI(); + confDir = f.getParentFile().getCanonicalPath(); + } else { + appConfFile = RedkaleClassLoader.getConfResourceAsURI(null, "application.xml"); // 不能传confDir + try { + appConfFile.toURL().openStream().close(); + } catch (IOException e) { // 没有application.xml就尝试读application.properties + appConfFile = RedkaleClassLoader.getConfResourceAsURI(null, "application.properties"); + } + confDir = appConfFile + .toString() + .replace("/application.xml", "") + .replace("/application.properties", ""); + fromCache = true; + } + } + } + System.setProperty(RESNAME_APP_CONF_DIR, confDir); + String text = Utility.readThenClose(appConfFile.toURL().openStream()); + AnyValue conf; + if (text.trim().startsWith("<")) { + conf = AnyValue.loadFromXml(text, (k, v) -> v.replace("${APP_HOME}", home)) + .getAnyValue("application"); + } else { + conf = AnyValue.loadFromProperties(text).getAnyValue("redkale"); + } + if (fromCache) { + ((AnyValueWriter) conf).addValue("[config-from-cache]", "true"); + } + + return conf; + } + + /** + * 检查name是否含特殊字符 + * + * @param name + * @return + */ + private static String checkName(String name) { + if (name == null || name.isEmpty()) { + return name; + } + for (char ch : name.toCharArray()) { + if (!((ch >= '0' && ch <= '9') + || (ch >= 'a' && ch <= 'z') + || (ch >= 'A' && ch <= 'Z') + || ch == '_' + || ch == '.' + || ch == '-')) { // 不能含特殊字符 + throw new RedkaleException("name only 0-9 a-z A-Z _ - ."); + } + } + return name; + } + + /** + * 检查node是否含特殊字符 + * + * @param name + * @return + */ + private static String checkNodeid(String nodeid) { + if (nodeid == null || nodeid.isEmpty()) { + return nodeid; + } + for (char ch : nodeid.toCharArray()) { + if (!((ch >= '0' && ch <= '9') + || (ch >= 'a' && ch <= 'z') + || (ch >= 'A' && ch <= 'Z') + || ch == '_' + || ch == '.' + || ch == '-')) { // 不能含特殊字符 + throw new RedkaleException("nodeid only 0-9 a-z A-Z _ - ."); + } + } + return nodeid; + } + + private String getCanonicalPath(File file) { + try { + return file.getCanonicalPath(); + } catch (IOException e) { + return file.getAbsolutePath(); + } + } + + private File getCanonicalFile(File file) { + try { + return file.getCanonicalFile(); + } catch (IOException e) { + return file; + } + } +} diff --git a/src/main/java/org/redkale/boot/Application.java b/src/main/java/org/redkale/boot/Application.java index 089e2e83e..c78663950 100644 --- a/src/main/java/org/redkale/boot/Application.java +++ b/src/main/java/org/redkale/boot/Application.java @@ -1,1655 +1,1655 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package org.redkale.boot; - -import java.io.*; -import java.lang.reflect.*; -import java.net.*; -import java.net.http.HttpClient; -import java.nio.ByteBuffer; -import java.nio.channels.DatagramChannel; -import java.nio.charset.StandardCharsets; -import java.nio.file.Path; -import java.util.*; -import java.util.concurrent.*; -import java.util.concurrent.atomic.*; -import java.util.concurrent.locks.ReentrantLock; -import java.util.function.Consumer; -import java.util.logging.*; -import org.redkale.annotation.Nonnull; -import org.redkale.asm.AsmMethodBoost; -import org.redkale.boot.ClassFilter.FilterEntry; -import org.redkale.cache.spi.CacheModuleEngine; -import org.redkale.cluster.*; -import org.redkale.cluster.spi.ClusterAgent; -import org.redkale.cluster.spi.ClusterModuleEngine; -import org.redkale.cluster.spi.HttpClusterRpcClient; -import org.redkale.cluster.spi.HttpLocalRpcClient; -import org.redkale.convert.Convert; -import org.redkale.convert.bson.BsonFactory; -import org.redkale.convert.json.*; -import org.redkale.convert.proto.ProtobufFactory; -import org.redkale.inject.ResourceEvent; -import org.redkale.inject.ResourceFactory; -import org.redkale.inject.ResourceTypeLoader; -import org.redkale.lock.spi.LockModuleEngine; -import org.redkale.mq.spi.MessageAgent; -import org.redkale.mq.spi.MessageModuleEngine; -import org.redkale.net.*; -import org.redkale.net.http.*; -import org.redkale.net.sncp.*; -import org.redkale.props.spi.PropertiesModule; -import org.redkale.schedule.spi.ScheduleModuleEngine; -import org.redkale.service.Service; -import org.redkale.source.*; -import org.redkale.source.spi.SourceModuleEngine; -import org.redkale.util.*; -import org.redkale.watch.WatchServlet; - -/** - * 进程启动类,全局对象。
- * - *

- * 程序启动执行步骤:
- *     1、读取application.xml
- *     2、进行classpath扫描动态加载Service、WebSocket与Servlet
- *     3、优先加载所有SNCP协议的服务,再加载其他协议服务, 最后加载WATCH协议的服务
- *     4、最后进行Service、Servlet与其他资源之间的依赖注入
- * 
- * - *

详情见: https://redkale.org - * - * @author zhangjx - */ -public final class Application { - - /** 当前进程启动的时间, 类型: long */ - public static final String RESNAME_APP_TIME = "APP_TIME"; - - /** 当前进程服务的名称, 类型:String */ - public static final String RESNAME_APP_NAME = "APP_NAME"; - - /** 当前进程的根目录, 类型:String、File、Path、URI */ - public static final String RESNAME_APP_HOME = "APP_HOME"; - - /** - * 当前进程的配置目录URI,如果不是绝对路径则视为HOME目录下的相对路径 类型:String、URI、File、Path
- * 若配置目录不是本地文件夹, 则File、Path类型的值为null - */ - public static final String RESNAME_APP_CONF_DIR = "APP_CONF_DIR"; - - /** 当前进程节点的nodeid, 类型:String */ - public static final String RESNAME_APP_NODEID = "APP_NODEID"; - - /** 当前进程节点的IP地址, 类型:InetSocketAddress、InetAddress、String */ - public static final String RESNAME_APP_ADDR = "APP_ADDR"; - - /** - * 当前进程的work线程池, 类型:Executor、ExecutorService - * - * @since 2.3.0 - */ - public static final String RESNAME_APP_EXECUTOR = "APP_EXECUTOR"; - - /** - * 使用RESNAME_APP_CLIENT_IOGROUP代替 - * - * @since 2.3.0 - */ - public static final String RESNAME_APP_CLIENT_ASYNCGROUP = "APP_CLIENT_ASYNCGROUP"; - - /** 当前Service所属的SNCP Server的地址 类型: SocketAddress、InetSocketAddress、String
*/ - public static final String RESNAME_SNCP_ADDRESS = "SNCP_ADDRESS"; - - /** 当前Service所属的SNCP Server所属的组 类型: String
*/ - public static final String RESNAME_SNCP_GROUP = "SNCP_GROUP"; - - /** "SERVER_ROOT" 当前Server的ROOT目录类型:String、File、Path */ - public static final String RESNAME_SERVER_ROOT = Server.RESNAME_SERVER_ROOT; - - /** 当前Server的ResourceFactory */ - public static final String RESNAME_SERVER_RESFACTORY = "SERVER_RESFACTORY"; - - public static final String SYSNAME_APP_NAME = "redkale.application.name"; - - public static final String SYSNAME_APP_NODEID = "redkale.application.nodeid"; - - public static final String SYSNAME_APP_HOME = "redkale.application.home"; - - public static final String SYSNAME_APP_CONF_DIR = "redkale.application.confdir"; - - public static final Set REDKALE_RESNAMES = Collections.unmodifiableSet(Set.of( - RESNAME_APP_NAME, - RESNAME_APP_NODEID, - RESNAME_APP_TIME, - RESNAME_APP_HOME, - RESNAME_APP_ADDR, - RESNAME_APP_CONF_DIR)); - - // UDP协议的ByteBuffer Capacity - private static final int UDP_CAPACITY = 1024; - - // 日志 - private final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); - - // 本进程节点ID - final String nodeid; - - // 本进程节点ID - final String name; - - // 本地IP地址 - final InetSocketAddress localAddress; - - // 配置信息,只读版Properties - private final Environment environment; - - // 全局根ResourceFactory - final ResourceFactory resourceFactory = ResourceFactory.create(); - - // NodeServer 资源, 顺序必须是sncps, others, watchs - final List servers = new CopyOnWriteArrayList<>(); - - // 配置项里的group信息, 注意: 只给SNCP使用 - private final SncpRpcGroups sncpRpcGroups = new SncpRpcGroups(); - - // 除logging配置之外的所有配置项,包含本地和远程配置项 - final Properties envProperties = new Properties(); - - // 业务逻辑线程池 - // @since 2.3.0 - @Nonnull - private ExecutorService workExecutor; - - // 给客户端使用,包含SNCP客户端、自定义数据库客户端连接池 - private AsyncIOGroup clientAsyncGroup; - - // 服务配置项 - final AnyValue config; - - // 是否启动了WATCH协议服务 - boolean watching; - - // ------------- 模块组件(必须靠后放,否则new Module时resourceFactory会为null) ------------- - // 日志组件 - // @since 2.8.0 - final LoggingModule loggingModule; - - // 配置组件 - final PropertiesModule propertiesModule; - - // 数据源组件 - private final SourceModuleEngine sourceModule; - - // ----------------------------------------------------------------------------------- - // 是否用于main方法运行 - private final boolean singletonMode; - - // 是否用于编译模式运行 - private final boolean compileMode; - - // 进程根目录 - private final File home; - - // 配置文件目录 - private final URI confDir; - - // 监听事件 - private final List listeners = new CopyOnWriteArrayList<>(); - - // 服务启动时间 - private final long startTime = System.currentTimeMillis(); - - // Server启动的计数器,用于确保所有Server都启动完后再进行下一步处理 - private final CountDownLatch shutdownLatch; - - // 根ClassLoader - private final RedkaleClassLoader classLoader; - - // Server根ClassLoader - private final RedkaleClassLoader serverClassLoader; - - // 系统模块组件 - private final List moduleEngines = new ArrayList<>(); - - /** - * 初始化步骤:
- * 1、基本环境变量设置
- * 2、ClassLoader初始化
- * 3、日志配置初始化
- * 4、本地和远程配置文件读取
- * 5、ClusterAgent和MessageAgent实例化
- * 6、Work线程池初始化 7、原生sql解析器初始化
- * - * @param singletonMode 是否测试模式 - * @param compileMode 是否编译模式 - * @param config 启动配置 - */ - @SuppressWarnings("UseSpecificCatch") // config: 不带redkale.前缀的配置项 - Application(final AppConfig appConfig) { - this.singletonMode = appConfig.singletonMode; - this.compileMode = appConfig.compileMode; - this.config = appConfig.config; - this.envProperties.putAll(appConfig.localEnvProperties); - this.environment = new Environment(this.envProperties); - this.name = appConfig.name; - this.nodeid = appConfig.nodeid; - this.home = appConfig.home; - this.confDir = appConfig.confDir; - this.localAddress = appConfig.localAddress; - this.classLoader = appConfig.classLoader; - this.serverClassLoader = appConfig.serverClassLoader; - - this.loggingModule = new LoggingModule(this); - this.propertiesModule = new PropertiesModule(this); - this.sourceModule = new SourceModuleEngine(this); - - // 设置基础信息资源 - this.resourceFactory.register(RESNAME_APP_NAME, String.class, this.name); - - this.resourceFactory.register(RESNAME_APP_NODEID, String.class, this.nodeid); - if (Utility.isNumeric(this.nodeid)) { // 兼容旧类型 - this.resourceFactory.register( - RESNAME_APP_NODEID, int.class, Math.abs(((Long) Long.parseLong(this.nodeid)).intValue())); - } - - this.resourceFactory.register(RESNAME_APP_TIME, long.class, this.startTime); - this.resourceFactory.register(RESNAME_APP_TIME, Long.class, this.startTime); - - this.resourceFactory.register(RESNAME_APP_HOME, String.class, this.home.getPath()); - this.resourceFactory.register(RESNAME_APP_HOME, Path.class, this.home.toPath()); - this.resourceFactory.register(RESNAME_APP_HOME, File.class, this.home); - this.resourceFactory.register(RESNAME_APP_HOME, URI.class, this.home.toURI()); - - this.resourceFactory.register(RESNAME_APP_ADDR, InetSocketAddress.class, this.localAddress); - this.resourceFactory.register(RESNAME_APP_ADDR, InetAddress.class, this.localAddress.getAddress()); - this.resourceFactory.register( - RESNAME_APP_ADDR, String.class, this.localAddress.getAddress().getHostAddress()); - - this.resourceFactory.register(RESNAME_APP_CONF_DIR, URI.class, this.confDir); - this.resourceFactory.register(RESNAME_APP_CONF_DIR, File.class, appConfig.confFile); - this.resourceFactory.register(RESNAME_APP_CONF_DIR, String.class, this.confDir.toString()); - - System.setProperty("redkale.version", Redkale.getDotedVersion()); - System.setProperty(SYSNAME_APP_NAME, this.name); - System.setProperty(SYSNAME_APP_NODEID, String.valueOf(this.nodeid)); - System.setProperty(SYSNAME_APP_HOME, this.home.getPath()); - System.setProperty(SYSNAME_APP_CONF_DIR, this.confDir.toString()); - - this.envProperties.put(RESNAME_APP_NAME, this.name); - this.envProperties.put(RESNAME_APP_NODEID, String.valueOf(this.nodeid)); - this.envProperties.put(RESNAME_APP_TIME, String.valueOf(this.startTime)); - this.envProperties.put(RESNAME_APP_HOME, this.home.getPath()); - this.envProperties.put(RESNAME_APP_ADDR, this.localAddress.getAddress().getHostAddress()); - this.envProperties.put(RESNAME_APP_CONF_DIR, this.confDir.toString()); - - // 初始化本地配置的System.properties、mimetypes - this.registerResourceEnvs(true, appConfig.localEnvProperties); - - // 需要在加载properties初始化System.properties之后再注册 - this.resourceFactory.register(Environment.class, environment); - this.resourceFactory.register(BsonFactory.root()); - this.resourceFactory.register(JsonFactory.root()); - this.resourceFactory.register(ProtobufFactory.root()); - this.resourceFactory.register(BsonFactory.root().getConvert()); - this.resourceFactory.register(JsonFactory.root().getConvert()); - this.resourceFactory.register(ProtobufFactory.root().getConvert()); - this.resourceFactory.register( - "bsonconvert", Convert.class, BsonFactory.root().getConvert()); - this.resourceFactory.register( - "jsonconvert", Convert.class, JsonFactory.root().getConvert()); - this.resourceFactory.register( - "protobufconvert", Convert.class, ProtobufFactory.root().getConvert()); - - // 系统内部模块组件 - moduleEngines.add(this.sourceModule); // 放第一,很多module依赖于source - moduleEngines.add(new MessageModuleEngine(this)); - moduleEngines.add(new ClusterModuleEngine(this)); - moduleEngines.add(new ScheduleModuleEngine(this)); - moduleEngines.add(new CacheModuleEngine(this)); - moduleEngines.add(new LockModuleEngine(this)); - - // 根据本地日志配置文件初始化日志 - loggingModule.reconfigLogging(true, appConfig.locaLogProperties); - - // 打印基础信息日志 - logger.log( - Level.INFO, - colorMessage( - logger, - 36, - 1, - "-------------------------------- Redkale " + Redkale.getDotedVersion() - + " --------------------------------")); - - final String confDirStr = this.confDir.toString(); - logger.log( - Level.INFO, - "APP_OS = " + System.getProperty("os.name") + " " - + System.getProperty("os.version") + " " + System.getProperty("os.arch") + "\r\n" - + "APP_JAVA = " - + System.getProperty( - "java.runtime.name", - System.getProperty("org.graalvm.nativeimage.kind") != null ? "Nativeimage" : "") - + " " - + System.getProperty( - "java.runtime.version", - System.getProperty("java.vendor.version", System.getProperty("java.vm.version"))) - + "\r\n" // graalvm.nativeimage 模式下无 java.runtime.xxx 属性 - + "APP_PID = " + ProcessHandle.current().pid() + "\r\n" - + RESNAME_APP_NAME + " = " + this.name + "\r\n" - + RESNAME_APP_NODEID + " = " + this.nodeid + "\r\n" - + "APP_LOADER = " + this.classLoader.getClass().getSimpleName() + "\r\n" - + RESNAME_APP_ADDR + " = " + this.localAddress.getHostString() + ":" - + this.localAddress.getPort() + "\r\n" - + RESNAME_APP_HOME + " = " + this.home.getPath().replace('\\', '/') + "\r\n" - + RESNAME_APP_CONF_DIR + " = " + confDirStr.substring(confDirStr.indexOf('!') + 1)); - - if (!compileMode && !(classLoader instanceof RedkaleClassLoader.RedkaleCacheClassLoader)) { - String lib = environment.getPropertyValue( - config.getValue("lib", "${APP_HOME}/libs/*").trim()); - lib = Utility.isEmpty(lib) ? confDirStr : (lib + ";" + confDirStr); - Server.loadLib(classLoader, logger, lib.isEmpty() ? confDirStr : (lib + ";" + confDirStr)); - } - this.shutdownLatch = new CountDownLatch(config.getAnyValues("server").length + 1); - } - - public void init() throws Exception { - // 注册ResourceType - this.initResourceTypeLoader(); - // 读取远程配置,并合并app.config - this.propertiesModule.initRemoteProperties(); - // 解析配置 - this.onEnvironmentLoaded(); - // init起始回调 - this.onAppPreInit(); - // 设置WorkExecutor - this.initWorkExecutor(); - // 回调Listener - initAppListeners(); - // init结束回调 - this.onAppPostInit(); - } - - private void initResourceTypeLoader() { - final Application application = this; - // 只有WatchService才能加载Application、WatchFactory - this.resourceFactory.register(new ResourceTypeLoader() { - - @Override - public Object load( - ResourceFactory rf, - String srcResourceName, - Object srcObj, - String resourceName, - Field field, - Object attachment) { - try { - field.set(srcObj, application); - return application; - } catch (Exception e) { - logger.log(Level.SEVERE, "Resource inject error", e); - throw e instanceof RuntimeException ? (RuntimeException) e : new RedkaleException(e); - } - } - - @Override - public Type resourceType() { - return Application.class; - } - - @Override - public boolean autoNone() { - return false; - } - }); - this.resourceFactory.register(new ResourceTypeLoader() { - - @Override - public Object load( - ResourceFactory rf, - String srcResourceName, - Object srcObj, - String resourceName, - Field field, - Object attachment) { - try { - boolean serv = - RESNAME_SERVER_RESFACTORY.equals(resourceName) || resourceName.equalsIgnoreCase("server"); - ResourceFactory rs = serv ? rf : (resourceName.isEmpty() ? application.resourceFactory : null); - field.set(srcObj, rs); - return rs; - } catch (Exception e) { - logger.log(Level.SEVERE, "Resource inject error", e); - throw e instanceof RuntimeException ? (RuntimeException) e : new RedkaleException(e); - } - } - - @Override - public Type resourceType() { - return ResourceFactory.class; - } - - @Override - public boolean autoNone() { - return false; - } - }); - this.resourceFactory.register(new ResourceTypeLoader() { - - @Override - public Object load( - ResourceFactory rf, - String srcResourceName, - Object srcObj, - String resourceName, - Field field, - Object attachment) { - try { - NodeServer server = null; - for (NodeServer ns : application.getNodeServers()) { - if (ns.getClass() != NodeSncpServer.class) { - continue; - } - if (resourceName.equals(ns.server.getName())) { - server = ns; - break; - } - } - field.set(srcObj, server); - return server; - } catch (Exception e) { - logger.log(Level.SEVERE, "Resource inject error", e); - throw e instanceof RuntimeException ? (RuntimeException) e : new RedkaleException(e); - } - } - - @Override - public Type resourceType() { - return NodeSncpServer.class; - } - - @Override - public boolean autoNone() { - return false; - } - }); - this.resourceFactory.register(new ResourceTypeLoader() { - - @Override - public Object load( - ResourceFactory rf, - String srcResourceName, - Object srcObj, - String resourceName, - Field field, - Object attachment) { - try { - NodeServer server = null; - for (NodeServer ns : application.getNodeServers()) { - if (ns.getClass() != NodeHttpServer.class) { - continue; - } - if (resourceName.equals(ns.server.getName())) { - server = ns; - break; - } - } - field.set(srcObj, server); - return server; - } catch (Exception e) { - logger.log(Level.SEVERE, "Resource inject error", e); - throw e instanceof RuntimeException ? (RuntimeException) e : new RedkaleException(e); - } - } - - @Override - public Type resourceType() { - return NodeHttpServer.class; - } - - @Override - public boolean autoNone() { - return false; - } - }); - this.resourceFactory.register(new ResourceTypeLoader() { - - @Override - public Object load( - ResourceFactory rf, - String srcResourceName, - Object srcObj, - String resourceName, - Field field, - Object attachment) { - try { - NodeServer server = null; - for (NodeServer ns : application.getNodeServers()) { - if (ns.getClass() != NodeWatchServer.class) { - continue; - } - if (resourceName.equals(ns.server.getName())) { - server = ns; - break; - } - } - field.set(srcObj, server); - return server; - } catch (Exception e) { - logger.log(Level.SEVERE, "Resource inject error", e); - throw e instanceof RuntimeException ? (RuntimeException) e : new RedkaleException(e); - } - } - - @Override - public Type resourceType() { - return NodeWatchServer.class; - } - - @Override - public boolean autoNone() { - return false; - } - }); - - // ------------------------------------ 注册 java.net.http.HttpClient ------------------------------------ - resourceFactory.register(new ResourceTypeLoader() { - - @Override - public Object load( - ResourceFactory rf, - String srcResourceName, - Object srcObj, - String resourceName, - Field field, - Object attachment) { - try { - java.net.http.HttpClient.Builder builder = java.net.http.HttpClient.newBuilder(); - if (resourceName.endsWith(".1.1")) { - builder.version(HttpClient.Version.HTTP_1_1); - } else if (resourceName.endsWith(".2")) { - builder.version(HttpClient.Version.HTTP_2); - } - java.net.http.HttpClient httpClient = builder.build(); - field.set(srcObj, httpClient); - rf.inject(resourceName, httpClient, null); // 给其可能包含@Resource的字段赋值; - rf.register(resourceName, java.net.http.HttpClient.class, httpClient); - return httpClient; - } catch (Exception e) { - logger.log(Level.SEVERE, java.net.http.HttpClient.class.getSimpleName() + " inject error", e); - return null; - } - } - - @Override - public Type resourceType() { - return java.net.http.HttpClient.class; - } - }); - // ------------------------------------ 注册 WebClient ------------------------------------ - resourceFactory.register(new ResourceTypeLoader() { - - @Override - public Object load( - ResourceFactory rf, - String srcResourceName, - Object srcObj, - String resourceName, - Field field, - Object attachment) { - try { - WebClient httpClient = WebClient.create(workExecutor, clientAsyncGroup); - field.set(srcObj, httpClient); - rf.inject(resourceName, httpClient, null); // 给其可能包含@Resource的字段赋值; - rf.register(resourceName, WebClient.class, httpClient); - return httpClient; - } catch (Exception e) { - logger.log(Level.SEVERE, WebClient.class.getSimpleName() + " inject error", e); - throw e instanceof RuntimeException ? (RuntimeException) e : new RedkaleException(e); - } - } - - @Override - public Type resourceType() { - return WebClient.class; - } - }); - // ------------------------------------ 注册 HttpRpcClient ------------------------------------ - resourceFactory.register(new ResourceTypeLoader() { - - @Override - public Object load( - ResourceFactory rf, - String srcResourceName, - Object srcObj, - String resourceName, - Field field, - Object attachment) { - try { - ClusterAgent clusterAgent = resourceFactory.find("", ClusterAgent.class); - MessageAgent messageAgent = resourceFactory.find(resourceName, MessageAgent.class); - if (messageAgent != null) { - if (clusterAgent == null - || !Objects.equals(clusterAgent.getName(), resourceName) - || messageAgent.isRpcFirst()) { - HttpRpcClient rpcClient = messageAgent.getHttpRpcClient(); - field.set(srcObj, rpcClient); - rf.inject(resourceName, rpcClient, null); // 给其可能包含@Resource的字段赋值; - rf.register(resourceName, HttpRpcClient.class, rpcClient); - return rpcClient; - } - } - if (clusterAgent == null) { - HttpRpcClient rpcClient = new HttpLocalRpcClient(application, resourceName); - field.set(srcObj, rpcClient); - rf.inject(resourceName, rpcClient, null); // 给其可能包含@Resource的字段赋值; - rf.register(resourceName, HttpRpcClient.class, rpcClient); - return rpcClient; - } - HttpRpcClient rpcClient = new HttpClusterRpcClient(application, resourceName, clusterAgent); - field.set(srcObj, rpcClient); - rf.inject(resourceName, rpcClient, null); // 给其可能包含@Resource的字段赋值; - rf.register(resourceName, HttpRpcClient.class, rpcClient); - return rpcClient; - } catch (Exception e) { - logger.log(Level.SEVERE, HttpRpcClient.class.getSimpleName() + " inject error", e); - throw e instanceof RuntimeException ? (RuntimeException) e : new RedkaleException(e); - } - } - - @Override - public Type resourceType() { - return HttpRpcClient.class; - } - }); - } - - private void registerResourceEnvs(boolean first, Properties... envs) { - for (Properties props : envs) { - props.forEach((k, v) -> { - String val = environment.getPropertyValue(v.toString(), envs); - if (k.toString().startsWith("system.property.")) { - String key = k.toString().substring("system.property.".length()); - if (System.getProperty(key) == null || !first) { - System.setProperty(key, val); - } - resourceFactory.register(!first, k.toString(), val); - } else if (k.toString().startsWith("mimetype.property.")) { - MimeType.add(k.toString().substring("mimetype.property.".length()), val); - } else { - resourceFactory.register(!first, k.toString(), val); - } - }); - } - } - - /** 设置WorkExecutor */ - private void initWorkExecutor() { - int bufferCapacity = 32 * 1024; - int bufferPoolSize = Utility.cpus() * 8; - final AnyValue executorConf = config.getAnyValue("executor", true); - StringBuilder executorLog = new StringBuilder(); - - final int workThreads = Math.max(Utility.cpus(), executorConf.getIntValue("threads", Utility.cpus() * 10)); - // 指定threads则不使用虚拟线程池 - this.workExecutor = executorConf.getValue("threads") != null - ? WorkThread.createExecutor(workThreads, "Redkale-WorkThread-%s") - : WorkThread.createWorkExecutor(workThreads, "Redkale-WorkThread-%s"); - String executorName = this.workExecutor.getClass().getSimpleName(); - executorLog.append("defaultWorkExecutor: {type=").append(executorName); - if (executorName.contains("VirtualExecutor") || executorName.contains("PerTaskExecutor")) { - executorLog.append(", threads=[virtual]}"); - } else { - executorLog.append(", threads=").append(workThreads).append("}"); - } - - ExecutorService clientWorkExecutor = this.workExecutor; - if (executorName.contains("VirtualExecutor") || executorName.contains("PerTaskExecutor")) { - executorLog.append(", clientWorkExecutor: [workExecutor]"); - } else { - // 给所有client给一个新的默认ExecutorService - int clientThreads = executorConf.getIntValue("clients", Utility.cpus() * 4); - clientWorkExecutor = WorkThread.createWorkExecutor(clientThreads, "Redkale-DefaultClient-WorkThread-%s"); - executorLog.append(", threads=").append(clientThreads).append("}"); - } - AsyncIOGroup ioGroup = new AsyncIOGroup( - "Redkale-DefaultClient-IOThread-%s", clientWorkExecutor, bufferCapacity, bufferPoolSize) - .skipClose(true); - this.clientAsyncGroup = ioGroup.start(); - - if (executorLog.length() > 0) { - logger.log(Level.INFO, executorLog.toString()); - } - this.resourceFactory.register(RESNAME_APP_EXECUTOR, Executor.class, this.workExecutor); - this.resourceFactory.register(RESNAME_APP_EXECUTOR, ExecutorService.class, this.workExecutor); - this.resourceFactory.register(RESNAME_APP_CLIENT_ASYNCGROUP, AsyncGroup.class, this.clientAsyncGroup); - this.resourceFactory.register(RESNAME_APP_CLIENT_ASYNCGROUP, AsyncIOGroup.class, this.clientAsyncGroup); - } - - private void initAppListeners() throws Exception { - // ------------------------------------------------------------------------ - for (AnyValue conf : config.getAnyValues("group")) { - final String group = conf.getValue("name", ""); - if (group.indexOf('$') >= 0 || group.indexOf('.') >= 0) { - throw new RedkaleException(" name cannot contains '$', '.' in " + group); - } - final String protocol = conf.getValue("protocol", "TCP").toUpperCase(); - if (!"TCP".equalsIgnoreCase(protocol) && !"UDP".equalsIgnoreCase(protocol)) { - throw new RedkaleException("Not supported Transport Protocol " + conf.getValue("protocol")); - } - SncpRpcGroup rg = sncpRpcGroups.computeIfAbsent(group, protocol); - String nodes = conf.getValue("nodes"); - if (Utility.isNotEmpty(nodes)) { - for (String node : nodes.replace(',', ';').split(";")) { - if (Utility.isNotBlank(node)) { - int pos = node.indexOf(':'); - String addr = node.substring(0, pos).trim(); - int port = Integer.parseInt(node.substring(pos + 1).trim()); - rg.putAddress(new InetSocketAddress(addr, port)); - } - } - } - for (AnyValue node : conf.getAnyValues("node")) { - rg.putAddress(new InetSocketAddress(node.getValue("addr"), node.getIntValue("port"))); - } - } - for (AnyValue conf : config.getAnyValues("listener")) { - final String listenClass = conf.getValue("value", ""); - if (listenClass.isEmpty()) { - continue; - } - Class clazz = classLoader.loadClass(listenClass); - if (!ApplicationListener.class.isAssignableFrom(clazz)) { - continue; - } - RedkaleClassLoader.putReflectionDeclaredConstructors(clazz, clazz.getName()); - @SuppressWarnings("unchecked") - ApplicationListener listener = - (ApplicationListener) clazz.getDeclaredConstructor().newInstance(); - resourceFactory.inject(listener); - listener.init(config); - this.listeners.add(listener); - } - // ------------------------------------------------------------------------ - } - - private static String colorMessage(Logger logger, int color, int type, String msg) { - final boolean linux = - System.getProperty("os.name").toLowerCase(Locale.ENGLISH).contains("linux"); - if (linux) { // Windows PowerShell 也能正常着色 - boolean supported = true; - Logger l = logger; - do { - if (l.getHandlers() == null) { - break; - } - for (Handler handler : l.getHandlers()) { - if (!(handler instanceof ConsoleHandler)) { - supported = false; - break; - } - } - if (!supported) { - break; - } - } while ((l = l.getParent()) != null); - // colour 颜色代号:背景颜色代号(41-46);前景色代号(31-36) - // type 样式代号:0无;1加粗;3斜体;4下划线 - // String.format("\033[%d;%dm%s\033[0m", colour, type, content) - if (supported) { - msg = "\033[" + color + (type > 0 ? (";" + type) : "") + "m" + msg + "\033[0m"; - } - } - return msg; - } - - private void startSelfServer() throws Exception { - if (config.getValue("port", "").isEmpty() || "0".equals(config.getValue("port"))) { - return; // 没有配置port则不启动进程自身的监听 - } - final Application application = this; - new Thread() { - { - setName("Redkale-Application-SelfServer-Thread"); - } - - @Override - public void run() { - try { - DatagramChannel channel = DatagramChannel.open(); - channel.configureBlocking(true); - channel.socket().setSoTimeout(6000); // 单位:毫秒 - channel.bind(new InetSocketAddress("127.0.0.1", config.getIntValue("port"))); - if (!singletonMode) { - signalShutdownHandle(); - } - boolean loop = true; - final ByteBuffer buffer = ByteBuffer.allocateDirect(UDP_CAPACITY); - while (loop) { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - SocketAddress address = readUdpData(channel, buffer, out); - String[] args = - JsonConvert.root().convertFrom(String[].class, out.toString(StandardCharsets.UTF_8)); - final String cmd = args[0]; - String[] params = args.length == 1 ? new String[0] : Arrays.copyOfRange(args, 1, args.length); - // 接收到命令必须要有回应, 无结果输出则回应回车换行符 - if ("SHUTDOWN".equalsIgnoreCase(cmd)) { - try { - long s = System.currentTimeMillis(); - logger.info(application.getClass().getSimpleName() + " shutdowning"); - application.shutdown(); - sendUdpData( - channel, - address, - buffer, - "--- shutdown finish ---".getBytes(StandardCharsets.UTF_8)); - long e = System.currentTimeMillis() - s; - logger.info(application.getClass().getSimpleName() + " shutdown in " + e + " ms"); - channel.close(); - } catch (Exception ex) { - logger.log(Level.INFO, "Shutdown fail", ex); - sendUdpData(channel, address, buffer, "shutdown fail".getBytes(StandardCharsets.UTF_8)); - } finally { - loop = false; - application.shutdownLatch.countDown(); - } - } else if ("APIDOC".equalsIgnoreCase(cmd)) { - try { - String rs = new ApiDocCommand(application).command(cmd, params); - if (rs == null || rs.isEmpty()) { - rs = "\r\n"; - } - sendUdpData(channel, address, buffer, rs.getBytes(StandardCharsets.UTF_8)); - } catch (Exception ex) { - sendUdpData(channel, address, buffer, "apidoc fail".getBytes(StandardCharsets.UTF_8)); - } - } else { - long s = System.currentTimeMillis(); - logger.info(application.getClass().getSimpleName() + " command " + cmd); - List rs = application.command(cmd, params); - StringBuilder sb = new StringBuilder(); - if (rs != null) { - for (Object o : rs) { - if (o instanceof CharSequence) { - sb.append(o).append("\r\n"); - } else { - sb.append(JsonConvert.root().convertTo(o)) - .append("\r\n"); - } - } - } - if (sb.length() == 0) { - sb.append("\r\n"); - } - sendUdpData(channel, address, buffer, sb.toString().getBytes(StandardCharsets.UTF_8)); - long e = System.currentTimeMillis() - s; - logger.info(application.getClass().getSimpleName() + " command in " + e + " ms"); - } - } - } catch (Exception e) { - logger.log(Level.INFO, "Control fail", e); - Utility.sleep(100); - System.exit(1); - } - } - }.start(); - } - - // 数据包前4个字节为数据内容的长度 - private static void sendUdpData(final DatagramChannel channel, SocketAddress dest, ByteBuffer buffer, byte[] bytes) - throws IOException { - buffer.clear(); - int count = (bytes.length + 4) / UDP_CAPACITY + ((bytes.length + 4) % UDP_CAPACITY > 0 ? 1 : 0); - int start = 0; - for (int i = 0; i < count; i++) { - if (start == 0) { - buffer.putInt(bytes.length); - } - int len = Math.min(buffer.remaining(), bytes.length - start); - buffer.put(bytes, start, len); - buffer.flip(); - boolean first = true; - while (buffer.hasRemaining()) { - if (!first) { - Utility.sleep(10); - } - if (dest == null) { - channel.write(buffer); - } else { - channel.send(buffer, dest); - } - first = false; - } - start += len; - buffer.clear(); - } - } - - private static SocketAddress readUdpData( - final DatagramChannel channel, ByteBuffer buffer, ByteArrayOutputStream out) throws IOException { - out.reset(); - buffer.clear(); - SocketAddress src = null; - if (channel.isConnected()) { - channel.read(buffer); - while (buffer.position() < 4) channel.read(buffer); - } else { - src = channel.receive(buffer); - while (buffer.position() < 4) src = channel.receive(buffer); - } - buffer.flip(); - final int dataSize = buffer.getInt(); - while (buffer.hasRemaining()) { - out.write(buffer.get()); - } - while (out.size() < dataSize) { - buffer.clear(); - channel.receive(buffer); - buffer.flip(); - while (buffer.hasRemaining()) { - out.write(buffer.get()); - } - } - return src; - } - - private static void sendCommand(Logger logger, int port, String cmd, String[] params) throws Exception { - final DatagramChannel channel = DatagramChannel.open(); - channel.configureBlocking(true); - channel.socket().setSoTimeout(6000); // 单位:毫秒 - SocketAddress dest = new InetSocketAddress("127.0.0.1", port); - channel.connect(dest); - // 命令和参数合成一个数组 - String[] args = new String[1 + (params == null ? 0 : params.length)]; - args[0] = cmd; - if (params != null) { - System.arraycopy(params, 0, args, 1, params.length); - } - final ByteBuffer buffer = ByteBuffer.allocateDirect(UDP_CAPACITY); - try { - sendUdpData(channel, dest, buffer, JsonConvert.root().convertToBytes(args)); - ByteArrayOutputStream out = new ByteArrayOutputStream(); - readUdpData(channel, buffer, out); - channel.close(); - String rs = out.toString(StandardCharsets.UTF_8).trim(); - if (logger != null) { - logger.info("Send: " + cmd + ", Reply: " + rs); - } - (System.out).println(rs); - } catch (Exception e) { - if (e instanceof PortUnreachableException) { - if ("APIDOC".equalsIgnoreCase(cmd)) { - final Application application = new Application(AppConfig.create(false, true)); - application.init(); - application.start(); - String rs = new ApiDocCommand(application).command(cmd, params); - application.shutdown(); - if (logger != null) { - logger.info(rs); - } - (System.out).println(rs); - return; - } - // if ("SHUTDOWN".equalsIgnoreCase(cmd)) { - // System.out .println("--- application not running ---"); - // } else { - (System.err).println("--- application not running ---"); - // } - return; - } - throw e; - } - } - - AsmMethodBoost createAsmMethodBoost(boolean remote, Class serviceClass) { - List list = null; - for (ModuleEngine item : moduleEngines) { - AsmMethodBoost boost = item.createAsmMethodBoost(remote, serviceClass); - if (boost != null) { - if (list == null) { - list = new ArrayList<>(); - } - list.add(boost); - } - } - if (list == null) { - return null; - } - return list.size() == 1 ? list.get(0) : AsmMethodBoost.create(remote, list); - } - - /** 进入Application.init方法时被调用 */ - private void onAppPreInit() { - for (ModuleEngine item : moduleEngines) { - item.onAppPreInit(); - } - } - - /** 结束Application.init方法前被调用 */ - private void onAppPostInit() { - for (ModuleEngine item : moduleEngines) { - item.onAppPostInit(); - } - } - - /** 进入Application.start方法被调用 */ - private void onAppPreStart() { - for (ApplicationListener listener : this.listeners) { - listener.onPreStart(this); - } - for (ModuleEngine item : moduleEngines) { - item.onAppPreStart(); - } - } - - /** 结束Application.start方法前被调用 */ - private void onAppPostStart() { - for (ApplicationListener listener : this.listeners) { - listener.onPostStart(this); - } - for (ModuleEngine item : moduleEngines) { - item.onAppPostStart(); - } - } - - /** - * 配置项加载后被调用 - * - * @param props 配置项全量 - */ - private void onEnvironmentLoaded() { - this.registerResourceEnvs(true, this.envProperties); - for (ModuleEngine item : moduleEngines) { - item.onEnvironmentLoaded(this.envProperties); - } - } - - /** - * 配置项变更时被调用 - * - * @param namespace 命名空间 - * @param events 变更项 - */ - void onEnvironmentChanged(String namespace, List events) { - for (ModuleEngine item : moduleEngines) { - item.onEnvironmentChanged(namespace, events); - } - } - - /** 服务全部启动前被调用 */ - private void onServersPreStart() { - for (ModuleEngine item : moduleEngines) { - item.onServersPreStart(); - } - } - - /** 服务全部启动后被调用 */ - private void onServersPostStart() { - for (ModuleEngine item : moduleEngines) { - item.onServersPostStart(); - } - } - - /** 执行Service.init方法前被调用 */ - void onServicePreInit(Service service) { - for (ModuleEngine item : moduleEngines) { - item.onServicePreInit(service); - } - } - - /** 执行Service.init方法后被调用 */ - void onServicePostInit(Service service) { - for (ModuleEngine item : moduleEngines) { - item.onServicePostInit(service); - } - } - - /** 执行Service.destroy方法前被调用 */ - void onServicePreDestroy(Service service) { - for (ModuleEngine item : moduleEngines) { - item.onServicePreDestroy(service); - } - } - - /** 执行Service.destroy方法后被调用 */ - void onServicePostDestroy(Service service) { - for (ModuleEngine item : moduleEngines) { - item.onServicePostDestroy(service); - } - } - - /** 服务全部停掉前被调用 */ - private void onServersPreStop() { - for (ApplicationListener listener : listeners) { - listener.onServersPreStop(this); - } - for (ModuleEngine item : moduleEngines) { - item.onServersPreStop(); - } - } - - /** 服务全部停掉后被调用 */ - private void onServersPostStop() { - for (ApplicationListener listener : listeners) { - listener.onServersPostStop(this); - } - for (ModuleEngine item : moduleEngines) { - item.onServersPostStop(); - } - } - - /** 进入Application.shutdown方法被调用 */ - private void onAppPreShutdown() { - for (ApplicationListener listener : this.listeners) { - try { - listener.onPreShutdown(this); - } catch (Exception e) { - logger.log(Level.WARNING, listener.getClass() + " preShutdown erroneous", e); - } - } - for (ModuleEngine item : moduleEngines) { - item.onAppPreShutdown(); - } - } - - /** 结束Application.shutdown方法前被调用 */ - private void onAppPostShutdown() { - for (ModuleEngine item : moduleEngines) { - item.onAppPostShutdown(); - } - } - - void onPreCompile() { - for (ApplicationListener listener : listeners) { - listener.onPreCompile(this); - } - for (ModuleEngine item : moduleEngines) { - item.onPreCompile(); - } - } - - void onPostCompile() { - for (ApplicationListener listener : listeners) { - listener.onPostCompile(this); - } - for (ModuleEngine item : moduleEngines) { - item.onPostCompile(); - } - } - - /** - * 启动 - * - * @throws Exception 异常 - */ - public void start() throws Exception { - this.onAppPreStart(); - final AnyValue[] entrys = config.getAnyValues("server"); - CountDownLatch serverCdl = new CountDownLatch(entrys.length); - final List sncps = new ArrayList<>(); - final List others = new ArrayList<>(); - final List watchs = new ArrayList<>(); - for (final AnyValue entry : entrys) { - if (entry.getValue("protocol", "").toUpperCase().startsWith("SNCP")) { - sncps.add(entry); - } else if (entry.getValue("protocol", "").toUpperCase().startsWith("WATCH")) { - watchs.add(entry); - } else { - others.add(entry); - } - } - if (watchs.size() > 1) { - throw new RedkaleException("Found one more WATCH Server"); - } - this.watching = !watchs.isEmpty(); - - this.onServersPreStart(); - runServers(serverCdl, sncps); // 必须确保SNCP服务都启动后再启动其他服务 - runServers(serverCdl, others); - runServers(serverCdl, watchs); // 必须在所有服务都启动后再启动WATCH服务 - serverCdl.await(); - this.onServersPostStart(); - - this.onAppPostStart(); - long intms = System.currentTimeMillis() - startTime; - String ms = String.valueOf(intms); - int repeat = ms.length() > 7 ? 0 : (7 - ms.length()) / 2; - logger.info(colorMessage( - logger, - 36, - 1, - "-".repeat(repeat) + "------------------------ Redkale started in " + ms + " ms " - + (ms.length() / 2 == 0 ? " " : "") + "-".repeat(repeat) + "------------------------") - + "\r\n"); - LoggingBaseHandler.traceEnable = true; - - if (!singletonMode && !compileMode) { - this.shutdownLatch.await(); - } - } - - /** - * 实例化单个Service - * - * @param 泛型 - * @param serviceClass 指定的service类 - * @param extServiceClasses 需要排除的service类 - * @return Service对象 - * @throws Exception 异常 - */ - public static T singleton(Class serviceClass, Class... extServiceClasses) - throws Exception { - return singleton("", serviceClass, extServiceClasses); - } - - /** - * 实例化单个Service - * - * @param 泛型 - * @param name Service的资源名 - * @param serviceClass 指定的service类 - * @param extServiceClasses 需要排除的service类 - * @return Service对象 - * @throws Exception 异常 - */ - public static T singleton( - String name, Class serviceClass, Class... extServiceClasses) throws Exception { - if (serviceClass == null) { - throw new IllegalArgumentException("serviceClass is null"); - } - final Application application = Application.create(true); - System.setProperty("redkale.singleton.serviceclass", serviceClass.getName()); - if (extServiceClasses != null && extServiceClasses.length > 0) { - StringBuilder sb = new StringBuilder(); - for (Class clazz : extServiceClasses) { - if (sb.length() > 0) { - sb.append(','); - } - sb.append(clazz.getName()); - } - System.setProperty("redkale.singleton.extserviceclasses", sb.toString()); - } - application.init(); - application.start(); - for (NodeServer server : application.servers) { - T service = server.resourceFactory.find(name, serviceClass); - if (service != null) { - return service; - } - } - if (Modifier.isAbstract(serviceClass.getModifiers())) { - throw new IllegalArgumentException("abstract class not allowed"); - } - if (serviceClass.isInterface()) { - throw new IllegalArgumentException("interface class not allowed"); - } - throw new IllegalArgumentException(serviceClass.getName() + " maybe have zero not-final public method"); - } - - public static Application create(final boolean singleton) throws IOException { - return new Application(AppConfig.create(singleton, false)); - } - - public static void main(String[] args) throws Exception { - Times.midnight(); // 先初始化一下Utility - Thread.currentThread().setName("Redkale-Application-Main-Thread"); - // 运行主程序 - String cmd = System.getProperty("cmd", System.getProperty("CMD")); - String[] params = args; - if (args != null && args.length > 0) { - for (int i = 0; i < args.length; i++) { - if (args[i] != null && args[i].toLowerCase().startsWith("--conf-file=")) { - System.setProperty(AppConfig.PARAM_APP_CONF_FILE, args[i].substring("--conf-file=".length())); - String[] newargs = new String[args.length - 1]; - System.arraycopy(args, 0, newargs, 0, i); - System.arraycopy(args, i + 1, newargs, i, args.length - 1 - i); - args = newargs; - break; - } - } - if (cmd == null) { - for (int i = 0; i < args.length; i++) { - if (args[i] != null && !args[i].startsWith("-")) { // 非-开头的第一个视为命令号 - cmd = args[i]; - if ("start".equalsIgnoreCase(cmd) || "startup".equalsIgnoreCase(cmd)) { - cmd = null; - } - params = new String[args.length - 1]; - System.arraycopy(args, 0, params, 0, i); - System.arraycopy(args, i + 1, params, i, args.length - 1 - i); - break; - } - } - } - if (cmd == null) { - if (args.length == 1 && ("--help".equalsIgnoreCase(args[0]) || "-h".equalsIgnoreCase(args[0]))) { - cmd = args[0]; - } - } - } - if (cmd != null) { - if ("stop".equalsIgnoreCase(cmd)) { - cmd = "shutdown"; - } - if ("help".equalsIgnoreCase(cmd) || "--help".equalsIgnoreCase(cmd) || "-h".equalsIgnoreCase(cmd)) { - (System.out).println(generateHelp()); - return; - } - boolean restart = "restart".equalsIgnoreCase(cmd); - AnyValue config = AppConfig.loadAppConfig(); - Application.sendCommand(null, config.getIntValue("port"), restart ? "SHUTDOWN" : cmd, params); - if (!restart) { - return; - } - } - - // PrepareCompiler.main(args); //测试代码 - final Application application = Application.create(false); - application.init(); - application.startSelfServer(); - try { - application.start(); - } catch (Exception e) { - application.logger.log(Level.SEVERE, "Application start error", e); - Utility.sleep(100); - System.exit(1); - } - System.exit(0); // 必须要有 - } - - public List command(String cmd, String[] params) { - List localServers = new ArrayList<>(servers); // 顺序sncps, others, watchs - List results = new ArrayList<>(); - localServers.stream().forEach((server) -> { - try { - List rs = server.command(cmd, params); - if (rs != null) { - results.addAll(rs); - } - } catch (Exception t) { - logger.log(Level.WARNING, " command server(" + server.getSocketAddress() + ") error", t); - } - }); - return results; - } - - public void shutdown() throws Exception { - long f = System.currentTimeMillis(); - this.onAppPreShutdown(); - stopServers(); - this.propertiesModule.destroy(); - if (this.workExecutor != null) { - this.workExecutor.shutdownNow(); - } - if (this.clientAsyncGroup != null) { - long s = System.currentTimeMillis(); - this.clientAsyncGroup.dispose(); - logger.info("AsyncGroup destroy in " + (System.currentTimeMillis() - s) + " ms"); - } - this.onAppPostShutdown(); - - long intms = System.currentTimeMillis() - f; - String ms = String.valueOf(intms); - int repeat = ms.length() > 7 ? 0 : (7 - ms.length()) / 2; - logger.info(colorMessage( - logger, - 36, - 1, - "-".repeat(repeat) + "------------------------ Redkale shutdown in " + ms + " ms " - + (ms.length() / 2 == 0 ? " " : "") + "-".repeat(repeat) + "------------------------") - + "\r\n" + "\r\n"); - LoggingBaseHandler.traceEnable = true; - } - - private static String generateHelp() { - return "" - + "Usage: redkale [command] [arguments]\r\n" - + "Command: \r\n" - + " start, startup start one process\r\n" - + " --conf-file=[file] application config file, eg. application.xml、application.properties\r\n" - + " shutdown, stop shutdown one process\r\n" - + " --conf-file=[file] application config file, eg. application.xml、application.properties\r\n" - + " restart restart one process\r\n" - + " --conf-file=[file] application config file, eg. application.xml、application.properties\r\n" - + " apidoc generate apidoc\r\n" - + " --api-skiprpc=[true|false] skip @RestService(rpcOnly=true) service or @RestMapping(rpcOnly=true) method, default is true\r\n" - + " --api-host=[url] api root url, default is http://localhost\r\n" - + " help, -h, --help show this help\r\n"; - } - - @SuppressWarnings("unchecked") - private void runServers(CountDownLatch serverCdl, final List serverConfs) throws Exception { - CountDownLatch serviceCdl = new CountDownLatch(serverConfs.size()); - CountDownLatch startCdl = new CountDownLatch(serverConfs.size()); - final AtomicBoolean inited = new AtomicBoolean(false); - final ReentrantLock nodeLock = new ReentrantLock(); - final Map> nodeClasses = new HashMap<>(); - for (final AnyValue serconf : serverConfs) { - Thread thread = new Thread() { - { - setName("Redkale-" - + serconf.getValue("protocol", "Server") - .toUpperCase() - .replaceFirst("\\..+", "") + ":" + serconf.getIntValue("port") + "-Thread"); - this.setDaemon(true); - } - - @Override - public void run() { - try { - // Thread ctd = Thread.currentThread(); - // ctd.setContextClassLoader(new URLClassLoader(new URL[0], ctd.getContextClassLoader())); - final String protocol = serconf.getValue("protocol", "") - .replaceFirst("\\..+", "") - .toUpperCase(); - NodeServer server = null; - if ("SNCP".equals(protocol)) { - server = NodeSncpServer.createNodeServer(Application.this, serconf); - } else if ("WATCH".equalsIgnoreCase(protocol)) { - AnyValueWriter serconf2 = (AnyValueWriter) serconf; - AnyValueWriter rest = (AnyValueWriter) serconf2.getAnyValue("rest"); - if (rest == null) { - rest = new AnyValueWriter(); - serconf2.addValue("rest", rest); - } - rest.setValue("base", WatchServlet.class.getName()); - server = new NodeWatchServer(Application.this, serconf); - } else if ("HTTP".equalsIgnoreCase(protocol)) { - server = new NodeHttpServer(Application.this, serconf); - } else { - if (!inited.get()) { - nodeLock.lock(); - try { - if (!inited.getAndSet(true)) { // 加载自定义的协议,如:SOCKS - ClassFilter profilter = - new ClassFilter(classLoader, NodeProtocol.class, NodeServer.class); - loadClassByFilters(profilter); - final Set> entrys = profilter.getFilterEntrys(); - for (FilterEntry entry : entrys) { - final Class type = entry.getType(); - NodeProtocol pros = type.getAnnotation(NodeProtocol.class); - String p = pros.value().toUpperCase(); - if ("SNCP".equals(p) || "HTTP".equals(p)) { - continue; - } - final Class old = nodeClasses.get(p); - if (old != null && old != type) { - throw new RedkaleException("Protocol(" + p + ") had NodeServer-Class(" - + old.getName() + ") but repeat NodeServer-Class(" - + type.getName() + ")"); - } - nodeClasses.put(p, type); - } - } - } finally { - nodeLock.unlock(); - } - } - Class nodeClass = nodeClasses.get(protocol); - if (nodeClass != null) { - server = NodeServer.create(nodeClass, Application.this, serconf); - } - } - if (server == null) { - logger.log( - Level.SEVERE, - "Not found Server Class for protocol({0})", - serconf.getValue("protocol")); - Utility.sleep(100); - System.exit(1); - } - server.serviceCdl = serviceCdl; - server.init(serconf); - if (!singletonMode && !compileMode) { - server.start(); - } else if (compileMode) { - server.getServer() - .getDispatcherServlet() - .init(server.getServer().getContext(), serconf); - } - servers.add(server); - serverCdl.countDown(); - startCdl.countDown(); - } catch (Exception ex) { - logger.log(Level.WARNING, serconf + " runServers error", ex); - Application.this.shutdownLatch.countDown(); - Utility.sleep(100); - System.exit(1); - } - } - }; - thread.start(); - } - startCdl.await(); - } - - private void stopServers() { - this.onServersPreStop(); - List localServers = new ArrayList<>(servers); // 顺序sncps, others, watchs - Collections.reverse(localServers); // 倒序, 必须让watchs先关闭,watch包含服务发现和注销逻辑 - localServers.stream().forEach(server -> { - try { - server.shutdown(); - } catch (Exception t) { - logger.log(Level.WARNING, " shutdown server(" + server.getSocketAddress() + ") error", t); - } finally { - shutdownLatch.countDown(); - } - }); - this.onServersPostStop(); - } - - // 使用了nohup或使用了后台&,Runtime.getRuntime().addShutdownHook失效 - private void signalShutdownHandle() { - Consumer> signalShutdownConsumer = Utility.signalShutdownConsumer(); - if (signalShutdownConsumer == null) { - return; - } - signalShutdownConsumer.accept(sig -> { - try { - long s = System.currentTimeMillis(); - logger.info(Application.this.getClass().getSimpleName() + " shutdowning " + sig); - shutdown(); - long e = System.currentTimeMillis() - s; - logger.info(Application.this.getClass().getSimpleName() + " shutdown in " + e + " ms"); - } catch (Exception ex) { - logger.log(Level.INFO, "Shutdown fail", ex); - } finally { - shutdownLatch.countDown(); - } - }); - } - - List getModuleEngines() { - return moduleEngines; - } - - public void loadClassByFilters(final ClassFilter... filters) throws IOException { - ClassFilter.Loader.load(getHome(), getClassLoader(), filters); - } - - public void loadServerClassFilters(final ClassFilter... filters) throws IOException { - ClassFilter.Loader.load(getHome(), getServerClassLoader(), filters); - } - - public DataSource loadDataSource(final String sourceName, boolean autoMemory) { - return sourceModule.loadDataSource(sourceName, autoMemory); - } - - public CacheSource loadCacheSource(final String sourceName, boolean autoMemory) { - return sourceModule.loadCacheSource(sourceName, autoMemory); - } - - public ExecutorService getWorkExecutor() { - return workExecutor; - } - - public boolean isVirtualWorkExecutor() { - // JDK21+ - return workExecutor != null && workExecutor.getClass().getSimpleName().contains("ThreadPerTaskExecutor"); - } - - public AsyncGroup getClientAsyncGroup() { - return clientAsyncGroup; - } - - public ResourceFactory getResourceFactory() { - return resourceFactory; - } - - public RedkaleClassLoader getClassLoader() { - return classLoader; - } - - public RedkaleClassLoader getServerClassLoader() { - return serverClassLoader; - } - - public List getNodeServers() { - return new ArrayList<>(servers); - } - - public SncpRpcGroups getSncpRpcGroups() { - return sncpRpcGroups; - } - - public String getNodeid() { - return nodeid; - } - - public String getName() { - return name; - } - - public File getHome() { - return home; - } - - public URI getConfDir() { - return confDir; - } - - public long getStartTime() { - return startTime; - } - - public Environment getEnvironment() { - return environment; - } - - public AnyValue getAppConfig() { - return config; - } - - public boolean isCompileMode() { - return compileMode; - } - - public boolean isSingletonMode() { - return singletonMode; - } -} +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.boot; + +import java.io.*; +import java.lang.reflect.*; +import java.net.*; +import java.net.http.HttpClient; +import java.nio.ByteBuffer; +import java.nio.channels.DatagramChannel; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.util.*; +import java.util.concurrent.*; +import java.util.concurrent.atomic.*; +import java.util.concurrent.locks.ReentrantLock; +import java.util.function.Consumer; +import java.util.logging.*; +import org.redkale.annotation.Nonnull; +import org.redkale.asm.AsmMethodBoost; +import org.redkale.boot.ClassFilter.FilterEntry; +import org.redkale.cache.spi.CacheModuleEngine; +import org.redkale.cluster.*; +import org.redkale.cluster.spi.ClusterAgent; +import org.redkale.cluster.spi.ClusterModuleEngine; +import org.redkale.cluster.spi.HttpClusterRpcClient; +import org.redkale.cluster.spi.HttpLocalRpcClient; +import org.redkale.convert.Convert; +import org.redkale.convert.bson.BsonFactory; +import org.redkale.convert.json.*; +import org.redkale.convert.proto.ProtobufFactory; +import org.redkale.inject.ResourceEvent; +import org.redkale.inject.ResourceFactory; +import org.redkale.inject.ResourceTypeLoader; +import org.redkale.lock.spi.LockModuleEngine; +import org.redkale.mq.spi.MessageAgent; +import org.redkale.mq.spi.MessageModuleEngine; +import org.redkale.net.*; +import org.redkale.net.http.*; +import org.redkale.net.sncp.*; +import org.redkale.props.spi.PropertiesModule; +import org.redkale.schedule.spi.ScheduleModuleEngine; +import org.redkale.service.Service; +import org.redkale.source.*; +import org.redkale.source.spi.SourceModuleEngine; +import org.redkale.util.*; +import org.redkale.watch.WatchServlet; + +/** + * 进程启动类,全局对象。
+ * + *
+ * 程序启动执行步骤:
+ *     1、读取application.xml
+ *     2、进行classpath扫描动态加载Service、WebSocket与Servlet
+ *     3、优先加载所有SNCP协议的服务,再加载其他协议服务, 最后加载WATCH协议的服务
+ *     4、最后进行Service、Servlet与其他资源之间的依赖注入
+ * 
+ * + *

详情见: https://redkale.org + * + * @author zhangjx + */ +public final class Application { + + /** 当前进程启动的时间, 类型: long */ + public static final String RESNAME_APP_TIME = "APP_TIME"; + + /** 当前进程服务的名称, 类型:String */ + public static final String RESNAME_APP_NAME = "APP_NAME"; + + /** 当前进程的根目录, 类型:String、File、Path、URI */ + public static final String RESNAME_APP_HOME = "APP_HOME"; + + /** + * 当前进程的配置目录URI,如果不是绝对路径则视为HOME目录下的相对路径 类型:String、URI、File、Path
+ * 若配置目录不是本地文件夹, 则File、Path类型的值为null + */ + public static final String RESNAME_APP_CONF_DIR = "APP_CONF_DIR"; + + /** 当前进程节点的nodeid, 类型:String */ + public static final String RESNAME_APP_NODEID = "APP_NODEID"; + + /** 当前进程节点的IP地址, 类型:InetSocketAddress、InetAddress、String */ + public static final String RESNAME_APP_ADDR = "APP_ADDR"; + + /** + * 当前进程的work线程池, 类型:Executor、ExecutorService + * + * @since 2.3.0 + */ + public static final String RESNAME_APP_EXECUTOR = "APP_EXECUTOR"; + + /** + * 使用RESNAME_APP_CLIENT_IOGROUP代替 + * + * @since 2.3.0 + */ + public static final String RESNAME_APP_CLIENT_ASYNCGROUP = "APP_CLIENT_ASYNCGROUP"; + + /** 当前Service所属的SNCP Server的地址 类型: SocketAddress、InetSocketAddress、String
*/ + public static final String RESNAME_SNCP_ADDRESS = "SNCP_ADDRESS"; + + /** 当前Service所属的SNCP Server所属的组 类型: String
*/ + public static final String RESNAME_SNCP_GROUP = "SNCP_GROUP"; + + /** "SERVER_ROOT" 当前Server的ROOT目录类型:String、File、Path */ + public static final String RESNAME_SERVER_ROOT = Server.RESNAME_SERVER_ROOT; + + /** 当前Server的ResourceFactory */ + public static final String RESNAME_SERVER_RESFACTORY = "SERVER_RESFACTORY"; + + public static final String SYSNAME_APP_NAME = "redkale.application.name"; + + public static final String SYSNAME_APP_NODEID = "redkale.application.nodeid"; + + public static final String SYSNAME_APP_HOME = "redkale.application.home"; + + public static final String SYSNAME_APP_CONF_DIR = "redkale.application.confdir"; + + public static final Set REDKALE_RESNAMES = Collections.unmodifiableSet(Set.of( + RESNAME_APP_NAME, + RESNAME_APP_NODEID, + RESNAME_APP_TIME, + RESNAME_APP_HOME, + RESNAME_APP_ADDR, + RESNAME_APP_CONF_DIR)); + + // UDP协议的ByteBuffer Capacity + private static final int UDP_CAPACITY = 1024; + + // 日志 + private final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); + + // 本进程节点ID + final String nodeid; + + // 本进程节点ID + final String name; + + // 本地IP地址 + final InetSocketAddress localAddress; + + // 配置信息,只读版Properties + private final Environment environment; + + // 全局根ResourceFactory + final ResourceFactory resourceFactory = ResourceFactory.create(); + + // NodeServer 资源, 顺序必须是sncps, others, watchs + final List servers = new CopyOnWriteArrayList<>(); + + // 配置项里的group信息, 注意: 只给SNCP使用 + private final SncpRpcGroups sncpRpcGroups = new SncpRpcGroups(); + + // 除logging配置之外的所有配置项,包含本地和远程配置项 + final Properties envProperties = new Properties(); + + // 业务逻辑线程池 + // @since 2.3.0 + @Nonnull + private ExecutorService workExecutor; + + // 给客户端使用,包含SNCP客户端、自定义数据库客户端连接池 + private AsyncIOGroup clientAsyncGroup; + + // 服务配置项 + final AnyValue config; + + // 是否启动了WATCH协议服务 + boolean watching; + + // ------------- 模块组件(必须靠后放,否则new Module时resourceFactory会为null) ------------- + // 日志组件 + // @since 2.8.0 + final LoggingModule loggingModule; + + // 配置组件 + final PropertiesModule propertiesModule; + + // 数据源组件 + private final SourceModuleEngine sourceModule; + + // ----------------------------------------------------------------------------------- + // 是否用于main方法运行 + private final boolean singletonMode; + + // 是否用于编译模式运行 + private final boolean compileMode; + + // 进程根目录 + private final File home; + + // 配置文件目录 + private final URI confDir; + + // 监听事件 + private final List listeners = new CopyOnWriteArrayList<>(); + + // 服务启动时间 + private final long startTime = System.currentTimeMillis(); + + // Server启动的计数器,用于确保所有Server都启动完后再进行下一步处理 + private final CountDownLatch shutdownLatch; + + // 根ClassLoader + private final RedkaleClassLoader classLoader; + + // Server根ClassLoader + private final RedkaleClassLoader serverClassLoader; + + // 系统模块组件 + private final List moduleEngines = new ArrayList<>(); + + /** + * 初始化步骤:
+ * 1、基本环境变量设置
+ * 2、ClassLoader初始化
+ * 3、日志配置初始化
+ * 4、本地和远程配置文件读取
+ * 5、ClusterAgent和MessageAgent实例化
+ * 6、Work线程池初始化 7、原生sql解析器初始化
+ * + * @param singletonMode 是否测试模式 + * @param compileMode 是否编译模式 + * @param config 启动配置 + */ + @SuppressWarnings("UseSpecificCatch") // config: 不带redkale.前缀的配置项 + Application(final AppConfig appConfig) { + this.singletonMode = appConfig.singletonMode; + this.compileMode = appConfig.compileMode; + this.config = appConfig.config; + this.envProperties.putAll(appConfig.localEnvProperties); + this.environment = new Environment(this.envProperties); + this.name = appConfig.name; + this.nodeid = appConfig.nodeid; + this.home = appConfig.home; + this.confDir = appConfig.confDir; + this.localAddress = appConfig.localAddress; + this.classLoader = appConfig.classLoader; + this.serverClassLoader = appConfig.serverClassLoader; + + this.loggingModule = new LoggingModule(this); + this.propertiesModule = new PropertiesModule(this); + this.sourceModule = new SourceModuleEngine(this); + + // 设置基础信息资源 + this.resourceFactory.register(RESNAME_APP_NAME, String.class, this.name); + + this.resourceFactory.register(RESNAME_APP_NODEID, String.class, this.nodeid); + if (Utility.isNumeric(this.nodeid)) { // 兼容旧类型 + this.resourceFactory.register( + RESNAME_APP_NODEID, int.class, Math.abs(((Long) Long.parseLong(this.nodeid)).intValue())); + } + + this.resourceFactory.register(RESNAME_APP_TIME, long.class, this.startTime); + this.resourceFactory.register(RESNAME_APP_TIME, Long.class, this.startTime); + + this.resourceFactory.register(RESNAME_APP_HOME, String.class, this.home.getPath()); + this.resourceFactory.register(RESNAME_APP_HOME, Path.class, this.home.toPath()); + this.resourceFactory.register(RESNAME_APP_HOME, File.class, this.home); + this.resourceFactory.register(RESNAME_APP_HOME, URI.class, this.home.toURI()); + + this.resourceFactory.register(RESNAME_APP_ADDR, InetSocketAddress.class, this.localAddress); + this.resourceFactory.register(RESNAME_APP_ADDR, InetAddress.class, this.localAddress.getAddress()); + this.resourceFactory.register( + RESNAME_APP_ADDR, String.class, this.localAddress.getAddress().getHostAddress()); + + this.resourceFactory.register(RESNAME_APP_CONF_DIR, URI.class, this.confDir); + this.resourceFactory.register(RESNAME_APP_CONF_DIR, File.class, appConfig.confFile); + this.resourceFactory.register(RESNAME_APP_CONF_DIR, String.class, this.confDir.toString()); + + System.setProperty("redkale.version", Redkale.getDotedVersion()); + System.setProperty(SYSNAME_APP_NAME, this.name); + System.setProperty(SYSNAME_APP_NODEID, String.valueOf(this.nodeid)); + System.setProperty(SYSNAME_APP_HOME, this.home.getPath()); + System.setProperty(SYSNAME_APP_CONF_DIR, this.confDir.toString()); + + this.envProperties.put(RESNAME_APP_NAME, this.name); + this.envProperties.put(RESNAME_APP_NODEID, String.valueOf(this.nodeid)); + this.envProperties.put(RESNAME_APP_TIME, String.valueOf(this.startTime)); + this.envProperties.put(RESNAME_APP_HOME, this.home.getPath()); + this.envProperties.put(RESNAME_APP_ADDR, this.localAddress.getAddress().getHostAddress()); + this.envProperties.put(RESNAME_APP_CONF_DIR, this.confDir.toString()); + + // 初始化本地配置的System.properties、mimetypes + this.registerResourceEnvs(true, appConfig.localEnvProperties); + + // 需要在加载properties初始化System.properties之后再注册 + this.resourceFactory.register(Environment.class, environment); + this.resourceFactory.register(BsonFactory.root()); + this.resourceFactory.register(JsonFactory.root()); + this.resourceFactory.register(ProtobufFactory.root()); + this.resourceFactory.register(BsonFactory.root().getConvert()); + this.resourceFactory.register(JsonFactory.root().getConvert()); + this.resourceFactory.register(ProtobufFactory.root().getConvert()); + this.resourceFactory.register( + "bsonconvert", Convert.class, BsonFactory.root().getConvert()); + this.resourceFactory.register( + "jsonconvert", Convert.class, JsonFactory.root().getConvert()); + this.resourceFactory.register( + "protobufconvert", Convert.class, ProtobufFactory.root().getConvert()); + + // 系统内部模块组件 + moduleEngines.add(this.sourceModule); // 放第一,很多module依赖于source + moduleEngines.add(new MessageModuleEngine(this)); + moduleEngines.add(new ClusterModuleEngine(this)); + moduleEngines.add(new ScheduleModuleEngine(this)); + moduleEngines.add(new CacheModuleEngine(this)); + moduleEngines.add(new LockModuleEngine(this)); + + // 根据本地日志配置文件初始化日志 + loggingModule.reconfigLogging(true, appConfig.locaLogProperties); + + // 打印基础信息日志 + logger.log( + Level.INFO, + colorMessage( + logger, + 36, + 1, + "-------------------------------- Redkale " + Redkale.getDotedVersion() + + " --------------------------------")); + + final String confDirStr = this.confDir.toString(); + logger.log( + Level.INFO, + "APP_OS = " + System.getProperty("os.name") + " " + + System.getProperty("os.version") + " " + System.getProperty("os.arch") + "\r\n" + + "APP_JAVA = " + + System.getProperty( + "java.runtime.name", + System.getProperty("org.graalvm.nativeimage.kind") != null ? "Nativeimage" : "") + + " " + + System.getProperty( + "java.runtime.version", + System.getProperty("java.vendor.version", System.getProperty("java.vm.version"))) + + "\r\n" // graalvm.nativeimage 模式下无 java.runtime.xxx 属性 + + "APP_PID = " + ProcessHandle.current().pid() + "\r\n" + + RESNAME_APP_NAME + " = " + this.name + "\r\n" + + RESNAME_APP_NODEID + " = " + this.nodeid + "\r\n" + + "APP_LOADER = " + this.classLoader.getClass().getSimpleName() + "\r\n" + + RESNAME_APP_ADDR + " = " + this.localAddress.getHostString() + ":" + + this.localAddress.getPort() + "\r\n" + + RESNAME_APP_HOME + " = " + this.home.getPath().replace('\\', '/') + "\r\n" + + RESNAME_APP_CONF_DIR + " = " + confDirStr.substring(confDirStr.indexOf('!') + 1)); + + if (!compileMode && !(classLoader instanceof RedkaleClassLoader.RedkaleCacheClassLoader)) { + String lib = environment.getPropertyValue( + config.getValue("lib", "${APP_HOME}/libs/*").trim()); + lib = Utility.isEmpty(lib) ? confDirStr : (lib + ";" + confDirStr); + Server.loadLib(classLoader, logger, lib.isEmpty() ? confDirStr : (lib + ";" + confDirStr)); + } + this.shutdownLatch = new CountDownLatch(config.getAnyValues("server").length + 1); + } + + public void init() throws Exception { + // 注册ResourceType + this.initResourceTypeLoader(); + // 读取远程配置,并合并app.config + this.propertiesModule.initRemoteProperties(); + // 解析配置 + this.onEnvironmentLoaded(); + // init起始回调 + this.onAppPreInit(); + // 设置WorkExecutor + this.initWorkExecutor(); + // 回调Listener + initAppListeners(); + // init结束回调 + this.onAppPostInit(); + } + + private void initResourceTypeLoader() { + final Application application = this; + // 只有WatchService才能加载Application、WatchFactory + this.resourceFactory.register(new ResourceTypeLoader() { + + @Override + public Object load( + ResourceFactory rf, + String srcResourceName, + Object srcObj, + String resourceName, + Field field, + Object attachment) { + try { + field.set(srcObj, application); + return application; + } catch (Exception e) { + logger.log(Level.SEVERE, "Resource inject error", e); + throw e instanceof RuntimeException ? (RuntimeException) e : new RedkaleException(e); + } + } + + @Override + public Type resourceType() { + return Application.class; + } + + @Override + public boolean autoNone() { + return false; + } + }); + this.resourceFactory.register(new ResourceTypeLoader() { + + @Override + public Object load( + ResourceFactory rf, + String srcResourceName, + Object srcObj, + String resourceName, + Field field, + Object attachment) { + try { + boolean serv = + RESNAME_SERVER_RESFACTORY.equals(resourceName) || resourceName.equalsIgnoreCase("server"); + ResourceFactory rs = serv ? rf : (resourceName.isEmpty() ? application.resourceFactory : null); + field.set(srcObj, rs); + return rs; + } catch (Exception e) { + logger.log(Level.SEVERE, "Resource inject error", e); + throw e instanceof RuntimeException ? (RuntimeException) e : new RedkaleException(e); + } + } + + @Override + public Type resourceType() { + return ResourceFactory.class; + } + + @Override + public boolean autoNone() { + return false; + } + }); + this.resourceFactory.register(new ResourceTypeLoader() { + + @Override + public Object load( + ResourceFactory rf, + String srcResourceName, + Object srcObj, + String resourceName, + Field field, + Object attachment) { + try { + NodeServer server = null; + for (NodeServer ns : application.getNodeServers()) { + if (ns.getClass() != NodeSncpServer.class) { + continue; + } + if (resourceName.equals(ns.server.getName())) { + server = ns; + break; + } + } + field.set(srcObj, server); + return server; + } catch (Exception e) { + logger.log(Level.SEVERE, "Resource inject error", e); + throw e instanceof RuntimeException ? (RuntimeException) e : new RedkaleException(e); + } + } + + @Override + public Type resourceType() { + return NodeSncpServer.class; + } + + @Override + public boolean autoNone() { + return false; + } + }); + this.resourceFactory.register(new ResourceTypeLoader() { + + @Override + public Object load( + ResourceFactory rf, + String srcResourceName, + Object srcObj, + String resourceName, + Field field, + Object attachment) { + try { + NodeServer server = null; + for (NodeServer ns : application.getNodeServers()) { + if (ns.getClass() != NodeHttpServer.class) { + continue; + } + if (resourceName.equals(ns.server.getName())) { + server = ns; + break; + } + } + field.set(srcObj, server); + return server; + } catch (Exception e) { + logger.log(Level.SEVERE, "Resource inject error", e); + throw e instanceof RuntimeException ? (RuntimeException) e : new RedkaleException(e); + } + } + + @Override + public Type resourceType() { + return NodeHttpServer.class; + } + + @Override + public boolean autoNone() { + return false; + } + }); + this.resourceFactory.register(new ResourceTypeLoader() { + + @Override + public Object load( + ResourceFactory rf, + String srcResourceName, + Object srcObj, + String resourceName, + Field field, + Object attachment) { + try { + NodeServer server = null; + for (NodeServer ns : application.getNodeServers()) { + if (ns.getClass() != NodeWatchServer.class) { + continue; + } + if (resourceName.equals(ns.server.getName())) { + server = ns; + break; + } + } + field.set(srcObj, server); + return server; + } catch (Exception e) { + logger.log(Level.SEVERE, "Resource inject error", e); + throw e instanceof RuntimeException ? (RuntimeException) e : new RedkaleException(e); + } + } + + @Override + public Type resourceType() { + return NodeWatchServer.class; + } + + @Override + public boolean autoNone() { + return false; + } + }); + + // ------------------------------------ 注册 java.net.http.HttpClient ------------------------------------ + resourceFactory.register(new ResourceTypeLoader() { + + @Override + public Object load( + ResourceFactory rf, + String srcResourceName, + Object srcObj, + String resourceName, + Field field, + Object attachment) { + try { + java.net.http.HttpClient.Builder builder = java.net.http.HttpClient.newBuilder(); + if (resourceName.endsWith(".1.1")) { + builder.version(HttpClient.Version.HTTP_1_1); + } else if (resourceName.endsWith(".2")) { + builder.version(HttpClient.Version.HTTP_2); + } + java.net.http.HttpClient httpClient = builder.build(); + field.set(srcObj, httpClient); + rf.inject(resourceName, httpClient, null); // 给其可能包含@Resource的字段赋值; + rf.register(resourceName, java.net.http.HttpClient.class, httpClient); + return httpClient; + } catch (Exception e) { + logger.log(Level.SEVERE, java.net.http.HttpClient.class.getSimpleName() + " inject error", e); + return null; + } + } + + @Override + public Type resourceType() { + return java.net.http.HttpClient.class; + } + }); + // ------------------------------------ 注册 WebClient ------------------------------------ + resourceFactory.register(new ResourceTypeLoader() { + + @Override + public Object load( + ResourceFactory rf, + String srcResourceName, + Object srcObj, + String resourceName, + Field field, + Object attachment) { + try { + WebClient httpClient = WebClient.create(workExecutor, clientAsyncGroup); + field.set(srcObj, httpClient); + rf.inject(resourceName, httpClient, null); // 给其可能包含@Resource的字段赋值; + rf.register(resourceName, WebClient.class, httpClient); + return httpClient; + } catch (Exception e) { + logger.log(Level.SEVERE, WebClient.class.getSimpleName() + " inject error", e); + throw e instanceof RuntimeException ? (RuntimeException) e : new RedkaleException(e); + } + } + + @Override + public Type resourceType() { + return WebClient.class; + } + }); + // ------------------------------------ 注册 HttpRpcClient ------------------------------------ + resourceFactory.register(new ResourceTypeLoader() { + + @Override + public Object load( + ResourceFactory rf, + String srcResourceName, + Object srcObj, + String resourceName, + Field field, + Object attachment) { + try { + ClusterAgent clusterAgent = resourceFactory.find("", ClusterAgent.class); + MessageAgent messageAgent = resourceFactory.find(resourceName, MessageAgent.class); + if (messageAgent != null) { + if (clusterAgent == null + || !Objects.equals(clusterAgent.getName(), resourceName) + || messageAgent.isRpcFirst()) { + HttpRpcClient rpcClient = messageAgent.getHttpRpcClient(); + field.set(srcObj, rpcClient); + rf.inject(resourceName, rpcClient, null); // 给其可能包含@Resource的字段赋值; + rf.register(resourceName, HttpRpcClient.class, rpcClient); + return rpcClient; + } + } + if (clusterAgent == null) { + HttpRpcClient rpcClient = new HttpLocalRpcClient(application, resourceName); + field.set(srcObj, rpcClient); + rf.inject(resourceName, rpcClient, null); // 给其可能包含@Resource的字段赋值; + rf.register(resourceName, HttpRpcClient.class, rpcClient); + return rpcClient; + } + HttpRpcClient rpcClient = new HttpClusterRpcClient(application, resourceName, clusterAgent); + field.set(srcObj, rpcClient); + rf.inject(resourceName, rpcClient, null); // 给其可能包含@Resource的字段赋值; + rf.register(resourceName, HttpRpcClient.class, rpcClient); + return rpcClient; + } catch (Exception e) { + logger.log(Level.SEVERE, HttpRpcClient.class.getSimpleName() + " inject error", e); + throw e instanceof RuntimeException ? (RuntimeException) e : new RedkaleException(e); + } + } + + @Override + public Type resourceType() { + return HttpRpcClient.class; + } + }); + } + + private void registerResourceEnvs(boolean first, Properties... envs) { + for (Properties props : envs) { + props.forEach((k, v) -> { + String val = environment.getPropertyValue(v.toString(), envs); + if (k.toString().startsWith("system.property.")) { + String key = k.toString().substring("system.property.".length()); + if (System.getProperty(key) == null || !first) { + System.setProperty(key, val); + } + resourceFactory.register(!first, k.toString(), val); + } else if (k.toString().startsWith("mimetype.property.")) { + MimeType.add(k.toString().substring("mimetype.property.".length()), val); + } else { + resourceFactory.register(!first, k.toString(), val); + } + }); + } + } + + /** 设置WorkExecutor */ + private void initWorkExecutor() { + int bufferCapacity = 32 * 1024; + int bufferPoolSize = Utility.cpus() * 8; + final AnyValue executorConf = config.getAnyValue("executor", true); + StringBuilder executorLog = new StringBuilder(); + + final int workThreads = Math.max(Utility.cpus(), executorConf.getIntValue("threads", Utility.cpus() * 10)); + // 指定threads则不使用虚拟线程池 + this.workExecutor = executorConf.getValue("threads") != null + ? WorkThread.createExecutor(workThreads, "Redkale-WorkThread-%s") + : WorkThread.createWorkExecutor(workThreads, "Redkale-WorkThread-%s"); + String executorName = this.workExecutor.getClass().getSimpleName(); + executorLog.append("defaultWorkExecutor: {type=").append(executorName); + if (executorName.contains("VirtualExecutor") || executorName.contains("PerTaskExecutor")) { + executorLog.append(", threads=[virtual]}"); + } else { + executorLog.append(", threads=").append(workThreads).append("}"); + } + + ExecutorService clientWorkExecutor = this.workExecutor; + if (executorName.contains("VirtualExecutor") || executorName.contains("PerTaskExecutor")) { + executorLog.append(", clientWorkExecutor: [workExecutor]"); + } else { + // 给所有client给一个新的默认ExecutorService + int clientThreads = executorConf.getIntValue("clients", Utility.cpus() * 4); + clientWorkExecutor = WorkThread.createWorkExecutor(clientThreads, "Redkale-DefaultClient-WorkThread-%s"); + executorLog.append(", threads=").append(clientThreads).append("}"); + } + AsyncIOGroup ioGroup = new AsyncIOGroup( + "Redkale-DefaultClient-IOThread-%s", clientWorkExecutor, bufferCapacity, bufferPoolSize) + .skipClose(true); + this.clientAsyncGroup = ioGroup.start(); + + if (executorLog.length() > 0) { + logger.log(Level.INFO, executorLog.toString()); + } + this.resourceFactory.register(RESNAME_APP_EXECUTOR, Executor.class, this.workExecutor); + this.resourceFactory.register(RESNAME_APP_EXECUTOR, ExecutorService.class, this.workExecutor); + this.resourceFactory.register(RESNAME_APP_CLIENT_ASYNCGROUP, AsyncGroup.class, this.clientAsyncGroup); + this.resourceFactory.register(RESNAME_APP_CLIENT_ASYNCGROUP, AsyncIOGroup.class, this.clientAsyncGroup); + } + + private void initAppListeners() throws Exception { + // ------------------------------------------------------------------------ + for (AnyValue conf : config.getAnyValues("group")) { + final String group = conf.getValue("name", ""); + if (group.indexOf('$') >= 0 || group.indexOf('.') >= 0) { + throw new RedkaleException(" name cannot contains '$', '.' in " + group); + } + final String protocol = conf.getValue("protocol", "TCP").toUpperCase(); + if (!"TCP".equalsIgnoreCase(protocol) && !"UDP".equalsIgnoreCase(protocol)) { + throw new RedkaleException("Not supported Transport Protocol " + conf.getValue("protocol")); + } + SncpRpcGroup rg = sncpRpcGroups.computeIfAbsent(group, protocol); + String nodes = conf.getValue("nodes"); + if (Utility.isNotEmpty(nodes)) { + for (String node : nodes.replace(',', ';').split(";")) { + if (Utility.isNotBlank(node)) { + int pos = node.indexOf(':'); + String addr = node.substring(0, pos).trim(); + int port = Integer.parseInt(node.substring(pos + 1).trim()); + rg.putAddress(new InetSocketAddress(addr, port)); + } + } + } + for (AnyValue node : conf.getAnyValues("node")) { + rg.putAddress(new InetSocketAddress(node.getValue("addr"), node.getIntValue("port"))); + } + } + for (AnyValue conf : config.getAnyValues("listener")) { + final String listenClass = conf.getValue("value", ""); + if (listenClass.isEmpty()) { + continue; + } + Class clazz = classLoader.loadClass(listenClass); + if (!ApplicationListener.class.isAssignableFrom(clazz)) { + continue; + } + RedkaleClassLoader.putReflectionDeclaredConstructors(clazz, clazz.getName()); + @SuppressWarnings("unchecked") + ApplicationListener listener = + (ApplicationListener) clazz.getDeclaredConstructor().newInstance(); + resourceFactory.inject(listener); + listener.init(config); + this.listeners.add(listener); + } + // ------------------------------------------------------------------------ + } + + private static String colorMessage(Logger logger, int color, int type, String msg) { + final boolean linux = + System.getProperty("os.name").toLowerCase(Locale.ENGLISH).contains("linux"); + if (linux) { // Windows PowerShell 也能正常着色 + boolean supported = true; + Logger l = logger; + do { + if (l.getHandlers() == null) { + break; + } + for (Handler handler : l.getHandlers()) { + if (!(handler instanceof ConsoleHandler)) { + supported = false; + break; + } + } + if (!supported) { + break; + } + } while ((l = l.getParent()) != null); + // colour 颜色代号:背景颜色代号(41-46);前景色代号(31-36) + // type 样式代号:0无;1加粗;3斜体;4下划线 + // String.format("\033[%d;%dm%s\033[0m", colour, type, content) + if (supported) { + msg = "\033[" + color + (type > 0 ? (";" + type) : "") + "m" + msg + "\033[0m"; + } + } + return msg; + } + + private void startSelfServer() throws Exception { + if (config.getValue("port", "").isEmpty() || "0".equals(config.getValue("port"))) { + return; // 没有配置port则不启动进程自身的监听 + } + final Application application = this; + new Thread() { + { + setName("Redkale-Application-SelfServer-Thread"); + } + + @Override + public void run() { + try { + DatagramChannel channel = DatagramChannel.open(); + channel.configureBlocking(true); + channel.socket().setSoTimeout(6000); // 单位:毫秒 + channel.bind(new InetSocketAddress("127.0.0.1", config.getIntValue("port"))); + if (!singletonMode) { + signalShutdownHandle(); + } + boolean loop = true; + final ByteBuffer buffer = ByteBuffer.allocateDirect(UDP_CAPACITY); + while (loop) { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + SocketAddress address = readUdpData(channel, buffer, out); + String[] args = + JsonConvert.root().convertFrom(String[].class, out.toString(StandardCharsets.UTF_8)); + final String cmd = args[0]; + String[] params = args.length == 1 ? new String[0] : Arrays.copyOfRange(args, 1, args.length); + // 接收到命令必须要有回应, 无结果输出则回应回车换行符 + if ("SHUTDOWN".equalsIgnoreCase(cmd)) { + try { + long s = System.currentTimeMillis(); + logger.info(application.getClass().getSimpleName() + " shutdowning"); + application.shutdown(); + sendUdpData( + channel, + address, + buffer, + "--- shutdown finish ---".getBytes(StandardCharsets.UTF_8)); + long e = System.currentTimeMillis() - s; + logger.info(application.getClass().getSimpleName() + " shutdown in " + e + " ms"); + channel.close(); + } catch (Exception ex) { + logger.log(Level.INFO, "Shutdown fail", ex); + sendUdpData(channel, address, buffer, "shutdown fail".getBytes(StandardCharsets.UTF_8)); + } finally { + loop = false; + application.shutdownLatch.countDown(); + } + } else if ("APIDOC".equalsIgnoreCase(cmd)) { + try { + String rs = new ApiDocCommand(application).command(cmd, params); + if (rs == null || rs.isEmpty()) { + rs = "\r\n"; + } + sendUdpData(channel, address, buffer, rs.getBytes(StandardCharsets.UTF_8)); + } catch (Exception ex) { + sendUdpData(channel, address, buffer, "apidoc fail".getBytes(StandardCharsets.UTF_8)); + } + } else { + long s = System.currentTimeMillis(); + logger.info(application.getClass().getSimpleName() + " command " + cmd); + List rs = application.command(cmd, params); + StringBuilder sb = new StringBuilder(); + if (rs != null) { + for (Object o : rs) { + if (o instanceof CharSequence) { + sb.append(o).append("\r\n"); + } else { + sb.append(JsonConvert.root().convertTo(o)) + .append("\r\n"); + } + } + } + if (sb.length() == 0) { + sb.append("\r\n"); + } + sendUdpData(channel, address, buffer, sb.toString().getBytes(StandardCharsets.UTF_8)); + long e = System.currentTimeMillis() - s; + logger.info(application.getClass().getSimpleName() + " command in " + e + " ms"); + } + } + } catch (Exception e) { + logger.log(Level.INFO, "Control fail", e); + Utility.sleep(100); + System.exit(1); + } + } + }.start(); + } + + // 数据包前4个字节为数据内容的长度 + private static void sendUdpData(final DatagramChannel channel, SocketAddress dest, ByteBuffer buffer, byte[] bytes) + throws IOException { + buffer.clear(); + int count = (bytes.length + 4) / UDP_CAPACITY + ((bytes.length + 4) % UDP_CAPACITY > 0 ? 1 : 0); + int start = 0; + for (int i = 0; i < count; i++) { + if (start == 0) { + buffer.putInt(bytes.length); + } + int len = Math.min(buffer.remaining(), bytes.length - start); + buffer.put(bytes, start, len); + buffer.flip(); + boolean first = true; + while (buffer.hasRemaining()) { + if (!first) { + Utility.sleep(10); + } + if (dest == null) { + channel.write(buffer); + } else { + channel.send(buffer, dest); + } + first = false; + } + start += len; + buffer.clear(); + } + } + + private static SocketAddress readUdpData( + final DatagramChannel channel, ByteBuffer buffer, ByteArrayOutputStream out) throws IOException { + out.reset(); + buffer.clear(); + SocketAddress src = null; + if (channel.isConnected()) { + channel.read(buffer); + while (buffer.position() < 4) channel.read(buffer); + } else { + src = channel.receive(buffer); + while (buffer.position() < 4) src = channel.receive(buffer); + } + buffer.flip(); + final int dataSize = buffer.getInt(); + while (buffer.hasRemaining()) { + out.write(buffer.get()); + } + while (out.size() < dataSize) { + buffer.clear(); + channel.receive(buffer); + buffer.flip(); + while (buffer.hasRemaining()) { + out.write(buffer.get()); + } + } + return src; + } + + private static void sendCommand(Logger logger, int port, String cmd, String[] params) throws Exception { + final DatagramChannel channel = DatagramChannel.open(); + channel.configureBlocking(true); + channel.socket().setSoTimeout(6000); // 单位:毫秒 + SocketAddress dest = new InetSocketAddress("127.0.0.1", port); + channel.connect(dest); + // 命令和参数合成一个数组 + String[] args = new String[1 + (params == null ? 0 : params.length)]; + args[0] = cmd; + if (params != null) { + System.arraycopy(params, 0, args, 1, params.length); + } + final ByteBuffer buffer = ByteBuffer.allocateDirect(UDP_CAPACITY); + try { + sendUdpData(channel, dest, buffer, JsonConvert.root().convertToBytes(args)); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + readUdpData(channel, buffer, out); + channel.close(); + String rs = out.toString(StandardCharsets.UTF_8).trim(); + if (logger != null) { + logger.info("Send: " + cmd + ", Reply: " + rs); + } + (System.out).println(rs); + } catch (Exception e) { + if (e instanceof PortUnreachableException) { + if ("APIDOC".equalsIgnoreCase(cmd)) { + final Application application = new Application(AppConfig.create(false, true)); + application.init(); + application.start(); + String rs = new ApiDocCommand(application).command(cmd, params); + application.shutdown(); + if (logger != null) { + logger.info(rs); + } + (System.out).println(rs); + return; + } + // if ("SHUTDOWN".equalsIgnoreCase(cmd)) { + // System.out .println("--- application not running ---"); + // } else { + (System.err).println("--- application not running ---"); + // } + return; + } + throw e; + } + } + + AsmMethodBoost createAsmMethodBoost(boolean remote, Class serviceClass) { + List list = null; + for (ModuleEngine item : moduleEngines) { + AsmMethodBoost boost = item.createAsmMethodBoost(remote, serviceClass); + if (boost != null) { + if (list == null) { + list = new ArrayList<>(); + } + list.add(boost); + } + } + if (list == null) { + return null; + } + return list.size() == 1 ? list.get(0) : AsmMethodBoost.create(remote, list); + } + + /** 进入Application.init方法时被调用 */ + private void onAppPreInit() { + for (ModuleEngine item : moduleEngines) { + item.onAppPreInit(); + } + } + + /** 结束Application.init方法前被调用 */ + private void onAppPostInit() { + for (ModuleEngine item : moduleEngines) { + item.onAppPostInit(); + } + } + + /** 进入Application.start方法被调用 */ + private void onAppPreStart() { + for (ApplicationListener listener : this.listeners) { + listener.onPreStart(this); + } + for (ModuleEngine item : moduleEngines) { + item.onAppPreStart(); + } + } + + /** 结束Application.start方法前被调用 */ + private void onAppPostStart() { + for (ApplicationListener listener : this.listeners) { + listener.onPostStart(this); + } + for (ModuleEngine item : moduleEngines) { + item.onAppPostStart(); + } + } + + /** + * 配置项加载后被调用 + * + * @param props 配置项全量 + */ + private void onEnvironmentLoaded() { + this.registerResourceEnvs(true, this.envProperties); + for (ModuleEngine item : moduleEngines) { + item.onEnvironmentLoaded(this.envProperties); + } + } + + /** + * 配置项变更时被调用 + * + * @param namespace 命名空间 + * @param events 变更项 + */ + void onEnvironmentChanged(String namespace, List events) { + for (ModuleEngine item : moduleEngines) { + item.onEnvironmentChanged(namespace, events); + } + } + + /** 服务全部启动前被调用 */ + private void onServersPreStart() { + for (ModuleEngine item : moduleEngines) { + item.onServersPreStart(); + } + } + + /** 服务全部启动后被调用 */ + private void onServersPostStart() { + for (ModuleEngine item : moduleEngines) { + item.onServersPostStart(); + } + } + + /** 执行Service.init方法前被调用 */ + void onServicePreInit(Service service) { + for (ModuleEngine item : moduleEngines) { + item.onServicePreInit(service); + } + } + + /** 执行Service.init方法后被调用 */ + void onServicePostInit(Service service) { + for (ModuleEngine item : moduleEngines) { + item.onServicePostInit(service); + } + } + + /** 执行Service.destroy方法前被调用 */ + void onServicePreDestroy(Service service) { + for (ModuleEngine item : moduleEngines) { + item.onServicePreDestroy(service); + } + } + + /** 执行Service.destroy方法后被调用 */ + void onServicePostDestroy(Service service) { + for (ModuleEngine item : moduleEngines) { + item.onServicePostDestroy(service); + } + } + + /** 服务全部停掉前被调用 */ + private void onServersPreStop() { + for (ApplicationListener listener : listeners) { + listener.onServersPreStop(this); + } + for (ModuleEngine item : moduleEngines) { + item.onServersPreStop(); + } + } + + /** 服务全部停掉后被调用 */ + private void onServersPostStop() { + for (ApplicationListener listener : listeners) { + listener.onServersPostStop(this); + } + for (ModuleEngine item : moduleEngines) { + item.onServersPostStop(); + } + } + + /** 进入Application.shutdown方法被调用 */ + private void onAppPreShutdown() { + for (ApplicationListener listener : this.listeners) { + try { + listener.onPreShutdown(this); + } catch (Exception e) { + logger.log(Level.WARNING, listener.getClass() + " preShutdown erroneous", e); + } + } + for (ModuleEngine item : moduleEngines) { + item.onAppPreShutdown(); + } + } + + /** 结束Application.shutdown方法前被调用 */ + private void onAppPostShutdown() { + for (ModuleEngine item : moduleEngines) { + item.onAppPostShutdown(); + } + } + + void onPreCompile() { + for (ApplicationListener listener : listeners) { + listener.onPreCompile(this); + } + for (ModuleEngine item : moduleEngines) { + item.onPreCompile(); + } + } + + void onPostCompile() { + for (ApplicationListener listener : listeners) { + listener.onPostCompile(this); + } + for (ModuleEngine item : moduleEngines) { + item.onPostCompile(); + } + } + + /** + * 启动 + * + * @throws Exception 异常 + */ + public void start() throws Exception { + this.onAppPreStart(); + final AnyValue[] entrys = config.getAnyValues("server"); + CountDownLatch serverCdl = new CountDownLatch(entrys.length); + final List sncps = new ArrayList<>(); + final List others = new ArrayList<>(); + final List watchs = new ArrayList<>(); + for (final AnyValue entry : entrys) { + if (entry.getValue("protocol", "").toUpperCase().startsWith("SNCP")) { + sncps.add(entry); + } else if (entry.getValue("protocol", "").toUpperCase().startsWith("WATCH")) { + watchs.add(entry); + } else { + others.add(entry); + } + } + if (watchs.size() > 1) { + throw new RedkaleException("Found one more WATCH Server"); + } + this.watching = !watchs.isEmpty(); + + this.onServersPreStart(); + runServers(serverCdl, sncps); // 必须确保SNCP服务都启动后再启动其他服务 + runServers(serverCdl, others); + runServers(serverCdl, watchs); // 必须在所有服务都启动后再启动WATCH服务 + serverCdl.await(); + this.onServersPostStart(); + + this.onAppPostStart(); + long intms = System.currentTimeMillis() - startTime; + String ms = String.valueOf(intms); + int repeat = ms.length() > 7 ? 0 : (7 - ms.length()) / 2; + logger.info(colorMessage( + logger, + 36, + 1, + "-".repeat(repeat) + "------------------------ Redkale started in " + ms + " ms " + + (ms.length() / 2 == 0 ? " " : "") + "-".repeat(repeat) + "------------------------") + + "\r\n"); + LoggingBaseHandler.traceEnable = true; + + if (!singletonMode && !compileMode) { + this.shutdownLatch.await(); + } + } + + /** + * 实例化单个Service + * + * @param 泛型 + * @param serviceClass 指定的service类 + * @param extServiceClasses 需要排除的service类 + * @return Service对象 + * @throws Exception 异常 + */ + public static T singleton(Class serviceClass, Class... extServiceClasses) + throws Exception { + return singleton("", serviceClass, extServiceClasses); + } + + /** + * 实例化单个Service + * + * @param 泛型 + * @param name Service的资源名 + * @param serviceClass 指定的service类 + * @param extServiceClasses 需要排除的service类 + * @return Service对象 + * @throws Exception 异常 + */ + public static T singleton( + String name, Class serviceClass, Class... extServiceClasses) throws Exception { + if (serviceClass == null) { + throw new IllegalArgumentException("serviceClass is null"); + } + final Application application = Application.create(true); + System.setProperty("redkale.singleton.serviceclass", serviceClass.getName()); + if (extServiceClasses != null && extServiceClasses.length > 0) { + StringBuilder sb = new StringBuilder(); + for (Class clazz : extServiceClasses) { + if (sb.length() > 0) { + sb.append(','); + } + sb.append(clazz.getName()); + } + System.setProperty("redkale.singleton.extserviceclasses", sb.toString()); + } + application.init(); + application.start(); + for (NodeServer server : application.servers) { + T service = server.resourceFactory.find(name, serviceClass); + if (service != null) { + return service; + } + } + if (Modifier.isAbstract(serviceClass.getModifiers())) { + throw new IllegalArgumentException("abstract class not allowed"); + } + if (serviceClass.isInterface()) { + throw new IllegalArgumentException("interface class not allowed"); + } + throw new IllegalArgumentException(serviceClass.getName() + " maybe have zero not-final public method"); + } + + public static Application create(final boolean singleton) throws IOException { + return new Application(AppConfig.create(singleton, false)); + } + + public static void main(String[] args) throws Exception { + Times.midnight(); // 先初始化一下Utility + Thread.currentThread().setName("Redkale-Application-Main-Thread"); + // 运行主程序 + String cmd = System.getProperty("cmd", System.getProperty("CMD")); + String[] params = args; + if (args != null && args.length > 0) { + for (int i = 0; i < args.length; i++) { + if (args[i] != null && args[i].toLowerCase().startsWith("--conf-file=")) { + System.setProperty(AppConfig.PARAM_APP_CONF_FILE, args[i].substring("--conf-file=".length())); + String[] newargs = new String[args.length - 1]; + System.arraycopy(args, 0, newargs, 0, i); + System.arraycopy(args, i + 1, newargs, i, args.length - 1 - i); + args = newargs; + break; + } + } + if (cmd == null) { + for (int i = 0; i < args.length; i++) { + if (args[i] != null && !args[i].startsWith("-")) { // 非-开头的第一个视为命令号 + cmd = args[i]; + if ("start".equalsIgnoreCase(cmd) || "startup".equalsIgnoreCase(cmd)) { + cmd = null; + } + params = new String[args.length - 1]; + System.arraycopy(args, 0, params, 0, i); + System.arraycopy(args, i + 1, params, i, args.length - 1 - i); + break; + } + } + } + if (cmd == null) { + if (args.length == 1 && ("--help".equalsIgnoreCase(args[0]) || "-h".equalsIgnoreCase(args[0]))) { + cmd = args[0]; + } + } + } + if (cmd != null) { + if ("stop".equalsIgnoreCase(cmd)) { + cmd = "shutdown"; + } + if ("help".equalsIgnoreCase(cmd) || "--help".equalsIgnoreCase(cmd) || "-h".equalsIgnoreCase(cmd)) { + (System.out).println(generateHelp()); + return; + } + boolean restart = "restart".equalsIgnoreCase(cmd); + AnyValue config = AppConfig.loadAppConfig(); + Application.sendCommand(null, config.getIntValue("port"), restart ? "SHUTDOWN" : cmd, params); + if (!restart) { + return; + } + } + + // PrepareCompiler.main(args); //测试代码 + final Application application = Application.create(false); + application.init(); + application.startSelfServer(); + try { + application.start(); + } catch (Exception e) { + application.logger.log(Level.SEVERE, "Application start error", e); + Utility.sleep(100); + System.exit(1); + } + System.exit(0); // 必须要有 + } + + public List command(String cmd, String[] params) { + List localServers = new ArrayList<>(servers); // 顺序sncps, others, watchs + List results = new ArrayList<>(); + localServers.stream().forEach((server) -> { + try { + List rs = server.command(cmd, params); + if (rs != null) { + results.addAll(rs); + } + } catch (Exception t) { + logger.log(Level.WARNING, " command server(" + server.getSocketAddress() + ") error", t); + } + }); + return results; + } + + public void shutdown() throws Exception { + long f = System.currentTimeMillis(); + this.onAppPreShutdown(); + stopServers(); + this.propertiesModule.destroy(); + if (this.workExecutor != null) { + this.workExecutor.shutdownNow(); + } + if (this.clientAsyncGroup != null) { + long s = System.currentTimeMillis(); + this.clientAsyncGroup.dispose(); + logger.info("AsyncGroup destroy in " + (System.currentTimeMillis() - s) + " ms"); + } + this.onAppPostShutdown(); + + long intms = System.currentTimeMillis() - f; + String ms = String.valueOf(intms); + int repeat = ms.length() > 7 ? 0 : (7 - ms.length()) / 2; + logger.info(colorMessage( + logger, + 36, + 1, + "-".repeat(repeat) + "------------------------ Redkale shutdown in " + ms + " ms " + + (ms.length() / 2 == 0 ? " " : "") + "-".repeat(repeat) + "------------------------") + + "\r\n" + "\r\n"); + LoggingBaseHandler.traceEnable = true; + } + + private static String generateHelp() { + return "" + + "Usage: redkale [command] [arguments]\r\n" + + "Command: \r\n" + + " start, startup start one process\r\n" + + " --conf-file=[file] application config file, eg. application.xml、application.properties\r\n" + + " shutdown, stop shutdown one process\r\n" + + " --conf-file=[file] application config file, eg. application.xml、application.properties\r\n" + + " restart restart one process\r\n" + + " --conf-file=[file] application config file, eg. application.xml、application.properties\r\n" + + " apidoc generate apidoc\r\n" + + " --api-skiprpc=[true|false] skip @RestService(rpcOnly=true) service or @RestMapping(rpcOnly=true) method, default is true\r\n" + + " --api-host=[url] api root url, default is http://localhost\r\n" + + " help, -h, --help show this help\r\n"; + } + + @SuppressWarnings("unchecked") + private void runServers(CountDownLatch serverCdl, final List serverConfs) throws Exception { + CountDownLatch serviceCdl = new CountDownLatch(serverConfs.size()); + CountDownLatch startCdl = new CountDownLatch(serverConfs.size()); + final AtomicBoolean inited = new AtomicBoolean(false); + final ReentrantLock nodeLock = new ReentrantLock(); + final Map> nodeClasses = new HashMap<>(); + for (final AnyValue serconf : serverConfs) { + Thread thread = new Thread() { + { + setName("Redkale-" + + serconf.getValue("protocol", "Server") + .toUpperCase() + .replaceFirst("\\..+", "") + ":" + serconf.getIntValue("port") + "-Thread"); + this.setDaemon(true); + } + + @Override + public void run() { + try { + // Thread ctd = Thread.currentThread(); + // ctd.setContextClassLoader(new URLClassLoader(new URL[0], ctd.getContextClassLoader())); + final String protocol = serconf.getValue("protocol", "") + .replaceFirst("\\..+", "") + .toUpperCase(); + NodeServer server = null; + if ("SNCP".equals(protocol)) { + server = NodeSncpServer.createNodeServer(Application.this, serconf); + } else if ("WATCH".equalsIgnoreCase(protocol)) { + AnyValueWriter serconf2 = (AnyValueWriter) serconf; + AnyValueWriter rest = (AnyValueWriter) serconf2.getAnyValue("rest"); + if (rest == null) { + rest = new AnyValueWriter(); + serconf2.addValue("rest", rest); + } + rest.setValue("base", WatchServlet.class.getName()); + server = new NodeWatchServer(Application.this, serconf); + } else if ("HTTP".equalsIgnoreCase(protocol)) { + server = new NodeHttpServer(Application.this, serconf); + } else { + if (!inited.get()) { + nodeLock.lock(); + try { + if (!inited.getAndSet(true)) { // 加载自定义的协议,如:SOCKS + ClassFilter profilter = + new ClassFilter(classLoader, NodeProtocol.class, NodeServer.class); + loadClassByFilters(profilter); + final Set> entrys = profilter.getFilterEntrys(); + for (FilterEntry entry : entrys) { + final Class type = entry.getType(); + NodeProtocol pros = type.getAnnotation(NodeProtocol.class); + String p = pros.value().toUpperCase(); + if ("SNCP".equals(p) || "HTTP".equals(p)) { + continue; + } + final Class old = nodeClasses.get(p); + if (old != null && old != type) { + throw new RedkaleException("Protocol(" + p + ") had NodeServer-Class(" + + old.getName() + ") but repeat NodeServer-Class(" + + type.getName() + ")"); + } + nodeClasses.put(p, type); + } + } + } finally { + nodeLock.unlock(); + } + } + Class nodeClass = nodeClasses.get(protocol); + if (nodeClass != null) { + server = NodeServer.create(nodeClass, Application.this, serconf); + } + } + if (server == null) { + logger.log( + Level.SEVERE, + "Not found Server Class for protocol({0})", + serconf.getValue("protocol")); + Utility.sleep(100); + System.exit(1); + } + server.serviceCdl = serviceCdl; + server.init(serconf); + if (!singletonMode && !compileMode) { + server.start(); + } else if (compileMode) { + server.getServer() + .getDispatcherServlet() + .init(server.getServer().getContext(), serconf); + } + servers.add(server); + serverCdl.countDown(); + startCdl.countDown(); + } catch (Exception ex) { + logger.log(Level.WARNING, serconf + " runServers error", ex); + Application.this.shutdownLatch.countDown(); + Utility.sleep(100); + System.exit(1); + } + } + }; + thread.start(); + } + startCdl.await(); + } + + private void stopServers() { + this.onServersPreStop(); + List localServers = new ArrayList<>(servers); // 顺序sncps, others, watchs + Collections.reverse(localServers); // 倒序, 必须让watchs先关闭,watch包含服务发现和注销逻辑 + localServers.stream().forEach(server -> { + try { + server.shutdown(); + } catch (Exception t) { + logger.log(Level.WARNING, " shutdown server(" + server.getSocketAddress() + ") error", t); + } finally { + shutdownLatch.countDown(); + } + }); + this.onServersPostStop(); + } + + // 使用了nohup或使用了后台&,Runtime.getRuntime().addShutdownHook失效 + private void signalShutdownHandle() { + Consumer> signalShutdownConsumer = Utility.signalShutdownConsumer(); + if (signalShutdownConsumer == null) { + return; + } + signalShutdownConsumer.accept(sig -> { + try { + long s = System.currentTimeMillis(); + logger.info(Application.this.getClass().getSimpleName() + " shutdowning " + sig); + shutdown(); + long e = System.currentTimeMillis() - s; + logger.info(Application.this.getClass().getSimpleName() + " shutdown in " + e + " ms"); + } catch (Exception ex) { + logger.log(Level.INFO, "Shutdown fail", ex); + } finally { + shutdownLatch.countDown(); + } + }); + } + + List getModuleEngines() { + return moduleEngines; + } + + public void loadClassByFilters(final ClassFilter... filters) throws IOException { + ClassFilter.Loader.load(getHome(), getClassLoader(), filters); + } + + public void loadServerClassFilters(final ClassFilter... filters) throws IOException { + ClassFilter.Loader.load(getHome(), getServerClassLoader(), filters); + } + + public DataSource loadDataSource(final String sourceName, boolean autoMemory) { + return sourceModule.loadDataSource(sourceName, autoMemory); + } + + public CacheSource loadCacheSource(final String sourceName, boolean autoMemory) { + return sourceModule.loadCacheSource(sourceName, autoMemory); + } + + public ExecutorService getWorkExecutor() { + return workExecutor; + } + + public boolean isVirtualWorkExecutor() { + // JDK21+ + return workExecutor != null && workExecutor.getClass().getSimpleName().contains("ThreadPerTaskExecutor"); + } + + public AsyncGroup getClientAsyncGroup() { + return clientAsyncGroup; + } + + public ResourceFactory getResourceFactory() { + return resourceFactory; + } + + public RedkaleClassLoader getClassLoader() { + return classLoader; + } + + public RedkaleClassLoader getServerClassLoader() { + return serverClassLoader; + } + + public List getNodeServers() { + return new ArrayList<>(servers); + } + + public SncpRpcGroups getSncpRpcGroups() { + return sncpRpcGroups; + } + + public String getNodeid() { + return nodeid; + } + + public String getName() { + return name; + } + + public File getHome() { + return home; + } + + public URI getConfDir() { + return confDir; + } + + public long getStartTime() { + return startTime; + } + + public Environment getEnvironment() { + return environment; + } + + public AnyValue getAppConfig() { + return config; + } + + public boolean isCompileMode() { + return compileMode; + } + + public boolean isSingletonMode() { + return singletonMode; + } +} diff --git a/src/main/java/org/redkale/boot/BootModule.java b/src/main/java/org/redkale/boot/BootModule.java index 45a8ee247..68288f7d0 100644 --- a/src/main/java/org/redkale/boot/BootModule.java +++ b/src/main/java/org/redkale/boot/BootModule.java @@ -1,52 +1,52 @@ -/* - * - */ -package org.redkale.boot; - -import java.util.List; -import java.util.Objects; -import java.util.Properties; -import org.redkale.inject.ResourceEvent; -import org.redkale.inject.ResourceFactory; -import org.redkale.util.Environment; - -/** @author zhangjx */ -public abstract class BootModule { - - protected final Application application; - - protected final ResourceFactory resourceFactory; - - protected final Environment environment; - - protected BootModule(Application application) { - this.application = application; - this.resourceFactory = Objects.requireNonNull(application.resourceFactory); - this.environment = Objects.requireNonNull(application.getEnvironment()); - } - - protected void removeEnvValue(String name) { - application.envProperties.remove(name); - } - - protected void putEnvValue(Object name, Object value) { - application.envProperties.put(name, value); - } - - protected List getModuleEngines() { - return application.getModuleEngines(); - } - - protected void reconfigLogging(boolean first, Properties allProps) { - application.loggingModule.reconfigLogging(first, allProps); - } - - protected void onEnvironmentChanged(String namespace, List events) { - if (namespace != null && namespace.contains("logging")) { - // 日志配置单独处理 - application.loggingModule.onEnvironmentUpdated(events); - } else { - application.onEnvironmentChanged(namespace, events); - } - } -} +/* + * + */ +package org.redkale.boot; + +import java.util.List; +import java.util.Objects; +import java.util.Properties; +import org.redkale.inject.ResourceEvent; +import org.redkale.inject.ResourceFactory; +import org.redkale.util.Environment; + +/** @author zhangjx */ +public abstract class BootModule { + + protected final Application application; + + protected final ResourceFactory resourceFactory; + + protected final Environment environment; + + protected BootModule(Application application) { + this.application = application; + this.resourceFactory = Objects.requireNonNull(application.resourceFactory); + this.environment = Objects.requireNonNull(application.getEnvironment()); + } + + protected void removeEnvValue(String name) { + application.envProperties.remove(name); + } + + protected void putEnvValue(Object name, Object value) { + application.envProperties.put(name, value); + } + + protected List getModuleEngines() { + return application.getModuleEngines(); + } + + protected void reconfigLogging(boolean first, Properties allProps) { + application.loggingModule.reconfigLogging(first, allProps); + } + + protected void onEnvironmentChanged(String namespace, List events) { + if (namespace != null && namespace.contains("logging")) { + // 日志配置单独处理 + application.loggingModule.onEnvironmentUpdated(events); + } else { + application.onEnvironmentChanged(namespace, events); + } + } +} diff --git a/src/main/java/org/redkale/boot/LoggingModule.java b/src/main/java/org/redkale/boot/LoggingModule.java index 2660a7371..3e5dd9ce2 100644 --- a/src/main/java/org/redkale/boot/LoggingModule.java +++ b/src/main/java/org/redkale/boot/LoggingModule.java @@ -1,192 +1,192 @@ -/* - * - */ -package org.redkale.boot; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.PrintStream; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.Set; -import java.util.logging.Handler; -import java.util.logging.LogManager; -import java.util.logging.SimpleFormatter; -import org.redkale.inject.ResourceEvent; -import org.redkale.net.sncp.SncpClient; -import org.redkale.util.Environment; - -/** - * 日志模块组件 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -class LoggingModule extends BootModule { - - // 日志配置资源 - private final Properties loggingProperties = new Properties(); - - LoggingModule(Application application) { - super(application); - } - - /** - * 配置变更 - * - * @param events 变更项 - */ - public void onEnvironmentUpdated(List events) { - Set loggingRemovedKeys = new HashSet<>(); - Properties loggingChangedProps = new Properties(); - for (ResourceEvent event : events) { - if (event.newValue() == null) { - if (loggingProperties.containsKey(event.name())) { - loggingRemovedKeys.add(event.name()); - } - } else { - loggingChangedProps.put(event.name(), event.newValue()); - } - } - if (!loggingRemovedKeys.isEmpty() || !loggingChangedProps.isEmpty()) { - Properties newProps = new Properties(this.loggingProperties); - loggingRemovedKeys.forEach(newProps::remove); - newProps.putAll(loggingChangedProps); - reconfigLogging(false, newProps); - } - } - - /** - * 设置日志策略 - * - * @param first 是否首次设置 - * @param allProps 配置项全量 - */ - public void reconfigLogging(boolean first, Properties allProps) { - String searchRawHandler = "java.util.logging.SearchHandler"; - String searchReadHandler = LoggingSearchHandler.class.getName(); - Properties onlyLogProps = new Properties(); - Environment envs = this.environment; - allProps.entrySet().forEach(x -> { - String key = x.getKey().toString(); - if (key.startsWith("java.util.logging.") || key.contains(".level") || key.equals("handlers")) { - String val = envs.getPropertyValue(x.getValue() - .toString() - .replace("%m", "%tY%tm") - .replace("%d", "%tY%tm%td") // 兼容旧时间格式 - .replace(searchRawHandler, searchReadHandler)); - onlyLogProps.put(key.replace(searchRawHandler, searchReadHandler), val); - } - }); - if (onlyLogProps.getProperty("java.util.logging.FileHandler.formatter") == null) { - if (application.isCompileMode()) { - onlyLogProps.setProperty("java.util.logging.FileHandler.formatter", SimpleFormatter.class.getName()); - if (onlyLogProps.getProperty("java.util.logging.SimpleFormatter.format") == null) { - onlyLogProps.setProperty( - "java.util.logging.SimpleFormatter.format", - LoggingFileHandler.FORMATTER_FORMAT.replaceAll("\r\n", "%n")); - } - } else { - onlyLogProps.setProperty( - "java.util.logging.FileHandler.formatter", LoggingFileHandler.LoggingFormater.class.getName()); - } - } - if (onlyLogProps.getProperty("java.util.logging.ConsoleHandler.formatter") == null) { - if (application.isCompileMode()) { - onlyLogProps.setProperty("java.util.logging.ConsoleHandler.formatter", SimpleFormatter.class.getName()); - if (onlyLogProps.getProperty("java.util.logging.SimpleFormatter.format") == null) { - onlyLogProps.setProperty( - "java.util.logging.SimpleFormatter.format", - LoggingFileHandler.FORMATTER_FORMAT.replaceAll("\r\n", "%n")); - } - } else { - onlyLogProps.setProperty( - "java.util.logging.ConsoleHandler.formatter", - LoggingFileHandler.LoggingFormater.class.getName()); - } - } - if (!application.isCompileMode()) { // ConsoleHandler替换成LoggingConsoleHandler - final String handlers = onlyLogProps.getProperty("handlers"); - if (handlers != null && handlers.contains("java.util.logging.ConsoleHandler")) { - final String consoleHandlerClass = LoggingFileHandler.LoggingConsoleHandler.class.getName(); - onlyLogProps.setProperty( - "handlers", handlers.replace("java.util.logging.ConsoleHandler", consoleHandlerClass)); - Properties prop = new Properties(); - String prefix = consoleHandlerClass + "."; - onlyLogProps.entrySet().forEach(x -> { - if (x.getKey().toString().startsWith("java.util.logging.ConsoleHandler.")) { - prop.put( - x.getKey().toString().replace("java.util.logging.ConsoleHandler.", prefix), - x.getValue()); - } - }); - prop.entrySet().forEach(x -> { - onlyLogProps.put(x.getKey(), x.getValue()); - }); - } - } - String fileHandlerPattern = onlyLogProps.getProperty("java.util.logging.FileHandler.pattern"); - if (fileHandlerPattern != null && fileHandlerPattern.contains("%")) { // 带日期格式 - final String fileHandlerClass = LoggingFileHandler.class.getName(); - Properties prop = new Properties(); - final String handlers = onlyLogProps.getProperty("handlers"); - if (handlers != null && handlers.contains("java.util.logging.FileHandler")) { - // singletonrun模式下不输出文件日志 - prop.setProperty( - "handlers", - handlers.replace( - "java.util.logging.FileHandler", - application.isSingletonMode() || application.isCompileMode() ? "" : fileHandlerClass)); - } - if (!prop.isEmpty()) { - String prefix = fileHandlerClass + "."; - onlyLogProps.entrySet().forEach(x -> { - if (x.getKey().toString().startsWith("java.util.logging.FileHandler.")) { - prop.put(x.getKey().toString().replace("java.util.logging.FileHandler.", prefix), x.getValue()); - } - }); - prop.entrySet().forEach(x -> onlyLogProps.put(x.getKey(), x.getValue())); - } - if (!application.isCompileMode()) { - onlyLogProps.put( - SncpClient.class.getSimpleName() + ".handlers", - LoggingFileHandler.LoggingSncpFileHandler.class.getName()); - } - } - if (application.isCompileMode()) { - onlyLogProps.put("handlers", "java.util.logging.ConsoleHandler"); - Map newprop = new HashMap(onlyLogProps); - newprop.forEach((k, v) -> { - if (k.toString().startsWith("java.util.logging.FileHandler.")) { - onlyLogProps.remove(k); - } - }); - } - - ByteArrayOutputStream out = new ByteArrayOutputStream(); - final PrintStream ps = new PrintStream(out); - onlyLogProps.forEach((x, y) -> ps.println(x + "=" + y)); - try { - LogManager manager = LogManager.getLogManager(); - manager.readConfiguration(new ByteArrayInputStream(out.toByteArray())); - this.loggingProperties.clear(); - this.loggingProperties.putAll(onlyLogProps); - Enumeration en = manager.getLoggerNames(); - while (en.hasMoreElements()) { - for (Handler handler : manager.getLogger(en.nextElement()).getHandlers()) { - if (handler instanceof LoggingSearchHandler) { - ((LoggingSearchHandler) handler).application = application; - } - } - } - } catch (IOException e) { // 不会发生 - } - } -} +/* + * + */ +package org.redkale.boot; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.logging.Handler; +import java.util.logging.LogManager; +import java.util.logging.SimpleFormatter; +import org.redkale.inject.ResourceEvent; +import org.redkale.net.sncp.SncpClient; +import org.redkale.util.Environment; + +/** + * 日志模块组件 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +class LoggingModule extends BootModule { + + // 日志配置资源 + private final Properties loggingProperties = new Properties(); + + LoggingModule(Application application) { + super(application); + } + + /** + * 配置变更 + * + * @param events 变更项 + */ + public void onEnvironmentUpdated(List events) { + Set loggingRemovedKeys = new HashSet<>(); + Properties loggingChangedProps = new Properties(); + for (ResourceEvent event : events) { + if (event.newValue() == null) { + if (loggingProperties.containsKey(event.name())) { + loggingRemovedKeys.add(event.name()); + } + } else { + loggingChangedProps.put(event.name(), event.newValue()); + } + } + if (!loggingRemovedKeys.isEmpty() || !loggingChangedProps.isEmpty()) { + Properties newProps = new Properties(this.loggingProperties); + loggingRemovedKeys.forEach(newProps::remove); + newProps.putAll(loggingChangedProps); + reconfigLogging(false, newProps); + } + } + + /** + * 设置日志策略 + * + * @param first 是否首次设置 + * @param allProps 配置项全量 + */ + public void reconfigLogging(boolean first, Properties allProps) { + String searchRawHandler = "java.util.logging.SearchHandler"; + String searchReadHandler = LoggingSearchHandler.class.getName(); + Properties onlyLogProps = new Properties(); + Environment envs = this.environment; + allProps.entrySet().forEach(x -> { + String key = x.getKey().toString(); + if (key.startsWith("java.util.logging.") || key.contains(".level") || key.equals("handlers")) { + String val = envs.getPropertyValue(x.getValue() + .toString() + .replace("%m", "%tY%tm") + .replace("%d", "%tY%tm%td") // 兼容旧时间格式 + .replace(searchRawHandler, searchReadHandler)); + onlyLogProps.put(key.replace(searchRawHandler, searchReadHandler), val); + } + }); + if (onlyLogProps.getProperty("java.util.logging.FileHandler.formatter") == null) { + if (application.isCompileMode()) { + onlyLogProps.setProperty("java.util.logging.FileHandler.formatter", SimpleFormatter.class.getName()); + if (onlyLogProps.getProperty("java.util.logging.SimpleFormatter.format") == null) { + onlyLogProps.setProperty( + "java.util.logging.SimpleFormatter.format", + LoggingFileHandler.FORMATTER_FORMAT.replaceAll("\r\n", "%n")); + } + } else { + onlyLogProps.setProperty( + "java.util.logging.FileHandler.formatter", LoggingFileHandler.LoggingFormater.class.getName()); + } + } + if (onlyLogProps.getProperty("java.util.logging.ConsoleHandler.formatter") == null) { + if (application.isCompileMode()) { + onlyLogProps.setProperty("java.util.logging.ConsoleHandler.formatter", SimpleFormatter.class.getName()); + if (onlyLogProps.getProperty("java.util.logging.SimpleFormatter.format") == null) { + onlyLogProps.setProperty( + "java.util.logging.SimpleFormatter.format", + LoggingFileHandler.FORMATTER_FORMAT.replaceAll("\r\n", "%n")); + } + } else { + onlyLogProps.setProperty( + "java.util.logging.ConsoleHandler.formatter", + LoggingFileHandler.LoggingFormater.class.getName()); + } + } + if (!application.isCompileMode()) { // ConsoleHandler替换成LoggingConsoleHandler + final String handlers = onlyLogProps.getProperty("handlers"); + if (handlers != null && handlers.contains("java.util.logging.ConsoleHandler")) { + final String consoleHandlerClass = LoggingFileHandler.LoggingConsoleHandler.class.getName(); + onlyLogProps.setProperty( + "handlers", handlers.replace("java.util.logging.ConsoleHandler", consoleHandlerClass)); + Properties prop = new Properties(); + String prefix = consoleHandlerClass + "."; + onlyLogProps.entrySet().forEach(x -> { + if (x.getKey().toString().startsWith("java.util.logging.ConsoleHandler.")) { + prop.put( + x.getKey().toString().replace("java.util.logging.ConsoleHandler.", prefix), + x.getValue()); + } + }); + prop.entrySet().forEach(x -> { + onlyLogProps.put(x.getKey(), x.getValue()); + }); + } + } + String fileHandlerPattern = onlyLogProps.getProperty("java.util.logging.FileHandler.pattern"); + if (fileHandlerPattern != null && fileHandlerPattern.contains("%")) { // 带日期格式 + final String fileHandlerClass = LoggingFileHandler.class.getName(); + Properties prop = new Properties(); + final String handlers = onlyLogProps.getProperty("handlers"); + if (handlers != null && handlers.contains("java.util.logging.FileHandler")) { + // singletonrun模式下不输出文件日志 + prop.setProperty( + "handlers", + handlers.replace( + "java.util.logging.FileHandler", + application.isSingletonMode() || application.isCompileMode() ? "" : fileHandlerClass)); + } + if (!prop.isEmpty()) { + String prefix = fileHandlerClass + "."; + onlyLogProps.entrySet().forEach(x -> { + if (x.getKey().toString().startsWith("java.util.logging.FileHandler.")) { + prop.put(x.getKey().toString().replace("java.util.logging.FileHandler.", prefix), x.getValue()); + } + }); + prop.entrySet().forEach(x -> onlyLogProps.put(x.getKey(), x.getValue())); + } + if (!application.isCompileMode()) { + onlyLogProps.put( + SncpClient.class.getSimpleName() + ".handlers", + LoggingFileHandler.LoggingSncpFileHandler.class.getName()); + } + } + if (application.isCompileMode()) { + onlyLogProps.put("handlers", "java.util.logging.ConsoleHandler"); + Map newprop = new HashMap(onlyLogProps); + newprop.forEach((k, v) -> { + if (k.toString().startsWith("java.util.logging.FileHandler.")) { + onlyLogProps.remove(k); + } + }); + } + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + final PrintStream ps = new PrintStream(out); + onlyLogProps.forEach((x, y) -> ps.println(x + "=" + y)); + try { + LogManager manager = LogManager.getLogManager(); + manager.readConfiguration(new ByteArrayInputStream(out.toByteArray())); + this.loggingProperties.clear(); + this.loggingProperties.putAll(onlyLogProps); + Enumeration en = manager.getLoggerNames(); + while (en.hasMoreElements()) { + for (Handler handler : manager.getLogger(en.nextElement()).getHandlers()) { + if (handler instanceof LoggingSearchHandler) { + ((LoggingSearchHandler) handler).application = application; + } + } + } + } catch (IOException e) { // 不会发生 + } + } +} diff --git a/src/main/java/org/redkale/boot/ModuleEngine.java b/src/main/java/org/redkale/boot/ModuleEngine.java index cd0fb2ee0..72802a46d 100644 --- a/src/main/java/org/redkale/boot/ModuleEngine.java +++ b/src/main/java/org/redkale/boot/ModuleEngine.java @@ -1,179 +1,179 @@ -/* - * - */ -package org.redkale.boot; - -import java.util.List; -import java.util.Objects; -import java.util.Properties; -import java.util.logging.Logger; -import org.redkale.asm.AsmMethodBoost; -import org.redkale.inject.ResourceEvent; -import org.redkale.inject.ResourceFactory; -import org.redkale.service.Service; -import org.redkale.util.AnyValue; -import org.redkale.util.Environment; - -/** - * 各组件的引擎类, 由Application管理 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public abstract class ModuleEngine { - - protected final Logger logger = Logger.getLogger(getClass().getSimpleName()); - - protected final Application application; - - protected final ResourceFactory resourceFactory; - - protected final Environment environment; - - public ModuleEngine(Application application) { - this.application = application; - this.resourceFactory = Objects.requireNonNull(application.resourceFactory); - this.environment = Objects.requireNonNull(application.getEnvironment()); - } - - /** - * 判断模块的配置项合并策略, 返回null表示模块不识别此配置项 - * - * @param path 配置项路径 - * @param key 配置项名称 - * @param val1 配置项原值 - * @param val2 配置项新值 - * @return MergeEnum - */ - public AnyValue.MergeEnum mergeAppConfigStrategy(String path, String key, AnyValue val1, AnyValue val2) { - return null; - } - - /** - * 动态扩展类的方法 - * - * @param remote 是否远程模式 - * @param serviceClass 类 - * @return 方法动态扩展器 - */ - public AsmMethodBoost createAsmMethodBoost(boolean remote, Class serviceClass) { - return null; - } - - /** 进入Application.init方法时被调用 此时状态: 1、远程配置项未获取 2、WorkExecutor未初始化 */ - public void onAppPreInit() { - // do nothing - } - - /** 结束Application.init方法前被调用 */ - public void onAppPostInit() { - // do nothing - } - - /** 进入Application.start方法被调用 */ - public void onAppPreStart() { - // do nothing - } - - /** 结束Application.start方法前被调用 */ - public void onAppPostStart() { - // do nothing - } - - /** - * 配置项加载后被调用 - * - * @param allProps 配置项全量 - */ - public void onEnvironmentLoaded(Properties allProps) { - // do nothing - } - - /** - * 配置项变更时被调用 - * - * @param namespace 命名空间 - * @param events 变更项 - */ - public void onEnvironmentChanged(String namespace, List events) { - // do nothing - } - - /** Application 在运行Compile前调用 */ - public void onPreCompile() { - // do nothing - } - - /** Application 在运行Compile后调用 */ - public void onPostCompile() { - // do nothing - } - - /** 服务全部启动前被调用 */ - public void onServersPreStart() { - // do nothing - } - - /** 服务全部启动后被调用 */ - public void onServersPostStart() { - // do nothing - } - - /** - * 执行Service.init方法前被调用 - * - * @param service Service - */ - public void onServicePreInit(Service service) { - // do nothing - } - - /** - * 执行Service.init方法后被调用 - * - * @param service Service - */ - public void onServicePostInit(Service service) { - // do nothing - } - - /** - * 执行Service.destroy方法前被调用 - * - * @param service Service - */ - public void onServicePreDestroy(Service service) { - // do nothing - } - - /** - * 执行Service.destroy方法后被调用 - * - * @param service Service - */ - public void onServicePostDestroy(Service service) { - // do nothing - } - - /** 服务全部停掉前被调用 */ - public void onServersPreStop() { - // do nothing - } - - /** 服务全部停掉后被调用 */ - public void onServersPostStop() { - // do nothing - } - - /** 进入Application.shutdown方法被调用 */ - public void onAppPreShutdown() { - // do nothing - } - - /** 结束Application.shutdown方法前被调用 */ - public void onAppPostShutdown() { - // do nothing - } -} +/* + * + */ +package org.redkale.boot; + +import java.util.List; +import java.util.Objects; +import java.util.Properties; +import java.util.logging.Logger; +import org.redkale.asm.AsmMethodBoost; +import org.redkale.inject.ResourceEvent; +import org.redkale.inject.ResourceFactory; +import org.redkale.service.Service; +import org.redkale.util.AnyValue; +import org.redkale.util.Environment; + +/** + * 各组件的引擎类, 由Application管理 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public abstract class ModuleEngine { + + protected final Logger logger = Logger.getLogger(getClass().getSimpleName()); + + protected final Application application; + + protected final ResourceFactory resourceFactory; + + protected final Environment environment; + + public ModuleEngine(Application application) { + this.application = application; + this.resourceFactory = Objects.requireNonNull(application.resourceFactory); + this.environment = Objects.requireNonNull(application.getEnvironment()); + } + + /** + * 判断模块的配置项合并策略, 返回null表示模块不识别此配置项 + * + * @param path 配置项路径 + * @param key 配置项名称 + * @param val1 配置项原值 + * @param val2 配置项新值 + * @return MergeEnum + */ + public AnyValue.MergeEnum mergeAppConfigStrategy(String path, String key, AnyValue val1, AnyValue val2) { + return null; + } + + /** + * 动态扩展类的方法 + * + * @param remote 是否远程模式 + * @param serviceClass 类 + * @return 方法动态扩展器 + */ + public AsmMethodBoost createAsmMethodBoost(boolean remote, Class serviceClass) { + return null; + } + + /** 进入Application.init方法时被调用 此时状态: 1、远程配置项未获取 2、WorkExecutor未初始化 */ + public void onAppPreInit() { + // do nothing + } + + /** 结束Application.init方法前被调用 */ + public void onAppPostInit() { + // do nothing + } + + /** 进入Application.start方法被调用 */ + public void onAppPreStart() { + // do nothing + } + + /** 结束Application.start方法前被调用 */ + public void onAppPostStart() { + // do nothing + } + + /** + * 配置项加载后被调用 + * + * @param allProps 配置项全量 + */ + public void onEnvironmentLoaded(Properties allProps) { + // do nothing + } + + /** + * 配置项变更时被调用 + * + * @param namespace 命名空间 + * @param events 变更项 + */ + public void onEnvironmentChanged(String namespace, List events) { + // do nothing + } + + /** Application 在运行Compile前调用 */ + public void onPreCompile() { + // do nothing + } + + /** Application 在运行Compile后调用 */ + public void onPostCompile() { + // do nothing + } + + /** 服务全部启动前被调用 */ + public void onServersPreStart() { + // do nothing + } + + /** 服务全部启动后被调用 */ + public void onServersPostStart() { + // do nothing + } + + /** + * 执行Service.init方法前被调用 + * + * @param service Service + */ + public void onServicePreInit(Service service) { + // do nothing + } + + /** + * 执行Service.init方法后被调用 + * + * @param service Service + */ + public void onServicePostInit(Service service) { + // do nothing + } + + /** + * 执行Service.destroy方法前被调用 + * + * @param service Service + */ + public void onServicePreDestroy(Service service) { + // do nothing + } + + /** + * 执行Service.destroy方法后被调用 + * + * @param service Service + */ + public void onServicePostDestroy(Service service) { + // do nothing + } + + /** 服务全部停掉前被调用 */ + public void onServersPreStop() { + // do nothing + } + + /** 服务全部停掉后被调用 */ + public void onServersPostStop() { + // do nothing + } + + /** 进入Application.shutdown方法被调用 */ + public void onAppPreShutdown() { + // do nothing + } + + /** 结束Application.shutdown方法前被调用 */ + public void onAppPostShutdown() { + // do nothing + } +} diff --git a/src/main/java/org/redkale/boot/NodeHttpServer.java b/src/main/java/org/redkale/boot/NodeHttpServer.java index 072863659..9ef93077f 100644 --- a/src/main/java/org/redkale/boot/NodeHttpServer.java +++ b/src/main/java/org/redkale/boot/NodeHttpServer.java @@ -1,662 +1,662 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package org.redkale.boot; - -import static org.redkale.boot.Application.RESNAME_SNCP_ADDRESS; - -import java.lang.annotation.Annotation; -import java.lang.reflect.*; -import java.net.*; -import java.util.*; -import java.util.concurrent.*; -import java.util.concurrent.locks.ReentrantLock; -import java.util.logging.Level; -import java.util.stream.Stream; -import org.redkale.annotation.*; -import org.redkale.asm.AsmMethodBoost; -import org.redkale.boot.ClassFilter.FilterEntry; -import org.redkale.cluster.spi.ClusterAgent; -import org.redkale.inject.ResourceFactory; -import org.redkale.inject.ResourceTypeLoader; -import org.redkale.mq.spi.MessageAgent; -import org.redkale.net.*; -import org.redkale.net.http.*; -import org.redkale.net.sncp.Sncp; -import org.redkale.service.Service; -import org.redkale.util.*; -import org.redkale.watch.*; - -/** - * HTTP Server节点的配置Server - * - *

详情见: https://redkale.org - * - * @author zhangjx - */ -@NodeProtocol("HTTP") -public class NodeHttpServer extends NodeServer { - - protected final boolean rest; // 是否加载REST服务, 为true加载rest节点信息并将所有可REST化的Service生成RestServlet - - protected final HttpServer httpServer; - - protected ClassFilter webSocketFilter; - - public NodeHttpServer(Application application, AnyValue serconf) { - super(application, createServer(application, serconf)); - this.httpServer = (HttpServer) server; - this.rest = serconf != null && serconf.getAnyValue("rest") != null; - } - - private static Server createServer(Application application, AnyValue serconf) { - return new HttpServer( - application, - application.getStartTime(), - application.getResourceFactory().createChild()); - } - - public HttpServer getHttpServer() { - return httpServer; - } - - @Override - public InetSocketAddress getSocketAddress() { - return httpServer == null ? null : httpServer.getSocketAddress(); - } - - @Override - @SuppressWarnings("unchecked") - protected ClassFilter createServiceClassFilter() { - return createClassFilter( - this.sncpGroup, - null, - Service.class, - new Class[] {org.redkale.watch.WatchService.class}, - Annotation.class, - "services", - "service"); - } - - @Override - @SuppressWarnings("unchecked") - protected ClassFilter createFilterClassFilter() { - return createClassFilter( - null, null, HttpFilter.class, new Class[] {WatchFilter.class}, null, "filters", "filter"); - } - - @Override - @SuppressWarnings("unchecked") - protected ClassFilter createServletClassFilter() { - return createClassFilter( - null, - WebServlet.class, - HttpServlet.class, - new Class[] {WatchServlet.class}, - null, - "servlets", - "servlet"); - } - - @Override - protected List createOtherClassFilters() { - this.webSocketFilter = - createClassFilter(null, RestWebSocket.class, WebSocket.class, null, null, "rest", "websocket"); - List filters = super.createOtherClassFilters(); - if (filters == null) { - filters = new ArrayList<>(); - } - filters.add(webSocketFilter); - return filters; - } - - @Override - protected void loadOthers(List otherFilters) throws Exception { - List filters = otherFilters; - if (filters != null) { - filters.remove(this.webSocketFilter); // webSocketFilter会在loadHttpFilter中处理,先剔除 - } - super.loadOthers(filters); - } - - @Override - protected void loadService(ClassFilter serviceFilter) throws Exception { - super.loadService(serviceFilter); - initWebSocketService(); - } - - @Override - protected void loadFilter(ClassFilter filterFilter) throws Exception { - if (httpServer != null) { - loadHttpFilter(filterFilter); - } - } - - @Override - @SuppressWarnings("unchecked") - protected void loadServlet(ClassFilter servletFilter) throws Exception { - if (httpServer != null) { - loadHttpServlet(servletFilter); - } - } - - private void initWebSocketService() { - final NodeServer self = this; - final ResourceFactory regFactory = application.getResourceFactory(); - resourceFactory.register(new ResourceTypeLoader() { - - @Override - public Object load( - ResourceFactory rf, - String srcResourceName, - Object srcObj, - String resourceName, - Field field, - Object attachment) { // 主要用于单点的服务 - try { - if (!(srcObj instanceof WebSocketServlet)) { - return null; - } - ResourceTypeLoader loader = null; - ResourceFactory sncpResFactory = null; - for (NodeServer ns : application.servers) { - if (!ns.isSNCP()) { - continue; - } - sncpResFactory = ns.resourceFactory; - loader = sncpResFactory.findTypeLoader(WebSocketNode.class, field); - if (loader != null) { - break; - } - } - Service nodeService = null; - if (loader != null) { - nodeService = (Service) - loader.load(sncpResFactory, srcResourceName, srcObj, resourceName, field, attachment); - } - regFactory.lock(); - try { - if (nodeService == null) { - nodeService = (Service) rf.find(resourceName, WebSocketNode.class); - } - if (sncpResFactory != null - && resourceFactory.find(RESNAME_SNCP_ADDRESS, String.class) == null) { - resourceFactory.register( - RESNAME_SNCP_ADDRESS, - InetSocketAddress.class, - sncpResFactory.find(RESNAME_SNCP_ADDRESS, InetSocketAddress.class)); - resourceFactory.register( - RESNAME_SNCP_ADDRESS, - SocketAddress.class, - sncpResFactory.find(RESNAME_SNCP_ADDRESS, SocketAddress.class)); - resourceFactory.register( - RESNAME_SNCP_ADDRESS, - String.class, - sncpResFactory.find(RESNAME_SNCP_ADDRESS, String.class)); - } - if (nodeService == null) { - MessageAgent messageAgent = null; - try { - Field c = WebSocketServlet.class.getDeclaredField("messageAgent"); - RedkaleClassLoader.putReflectionField("messageAgent", c); - c.setAccessible(true); - messageAgent = (MessageAgent) c.get(srcObj); - } catch (Exception ex) { - logger.log(Level.WARNING, "WebSocketServlet getMessageAgent error", ex); - } - AsmMethodBoost methodBoost = - application.createAsmMethodBoost(false, WebSocketNodeService.class); - nodeService = Sncp.createLocalService( - serverClassLoader, - resourceName, - WebSocketNodeService.class, - methodBoost, - application.getResourceFactory(), - application.getSncpRpcGroups(), - sncpClient, - messageAgent, - (String) null, - (AnyValue) null); - regFactory.register(resourceName, WebSocketNode.class, nodeService); - } - resourceFactory.inject(resourceName, nodeService, self); - field.set(srcObj, nodeService); - logger.fine("Load Service " + nodeService); - return nodeService; - } finally { - regFactory.unlock(); - } - } catch (Exception e) { - logger.log(Level.SEVERE, "WebSocketNode inject error", e); - throw e instanceof RuntimeException ? (RuntimeException) e : new RedkaleException(e); - } - } - - @Override - public Type resourceType() { - return WebSocketNode.class; - } - }); - } - - @SuppressWarnings("unchecked") - protected void loadHttpFilter(final ClassFilter classFilter) throws Exception { - final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null; - List> list = new ArrayList(classFilter.getFilterEntrys()); - for (FilterEntry entry : list) { - Class clazz = (Class) entry.getType(); - if (Modifier.isAbstract(clazz.getModifiers())) { - continue; - } - if (entry.isExpect()) { // 跳过不自动加载的Filter - continue; - } - RedkaleClassLoader.putReflectionDeclaredConstructors(clazz, clazz.getName()); - final HttpFilter filter = clazz.getDeclaredConstructor().newInstance(); - resourceFactory.inject(filter, this); - AnyValueWriter filterConf = (AnyValueWriter) entry.getProperty(); - this.httpServer.addHttpFilter(filter, filterConf); - if (sb != null) { - sb.append("Load ").append(clazz.getName()).append(LINE_SEPARATOR); - } - } - if (sb != null && sb.length() > 0) { - logger.log(Level.INFO, sb.toString()); - } - } - - @SuppressWarnings("unchecked") - protected void loadHttpServlet(final ClassFilter servletFilter) throws Exception { - RedkaleClassLoader.putReflectionPublicClasses(HttpServlet.class.getName()); - RedkaleClassLoader.putReflectionPublicClasses(HttpDispatcherServlet.class.getName()); - RedkaleClassLoader.putReflectionDeclaredConstructors( - HttpResourceServlet.class, HttpResourceServlet.class.getName()); - final AnyValue servletsConf = this.serverConf.getAnyValue("servlets"); - final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null; - String prefix0 = servletsConf == null ? "" : servletsConf.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; - } - final String prefix = prefix0; - List> list = new ArrayList(servletFilter.getFilterEntrys()); - list.sort( - (FilterEntry o1, - FilterEntry - o2) -> { // 必须保证WebSocketServlet优先加载, 因为要确保其他的HttpServlet可以注入本地模式的WebSocketNode - boolean ws1 = WebSocketServlet.class.isAssignableFrom(o1.getType()); - boolean ws2 = WebSocketServlet.class.isAssignableFrom(o2.getType()); - if (ws1 == ws2) { - Priority p1 = o1.getType().getAnnotation(Priority.class); - Priority p2 = o2.getType().getAnnotation(Priority.class); - int v = (p2 == null ? 0 : p2.value()) - (p1 == null ? 0 : p1.value()); - return v == 0 - ? o1.getType().getName().compareTo(o2.getType().getName()) - : 0; - } - return ws1 ? -1 : 1; - }); - final long starts = System.currentTimeMillis(); - final List> ss = sb == null ? null : new ArrayList<>(); - for (FilterEntry entry : list) { - Class clazz = (Class) entry.getType(); - if (Modifier.isAbstract(clazz.getModifiers())) { - continue; - } - if (clazz.getAnnotation(Rest.RestDyn.class) != null) { - continue; // 动态生成的跳过 - } - if (entry.isExpect()) { // 跳过不自动加载的Servlet - continue; - } - WebServlet ws = clazz.getAnnotation(WebServlet.class); - if (ws == null) { - continue; - } - if (ws.value().length == 0) { - logger.log(Level.INFO, "Not found @WebServlet.value in " + clazz.getName()); - continue; - } - RedkaleClassLoader.putReflectionDeclaredConstructors(clazz, clazz.getName()); - final HttpServlet servlet = clazz.getDeclaredConstructor().newInstance(); - resourceFactory.inject(servlet, this); - final String[] mappings = ws.value(); - String pref = ws.repair() ? prefix : ""; - AnyValueWriter servletConf = (AnyValueWriter) entry.getProperty(); - this.httpServer.addHttpServlet(servlet, pref, servletConf, mappings); - if (ss != null) { - for (int i = 0; i < mappings.length; i++) { - mappings[i] = pref + mappings[i]; - } - ss.add(new AbstractMap.SimpleEntry<>("HttpServlet (type=" + clazz.getName() + ")", mappings)); - } - } - final CopyOnWriteArrayList> rests = - sb == null ? null : new CopyOnWriteArrayList<>(); - final CopyOnWriteArrayList> webss = - sb == null ? null : new CopyOnWriteArrayList<>(); - if (rest && serverConf != null) { - final List restedObjects = new ArrayList<>(); - final ReentrantLock restedLock = new ReentrantLock(); - for (AnyValue restConf : serverConf.getAnyValues("rest")) { - loadRestServlet(webSocketFilter, restConf, restedObjects, restedLock, sb, rests, webss); - } - this.webSocketFilter = null; - } - int max = 0; - if (ss != null && sb != null) { - int maxTypeLength = 0; - int maxNameLength = 0; - if (rests != null) { - for (AbstractMap.SimpleEntry en : rests) { - int pos = en.getKey().indexOf(':'); - if (pos > maxTypeLength) { - maxTypeLength = pos; - } - int len = en.getKey().length() - pos - 1; - if (len > maxNameLength) { - maxNameLength = len; - } - } - } - if (webss != null) { - for (AbstractMap.SimpleEntry en : webss) { - int pos = en.getKey().indexOf(':'); - if (pos > maxTypeLength) { - maxTypeLength = pos; - } - int len = en.getKey().length() - pos - 1; - if (len > maxNameLength) { - maxNameLength = len; - } - } - } - if (rests != null) { - for (AbstractMap.SimpleEntry en : rests) { - StringBuilder sub = new StringBuilder(); - int pos = en.getKey().indexOf(':'); - sub.append("RestServlet (type=").append(en.getKey().substring(0, pos)); - for (int i = 0; i < maxTypeLength - pos; i++) { - sub.append(' '); - } - String n = en.getKey().substring(pos + 1); - sub.append(", name='").append(n).append("'"); - for (int i = 0; i < maxNameLength - n.length(); i++) { - sub.append(' '); - } - sub.append(")"); - ss.add(new AbstractMap.SimpleEntry<>(sub.toString(), en.getValue())); - } - } - if (webss != null) { - for (AbstractMap.SimpleEntry en : webss) { - StringBuilder sub = new StringBuilder(); - int pos = en.getKey().indexOf(':'); - sub.append("RestWebSocket (type=").append(en.getKey().substring(0, pos)); - for (int i = 0; i < maxTypeLength - pos; i++) { - sub.append(' '); - } - String n = en.getKey().substring(pos + 1); - sub.append(", name='").append(n).append("'"); - for (int i = 0; i < maxNameLength - n.length(); i++) { - sub.append(' '); - } - sub.append(")"); - ss.add(new AbstractMap.SimpleEntry<>(sub.toString(), en.getValue())); - } - } - ss.sort((AbstractMap.SimpleEntry o1, AbstractMap.SimpleEntry o2) -> - o1.getKey().compareTo(o2.getKey())); - for (AbstractMap.SimpleEntry as : ss) { - if (as.getKey().length() > max) { - max = as.getKey().length(); - } - } - for (AbstractMap.SimpleEntry as : ss) { - sb.append("Load ").append(as.getKey()); - for (int i = 0; i < max - as.getKey().length(); i++) { - sb.append(' '); - } - sb.append(" mapping to ") - .append(Arrays.toString(as.getValue())) - .append(LINE_SEPARATOR); - } - sb.append("All HttpServlets load in ") - .append(System.currentTimeMillis() - starts) - .append(" ms") - .append(LINE_SEPARATOR); - } - if (sb != null && sb.length() > 0) { - logger.log(Level.INFO, sb.toString().trim()); - } - } - - @SuppressWarnings("unchecked") - protected void loadRestServlet( - final ClassFilter webSocketFilter, - final AnyValue restConf, - final List restedObjects, - final ReentrantLock restedLock, - final StringBuilder sb, - final CopyOnWriteArrayList> rests, - final CopyOnWriteArrayList> webss) - throws Exception { - if (!rest) { - return; - } - if (restConf == null) { - return; // 不存在REST服务 - } - 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; - } - - String mqname = restConf.getValue("mq"); - MessageAgent agent0 = null; - if (mqname != null) { - agent0 = application.getResourceFactory().find(mqname, MessageAgent.class); - if (agent0 == null) { - throw new RedkaleException( - "not found " + MessageAgent.class.getSimpleName() + " config for (name=" + mqname + ")"); - } - } - final MessageAgent messageAgent = agent0; - if (messageAgent != null) { - prefix0 = ""; // 开启MQ时,prefix字段失效 - } - final String prefix = prefix0; - final boolean autoload = restConf.getBoolValue("autoload", true); - { // 加载RestService - String userTypeStr = restConf.getValue("usertype"); - final Class userType = userTypeStr == null ? null : this.serverClassLoader.loadClass(userTypeStr); - - final Class baseServletType = - this.serverClassLoader.loadClass(restConf.getValue("base", HttpServlet.class.getName())); - final Set includeValues = new HashSet<>(); - final Set excludeValues = new HashSet<>(); - for (AnyValue item : restConf.getAnyValues("service")) { - if (item.getBoolValue("ignore", false)) { - excludeValues.add(item.getValue("value", "")); - } else { - includeValues.add(item.getValue("value", "")); - } - } - - final ClassFilter restFilter = ClassFilter.create( - serverClassLoader, - null, - application.isCompileMode() ? "" : restConf.getValue("includes", ""), - application.isCompileMode() ? "" : restConf.getValue("excludes", ""), - includeValues, - excludeValues); - final CountDownLatch scdl = new CountDownLatch(super.servletServices.size()); - Stream stream = super.servletServices.stream(); - if (!application.isCompileMode()) { - stream = stream.parallel(); // 不能并行,否则在maven plugin运行环境下ClassLoader不对 - } - stream.forEach((service) -> { - try { - final Class stype = Sncp.getResourceType(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; - } - restedLock.lock(); - try { - if (restedObjects.contains(service)) { - logger.log(Level.WARNING, stype.getName() + " repeat create rest servlet, so ignore"); - return; - } - restedObjects.add(service); // 避免重复创建Rest对象 - } finally { - restedLock.unlock(); - } - 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); - dynServletMap.put(service, servlet); - if (messageAgent != null) { - messageAgent.putService(this, service, servlet); - } - // if (finest) logger.finest("Create RestServlet(resource.name='" + name + "') = " + servlet); - if (rests != null) { - String[] mappings = servlet.getClass() - .getAnnotation(WebServlet.class) - .value(); - for (int i = 0; i < mappings.length; i++) { - mappings[i] = prefix2 + mappings[i]; - } - rests.add(new AbstractMap.SimpleEntry<>( - Sncp.getResourceType(service).getName() + ":" + name, mappings)); - } - } finally { - scdl.countDown(); - } - }); - scdl.await(); - } - if (webSocketFilter != null) { // 加载RestWebSocket - final Set includeValues = new HashSet<>(); - final Set excludeValues = new HashSet<>(); - for (AnyValue item : restConf.getAnyValues("websocket")) { - if (item.getBoolValue("ignore", false)) { - excludeValues.add(item.getValue("value", "")); - } else { - includeValues.add(item.getValue("value", "")); - } - } - final ClassFilter restFilter = ClassFilter.create( - serverClassLoader, - null, - application.isCompileMode() ? "" : restConf.getValue("includes", ""), - application.isCompileMode() ? "" : restConf.getValue("excludes", ""), - includeValues, - excludeValues); - - List> list = new ArrayList(webSocketFilter.getFilterEntrys()); - for (FilterEntry en : list) { - Class clazz = (Class) en.getType(); - if (Modifier.isAbstract(clazz.getModifiers())) { - logger.log(Level.FINE, clazz.getName() + " cannot abstract on rest websocket, so ignore"); - continue; - } - if (Modifier.isFinal(clazz.getModifiers())) { - logger.log(Level.FINE, clazz.getName() + " cannot final on rest websocket, so ignore"); - continue; - } - final Class stype = en.getType(); - if (stype.getAnnotation(Rest.RestDyn.class) != null) { - continue; - } - RestWebSocket rs = stype.getAnnotation(RestWebSocket.class); - if (rs == null || rs.ignore()) { - continue; - } - - final String stypename = stype.getName(); - if (!autoload && !includeValues.contains(stypename)) { - continue; - } - if (!restFilter.accept(stypename)) { - continue; - } - if (restedObjects.contains(stype)) { - logger.log(Level.WARNING, stype.getName() + " repeat create rest websocket, so ignore"); - continue; - } - restedObjects.add(stype); // 避免重复创建Rest对象 - WebSocketServlet servlet = httpServer.addRestWebSocketServlet( - serverClassLoader, stype, messageAgent, prefix, en.getProperty()); - if (servlet == null) { - continue; // 没有RestOnMessage方法的HttpServlet调用Rest.createRestWebSocketServlet就会返回null - } - String prefix2 = prefix; - WebServlet ws = servlet.getClass().getAnnotation(WebServlet.class); - if (ws != null && !ws.repair()) { - prefix2 = ""; - } - resourceFactory.inject(servlet, NodeHttpServer.this); - if (logger.isLoggable(Level.FINEST)) { - logger.finest(stype.getName() + " create a RestWebSocketServlet"); - } - if (webss != null) { - String[] mappings = - servlet.getClass().getAnnotation(WebServlet.class).value(); - for (int i = 0; i < mappings.length; i++) { - mappings[i] = prefix2 + mappings[i]; - } - webss.add(new AbstractMap.SimpleEntry<>(stype.getName() + ":" + rs.name(), mappings)); - } - } - } - if (messageAgent != null) { - this.messageAgents.put(messageAgent.getName(), messageAgent); - } - } - - @Override // loadServlet执行之后调用 - protected void postLoadServlets() { - final ClusterAgent cluster = application.getResourceFactory().find("", ClusterAgent.class); - if (!application.isCompileMode() && cluster != null) { - NodeProtocol pros = getClass().getAnnotation(NodeProtocol.class); - String protocol = pros.value().toUpperCase(); - if (!cluster.containsProtocol(protocol)) { - return; - } - if (!cluster.containsPort(server.getSocketAddress().getPort())) { - return; - } - cluster.register(this, protocol, dynServletMap.keySet(), new HashSet<>(), dynServletMap.keySet()); - } - } - - @Override - protected void afterClusterDeregisterOnPreDestroyServices(ClusterAgent cluster, String protocol) { - cluster.deregister(this, protocol, dynServletMap.keySet(), new HashSet<>(), dynServletMap.keySet()); - } -} +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.boot; + +import static org.redkale.boot.Application.RESNAME_SNCP_ADDRESS; + +import java.lang.annotation.Annotation; +import java.lang.reflect.*; +import java.net.*; +import java.util.*; +import java.util.concurrent.*; +import java.util.concurrent.locks.ReentrantLock; +import java.util.logging.Level; +import java.util.stream.Stream; +import org.redkale.annotation.*; +import org.redkale.asm.AsmMethodBoost; +import org.redkale.boot.ClassFilter.FilterEntry; +import org.redkale.cluster.spi.ClusterAgent; +import org.redkale.inject.ResourceFactory; +import org.redkale.inject.ResourceTypeLoader; +import org.redkale.mq.spi.MessageAgent; +import org.redkale.net.*; +import org.redkale.net.http.*; +import org.redkale.net.sncp.Sncp; +import org.redkale.service.Service; +import org.redkale.util.*; +import org.redkale.watch.*; + +/** + * HTTP Server节点的配置Server + * + *

详情见: https://redkale.org + * + * @author zhangjx + */ +@NodeProtocol("HTTP") +public class NodeHttpServer extends NodeServer { + + protected final boolean rest; // 是否加载REST服务, 为true加载rest节点信息并将所有可REST化的Service生成RestServlet + + protected final HttpServer httpServer; + + protected ClassFilter webSocketFilter; + + public NodeHttpServer(Application application, AnyValue serconf) { + super(application, createServer(application, serconf)); + this.httpServer = (HttpServer) server; + this.rest = serconf != null && serconf.getAnyValue("rest") != null; + } + + private static Server createServer(Application application, AnyValue serconf) { + return new HttpServer( + application, + application.getStartTime(), + application.getResourceFactory().createChild()); + } + + public HttpServer getHttpServer() { + return httpServer; + } + + @Override + public InetSocketAddress getSocketAddress() { + return httpServer == null ? null : httpServer.getSocketAddress(); + } + + @Override + @SuppressWarnings("unchecked") + protected ClassFilter createServiceClassFilter() { + return createClassFilter( + this.sncpGroup, + null, + Service.class, + new Class[] {org.redkale.watch.WatchService.class}, + Annotation.class, + "services", + "service"); + } + + @Override + @SuppressWarnings("unchecked") + protected ClassFilter createFilterClassFilter() { + return createClassFilter( + null, null, HttpFilter.class, new Class[] {WatchFilter.class}, null, "filters", "filter"); + } + + @Override + @SuppressWarnings("unchecked") + protected ClassFilter createServletClassFilter() { + return createClassFilter( + null, + WebServlet.class, + HttpServlet.class, + new Class[] {WatchServlet.class}, + null, + "servlets", + "servlet"); + } + + @Override + protected List createOtherClassFilters() { + this.webSocketFilter = + createClassFilter(null, RestWebSocket.class, WebSocket.class, null, null, "rest", "websocket"); + List filters = super.createOtherClassFilters(); + if (filters == null) { + filters = new ArrayList<>(); + } + filters.add(webSocketFilter); + return filters; + } + + @Override + protected void loadOthers(List otherFilters) throws Exception { + List filters = otherFilters; + if (filters != null) { + filters.remove(this.webSocketFilter); // webSocketFilter会在loadHttpFilter中处理,先剔除 + } + super.loadOthers(filters); + } + + @Override + protected void loadService(ClassFilter serviceFilter) throws Exception { + super.loadService(serviceFilter); + initWebSocketService(); + } + + @Override + protected void loadFilter(ClassFilter filterFilter) throws Exception { + if (httpServer != null) { + loadHttpFilter(filterFilter); + } + } + + @Override + @SuppressWarnings("unchecked") + protected void loadServlet(ClassFilter servletFilter) throws Exception { + if (httpServer != null) { + loadHttpServlet(servletFilter); + } + } + + private void initWebSocketService() { + final NodeServer self = this; + final ResourceFactory regFactory = application.getResourceFactory(); + resourceFactory.register(new ResourceTypeLoader() { + + @Override + public Object load( + ResourceFactory rf, + String srcResourceName, + Object srcObj, + String resourceName, + Field field, + Object attachment) { // 主要用于单点的服务 + try { + if (!(srcObj instanceof WebSocketServlet)) { + return null; + } + ResourceTypeLoader loader = null; + ResourceFactory sncpResFactory = null; + for (NodeServer ns : application.servers) { + if (!ns.isSNCP()) { + continue; + } + sncpResFactory = ns.resourceFactory; + loader = sncpResFactory.findTypeLoader(WebSocketNode.class, field); + if (loader != null) { + break; + } + } + Service nodeService = null; + if (loader != null) { + nodeService = (Service) + loader.load(sncpResFactory, srcResourceName, srcObj, resourceName, field, attachment); + } + regFactory.lock(); + try { + if (nodeService == null) { + nodeService = (Service) rf.find(resourceName, WebSocketNode.class); + } + if (sncpResFactory != null + && resourceFactory.find(RESNAME_SNCP_ADDRESS, String.class) == null) { + resourceFactory.register( + RESNAME_SNCP_ADDRESS, + InetSocketAddress.class, + sncpResFactory.find(RESNAME_SNCP_ADDRESS, InetSocketAddress.class)); + resourceFactory.register( + RESNAME_SNCP_ADDRESS, + SocketAddress.class, + sncpResFactory.find(RESNAME_SNCP_ADDRESS, SocketAddress.class)); + resourceFactory.register( + RESNAME_SNCP_ADDRESS, + String.class, + sncpResFactory.find(RESNAME_SNCP_ADDRESS, String.class)); + } + if (nodeService == null) { + MessageAgent messageAgent = null; + try { + Field c = WebSocketServlet.class.getDeclaredField("messageAgent"); + RedkaleClassLoader.putReflectionField("messageAgent", c); + c.setAccessible(true); + messageAgent = (MessageAgent) c.get(srcObj); + } catch (Exception ex) { + logger.log(Level.WARNING, "WebSocketServlet getMessageAgent error", ex); + } + AsmMethodBoost methodBoost = + application.createAsmMethodBoost(false, WebSocketNodeService.class); + nodeService = Sncp.createLocalService( + serverClassLoader, + resourceName, + WebSocketNodeService.class, + methodBoost, + application.getResourceFactory(), + application.getSncpRpcGroups(), + sncpClient, + messageAgent, + (String) null, + (AnyValue) null); + regFactory.register(resourceName, WebSocketNode.class, nodeService); + } + resourceFactory.inject(resourceName, nodeService, self); + field.set(srcObj, nodeService); + logger.fine("Load Service " + nodeService); + return nodeService; + } finally { + regFactory.unlock(); + } + } catch (Exception e) { + logger.log(Level.SEVERE, "WebSocketNode inject error", e); + throw e instanceof RuntimeException ? (RuntimeException) e : new RedkaleException(e); + } + } + + @Override + public Type resourceType() { + return WebSocketNode.class; + } + }); + } + + @SuppressWarnings("unchecked") + protected void loadHttpFilter(final ClassFilter classFilter) throws Exception { + final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null; + List> list = new ArrayList(classFilter.getFilterEntrys()); + for (FilterEntry entry : list) { + Class clazz = (Class) entry.getType(); + if (Modifier.isAbstract(clazz.getModifiers())) { + continue; + } + if (entry.isExpect()) { // 跳过不自动加载的Filter + continue; + } + RedkaleClassLoader.putReflectionDeclaredConstructors(clazz, clazz.getName()); + final HttpFilter filter = clazz.getDeclaredConstructor().newInstance(); + resourceFactory.inject(filter, this); + AnyValueWriter filterConf = (AnyValueWriter) entry.getProperty(); + this.httpServer.addHttpFilter(filter, filterConf); + if (sb != null) { + sb.append("Load ").append(clazz.getName()).append(LINE_SEPARATOR); + } + } + if (sb != null && sb.length() > 0) { + logger.log(Level.INFO, sb.toString()); + } + } + + @SuppressWarnings("unchecked") + protected void loadHttpServlet(final ClassFilter servletFilter) throws Exception { + RedkaleClassLoader.putReflectionPublicClasses(HttpServlet.class.getName()); + RedkaleClassLoader.putReflectionPublicClasses(HttpDispatcherServlet.class.getName()); + RedkaleClassLoader.putReflectionDeclaredConstructors( + HttpResourceServlet.class, HttpResourceServlet.class.getName()); + final AnyValue servletsConf = this.serverConf.getAnyValue("servlets"); + final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null; + String prefix0 = servletsConf == null ? "" : servletsConf.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; + } + final String prefix = prefix0; + List> list = new ArrayList(servletFilter.getFilterEntrys()); + list.sort( + (FilterEntry o1, + FilterEntry + o2) -> { // 必须保证WebSocketServlet优先加载, 因为要确保其他的HttpServlet可以注入本地模式的WebSocketNode + boolean ws1 = WebSocketServlet.class.isAssignableFrom(o1.getType()); + boolean ws2 = WebSocketServlet.class.isAssignableFrom(o2.getType()); + if (ws1 == ws2) { + Priority p1 = o1.getType().getAnnotation(Priority.class); + Priority p2 = o2.getType().getAnnotation(Priority.class); + int v = (p2 == null ? 0 : p2.value()) - (p1 == null ? 0 : p1.value()); + return v == 0 + ? o1.getType().getName().compareTo(o2.getType().getName()) + : 0; + } + return ws1 ? -1 : 1; + }); + final long starts = System.currentTimeMillis(); + final List> ss = sb == null ? null : new ArrayList<>(); + for (FilterEntry entry : list) { + Class clazz = (Class) entry.getType(); + if (Modifier.isAbstract(clazz.getModifiers())) { + continue; + } + if (clazz.getAnnotation(Rest.RestDyn.class) != null) { + continue; // 动态生成的跳过 + } + if (entry.isExpect()) { // 跳过不自动加载的Servlet + continue; + } + WebServlet ws = clazz.getAnnotation(WebServlet.class); + if (ws == null) { + continue; + } + if (ws.value().length == 0) { + logger.log(Level.INFO, "Not found @WebServlet.value in " + clazz.getName()); + continue; + } + RedkaleClassLoader.putReflectionDeclaredConstructors(clazz, clazz.getName()); + final HttpServlet servlet = clazz.getDeclaredConstructor().newInstance(); + resourceFactory.inject(servlet, this); + final String[] mappings = ws.value(); + String pref = ws.repair() ? prefix : ""; + AnyValueWriter servletConf = (AnyValueWriter) entry.getProperty(); + this.httpServer.addHttpServlet(servlet, pref, servletConf, mappings); + if (ss != null) { + for (int i = 0; i < mappings.length; i++) { + mappings[i] = pref + mappings[i]; + } + ss.add(new AbstractMap.SimpleEntry<>("HttpServlet (type=" + clazz.getName() + ")", mappings)); + } + } + final CopyOnWriteArrayList> rests = + sb == null ? null : new CopyOnWriteArrayList<>(); + final CopyOnWriteArrayList> webss = + sb == null ? null : new CopyOnWriteArrayList<>(); + if (rest && serverConf != null) { + final List restedObjects = new ArrayList<>(); + final ReentrantLock restedLock = new ReentrantLock(); + for (AnyValue restConf : serverConf.getAnyValues("rest")) { + loadRestServlet(webSocketFilter, restConf, restedObjects, restedLock, sb, rests, webss); + } + this.webSocketFilter = null; + } + int max = 0; + if (ss != null && sb != null) { + int maxTypeLength = 0; + int maxNameLength = 0; + if (rests != null) { + for (AbstractMap.SimpleEntry en : rests) { + int pos = en.getKey().indexOf(':'); + if (pos > maxTypeLength) { + maxTypeLength = pos; + } + int len = en.getKey().length() - pos - 1; + if (len > maxNameLength) { + maxNameLength = len; + } + } + } + if (webss != null) { + for (AbstractMap.SimpleEntry en : webss) { + int pos = en.getKey().indexOf(':'); + if (pos > maxTypeLength) { + maxTypeLength = pos; + } + int len = en.getKey().length() - pos - 1; + if (len > maxNameLength) { + maxNameLength = len; + } + } + } + if (rests != null) { + for (AbstractMap.SimpleEntry en : rests) { + StringBuilder sub = new StringBuilder(); + int pos = en.getKey().indexOf(':'); + sub.append("RestServlet (type=").append(en.getKey().substring(0, pos)); + for (int i = 0; i < maxTypeLength - pos; i++) { + sub.append(' '); + } + String n = en.getKey().substring(pos + 1); + sub.append(", name='").append(n).append("'"); + for (int i = 0; i < maxNameLength - n.length(); i++) { + sub.append(' '); + } + sub.append(")"); + ss.add(new AbstractMap.SimpleEntry<>(sub.toString(), en.getValue())); + } + } + if (webss != null) { + for (AbstractMap.SimpleEntry en : webss) { + StringBuilder sub = new StringBuilder(); + int pos = en.getKey().indexOf(':'); + sub.append("RestWebSocket (type=").append(en.getKey().substring(0, pos)); + for (int i = 0; i < maxTypeLength - pos; i++) { + sub.append(' '); + } + String n = en.getKey().substring(pos + 1); + sub.append(", name='").append(n).append("'"); + for (int i = 0; i < maxNameLength - n.length(); i++) { + sub.append(' '); + } + sub.append(")"); + ss.add(new AbstractMap.SimpleEntry<>(sub.toString(), en.getValue())); + } + } + ss.sort((AbstractMap.SimpleEntry o1, AbstractMap.SimpleEntry o2) -> + o1.getKey().compareTo(o2.getKey())); + for (AbstractMap.SimpleEntry as : ss) { + if (as.getKey().length() > max) { + max = as.getKey().length(); + } + } + for (AbstractMap.SimpleEntry as : ss) { + sb.append("Load ").append(as.getKey()); + for (int i = 0; i < max - as.getKey().length(); i++) { + sb.append(' '); + } + sb.append(" mapping to ") + .append(Arrays.toString(as.getValue())) + .append(LINE_SEPARATOR); + } + sb.append("All HttpServlets load in ") + .append(System.currentTimeMillis() - starts) + .append(" ms") + .append(LINE_SEPARATOR); + } + if (sb != null && sb.length() > 0) { + logger.log(Level.INFO, sb.toString().trim()); + } + } + + @SuppressWarnings("unchecked") + protected void loadRestServlet( + final ClassFilter webSocketFilter, + final AnyValue restConf, + final List restedObjects, + final ReentrantLock restedLock, + final StringBuilder sb, + final CopyOnWriteArrayList> rests, + final CopyOnWriteArrayList> webss) + throws Exception { + if (!rest) { + return; + } + if (restConf == null) { + return; // 不存在REST服务 + } + 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; + } + + String mqname = restConf.getValue("mq"); + MessageAgent agent0 = null; + if (mqname != null) { + agent0 = application.getResourceFactory().find(mqname, MessageAgent.class); + if (agent0 == null) { + throw new RedkaleException( + "not found " + MessageAgent.class.getSimpleName() + " config for (name=" + mqname + ")"); + } + } + final MessageAgent messageAgent = agent0; + if (messageAgent != null) { + prefix0 = ""; // 开启MQ时,prefix字段失效 + } + final String prefix = prefix0; + final boolean autoload = restConf.getBoolValue("autoload", true); + { // 加载RestService + String userTypeStr = restConf.getValue("usertype"); + final Class userType = userTypeStr == null ? null : this.serverClassLoader.loadClass(userTypeStr); + + final Class baseServletType = + this.serverClassLoader.loadClass(restConf.getValue("base", HttpServlet.class.getName())); + final Set includeValues = new HashSet<>(); + final Set excludeValues = new HashSet<>(); + for (AnyValue item : restConf.getAnyValues("service")) { + if (item.getBoolValue("ignore", false)) { + excludeValues.add(item.getValue("value", "")); + } else { + includeValues.add(item.getValue("value", "")); + } + } + + final ClassFilter restFilter = ClassFilter.create( + serverClassLoader, + null, + application.isCompileMode() ? "" : restConf.getValue("includes", ""), + application.isCompileMode() ? "" : restConf.getValue("excludes", ""), + includeValues, + excludeValues); + final CountDownLatch scdl = new CountDownLatch(super.servletServices.size()); + Stream stream = super.servletServices.stream(); + if (!application.isCompileMode()) { + stream = stream.parallel(); // 不能并行,否则在maven plugin运行环境下ClassLoader不对 + } + stream.forEach((service) -> { + try { + final Class stype = Sncp.getResourceType(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; + } + restedLock.lock(); + try { + if (restedObjects.contains(service)) { + logger.log(Level.WARNING, stype.getName() + " repeat create rest servlet, so ignore"); + return; + } + restedObjects.add(service); // 避免重复创建Rest对象 + } finally { + restedLock.unlock(); + } + 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); + dynServletMap.put(service, servlet); + if (messageAgent != null) { + messageAgent.putService(this, service, servlet); + } + // if (finest) logger.finest("Create RestServlet(resource.name='" + name + "') = " + servlet); + if (rests != null) { + String[] mappings = servlet.getClass() + .getAnnotation(WebServlet.class) + .value(); + for (int i = 0; i < mappings.length; i++) { + mappings[i] = prefix2 + mappings[i]; + } + rests.add(new AbstractMap.SimpleEntry<>( + Sncp.getResourceType(service).getName() + ":" + name, mappings)); + } + } finally { + scdl.countDown(); + } + }); + scdl.await(); + } + if (webSocketFilter != null) { // 加载RestWebSocket + final Set includeValues = new HashSet<>(); + final Set excludeValues = new HashSet<>(); + for (AnyValue item : restConf.getAnyValues("websocket")) { + if (item.getBoolValue("ignore", false)) { + excludeValues.add(item.getValue("value", "")); + } else { + includeValues.add(item.getValue("value", "")); + } + } + final ClassFilter restFilter = ClassFilter.create( + serverClassLoader, + null, + application.isCompileMode() ? "" : restConf.getValue("includes", ""), + application.isCompileMode() ? "" : restConf.getValue("excludes", ""), + includeValues, + excludeValues); + + List> list = new ArrayList(webSocketFilter.getFilterEntrys()); + for (FilterEntry en : list) { + Class clazz = (Class) en.getType(); + if (Modifier.isAbstract(clazz.getModifiers())) { + logger.log(Level.FINE, clazz.getName() + " cannot abstract on rest websocket, so ignore"); + continue; + } + if (Modifier.isFinal(clazz.getModifiers())) { + logger.log(Level.FINE, clazz.getName() + " cannot final on rest websocket, so ignore"); + continue; + } + final Class stype = en.getType(); + if (stype.getAnnotation(Rest.RestDyn.class) != null) { + continue; + } + RestWebSocket rs = stype.getAnnotation(RestWebSocket.class); + if (rs == null || rs.ignore()) { + continue; + } + + final String stypename = stype.getName(); + if (!autoload && !includeValues.contains(stypename)) { + continue; + } + if (!restFilter.accept(stypename)) { + continue; + } + if (restedObjects.contains(stype)) { + logger.log(Level.WARNING, stype.getName() + " repeat create rest websocket, so ignore"); + continue; + } + restedObjects.add(stype); // 避免重复创建Rest对象 + WebSocketServlet servlet = httpServer.addRestWebSocketServlet( + serverClassLoader, stype, messageAgent, prefix, en.getProperty()); + if (servlet == null) { + continue; // 没有RestOnMessage方法的HttpServlet调用Rest.createRestWebSocketServlet就会返回null + } + String prefix2 = prefix; + WebServlet ws = servlet.getClass().getAnnotation(WebServlet.class); + if (ws != null && !ws.repair()) { + prefix2 = ""; + } + resourceFactory.inject(servlet, NodeHttpServer.this); + if (logger.isLoggable(Level.FINEST)) { + logger.finest(stype.getName() + " create a RestWebSocketServlet"); + } + if (webss != null) { + String[] mappings = + servlet.getClass().getAnnotation(WebServlet.class).value(); + for (int i = 0; i < mappings.length; i++) { + mappings[i] = prefix2 + mappings[i]; + } + webss.add(new AbstractMap.SimpleEntry<>(stype.getName() + ":" + rs.name(), mappings)); + } + } + } + if (messageAgent != null) { + this.messageAgents.put(messageAgent.getName(), messageAgent); + } + } + + @Override // loadServlet执行之后调用 + protected void postLoadServlets() { + final ClusterAgent cluster = application.getResourceFactory().find("", ClusterAgent.class); + if (!application.isCompileMode() && cluster != null) { + NodeProtocol pros = getClass().getAnnotation(NodeProtocol.class); + String protocol = pros.value().toUpperCase(); + if (!cluster.containsProtocol(protocol)) { + return; + } + if (!cluster.containsPort(server.getSocketAddress().getPort())) { + return; + } + cluster.register(this, protocol, dynServletMap.keySet(), new HashSet<>(), dynServletMap.keySet()); + } + } + + @Override + protected void afterClusterDeregisterOnPreDestroyServices(ClusterAgent cluster, String protocol) { + cluster.deregister(this, protocol, dynServletMap.keySet(), new HashSet<>(), dynServletMap.keySet()); + } +} diff --git a/src/main/java/org/redkale/boot/NodeServer.java b/src/main/java/org/redkale/boot/NodeServer.java index 57b76ac6f..5731866bc 100644 --- a/src/main/java/org/redkale/boot/NodeServer.java +++ b/src/main/java/org/redkale/boot/NodeServer.java @@ -1,1128 +1,1128 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package org.redkale.boot; - -import static org.redkale.boot.Application.*; - -import java.io.*; -import java.lang.annotation.Annotation; -import java.lang.reflect.*; -import java.net.*; -import java.nio.file.Path; -import java.util.*; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.logging.*; -import org.redkale.annotation.*; -import org.redkale.annotation.AutoLoad; -import org.redkale.annotation.Command; -import org.redkale.asm.AsmMethodBoost; -import org.redkale.boot.ClassFilter.FilterEntry; -import org.redkale.cluster.spi.ClusterAgent; -import org.redkale.inject.ResourceFactory; -import org.redkale.inject.ResourceTypeLoader; -import org.redkale.mq.spi.MessageAgent; -import org.redkale.net.*; -import org.redkale.net.Filter; -import org.redkale.net.client.ClientAddress; -import org.redkale.net.http.*; -import org.redkale.net.http.WebSocketNodeService; -import org.redkale.net.sncp.*; -import org.redkale.service.*; -import org.redkale.source.*; -import org.redkale.util.*; - -/** - * Server节点的初始化配置类 - * - *

详情见: https://redkale.org - * - * @author zhangjx - */ -@SuppressWarnings("unchecked") -public abstract class NodeServer { - - // INFO日志的换行符 - public static final String LINE_SEPARATOR = "\r\n"; - - // 日志输出对象 - protected final Logger logger; - - // 进程主类 - protected final Application application; - - // 依赖注入工厂类 - protected final ResourceFactory resourceFactory; - - // 当前Server对象 - protected final Server server; - - // ClassLoader - protected RedkaleClassLoader serverClassLoader; - - protected final Thread serverThread; - - // server节点的配置 - protected AnyValue serverConf; - - protected final String threadName; - - // 加载server节点后的拦截器 - protected NodeInterceptor interceptor; - - // 本地模式的Service对象集合 - protected final Set localServices = new LinkedHashSet<>(); - - // 远程模式的Service对象集合 - protected final Set remoteServices = new LinkedHashSet<>(); - - // 需要转换成Servlet的Service对象集合, Component的Service不在其内 - protected final Set servletServices = new LinkedHashSet<>(); - - // 存在SncpServlet、RestServlet - protected final Map dynServletMap = new LinkedHashMap<>(); - - // MessageAgent对象集合 - protected final Map messageAgents = new HashMap<>(); - - // 需要远程模式Service的MessageAgent对象集合 - protected final Map sncpRemoteAgents = new HashMap<>(); - - // 当前Server的SNCP协议的组 - protected String sncpGroup = null; - - // 当前Server的SNCP服务Client - protected SncpClient sncpClient; - - // SncpClient的AsyncGroup - private AsyncIOGroup sncpAsyncGroup; - - // SNCP服务的地址, 非SNCP为null - private InetSocketAddress sncpAddress; - - private volatile int maxTypeLength = 0; - - private volatile int maxNameLength = 0; - - CountDownLatch serviceCdl; - - public NodeServer(Application application, Server server) { - this.threadName = Thread.currentThread().getName(); - this.application = application; - this.server = server; - this.resourceFactory = server.getResourceFactory(); - this.logger = Logger.getLogger(this.getClass().getSimpleName()); - if (application.isCompileMode() - || application.getServerClassLoader() instanceof RedkaleClassLoader.RedkaleCacheClassLoader) { - this.serverClassLoader = application.getServerClassLoader(); - } else { - this.serverClassLoader = new RedkaleClassLoader(application.getServerClassLoader()); - } - Thread.currentThread().setContextClassLoader(this.serverClassLoader); - this.serverThread = Thread.currentThread(); - this.server.setServerClassLoader(serverClassLoader); - } - - public static NodeServer create(Class clazz, Application application, AnyValue serconf) { - try { - RedkaleClassLoader.putReflectionDeclaredConstructors( - clazz, clazz.getName(), Application.class, AnyValue.class); - return clazz.getDeclaredConstructor(Application.class, AnyValue.class) - .newInstance(application, serconf); - } catch (Exception e) { - throw new RedkaleException(e); - } - } - - public void init(AnyValue config) throws Exception { - this.serverConf = config == null ? AnyValue.create() : config; - if (isSNCP()) { // SNCP协议 - String host = this.serverConf - .getValue("host", isWATCH() ? "127.0.0.1" : "0.0.0.0") - .replace("0.0.0.0", ""); - if (host.isEmpty()) { - host = application.localAddress.getAddress().getHostAddress(); - } - this.sncpAddress = new InetSocketAddress(host, this.serverConf.getIntValue("port")); - this.sncpGroup = application.getSncpRpcGroups().getGroup(this.sncpAddress); - // 单向SNCP服务不需要对等group - // if (this.sncpGroup == null) { - // throw new RedkaleException("Server (" + String.valueOf(config).replaceAll("\\s+", " ") + ") not found - // info"); - // } - } - // 单点服务不会有 sncpAddress、sncpGroup - if (this.sncpAddress != null) { - this.resourceFactory.register(RESNAME_SNCP_ADDRESS, this.sncpAddress); - this.resourceFactory.register(RESNAME_SNCP_ADDRESS, SocketAddress.class, this.sncpAddress); - this.resourceFactory.register(RESNAME_SNCP_ADDRESS, InetSocketAddress.class, this.sncpAddress); - this.resourceFactory.register( - RESNAME_SNCP_ADDRESS, - String.class, - this.sncpAddress.getHostString() + ":" + this.sncpAddress.getPort()); - } - if (this.sncpGroup != null) { - this.resourceFactory.register(RESNAME_SNCP_GROUP, this.sncpGroup); - } - { - // 设置root文件夹 - String webroot = this.serverConf.getValue("root", "root"); - File myroot = new File(webroot); - if (!webroot.contains(":") && !webroot.startsWith("/")) { - myroot = new File(System.getProperty(Application.RESNAME_APP_HOME), webroot); - } - - resourceFactory.register(Server.RESNAME_SERVER_ROOT, String.class, myroot.getCanonicalPath()); - resourceFactory.register(Server.RESNAME_SERVER_ROOT, File.class, myroot.getCanonicalFile()); - resourceFactory.register(Server.RESNAME_SERVER_ROOT, Path.class, myroot.toPath()); - - // 加入指定的classpath - Server.loadLib(serverClassLoader, logger, this.serverConf.getValue("lib", "")); - this.serverThread.setContextClassLoader(this.serverClassLoader); - } - // 必须要进行初始化, 构建Service时需要使用Context中的ExecutorService - server.init(this.serverConf); - if (this.sncpAddress != null) { // 初始化SncpClient - this.sncpAsyncGroup = new AsyncIOGroup( - "Redkale-SncpClient-IOThread-%s", - application.getWorkExecutor(), server.getBufferCapacity(), server.getBufferPoolSize()) - .skipClose(true); - this.sncpClient = new SncpClient( - server.getName(), - this.sncpAsyncGroup, - application.getNodeid(), - this.sncpAddress, - new ClientAddress(this.sncpAddress), - server.getNetprotocol(), - Utility.cpus(), - 1000); - } - - registerResTypeLoader(); // 给DataSource、CacheSource注册依赖注入时的监听回调事件。 - String interceptorClass = this.serverConf.getValue("interceptor", ""); - if (!interceptorClass.isEmpty()) { - Class clazz = serverClassLoader.loadClass(interceptorClass); - RedkaleClassLoader.putReflectionDeclaredConstructors(clazz, clazz.getName()); - this.interceptor = (NodeInterceptor) clazz.getDeclaredConstructor().newInstance(); - } - - ClassFilter serviceFilter = createServiceClassFilter(); - if (application.isSingletonMode()) { // singleton模式下只加载指定的Service - final String ssc = System.getProperty("redkale.singleton.serviceclass"); - final String extssc = System.getProperty("redkale.singleton.extserviceclasses"); - if (ssc != null) { - final List sscList = new ArrayList<>(); - sscList.add(ssc); - if (extssc != null && !extssc.isEmpty()) { - for (String s : extssc.split(",")) { - if (!s.isEmpty()) { - sscList.add(s); - } - } - } - serviceFilter.setExpectPredicate(c -> !sscList.contains(c)); - } - } - ClassFilter filterFilter = createFilterClassFilter(); - ClassFilter servletFilter = createServletClassFilter(); - List otherFilters = createOtherClassFilters(); - List filters = new ArrayList<>(); - if (serviceFilter != null) { - filters.add(serviceFilter); - } - if (filterFilter != null) { - filters.add(filterFilter); - } - if (servletFilter != null) { - filters.add(servletFilter); - } - if (otherFilters != null) { - filters.addAll(otherFilters); - } - long s = System.currentTimeMillis(); - application.loadClassByFilters(filters.toArray(new ClassFilter[filters.size()])); - long e = System.currentTimeMillis() - s; - logger.info(this.getClass().getSimpleName() + " load filter class in " + e + " ms"); - loadService(serviceFilter); // 必须在servlet之前 - loadOthers(otherFilters); - if (!application.isSingletonMode()) { // 非singleton模式下才加载Filter、Servlet - loadFilter(filterFilter); - loadServlet(servletFilter); - postLoadServlets(); - } - if (this.interceptor != null) { - this.resourceFactory.inject(this.interceptor); - } - } - - protected void loadOthers(List otherFilters) throws Exception {} - - protected abstract void loadFilter(ClassFilter filterFilter) throws Exception; - - protected abstract void loadServlet(ClassFilter servletFilter) throws Exception; - - private void registerResTypeLoader() { - // --------------------- 注册 Local AutoLoad(false) Service --------------------- - resourceFactory.register(new ResourceTypeLoader() { - @Override - public Object load( - ResourceFactory rf, - String srcResourceName, - final Object srcObj, - final String resourceName, - Field field, - final Object attachment) { - return loadResourceService(rf, srcResourceName, srcObj, resourceName, field, attachment); - } - - @Override - public Type resourceType() { - return Service.class; - } - }); - // ----------------------------- 注册 WebSocketNode ----------------------------- - final NodeServer self = this; - final ResourceFactory appResFactory = application.getResourceFactory(); - resourceFactory.register(new ResourceTypeLoader() { - @Override - public Object load( - ResourceFactory rf, - String srcResourceName, - final Object srcObj, - final String resourceName, - Field field, - final Object attachment) { - try { - if ((srcObj instanceof Service) && Sncp.isRemote((Service) srcObj)) { - return null; // 远程模式不得注入 - } - Service nodeService = rf.find(resourceName, WebSocketNode.class); - if (nodeService == null) { - final HashSet groups = new HashSet<>(); - if (groups.isEmpty() && isSNCP() && NodeServer.this.sncpGroup != null) { - groups.add(NodeServer.this.sncpGroup); - } - AsmMethodBoost methodBoost = - application.createAsmMethodBoost(false, WebSocketNodeService.class); - nodeService = Sncp.createLocalService( - serverClassLoader, - resourceName, - WebSocketNodeService.class, - methodBoost, - application.getResourceFactory(), - application.getSncpRpcGroups(), - sncpClient, - null, - (String) null, - (AnyValue) null); - (isSNCP() ? appResFactory : resourceFactory) - .register(resourceName, WebSocketNode.class, nodeService); - ((org.redkale.net.http.WebSocketNodeService) nodeService).setName(resourceName); - } - resourceFactory.inject(resourceName, nodeService, self); - field.set(srcObj, nodeService); - if (Sncp.isRemote(nodeService)) { - remoteServices.add(nodeService); - } else { - rf.inject(resourceName, nodeService); // 动态加载的Service也存在按需加载的注入资源 - localServices.add(nodeService); - if (!Sncp.isComponent(nodeService)) { - servletServices.add(nodeService); - } - } - return nodeService; - } catch (Exception e) { - logger.log(Level.SEVERE, "WebSocketNode inject error", e); - throw e instanceof RuntimeException ? (RuntimeException) e : new RedkaleException(e); - } - } - - @Override - public Type resourceType() { - return WebSocketNode.class; - } - - @Override - public boolean autoNone() { - return false; - } - }); - } - - // Service.class的ResourceTypeLoader - private Object loadResourceService( - ResourceFactory rf, - String srcResourceName, - Object srcObj, - String resourceName, - Field field, - Object attachment) { - final NodeServer self = this; - final ResourceFactory appResFactory = application.getResourceFactory(); - Class serviceImplClass = Service.class; - try { - serviceImplClass = (Class) field.getType(); - if (serviceImplClass.getAnnotation(Local.class) == null) { - return null; - } - if ((srcObj instanceof Service) && Sncp.isRemote((Service) srcObj)) { - return null; // 远程模式不得注入 AutoLoad Service - } - boolean auto = true; - AutoLoad al = serviceImplClass.getAnnotation(AutoLoad.class); - if (al != null) { - auto = al.value(); - } - org.redkale.util.AutoLoad al2 = serviceImplClass.getAnnotation(org.redkale.util.AutoLoad.class); - if (al2 != null) { - auto = al2.value(); - } - if (auto && !Utility.isAbstractOrInterface(serviceImplClass)) { - return null; - } - - // ResourceFactory resfactory = (isSNCP() ? appResFactory : resourceFactory); - Service service; - if (Modifier.isFinal(serviceImplClass.getModifiers()) || Sncp.isComponent(serviceImplClass)) { - service = (Service) serviceImplClass.getConstructor().newInstance(); - } else if (Utility.isAbstractOrInterface(serviceImplClass)) { // 没有具体实现类 - AsmMethodBoost methodBoost = application.createAsmMethodBoost(true, serviceImplClass); - MessageAgent mqAgent = appResFactory.find("", MessageAgent.class); - service = Sncp.createRemoteService( - serverClassLoader, - resourceName, - serviceImplClass, - methodBoost, - appResFactory, - application.getSncpRpcGroups(), - this.sncpClient, - mqAgent, - null, - null); - } else { - AsmMethodBoost methodBoost = application.createAsmMethodBoost(false, serviceImplClass); - service = Sncp.createLocalService( - serverClassLoader, - resourceName, - serviceImplClass, - methodBoost, - appResFactory, - application.getSncpRpcGroups(), - sncpClient, - null, - null, - null); - } - appResFactory.register(resourceName, serviceImplClass, service); - - field.set(srcObj, service); - rf.inject(resourceName, service, self); // 给其可能包含@Resource的字段赋值; - if (!application.isCompileMode() && !Sncp.isRemote(service)) { - service.init(null); - } - logger.info("Load Service(" + (Sncp.isRemote(service) ? "Remote" : "@Local") + " @AutoLoad service = " - + serviceImplClass.getSimpleName() + ", resourceName = '" + resourceName + "')"); - return service; - } catch (Exception e) { - logger.log( - Level.SEVERE, - "Load @AutoLoad(false) Service inject " + serviceImplClass + " to " + srcObj + " error", - e); - return null; - } - } - - private class ExpectServiceLoader implements ResourceTypeLoader { - - private final Class type; - - private final Class serviceImplClass; - - private final AtomicInteger serviceCount; - - private final SncpRpcGroups rpcGroups; - - private final FilterEntry entry; - - private final String group; - - private final boolean localMode; - - public ExpectServiceLoader( - Class type, - Class serviceImplClass, - AtomicInteger serviceCount, - SncpRpcGroups rpcGroups, - FilterEntry entry, - String group, - boolean localMode) { - this.type = type; - this.serviceImplClass = serviceImplClass; - this.serviceCount = serviceCount; - this.rpcGroups = rpcGroups; - this.entry = entry; - this.group = group; - this.localMode = localMode; - } - - @Override - public Object load( - ResourceFactory rf, - String srcResourceName, - final Object srcObj, - final String resourceName, - Field field, - final Object attachment) { - try { - final ResourceFactory appResourceFactory = application.getResourceFactory(); - ResourceFactory regFactory = isSNCP() ? application.getResourceFactory() : resourceFactory; - - if (Sncp.loadRemoteMethodActions(Sncp.getResourceType(serviceImplClass)) - .isEmpty() - && (serviceImplClass.getAnnotation(Priority.class) == null - && serviceImplClass.getAnnotation(javax.annotation.Priority.class) - == null)) { // class没有可用的方法且没有标记启动优先级的, 通常为BaseService - if (!serviceImplClass.getName().startsWith("org.redkale.") - && !serviceImplClass.getSimpleName().contains("Base")) { - logger.log( - Level.FINE, - serviceImplClass + " cannot load because not found less one public non-final method"); - } - return null; - } - RedkaleClassLoader.putReflectionPublicMethods(serviceImplClass.getName()); - MessageAgent mqAgent = getMessageAgent(entry.getProperty()); - Service service; - if (Sncp.isComponent(serviceImplClass)) { // Component - RedkaleClassLoader.putReflectionPublicConstructors(serviceImplClass, serviceImplClass.getName()); - if (!acceptsComponent(serviceImplClass)) { - return null; - } - service = serviceImplClass.getDeclaredConstructor().newInstance(); - } else if (srcObj instanceof WebSocketServlet || localMode) { // 本地模式 - AsmMethodBoost methodBoost = application.createAsmMethodBoost(false, serviceImplClass); - service = Sncp.createLocalService( - serverClassLoader, - resourceName, - serviceImplClass, - methodBoost, - appResourceFactory, - rpcGroups, - sncpClient, - mqAgent, - group, - entry.getProperty()); - } else { - AsmMethodBoost methodBoost = application.createAsmMethodBoost(true, serviceImplClass); - service = Sncp.createRemoteService( - serverClassLoader, - resourceName, - serviceImplClass, - methodBoost, - appResourceFactory, - rpcGroups, - sncpClient, - mqAgent, - group, - entry.getProperty()); - } - final Class restype = Sncp.getResourceType(service); - if (rf.find(resourceName, restype) == null) { - regFactory.register(resourceName, restype, service); - } else if (isSNCP() && !entry.isAutoload()) { - throw new RedkaleException(restype.getSimpleName() + "(class:" + serviceImplClass.getName() - + ", name:" + resourceName + ", group:" + group + ") is repeat."); - } - if (Sncp.isRemote(service)) { - remoteServices.add(service); - if (mqAgent != null) { - sncpRemoteAgents.put(mqAgent.getName(), mqAgent); - } - } else { - if (field != null) { - rf.inject(resourceName, service); // 动态加载的Service也存在按需加载的注入资源 - } - localServices.add(service); - if (!Sncp.isComponent(service)) { - servletServices.add(service); - } - } - serviceCount.incrementAndGet(); - return service; - } catch (Exception e) { - throw e instanceof RuntimeException ? (RuntimeException) e : new RedkaleException(e); - } - } - - @Override - public Type resourceType() { - return type; - } - } - - @SuppressWarnings("unchecked") - protected void loadService(ClassFilter serviceFilter) throws Exception { - Objects.requireNonNull(serviceFilter); - final long starts = System.currentTimeMillis(); - final Set> entrys = (Set) serviceFilter.getAllFilterEntrys(); - final SncpRpcGroups rpcGroups = application.getSncpRpcGroups(); - final AtomicInteger serviceCount = new AtomicInteger(); - for (FilterEntry entry : entrys) { // service实现类 - final Class serviceImplClass = entry.getType(); - if (Modifier.isFinal(serviceImplClass.getModifiers())) { - continue; // 修饰final的类跳过 - } - if (!Modifier.isPublic(serviceImplClass.getModifiers())) { - continue; - } - if (Sncp.isSncpDyn(serviceImplClass)) { - continue; // 动态生成的跳过 - } - if (entry.isExpect()) { - if (Modifier.isAbstract(serviceImplClass.getModifiers())) { - continue; // 修饰abstract的类跳过 - } - if (DataSource.class.isAssignableFrom(serviceImplClass)) { - continue; - } - if (CacheSource.class.isAssignableFrom(serviceImplClass)) { - continue; - } - } - if (entry.getName().contains(Resource.PARENT_NAME)) { - throw new RedkaleException( - " value cannot contains '" + Resource.PARENT_NAME + "' in " + entry.getProperty()); - } - if (!entry.isEmptyGroup() && !entry.isRemote() && !rpcGroups.containsGroup(entry.getGroup())) { - throw new RedkaleException("Not found group(" + entry.getGroup() + ")"); - } - Service oldOther = resourceFactory.find(entry.getName(), serviceImplClass); - if (oldOther != null) { // Server加载Service时需要判断是否已在其他协议服务中加载 - if (!Sncp.isRemote(oldOther)) { - if (!Sncp.isComponent(oldOther)) { - servletServices.add(oldOther); - } - } - continue; - } - boolean isLocalGroup0 = rpcGroups.isLocalGroup(this.sncpGroup, this.sncpAddress, entry); - final String group = isLocalGroup0 ? null : entry.getGroup(); - final boolean localMode = serviceImplClass.getAnnotation(Local.class) != null || isLocalGroup0; // 本地模式 - if ((localMode || Sncp.isComponent(serviceImplClass)) && Utility.isAbstractOrInterface(serviceImplClass)) { - continue; // 本地模式或Component不能实例化接口和抽象类的Service类 - } - if (entry.isExpect()) { - Class t = ResourceFactory.getResourceType(entry.getType()); - if (resourceFactory.findResourceTypeLoader(t) == null) { - resourceFactory.register(new ExpectServiceLoader( - t, serviceImplClass, serviceCount, rpcGroups, entry, group, localMode)); - } - } else { - ExpectServiceLoader resourceLoader = new ExpectServiceLoader( - serviceImplClass, serviceImplClass, serviceCount, rpcGroups, entry, group, localMode); - resourceLoader.load(resourceFactory, null, null, entry.getName(), null, false); - } - } - long et = System.currentTimeMillis(); - if (serviceCdl != null) { - serviceCdl.countDown(); - serviceCdl.await(); - } - logger.info(this.getClass().getSimpleName() + " construct services in " + (et - starts) + " ms and await " - + (System.currentTimeMillis() - et) + " ms"); - - final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null; - // ---------------- inject ---------------- - new ArrayList<>(localServices).forEach(y -> { - resourceFactory.inject(Sncp.getResourceName(y), y, NodeServer.this); - }); - // 远程模式不可inject, 里面存在@Resource.required=true依赖 - // new ArrayList<>(remoteServices).forEach(y -> { - // resourceFactory.inject(Sncp.getResourceName(y), y, NodeServer.this); - // calcMaxLength(y); - // }); - - if (sb != null) { - remoteServices.forEach(y -> { - sb.append(Sncp.toSimpleString(y, maxNameLength, maxTypeLength)) - .append(" load and inject") - .append(LINE_SEPARATOR); - }); - } - if (isSNCP() && !sncpRemoteAgents.isEmpty()) { - sncpRemoteAgents.values().forEach(agent -> { - // mqAgent.putSncpResp((NodeSncpServer) this); - // mqAgent.startSncpRespConsumer(); - }); - } - // ----------------- init ----------------- - List swlist = new ArrayList<>(localServices); - swlist.forEach(y -> calcMaxLength(y)); - swlist.sort((o1, o2) -> { - Priority p1 = o1.getClass().getAnnotation(Priority.class); - Priority p2 = o2.getClass().getAnnotation(Priority.class); - int v = (p2 == null ? 0 : p2.value()) - (p1 == null ? 0 : p1.value()); - if (v != 0) { - return v; - } - int v1 = o1.getClass().getAnnotation(Component.class) == null ? -1 : 1; - int v2 = o2.getClass().getAnnotation(Component.class) == null ? -1 : 1; - if (v1 != v2) { - return v1 - v2; - } - int rs = Sncp.getResourceType(o1) - .getName() - .compareTo(Sncp.getResourceType(o2).getName()); - if (rs == 0) { - rs = Sncp.getResourceName(o1).compareTo(Sncp.getResourceName(o2)); - } - return rs; - }); - localServices.clear(); - localServices.addAll(swlist); - // this.loadPersistData(); - long preinits = System.currentTimeMillis(); - preInitServices(localServices, remoteServices, servletServices); - long preinite = System.currentTimeMillis() - preinits; - final List slist = sb == null ? null : new CopyOnWriteArrayList<>(); - if (application.isCompileMode()) { - localServices.stream().forEach(y -> { - String serstr = Sncp.toSimpleString(y, maxNameLength, maxTypeLength); - if (slist != null) { - slist.add(new StringBuilder() - .append(serstr) - .append(" load") - .append(LINE_SEPARATOR) - .toString()); - } - }); - } else { - localServices.stream().forEach(y -> { - long s = System.currentTimeMillis(); - application.onServicePreInit(y); - y.init(Sncp.getResourceConf(y)); - application.onServicePostInit(y); - long e = System.currentTimeMillis() - s; - if (slist != null) { - String serstr = Sncp.toSimpleString(y, maxNameLength, maxTypeLength); - slist.add(new StringBuilder() - .append(serstr) - .append(" load and init in ") - .append(e < 10 ? " " : (e < 100 ? " " : "")) - .append(e) - .append(" ms") - .append(LINE_SEPARATOR) - .toString()); - } - }); - localServices.stream().forEach(y -> { - if (Sncp.isComponent(y)) { - long s = System.currentTimeMillis(); - boolean rs = interceptComponent(y); - long e = System.currentTimeMillis() - s; - if (rs && slist != null) { - String serstr = Sncp.toSimpleString(y, maxNameLength, maxTypeLength); - slist.add(new StringBuilder() - .append(serstr) - .append(" component-start in ") - .append(e < 10 ? " " : (e < 100 ? " " : "")) - .append(e) - .append(" ms") - .append(LINE_SEPARATOR) - .toString()); - } - } - }); - } - if (slist != null && sb != null) { - List wlist = - new ArrayList<>(slist); // 直接使用CopyOnWriteArrayList偶尔会出现莫名的异常(CopyOnWriteArrayList源码1185行) - for (String s : wlist) { - sb.append(s); - } - sb.append("All ") - .append(localServices.size()) - .append(" Services load in ") - .append(System.currentTimeMillis() - starts) - .append(" ms"); - } - if (sb != null && preinite > 10) { - sb.append(ClusterAgent.class.getSimpleName()) - .append(" register in ") - .append(preinite) - .append(" ms" + LINE_SEPARATOR); - } - if (sb != null && sb.length() > 0) { - logger.log(Level.INFO, sb.toString()); - } - } - - private void calcMaxLength(Service y) { // 计算toString中的长度 - String n = Sncp.getResourceName(y); - maxNameLength = Math.max(maxNameLength, n == null ? 0 : n.length()); - maxTypeLength = - Math.max(maxTypeLength, Sncp.getResourceType(y).getName().length() + 1); - } - - protected boolean acceptsComponent(Class serviceImplClass) { - if (Modifier.isAbstract(serviceImplClass.getModifiers()) - || Modifier.isInterface(serviceImplClass.getModifiers())) { - return false; - } - return true; - } - - protected boolean interceptComponent(Service service) { - return false; - } - - protected MessageAgent getMessageAgent(AnyValue serviceConf) { - MessageAgent agent = null; - if (serviceConf != null && serviceConf.getValue("mq") != null) { - agent = application.getResourceFactory().find(serviceConf.getValue("mq"), MessageAgent.class); - if (agent != null) { - messageAgents.put(agent.getName(), agent); - } - } - return agent; - } - - // Service.init执行之前调用 - protected void preInitServices( - Set localServices, Set remoteServices, Set servletServices) { - final ClusterAgent cluster = application.getResourceFactory().find("", ClusterAgent.class); - if (!application.isCompileMode() && cluster != null) { - NodeProtocol pros = getClass().getAnnotation(NodeProtocol.class); - String protocol = pros.value().toUpperCase(); - if (!cluster.containsProtocol(protocol)) { - return; - } - if (!cluster.containsPort(server.getSocketAddress().getPort())) { - return; - } - cluster.register(this, protocol, localServices, remoteServices, servletServices); - } - } - - // loadServlet执行之后调用 - protected void postLoadServlets() {} - - // Service.destroy执行之前调用 - protected void preDestroyServices( - Set localServices, Set remoteServices, Set servletServices) { - final ClusterAgent cluster = application.getResourceFactory().find("", ClusterAgent.class); - if (!application.isCompileMode() && cluster != null) { // 服务注销 - NodeProtocol pros = getClass().getAnnotation(NodeProtocol.class); - String protocol = pros.value().toUpperCase(); - if (cluster.containsProtocol(protocol) - && cluster.containsPort(server.getSocketAddress().getPort())) { - cluster.deregister(this, protocol, localServices, remoteServices, servletServices); - afterClusterDeregisterOnPreDestroyServices(cluster, protocol); - } - } - if (!application.isCompileMode() && !this.messageAgents.isEmpty()) { // MQ - } - } - - protected void afterClusterDeregisterOnPreDestroyServices(ClusterAgent cluster, String protocol) {} - - // Server.start执行之后调用 - protected void postStartServer( - Set localServices, Set remoteServices, Set servletServices) {} - - protected abstract ClassFilter createFilterClassFilter(); - - protected abstract ClassFilter createServletClassFilter(); - - protected List createOtherClassFilters() { - return null; - } - - protected ClassFilter createServiceClassFilter() { - return createClassFilter( - this.sncpGroup, - null, - Service.class, - (!isSNCP() && application.watching) ? null : new Class[] {org.redkale.watch.WatchService.class}, - Annotation.class, - "services", - "service"); - } - - protected ClassFilter createClassFilter( - final String localGroup, - Class ref, - Class inter, - Class[] excludeSuperClasses, - Class ref2, - String properties, - String property) { - ClassFilter cf = new ClassFilter(this.serverClassLoader, ref, inter, excludeSuperClasses, null); - if (properties == null) { - cf.setRefused(true); - return cf; - } - if (this.serverConf == null) { - cf.setRefused(true); - return cf; - } - AnyValue[] proplist = this.serverConf.getAnyValues(properties); - if (proplist == null || proplist.length < 1) { - cf.setRefused(true); - return cf; - } - cf = null; - for (AnyValue list : proplist) { - AnyValueWriter prop = null; - String sc = list.getValue("group"); - String mq = list.getValue("mq"); - if (sc != null) { - sc = sc.trim(); - } - if (sc == null) { - sc = localGroup; - } - if (sc != null || mq != null) { - prop = new AnyValueWriter(); - if (sc != null) { - prop.addValue("group", sc); - } - if (mq != null) { - prop.addValue("mq", mq); - } - } - ClassFilter filter = new ClassFilter(this.serverClassLoader, ref, inter, excludeSuperClasses, prop); - for (AnyValue av : list.getAnyValues(property)) { // 节点 - final AnyValue[] items = av.getAnyValues("property"); - if (items.length > 0) { // 存在 节点 - AnyValueWriter dav = AnyValueWriter.create(); - final AnyValue.Entry[] strings = av.getStringEntrys(); - if (strings != null) { // 将节点的属性值传给dav - for (AnyValue.Entry en : strings) { - dav.addValue(en.name, en.getValue()); - } - } - final AnyValue.Entry[] anys = av.getAnyEntrys(); - if (anys != null) { - for (AnyValue.Entry en : anys) { // 将节点的非property属性节点传给dav - if (!"property".equals(en.name)) { - dav.addValue(en.name, en.getValue()); - } - } - } - AnyValueWriter ps = AnyValueWriter.create(); - for (AnyValue item : items) { - ps.addValue(item.getValue("name"), item.getValue("value")); - } - dav.addValue("properties", ps); - av = dav; - } - if (!av.getBoolValue("ignore", false)) { - filter.filter(av, av.getValue("value"), false); - } - } - if (list.getBoolValue("autoload", true)) { - String includes = list.getValue("includes", ""); - String excludes = list.getValue("excludes", ""); - filter.setIncludePatterns(includes.split(";")); - filter.setExcludePatterns(excludes.split(";")); - } else if (ref2 == null || ref2 == Annotation.class) { // service如果是autoload=false则不需要加载 - filter.setRefused(true); - } else if (ref2 != Annotation.class) { - filter.setAnnotationClass(ref2); - } - cf = (cf == null) ? filter : cf.or(filter); - } - return cf; - } - - public abstract InetSocketAddress getSocketAddress(); - - public boolean isSNCP() { - return false; - } - - public boolean isWATCH() { - return false; - } - - public Application getApplication() { - return application; - } - - public ResourceFactory getResourceFactory() { - return resourceFactory; - } - - public RedkaleClassLoader getServerClassLoader() { - return serverClassLoader; - } - - public void setServerClassLoader(RedkaleClassLoader serverClassLoader) { - Objects.requireNonNull(this.serverClassLoader); - this.serverClassLoader = serverClassLoader; - this.serverThread.setContextClassLoader(serverClassLoader); - } - - public InetSocketAddress getSncpAddress() { - return sncpAddress; - } - - public AnyValue getServerConf() { - return serverConf; - } - - public Logger getLogger() { - return logger; - } - - public String getSncpGroup() { - return sncpGroup; - } - - public void start() throws IOException { - if (interceptor != null) { - interceptor.preStart(this); - } - if (this.sncpAsyncGroup != null) { - this.sncpAsyncGroup.start(); - } - server.start(); - postStartServer(localServices, remoteServices, servletServices); - } - - 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); - preDestroyServices(localServices, remoteServices, servletServices); - localServices.forEach(y -> { - long s = System.currentTimeMillis(); - if (finest) { - logger.finest(Sncp.getResourceType(y) + " is destroying"); - } - application.onServicePreDestroy(y); - y.destroy(Sncp.getResourceConf(y)); - if (finest) { - logger.finest(Sncp.getResourceType(y) + " was destroyed"); - } - application.onServicePostDestroy(y); - long e = System.currentTimeMillis() - s; - if (e > 2 && sb != null) { - sb.append(Sncp.toSimpleString(y, maxNameLength, maxTypeLength)) - .append(" destroy ") - .append(e) - .append("ms") - .append(LINE_SEPARATOR); - } - }); - if (sb != null && sb.length() > 0) { - logger.log(Level.INFO, sb.toString()); - } - if (this.sncpAsyncGroup != null) { - long s = System.currentTimeMillis(); - this.sncpAsyncGroup.dispose(); - logger.info("SncpAsyncGroup destroy in " + (System.currentTimeMillis() - s) + " ms"); - } - if (this.sncpClient != null) { - long s = System.currentTimeMillis(); - this.sncpClient.close(); - logger.info("SncpClient close in " + (System.currentTimeMillis() - s) + " ms"); - } - server.shutdown(); - } - - public List command(String cmd, String[] params) throws IOException { - final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null; - List results = new ArrayList<>(); - localServices.forEach(y -> { - Set methods = new HashSet<>(); - Class loop = y.getClass(); - // do { public方法不用递归 - for (Method m : loop.getMethods()) { - Command c = m.getAnnotation(Command.class); - org.redkale.util.Command c2 = m.getAnnotation(org.redkale.util.Command.class); - if (c == null && c2 == null) { - continue; - } - if (Modifier.isStatic(m.getModifiers())) { - logger.log(Level.WARNING, m + " is static on @Command"); - continue; - } - if (m.getParameterCount() != 1 && m.getParameterCount() != 2) { - logger.log(Level.WARNING, m + " parameter count = " + m.getParameterCount() + " on @Command"); - continue; - } - if (m.getParameterTypes()[0] != String.class) { - logger.log(Level.WARNING, m + " parameters[0] type is not String.class on @Command"); - continue; - } - if (m.getParameterCount() == 2 && m.getParameterTypes()[1] != String[].class) { - logger.log(Level.WARNING, m + " parameters[1] type is not String[].class on @Command"); - continue; - } - if (!c.value().isEmpty() && !c.value().equalsIgnoreCase(cmd)) { - continue; - } - methods.add(m); - } - // } while ((loop = loop.getSuperclass()) != Object.class); - if (methods.isEmpty()) { - return; - } - long s = System.currentTimeMillis(); - Method one = null; - try { - for (Method method : methods) { - one = method; - Object r = method.getParameterCount() == 2 ? method.invoke(y, cmd, params) : method.invoke(y, cmd); - if (r != null) { - results.add(r); - } - } - } catch (Exception ex) { - logger.log(Level.SEVERE, one + " run error, cmd = " + cmd, ex); - } - long e = System.currentTimeMillis() - s; - if (e > 10 && sb != null) { - sb.append(Sncp.toSimpleString(y, maxNameLength, maxTypeLength)) - .append(" command (") - .append(cmd) - .append(") ") - .append(e) - .append("ms") - .append(LINE_SEPARATOR); - } - }); - if (sb != null && sb.length() > 0) { - logger.log(Level.INFO, sb.toString()); - } - return results; - } - - public T getServer() { - return (T) server; - } - - public Set getServletServices() { - return new LinkedHashSet<>(servletServices); - } - - public Set getLocalServices() { - return new LinkedHashSet<>(localServices); - } - - public Set getRemoteServices() { - return new LinkedHashSet<>(remoteServices); - } - - public String getThreadName() { - return this.threadName; - } -} +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.boot; + +import static org.redkale.boot.Application.*; + +import java.io.*; +import java.lang.annotation.Annotation; +import java.lang.reflect.*; +import java.net.*; +import java.nio.file.Path; +import java.util.*; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.logging.*; +import org.redkale.annotation.*; +import org.redkale.annotation.AutoLoad; +import org.redkale.annotation.Command; +import org.redkale.asm.AsmMethodBoost; +import org.redkale.boot.ClassFilter.FilterEntry; +import org.redkale.cluster.spi.ClusterAgent; +import org.redkale.inject.ResourceFactory; +import org.redkale.inject.ResourceTypeLoader; +import org.redkale.mq.spi.MessageAgent; +import org.redkale.net.*; +import org.redkale.net.Filter; +import org.redkale.net.client.ClientAddress; +import org.redkale.net.http.*; +import org.redkale.net.http.WebSocketNodeService; +import org.redkale.net.sncp.*; +import org.redkale.service.*; +import org.redkale.source.*; +import org.redkale.util.*; + +/** + * Server节点的初始化配置类 + * + *

详情见: https://redkale.org + * + * @author zhangjx + */ +@SuppressWarnings("unchecked") +public abstract class NodeServer { + + // INFO日志的换行符 + public static final String LINE_SEPARATOR = "\r\n"; + + // 日志输出对象 + protected final Logger logger; + + // 进程主类 + protected final Application application; + + // 依赖注入工厂类 + protected final ResourceFactory resourceFactory; + + // 当前Server对象 + protected final Server server; + + // ClassLoader + protected RedkaleClassLoader serverClassLoader; + + protected final Thread serverThread; + + // server节点的配置 + protected AnyValue serverConf; + + protected final String threadName; + + // 加载server节点后的拦截器 + protected NodeInterceptor interceptor; + + // 本地模式的Service对象集合 + protected final Set localServices = new LinkedHashSet<>(); + + // 远程模式的Service对象集合 + protected final Set remoteServices = new LinkedHashSet<>(); + + // 需要转换成Servlet的Service对象集合, Component的Service不在其内 + protected final Set servletServices = new LinkedHashSet<>(); + + // 存在SncpServlet、RestServlet + protected final Map dynServletMap = new LinkedHashMap<>(); + + // MessageAgent对象集合 + protected final Map messageAgents = new HashMap<>(); + + // 需要远程模式Service的MessageAgent对象集合 + protected final Map sncpRemoteAgents = new HashMap<>(); + + // 当前Server的SNCP协议的组 + protected String sncpGroup = null; + + // 当前Server的SNCP服务Client + protected SncpClient sncpClient; + + // SncpClient的AsyncGroup + private AsyncIOGroup sncpAsyncGroup; + + // SNCP服务的地址, 非SNCP为null + private InetSocketAddress sncpAddress; + + private volatile int maxTypeLength = 0; + + private volatile int maxNameLength = 0; + + CountDownLatch serviceCdl; + + public NodeServer(Application application, Server server) { + this.threadName = Thread.currentThread().getName(); + this.application = application; + this.server = server; + this.resourceFactory = server.getResourceFactory(); + this.logger = Logger.getLogger(this.getClass().getSimpleName()); + if (application.isCompileMode() + || application.getServerClassLoader() instanceof RedkaleClassLoader.RedkaleCacheClassLoader) { + this.serverClassLoader = application.getServerClassLoader(); + } else { + this.serverClassLoader = new RedkaleClassLoader(application.getServerClassLoader()); + } + Thread.currentThread().setContextClassLoader(this.serverClassLoader); + this.serverThread = Thread.currentThread(); + this.server.setServerClassLoader(serverClassLoader); + } + + public static NodeServer create(Class clazz, Application application, AnyValue serconf) { + try { + RedkaleClassLoader.putReflectionDeclaredConstructors( + clazz, clazz.getName(), Application.class, AnyValue.class); + return clazz.getDeclaredConstructor(Application.class, AnyValue.class) + .newInstance(application, serconf); + } catch (Exception e) { + throw new RedkaleException(e); + } + } + + public void init(AnyValue config) throws Exception { + this.serverConf = config == null ? AnyValue.create() : config; + if (isSNCP()) { // SNCP协议 + String host = this.serverConf + .getValue("host", isWATCH() ? "127.0.0.1" : "0.0.0.0") + .replace("0.0.0.0", ""); + if (host.isEmpty()) { + host = application.localAddress.getAddress().getHostAddress(); + } + this.sncpAddress = new InetSocketAddress(host, this.serverConf.getIntValue("port")); + this.sncpGroup = application.getSncpRpcGroups().getGroup(this.sncpAddress); + // 单向SNCP服务不需要对等group + // if (this.sncpGroup == null) { + // throw new RedkaleException("Server (" + String.valueOf(config).replaceAll("\\s+", " ") + ") not found + // info"); + // } + } + // 单点服务不会有 sncpAddress、sncpGroup + if (this.sncpAddress != null) { + this.resourceFactory.register(RESNAME_SNCP_ADDRESS, this.sncpAddress); + this.resourceFactory.register(RESNAME_SNCP_ADDRESS, SocketAddress.class, this.sncpAddress); + this.resourceFactory.register(RESNAME_SNCP_ADDRESS, InetSocketAddress.class, this.sncpAddress); + this.resourceFactory.register( + RESNAME_SNCP_ADDRESS, + String.class, + this.sncpAddress.getHostString() + ":" + this.sncpAddress.getPort()); + } + if (this.sncpGroup != null) { + this.resourceFactory.register(RESNAME_SNCP_GROUP, this.sncpGroup); + } + { + // 设置root文件夹 + String webroot = this.serverConf.getValue("root", "root"); + File myroot = new File(webroot); + if (!webroot.contains(":") && !webroot.startsWith("/")) { + myroot = new File(System.getProperty(Application.RESNAME_APP_HOME), webroot); + } + + resourceFactory.register(Server.RESNAME_SERVER_ROOT, String.class, myroot.getCanonicalPath()); + resourceFactory.register(Server.RESNAME_SERVER_ROOT, File.class, myroot.getCanonicalFile()); + resourceFactory.register(Server.RESNAME_SERVER_ROOT, Path.class, myroot.toPath()); + + // 加入指定的classpath + Server.loadLib(serverClassLoader, logger, this.serverConf.getValue("lib", "")); + this.serverThread.setContextClassLoader(this.serverClassLoader); + } + // 必须要进行初始化, 构建Service时需要使用Context中的ExecutorService + server.init(this.serverConf); + if (this.sncpAddress != null) { // 初始化SncpClient + this.sncpAsyncGroup = new AsyncIOGroup( + "Redkale-SncpClient-IOThread-%s", + application.getWorkExecutor(), server.getBufferCapacity(), server.getBufferPoolSize()) + .skipClose(true); + this.sncpClient = new SncpClient( + server.getName(), + this.sncpAsyncGroup, + application.getNodeid(), + this.sncpAddress, + new ClientAddress(this.sncpAddress), + server.getNetprotocol(), + Utility.cpus(), + 1000); + } + + registerResTypeLoader(); // 给DataSource、CacheSource注册依赖注入时的监听回调事件。 + String interceptorClass = this.serverConf.getValue("interceptor", ""); + if (!interceptorClass.isEmpty()) { + Class clazz = serverClassLoader.loadClass(interceptorClass); + RedkaleClassLoader.putReflectionDeclaredConstructors(clazz, clazz.getName()); + this.interceptor = (NodeInterceptor) clazz.getDeclaredConstructor().newInstance(); + } + + ClassFilter serviceFilter = createServiceClassFilter(); + if (application.isSingletonMode()) { // singleton模式下只加载指定的Service + final String ssc = System.getProperty("redkale.singleton.serviceclass"); + final String extssc = System.getProperty("redkale.singleton.extserviceclasses"); + if (ssc != null) { + final List sscList = new ArrayList<>(); + sscList.add(ssc); + if (extssc != null && !extssc.isEmpty()) { + for (String s : extssc.split(",")) { + if (!s.isEmpty()) { + sscList.add(s); + } + } + } + serviceFilter.setExpectPredicate(c -> !sscList.contains(c)); + } + } + ClassFilter filterFilter = createFilterClassFilter(); + ClassFilter servletFilter = createServletClassFilter(); + List otherFilters = createOtherClassFilters(); + List filters = new ArrayList<>(); + if (serviceFilter != null) { + filters.add(serviceFilter); + } + if (filterFilter != null) { + filters.add(filterFilter); + } + if (servletFilter != null) { + filters.add(servletFilter); + } + if (otherFilters != null) { + filters.addAll(otherFilters); + } + long s = System.currentTimeMillis(); + application.loadClassByFilters(filters.toArray(new ClassFilter[filters.size()])); + long e = System.currentTimeMillis() - s; + logger.info(this.getClass().getSimpleName() + " load filter class in " + e + " ms"); + loadService(serviceFilter); // 必须在servlet之前 + loadOthers(otherFilters); + if (!application.isSingletonMode()) { // 非singleton模式下才加载Filter、Servlet + loadFilter(filterFilter); + loadServlet(servletFilter); + postLoadServlets(); + } + if (this.interceptor != null) { + this.resourceFactory.inject(this.interceptor); + } + } + + protected void loadOthers(List otherFilters) throws Exception {} + + protected abstract void loadFilter(ClassFilter filterFilter) throws Exception; + + protected abstract void loadServlet(ClassFilter servletFilter) throws Exception; + + private void registerResTypeLoader() { + // --------------------- 注册 Local AutoLoad(false) Service --------------------- + resourceFactory.register(new ResourceTypeLoader() { + @Override + public Object load( + ResourceFactory rf, + String srcResourceName, + final Object srcObj, + final String resourceName, + Field field, + final Object attachment) { + return loadResourceService(rf, srcResourceName, srcObj, resourceName, field, attachment); + } + + @Override + public Type resourceType() { + return Service.class; + } + }); + // ----------------------------- 注册 WebSocketNode ----------------------------- + final NodeServer self = this; + final ResourceFactory appResFactory = application.getResourceFactory(); + resourceFactory.register(new ResourceTypeLoader() { + @Override + public Object load( + ResourceFactory rf, + String srcResourceName, + final Object srcObj, + final String resourceName, + Field field, + final Object attachment) { + try { + if ((srcObj instanceof Service) && Sncp.isRemote((Service) srcObj)) { + return null; // 远程模式不得注入 + } + Service nodeService = rf.find(resourceName, WebSocketNode.class); + if (nodeService == null) { + final HashSet groups = new HashSet<>(); + if (groups.isEmpty() && isSNCP() && NodeServer.this.sncpGroup != null) { + groups.add(NodeServer.this.sncpGroup); + } + AsmMethodBoost methodBoost = + application.createAsmMethodBoost(false, WebSocketNodeService.class); + nodeService = Sncp.createLocalService( + serverClassLoader, + resourceName, + WebSocketNodeService.class, + methodBoost, + application.getResourceFactory(), + application.getSncpRpcGroups(), + sncpClient, + null, + (String) null, + (AnyValue) null); + (isSNCP() ? appResFactory : resourceFactory) + .register(resourceName, WebSocketNode.class, nodeService); + ((org.redkale.net.http.WebSocketNodeService) nodeService).setName(resourceName); + } + resourceFactory.inject(resourceName, nodeService, self); + field.set(srcObj, nodeService); + if (Sncp.isRemote(nodeService)) { + remoteServices.add(nodeService); + } else { + rf.inject(resourceName, nodeService); // 动态加载的Service也存在按需加载的注入资源 + localServices.add(nodeService); + if (!Sncp.isComponent(nodeService)) { + servletServices.add(nodeService); + } + } + return nodeService; + } catch (Exception e) { + logger.log(Level.SEVERE, "WebSocketNode inject error", e); + throw e instanceof RuntimeException ? (RuntimeException) e : new RedkaleException(e); + } + } + + @Override + public Type resourceType() { + return WebSocketNode.class; + } + + @Override + public boolean autoNone() { + return false; + } + }); + } + + // Service.class的ResourceTypeLoader + private Object loadResourceService( + ResourceFactory rf, + String srcResourceName, + Object srcObj, + String resourceName, + Field field, + Object attachment) { + final NodeServer self = this; + final ResourceFactory appResFactory = application.getResourceFactory(); + Class serviceImplClass = Service.class; + try { + serviceImplClass = (Class) field.getType(); + if (serviceImplClass.getAnnotation(Local.class) == null) { + return null; + } + if ((srcObj instanceof Service) && Sncp.isRemote((Service) srcObj)) { + return null; // 远程模式不得注入 AutoLoad Service + } + boolean auto = true; + AutoLoad al = serviceImplClass.getAnnotation(AutoLoad.class); + if (al != null) { + auto = al.value(); + } + org.redkale.util.AutoLoad al2 = serviceImplClass.getAnnotation(org.redkale.util.AutoLoad.class); + if (al2 != null) { + auto = al2.value(); + } + if (auto && !Utility.isAbstractOrInterface(serviceImplClass)) { + return null; + } + + // ResourceFactory resfactory = (isSNCP() ? appResFactory : resourceFactory); + Service service; + if (Modifier.isFinal(serviceImplClass.getModifiers()) || Sncp.isComponent(serviceImplClass)) { + service = (Service) serviceImplClass.getConstructor().newInstance(); + } else if (Utility.isAbstractOrInterface(serviceImplClass)) { // 没有具体实现类 + AsmMethodBoost methodBoost = application.createAsmMethodBoost(true, serviceImplClass); + MessageAgent mqAgent = appResFactory.find("", MessageAgent.class); + service = Sncp.createRemoteService( + serverClassLoader, + resourceName, + serviceImplClass, + methodBoost, + appResFactory, + application.getSncpRpcGroups(), + this.sncpClient, + mqAgent, + null, + null); + } else { + AsmMethodBoost methodBoost = application.createAsmMethodBoost(false, serviceImplClass); + service = Sncp.createLocalService( + serverClassLoader, + resourceName, + serviceImplClass, + methodBoost, + appResFactory, + application.getSncpRpcGroups(), + sncpClient, + null, + null, + null); + } + appResFactory.register(resourceName, serviceImplClass, service); + + field.set(srcObj, service); + rf.inject(resourceName, service, self); // 给其可能包含@Resource的字段赋值; + if (!application.isCompileMode() && !Sncp.isRemote(service)) { + service.init(null); + } + logger.info("Load Service(" + (Sncp.isRemote(service) ? "Remote" : "@Local") + " @AutoLoad service = " + + serviceImplClass.getSimpleName() + ", resourceName = '" + resourceName + "')"); + return service; + } catch (Exception e) { + logger.log( + Level.SEVERE, + "Load @AutoLoad(false) Service inject " + serviceImplClass + " to " + srcObj + " error", + e); + return null; + } + } + + private class ExpectServiceLoader implements ResourceTypeLoader { + + private final Class type; + + private final Class serviceImplClass; + + private final AtomicInteger serviceCount; + + private final SncpRpcGroups rpcGroups; + + private final FilterEntry entry; + + private final String group; + + private final boolean localMode; + + public ExpectServiceLoader( + Class type, + Class serviceImplClass, + AtomicInteger serviceCount, + SncpRpcGroups rpcGroups, + FilterEntry entry, + String group, + boolean localMode) { + this.type = type; + this.serviceImplClass = serviceImplClass; + this.serviceCount = serviceCount; + this.rpcGroups = rpcGroups; + this.entry = entry; + this.group = group; + this.localMode = localMode; + } + + @Override + public Object load( + ResourceFactory rf, + String srcResourceName, + final Object srcObj, + final String resourceName, + Field field, + final Object attachment) { + try { + final ResourceFactory appResourceFactory = application.getResourceFactory(); + ResourceFactory regFactory = isSNCP() ? application.getResourceFactory() : resourceFactory; + + if (Sncp.loadRemoteMethodActions(Sncp.getResourceType(serviceImplClass)) + .isEmpty() + && (serviceImplClass.getAnnotation(Priority.class) == null + && serviceImplClass.getAnnotation(javax.annotation.Priority.class) + == null)) { // class没有可用的方法且没有标记启动优先级的, 通常为BaseService + if (!serviceImplClass.getName().startsWith("org.redkale.") + && !serviceImplClass.getSimpleName().contains("Base")) { + logger.log( + Level.FINE, + serviceImplClass + " cannot load because not found less one public non-final method"); + } + return null; + } + RedkaleClassLoader.putReflectionPublicMethods(serviceImplClass.getName()); + MessageAgent mqAgent = getMessageAgent(entry.getProperty()); + Service service; + if (Sncp.isComponent(serviceImplClass)) { // Component + RedkaleClassLoader.putReflectionPublicConstructors(serviceImplClass, serviceImplClass.getName()); + if (!acceptsComponent(serviceImplClass)) { + return null; + } + service = serviceImplClass.getDeclaredConstructor().newInstance(); + } else if (srcObj instanceof WebSocketServlet || localMode) { // 本地模式 + AsmMethodBoost methodBoost = application.createAsmMethodBoost(false, serviceImplClass); + service = Sncp.createLocalService( + serverClassLoader, + resourceName, + serviceImplClass, + methodBoost, + appResourceFactory, + rpcGroups, + sncpClient, + mqAgent, + group, + entry.getProperty()); + } else { + AsmMethodBoost methodBoost = application.createAsmMethodBoost(true, serviceImplClass); + service = Sncp.createRemoteService( + serverClassLoader, + resourceName, + serviceImplClass, + methodBoost, + appResourceFactory, + rpcGroups, + sncpClient, + mqAgent, + group, + entry.getProperty()); + } + final Class restype = Sncp.getResourceType(service); + if (rf.find(resourceName, restype) == null) { + regFactory.register(resourceName, restype, service); + } else if (isSNCP() && !entry.isAutoload()) { + throw new RedkaleException(restype.getSimpleName() + "(class:" + serviceImplClass.getName() + + ", name:" + resourceName + ", group:" + group + ") is repeat."); + } + if (Sncp.isRemote(service)) { + remoteServices.add(service); + if (mqAgent != null) { + sncpRemoteAgents.put(mqAgent.getName(), mqAgent); + } + } else { + if (field != null) { + rf.inject(resourceName, service); // 动态加载的Service也存在按需加载的注入资源 + } + localServices.add(service); + if (!Sncp.isComponent(service)) { + servletServices.add(service); + } + } + serviceCount.incrementAndGet(); + return service; + } catch (Exception e) { + throw e instanceof RuntimeException ? (RuntimeException) e : new RedkaleException(e); + } + } + + @Override + public Type resourceType() { + return type; + } + } + + @SuppressWarnings("unchecked") + protected void loadService(ClassFilter serviceFilter) throws Exception { + Objects.requireNonNull(serviceFilter); + final long starts = System.currentTimeMillis(); + final Set> entrys = (Set) serviceFilter.getAllFilterEntrys(); + final SncpRpcGroups rpcGroups = application.getSncpRpcGroups(); + final AtomicInteger serviceCount = new AtomicInteger(); + for (FilterEntry entry : entrys) { // service实现类 + final Class serviceImplClass = entry.getType(); + if (Modifier.isFinal(serviceImplClass.getModifiers())) { + continue; // 修饰final的类跳过 + } + if (!Modifier.isPublic(serviceImplClass.getModifiers())) { + continue; + } + if (Sncp.isSncpDyn(serviceImplClass)) { + continue; // 动态生成的跳过 + } + if (entry.isExpect()) { + if (Modifier.isAbstract(serviceImplClass.getModifiers())) { + continue; // 修饰abstract的类跳过 + } + if (DataSource.class.isAssignableFrom(serviceImplClass)) { + continue; + } + if (CacheSource.class.isAssignableFrom(serviceImplClass)) { + continue; + } + } + if (entry.getName().contains(Resource.PARENT_NAME)) { + throw new RedkaleException( + " value cannot contains '" + Resource.PARENT_NAME + "' in " + entry.getProperty()); + } + if (!entry.isEmptyGroup() && !entry.isRemote() && !rpcGroups.containsGroup(entry.getGroup())) { + throw new RedkaleException("Not found group(" + entry.getGroup() + ")"); + } + Service oldOther = resourceFactory.find(entry.getName(), serviceImplClass); + if (oldOther != null) { // Server加载Service时需要判断是否已在其他协议服务中加载 + if (!Sncp.isRemote(oldOther)) { + if (!Sncp.isComponent(oldOther)) { + servletServices.add(oldOther); + } + } + continue; + } + boolean isLocalGroup0 = rpcGroups.isLocalGroup(this.sncpGroup, this.sncpAddress, entry); + final String group = isLocalGroup0 ? null : entry.getGroup(); + final boolean localMode = serviceImplClass.getAnnotation(Local.class) != null || isLocalGroup0; // 本地模式 + if ((localMode || Sncp.isComponent(serviceImplClass)) && Utility.isAbstractOrInterface(serviceImplClass)) { + continue; // 本地模式或Component不能实例化接口和抽象类的Service类 + } + if (entry.isExpect()) { + Class t = ResourceFactory.getResourceType(entry.getType()); + if (resourceFactory.findResourceTypeLoader(t) == null) { + resourceFactory.register(new ExpectServiceLoader( + t, serviceImplClass, serviceCount, rpcGroups, entry, group, localMode)); + } + } else { + ExpectServiceLoader resourceLoader = new ExpectServiceLoader( + serviceImplClass, serviceImplClass, serviceCount, rpcGroups, entry, group, localMode); + resourceLoader.load(resourceFactory, null, null, entry.getName(), null, false); + } + } + long et = System.currentTimeMillis(); + if (serviceCdl != null) { + serviceCdl.countDown(); + serviceCdl.await(); + } + logger.info(this.getClass().getSimpleName() + " construct services in " + (et - starts) + " ms and await " + + (System.currentTimeMillis() - et) + " ms"); + + final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null; + // ---------------- inject ---------------- + new ArrayList<>(localServices).forEach(y -> { + resourceFactory.inject(Sncp.getResourceName(y), y, NodeServer.this); + }); + // 远程模式不可inject, 里面存在@Resource.required=true依赖 + // new ArrayList<>(remoteServices).forEach(y -> { + // resourceFactory.inject(Sncp.getResourceName(y), y, NodeServer.this); + // calcMaxLength(y); + // }); + + if (sb != null) { + remoteServices.forEach(y -> { + sb.append(Sncp.toSimpleString(y, maxNameLength, maxTypeLength)) + .append(" load and inject") + .append(LINE_SEPARATOR); + }); + } + if (isSNCP() && !sncpRemoteAgents.isEmpty()) { + sncpRemoteAgents.values().forEach(agent -> { + // mqAgent.putSncpResp((NodeSncpServer) this); + // mqAgent.startSncpRespConsumer(); + }); + } + // ----------------- init ----------------- + List swlist = new ArrayList<>(localServices); + swlist.forEach(y -> calcMaxLength(y)); + swlist.sort((o1, o2) -> { + Priority p1 = o1.getClass().getAnnotation(Priority.class); + Priority p2 = o2.getClass().getAnnotation(Priority.class); + int v = (p2 == null ? 0 : p2.value()) - (p1 == null ? 0 : p1.value()); + if (v != 0) { + return v; + } + int v1 = o1.getClass().getAnnotation(Component.class) == null ? -1 : 1; + int v2 = o2.getClass().getAnnotation(Component.class) == null ? -1 : 1; + if (v1 != v2) { + return v1 - v2; + } + int rs = Sncp.getResourceType(o1) + .getName() + .compareTo(Sncp.getResourceType(o2).getName()); + if (rs == 0) { + rs = Sncp.getResourceName(o1).compareTo(Sncp.getResourceName(o2)); + } + return rs; + }); + localServices.clear(); + localServices.addAll(swlist); + // this.loadPersistData(); + long preinits = System.currentTimeMillis(); + preInitServices(localServices, remoteServices, servletServices); + long preinite = System.currentTimeMillis() - preinits; + final List slist = sb == null ? null : new CopyOnWriteArrayList<>(); + if (application.isCompileMode()) { + localServices.stream().forEach(y -> { + String serstr = Sncp.toSimpleString(y, maxNameLength, maxTypeLength); + if (slist != null) { + slist.add(new StringBuilder() + .append(serstr) + .append(" load") + .append(LINE_SEPARATOR) + .toString()); + } + }); + } else { + localServices.stream().forEach(y -> { + long s = System.currentTimeMillis(); + application.onServicePreInit(y); + y.init(Sncp.getResourceConf(y)); + application.onServicePostInit(y); + long e = System.currentTimeMillis() - s; + if (slist != null) { + String serstr = Sncp.toSimpleString(y, maxNameLength, maxTypeLength); + slist.add(new StringBuilder() + .append(serstr) + .append(" load and init in ") + .append(e < 10 ? " " : (e < 100 ? " " : "")) + .append(e) + .append(" ms") + .append(LINE_SEPARATOR) + .toString()); + } + }); + localServices.stream().forEach(y -> { + if (Sncp.isComponent(y)) { + long s = System.currentTimeMillis(); + boolean rs = interceptComponent(y); + long e = System.currentTimeMillis() - s; + if (rs && slist != null) { + String serstr = Sncp.toSimpleString(y, maxNameLength, maxTypeLength); + slist.add(new StringBuilder() + .append(serstr) + .append(" component-start in ") + .append(e < 10 ? " " : (e < 100 ? " " : "")) + .append(e) + .append(" ms") + .append(LINE_SEPARATOR) + .toString()); + } + } + }); + } + if (slist != null && sb != null) { + List wlist = + new ArrayList<>(slist); // 直接使用CopyOnWriteArrayList偶尔会出现莫名的异常(CopyOnWriteArrayList源码1185行) + for (String s : wlist) { + sb.append(s); + } + sb.append("All ") + .append(localServices.size()) + .append(" Services load in ") + .append(System.currentTimeMillis() - starts) + .append(" ms"); + } + if (sb != null && preinite > 10) { + sb.append(ClusterAgent.class.getSimpleName()) + .append(" register in ") + .append(preinite) + .append(" ms" + LINE_SEPARATOR); + } + if (sb != null && sb.length() > 0) { + logger.log(Level.INFO, sb.toString()); + } + } + + private void calcMaxLength(Service y) { // 计算toString中的长度 + String n = Sncp.getResourceName(y); + maxNameLength = Math.max(maxNameLength, n == null ? 0 : n.length()); + maxTypeLength = + Math.max(maxTypeLength, Sncp.getResourceType(y).getName().length() + 1); + } + + protected boolean acceptsComponent(Class serviceImplClass) { + if (Modifier.isAbstract(serviceImplClass.getModifiers()) + || Modifier.isInterface(serviceImplClass.getModifiers())) { + return false; + } + return true; + } + + protected boolean interceptComponent(Service service) { + return false; + } + + protected MessageAgent getMessageAgent(AnyValue serviceConf) { + MessageAgent agent = null; + if (serviceConf != null && serviceConf.getValue("mq") != null) { + agent = application.getResourceFactory().find(serviceConf.getValue("mq"), MessageAgent.class); + if (agent != null) { + messageAgents.put(agent.getName(), agent); + } + } + return agent; + } + + // Service.init执行之前调用 + protected void preInitServices( + Set localServices, Set remoteServices, Set servletServices) { + final ClusterAgent cluster = application.getResourceFactory().find("", ClusterAgent.class); + if (!application.isCompileMode() && cluster != null) { + NodeProtocol pros = getClass().getAnnotation(NodeProtocol.class); + String protocol = pros.value().toUpperCase(); + if (!cluster.containsProtocol(protocol)) { + return; + } + if (!cluster.containsPort(server.getSocketAddress().getPort())) { + return; + } + cluster.register(this, protocol, localServices, remoteServices, servletServices); + } + } + + // loadServlet执行之后调用 + protected void postLoadServlets() {} + + // Service.destroy执行之前调用 + protected void preDestroyServices( + Set localServices, Set remoteServices, Set servletServices) { + final ClusterAgent cluster = application.getResourceFactory().find("", ClusterAgent.class); + if (!application.isCompileMode() && cluster != null) { // 服务注销 + NodeProtocol pros = getClass().getAnnotation(NodeProtocol.class); + String protocol = pros.value().toUpperCase(); + if (cluster.containsProtocol(protocol) + && cluster.containsPort(server.getSocketAddress().getPort())) { + cluster.deregister(this, protocol, localServices, remoteServices, servletServices); + afterClusterDeregisterOnPreDestroyServices(cluster, protocol); + } + } + if (!application.isCompileMode() && !this.messageAgents.isEmpty()) { // MQ + } + } + + protected void afterClusterDeregisterOnPreDestroyServices(ClusterAgent cluster, String protocol) {} + + // Server.start执行之后调用 + protected void postStartServer( + Set localServices, Set remoteServices, Set servletServices) {} + + protected abstract ClassFilter createFilterClassFilter(); + + protected abstract ClassFilter createServletClassFilter(); + + protected List createOtherClassFilters() { + return null; + } + + protected ClassFilter createServiceClassFilter() { + return createClassFilter( + this.sncpGroup, + null, + Service.class, + (!isSNCP() && application.watching) ? null : new Class[] {org.redkale.watch.WatchService.class}, + Annotation.class, + "services", + "service"); + } + + protected ClassFilter createClassFilter( + final String localGroup, + Class ref, + Class inter, + Class[] excludeSuperClasses, + Class ref2, + String properties, + String property) { + ClassFilter cf = new ClassFilter(this.serverClassLoader, ref, inter, excludeSuperClasses, null); + if (properties == null) { + cf.setRefused(true); + return cf; + } + if (this.serverConf == null) { + cf.setRefused(true); + return cf; + } + AnyValue[] proplist = this.serverConf.getAnyValues(properties); + if (proplist == null || proplist.length < 1) { + cf.setRefused(true); + return cf; + } + cf = null; + for (AnyValue list : proplist) { + AnyValueWriter prop = null; + String sc = list.getValue("group"); + String mq = list.getValue("mq"); + if (sc != null) { + sc = sc.trim(); + } + if (sc == null) { + sc = localGroup; + } + if (sc != null || mq != null) { + prop = new AnyValueWriter(); + if (sc != null) { + prop.addValue("group", sc); + } + if (mq != null) { + prop.addValue("mq", mq); + } + } + ClassFilter filter = new ClassFilter(this.serverClassLoader, ref, inter, excludeSuperClasses, prop); + for (AnyValue av : list.getAnyValues(property)) { // 节点 + final AnyValue[] items = av.getAnyValues("property"); + if (items.length > 0) { // 存在 节点 + AnyValueWriter dav = AnyValueWriter.create(); + final AnyValue.Entry[] strings = av.getStringEntrys(); + if (strings != null) { // 将节点的属性值传给dav + for (AnyValue.Entry en : strings) { + dav.addValue(en.name, en.getValue()); + } + } + final AnyValue.Entry[] anys = av.getAnyEntrys(); + if (anys != null) { + for (AnyValue.Entry en : anys) { // 将节点的非property属性节点传给dav + if (!"property".equals(en.name)) { + dav.addValue(en.name, en.getValue()); + } + } + } + AnyValueWriter ps = AnyValueWriter.create(); + for (AnyValue item : items) { + ps.addValue(item.getValue("name"), item.getValue("value")); + } + dav.addValue("properties", ps); + av = dav; + } + if (!av.getBoolValue("ignore", false)) { + filter.filter(av, av.getValue("value"), false); + } + } + if (list.getBoolValue("autoload", true)) { + String includes = list.getValue("includes", ""); + String excludes = list.getValue("excludes", ""); + filter.setIncludePatterns(includes.split(";")); + filter.setExcludePatterns(excludes.split(";")); + } else if (ref2 == null || ref2 == Annotation.class) { // service如果是autoload=false则不需要加载 + filter.setRefused(true); + } else if (ref2 != Annotation.class) { + filter.setAnnotationClass(ref2); + } + cf = (cf == null) ? filter : cf.or(filter); + } + return cf; + } + + public abstract InetSocketAddress getSocketAddress(); + + public boolean isSNCP() { + return false; + } + + public boolean isWATCH() { + return false; + } + + public Application getApplication() { + return application; + } + + public ResourceFactory getResourceFactory() { + return resourceFactory; + } + + public RedkaleClassLoader getServerClassLoader() { + return serverClassLoader; + } + + public void setServerClassLoader(RedkaleClassLoader serverClassLoader) { + Objects.requireNonNull(this.serverClassLoader); + this.serverClassLoader = serverClassLoader; + this.serverThread.setContextClassLoader(serverClassLoader); + } + + public InetSocketAddress getSncpAddress() { + return sncpAddress; + } + + public AnyValue getServerConf() { + return serverConf; + } + + public Logger getLogger() { + return logger; + } + + public String getSncpGroup() { + return sncpGroup; + } + + public void start() throws IOException { + if (interceptor != null) { + interceptor.preStart(this); + } + if (this.sncpAsyncGroup != null) { + this.sncpAsyncGroup.start(); + } + server.start(); + postStartServer(localServices, remoteServices, servletServices); + } + + 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); + preDestroyServices(localServices, remoteServices, servletServices); + localServices.forEach(y -> { + long s = System.currentTimeMillis(); + if (finest) { + logger.finest(Sncp.getResourceType(y) + " is destroying"); + } + application.onServicePreDestroy(y); + y.destroy(Sncp.getResourceConf(y)); + if (finest) { + logger.finest(Sncp.getResourceType(y) + " was destroyed"); + } + application.onServicePostDestroy(y); + long e = System.currentTimeMillis() - s; + if (e > 2 && sb != null) { + sb.append(Sncp.toSimpleString(y, maxNameLength, maxTypeLength)) + .append(" destroy ") + .append(e) + .append("ms") + .append(LINE_SEPARATOR); + } + }); + if (sb != null && sb.length() > 0) { + logger.log(Level.INFO, sb.toString()); + } + if (this.sncpAsyncGroup != null) { + long s = System.currentTimeMillis(); + this.sncpAsyncGroup.dispose(); + logger.info("SncpAsyncGroup destroy in " + (System.currentTimeMillis() - s) + " ms"); + } + if (this.sncpClient != null) { + long s = System.currentTimeMillis(); + this.sncpClient.close(); + logger.info("SncpClient close in " + (System.currentTimeMillis() - s) + " ms"); + } + server.shutdown(); + } + + public List command(String cmd, String[] params) throws IOException { + final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null; + List results = new ArrayList<>(); + localServices.forEach(y -> { + Set methods = new HashSet<>(); + Class loop = y.getClass(); + // do { public方法不用递归 + for (Method m : loop.getMethods()) { + Command c = m.getAnnotation(Command.class); + org.redkale.util.Command c2 = m.getAnnotation(org.redkale.util.Command.class); + if (c == null && c2 == null) { + continue; + } + if (Modifier.isStatic(m.getModifiers())) { + logger.log(Level.WARNING, m + " is static on @Command"); + continue; + } + if (m.getParameterCount() != 1 && m.getParameterCount() != 2) { + logger.log(Level.WARNING, m + " parameter count = " + m.getParameterCount() + " on @Command"); + continue; + } + if (m.getParameterTypes()[0] != String.class) { + logger.log(Level.WARNING, m + " parameters[0] type is not String.class on @Command"); + continue; + } + if (m.getParameterCount() == 2 && m.getParameterTypes()[1] != String[].class) { + logger.log(Level.WARNING, m + " parameters[1] type is not String[].class on @Command"); + continue; + } + if (!c.value().isEmpty() && !c.value().equalsIgnoreCase(cmd)) { + continue; + } + methods.add(m); + } + // } while ((loop = loop.getSuperclass()) != Object.class); + if (methods.isEmpty()) { + return; + } + long s = System.currentTimeMillis(); + Method one = null; + try { + for (Method method : methods) { + one = method; + Object r = method.getParameterCount() == 2 ? method.invoke(y, cmd, params) : method.invoke(y, cmd); + if (r != null) { + results.add(r); + } + } + } catch (Exception ex) { + logger.log(Level.SEVERE, one + " run error, cmd = " + cmd, ex); + } + long e = System.currentTimeMillis() - s; + if (e > 10 && sb != null) { + sb.append(Sncp.toSimpleString(y, maxNameLength, maxTypeLength)) + .append(" command (") + .append(cmd) + .append(") ") + .append(e) + .append("ms") + .append(LINE_SEPARATOR); + } + }); + if (sb != null && sb.length() > 0) { + logger.log(Level.INFO, sb.toString()); + } + return results; + } + + public T getServer() { + return (T) server; + } + + public Set getServletServices() { + return new LinkedHashSet<>(servletServices); + } + + public Set getLocalServices() { + return new LinkedHashSet<>(localServices); + } + + public Set getRemoteServices() { + return new LinkedHashSet<>(remoteServices); + } + + public String getThreadName() { + return this.threadName; + } +} diff --git a/src/main/java/org/redkale/cache/CacheManager.java b/src/main/java/org/redkale/cache/CacheManager.java index 814ba0c80..c342b3995 100644 --- a/src/main/java/org/redkale/cache/CacheManager.java +++ b/src/main/java/org/redkale/cache/CacheManager.java @@ -1,842 +1,842 @@ -/* - * - */ -package org.redkale.cache; - -import java.lang.reflect.Type; -import java.time.Duration; -import java.util.concurrent.CompletableFuture; -import org.redkale.util.ThrowSupplier; - -/** - * 缓存管理器 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public interface CacheManager { - - /** 默认的hash */ - public static final String DEFAULT_HASH = "cache-hash"; - - // -------------------------------------- 本地缓存 -------------------------------------- - /** - * 本地获取缓存数据, 过期返回null - * - * @param 泛型 - * @param hash 缓存hash - * @param key 缓存键 - * @param type 数据类型 - * @return 数据值 - */ - public T localGet(final String hash, final String key, final Type type); - - /** - * 本地获取缓存数据, 过期返回null - * - * @param 泛型 - * @param key 缓存键 - * @param type 数据类型 - * @return 数据值 - */ - default T localGet(final String key, final Type type) { - return localGet(DEFAULT_HASH, key, type); - } - - /** - * 本地获取字符串缓存数据, 过期返回null - * - * @param hash 缓存hash - * @param key 缓存键 - * @return 数据值 - */ - default String localGetString(final String hash, final String key) { - return localGet(hash, key, String.class); - } - - /** - * 本地获取字符串缓存数据, 过期返回null - * - * @param key 缓存键 - * @return 数据值 - */ - default String localGetString(final String key) { - return localGetString(DEFAULT_HASH, key); - } - - /** - * 本地获取缓存数据, 过期返回null - * - * @param 泛型 - * @param hash 缓存hash - * @param key 缓存键 - * @param type 数据类型 - * @param nullable 是否缓存null值 - * @param expire 过期时长,Duration.ZERO为永不过期 - * @param supplier 数据函数 - * @return 数据值 - */ - public T localGetSet( - final String hash, - final String key, - final Type type, - boolean nullable, - Duration expire, - ThrowSupplier supplier); - - /** - * 本地获取缓存数据, 过期返回null - * - * @param 泛型 - * @param key 缓存键 - * @param type 数据类型 - * @param nullable 是否缓存null值 - * @param expire 过期时长,Duration.ZERO为永不过期 - * @param supplier 数据函数 - * @return 数据值 - */ - default T localGetSet( - final String key, final Type type, boolean nullable, Duration expire, ThrowSupplier supplier) { - return localGetSet(DEFAULT_HASH, key, type, nullable, expire, supplier); - } - - /** - * 本地异步获取缓存数据, 过期返回null - * - * @param 泛型 - * @param hash 缓存hash - * @param key 缓存键 - * @param type 数据类型 - * @param nullable 是否缓存null值 - * @param expire 过期时长,Duration.ZERO为永不过期 - * @param supplier 数据函数 - * @return 数据值 - */ - public CompletableFuture localGetSetAsync( - String hash, - String key, - Type type, - boolean nullable, - Duration expire, - ThrowSupplier> supplier); - - /** - * 本地异步获取缓存数据, 过期返回null - * - * @param 泛型 - * @param key 缓存键 - * @param type 数据类型 - * @param nullable 是否缓存null值 - * @param expire 过期时长,Duration.ZERO为永不过期 - * @param supplier 数据函数 - * @return 数据值 - */ - default CompletableFuture localGetSetAsync( - String key, Type type, boolean nullable, Duration expire, ThrowSupplier> supplier) { - return localGetSetAsync(DEFAULT_HASH, key, type, nullable, expire, supplier); - } - - /** - * 本地缓存数据 - * - * @param 泛型 - * @param hash 缓存hash - * @param key 缓存键 - * @param type 数据类型 - * @param value 数据值 - * @param expire 过期时长,Duration.ZERO为永不过期 - */ - public void localSet(String hash, String key, Type type, T value, Duration expire); - - /** - * 本地缓存数据 - * - * @param 泛型 - * @param key 缓存键 - * @param type 数据类型 - * @param value 数据值 - * @param expire 过期时长,Duration.ZERO为永不过期 - */ - default void localSet(String key, Type type, T value, Duration expire) { - localSet(DEFAULT_HASH, key, type, value, expire); - } - - /** - * 本地缓存字符串数据 - * - * @param hash 缓存hash - * @param key 缓存键 - * @param value 数据值 - * @param expire 过期时长,Duration.ZERO为永不过期 - */ - default void localSetString(final String hash, final String key, final String value, Duration expire) { - localSet(hash, key, String.class, value, expire); - } - - /** - * 本地缓存字符串数据 - * - * @param key 缓存键 - * @param value 数据值 - * @param expire 过期时长,Duration.ZERO为永不过期 - */ - default void localSetString(final String key, final String value, Duration expire) { - localSetString(DEFAULT_HASH, key, value, expire); - } - - /** - * 本地删除缓存数据 - * - * @param hash 缓存hash - * @param key 缓存键 - * @return 删除数量 - */ - public long localDel(String hash, String key); - - /** - * 本地删除缓存数据 - * - * @param key 缓存键 - * @return 删除数量 - */ - default long localDel(String key) { - return localDel(DEFAULT_HASH, key); - } - - // -------------------------------------- 远程缓存 -------------------------------------- - /** - * 远程获取缓存数据, 过期返回null - * - * @param 泛型 - * @param hash 缓存hash - * @param key 缓存键 - * @param type 数据类型 - * @return 数据值 - */ - public T remoteGet(final String hash, final String key, final Type type); - - /** - * 远程获取缓存数据, 过期返回null - * - * @param 泛型 - * @param key 缓存键 - * @param type 数据类型 - * @return 数据值 - */ - default T remoteGet(final String key, final Type type) { - return remoteGet(DEFAULT_HASH, key, type); - } - - /** - * 远程获取字符串缓存数据, 过期返回null - * - * @param hash 缓存hash - * @param key 缓存键 - * @return 数据值 - */ - default String remoteGetString(final String hash, final String key) { - return remoteGet(hash, key, String.class); - } - - /** - * 远程获取字符串缓存数据, 过期返回null - * - * @param key 缓存键 - * @return 数据值 - */ - default String remoteGetString(final String key) { - return remoteGetString(DEFAULT_HASH, key); - } - - /** - * 远程异步获取缓存数据, 过期返回null - * - * @param 泛型 - * @param hash 缓存hash - * @param key 缓存键 - * @param type 数据类型 - * @return 数据值 - */ - public CompletableFuture remoteGetAsync(final String hash, final String key, final Type type); - - /** - * 远程异步获取缓存数据, 过期返回null - * - * @param 泛型 - * @param key 缓存键 - * @param type 数据类型 - * @return 数据值 - */ - default CompletableFuture remoteGetAsync(final String key, final Type type) { - return remoteGetAsync(DEFAULT_HASH, key, type); - } - - /** - * 远程异步获取字符串缓存数据, 过期返回null - * - * @param hash 缓存hash - * @param key 缓存键 - * @return 数据值 - */ - default CompletableFuture remoteGetStringAsync(final String hash, final String key) { - return remoteGetAsync(hash, key, String.class); - } - - /** - * 远程异步获取字符串缓存数据, 过期返回null - * - * @param key 缓存键 - * @return 数据值 - */ - default CompletableFuture remoteGetStringAsync(final String key) { - return remoteGetStringAsync(DEFAULT_HASH, key); - } - - /** - * 远程获取缓存数据, 过期返回null - * - * @param 泛型 - * @param hash 缓存hash - * @param key 缓存键 - * @param type 数据类型 - * @param nullable 是否缓存null值 - * @param expire 过期时长,Duration.ZERO为永不过期 - * @param supplier 数据函数 - * @return 数据值 - */ - public T remoteGetSet( - final String hash, - final String key, - final Type type, - boolean nullable, - Duration expire, - ThrowSupplier supplier); - - /** - * 远程获取缓存数据, 过期返回null - * - * @param 泛型 - * @param key 缓存键 - * @param type 数据类型 - * @param nullable 是否缓存null值 - * @param expire 过期时长,Duration.ZERO为永不过期 - * @param supplier 数据函数 - * @return 数据值 - */ - default T remoteGetSet( - final String key, final Type type, boolean nullable, Duration expire, ThrowSupplier supplier) { - return remoteGetSet(DEFAULT_HASH, key, type, nullable, expire, supplier); - } - - /** - * 远程异步获取缓存数据, 过期返回null - * - * @param 泛型 - * @param hash 缓存hash - * @param key 缓存键 - * @param type 数据类型 - * @param nullable 是否缓存null值 - * @param expire 过期时长,Duration.ZERO为永不过期 - * @param supplier 数据函数 - * @return 数据值 - */ - public CompletableFuture remoteGetSetAsync( - String hash, - String key, - Type type, - boolean nullable, - Duration expire, - ThrowSupplier> supplier); - - /** - * 远程异步获取缓存数据, 过期返回null - * - * @param 泛型 - * @param key 缓存键 - * @param type 数据类型 - * @param nullable 是否缓存null值 - * @param expire 过期时长,Duration.ZERO为永不过期 - * @param supplier 数据函数 - * @return 数据值 - */ - default CompletableFuture remoteGetSetAsync( - String key, Type type, boolean nullable, Duration expire, ThrowSupplier> supplier) { - return remoteGetSetAsync(DEFAULT_HASH, key, type, nullable, expire, supplier); - } - - /** - * 远程缓存数据 - * - * @param 泛型 - * @param hash 缓存hash - * @param key 缓存键 - * @param type 数据类型 - * @param value 数据值 - * @param expire 过期时长,Duration.ZERO为永不过期 - */ - public void remoteSet(final String hash, final String key, final Type type, final T value, Duration expire); - - /** - * 远程缓存数据 - * - * @param 泛型 - * @param key 缓存键 - * @param type 数据类型 - * @param value 数据值 - * @param expire 过期时长,Duration.ZERO为永不过期 - */ - default void remoteSet(final String key, final Type type, final T value, Duration expire) { - remoteSet(DEFAULT_HASH, key, type, value, expire); - } - - /** - * 远程缓存字符串数据 - * - * @param hash 缓存hash - * @param key 缓存键 - * @param value 数据值 - * @param expire 过期时长,Duration.ZERO为永不过期 - */ - default void remoteSetString(final String hash, final String key, final String value, Duration expire) { - remoteSet(hash, key, String.class, value, expire); - } - - /** - * 远程缓存字符串数据 - * - * @param key 缓存键 - * @param value 数据值 - * @param expire 过期时长,Duration.ZERO为永不过期 - */ - default void remoteSetString(final String key, final String value, Duration expire) { - remoteSetString(DEFAULT_HASH, key, value, expire); - } - - /** - * 远程异步缓存数据 - * - * @param 泛型 - * @param hash 缓存hash - * @param key 缓存键 - * @param type 数据类型 - * @param value 数据值 - * @param expire 过期时长,Duration.ZERO为永不过期 - * @return void - */ - public CompletableFuture remoteSetAsync(String hash, String key, Type type, T value, Duration expire); - - /** - * 远程异步缓存数据 - * - * @param 泛型 - * @param key 缓存键 - * @param type 数据类型 - * @param value 数据值 - * @param expire 过期时长,Duration.ZERO为永不过期 - * @return void - */ - default CompletableFuture remoteSetAsync(String key, Type type, T value, Duration expire) { - return remoteSetAsync(DEFAULT_HASH, key, type, value, expire); - } - - /** - * 远程异步缓存字符串数据 - * - * @param hash 缓存hash - * @param key 缓存键 - * @param value 数据值 - * @param expire 过期时长,Duration.ZERO为永不过期 - * @return void - */ - default CompletableFuture remoteSetStringAsync( - final String hash, final String key, final String value, Duration expire) { - return remoteSetAsync(hash, key, String.class, value, expire); - } - - /** - * 远程异步缓存字符串数据 - * - * @param key 缓存键 - * @param value 数据值 - * @param expire 过期时长,Duration.ZERO为永不过期 - * @return void - */ - default CompletableFuture remoteSetStringAsync(final String key, final String value, Duration expire) { - return remoteSetStringAsync(DEFAULT_HASH, key, value, expire); - } - - /** - * 远程删除缓存数据 - * - * @param hash 缓存hash - * @param key 缓存键 - * @return 删除数量 - */ - public long remoteDel(String hash, String key); - - /** - * 远程删除缓存数据 - * - * @param key 缓存键 - * @return 删除数量 - */ - default long remoteDel(String key) { - return remoteDel(DEFAULT_HASH, key); - } - - /** - * 远程异步删除缓存数据 - * - * @param hash 缓存hash - * @param key 缓存键 - * @return 删除数量 - */ - public CompletableFuture remoteDelAsync(String hash, String key); - - /** - * 远程异步删除缓存数据 - * - * @param key 缓存键 - * @return 删除数量 - */ - default CompletableFuture remoteDelAsync(String key) { - return remoteDelAsync(DEFAULT_HASH, key); - } - - // -------------------------------------- both缓存 -------------------------------------- - /** - * 本地或远程获取缓存数据, 过期返回null - * - * @param 泛型 - * @param hash 缓存hash - * @param key 缓存键 - * @param type 数据类型 - * @return 数据值 - */ - public T bothGet(final String hash, final String key, final Type type); - - /** - * 本地或远程获取缓存数据, 过期返回null - * - * @param 泛型 - * @param key 缓存键 - * @param type 数据类型 - * @return 数据值 - */ - default T bothGet(final String key, final Type type) { - return bothGet(DEFAULT_HASH, key, type); - } - - /** - * 本地或远程获取字符串缓存数据, 过期返回null - * - * @param hash 缓存hash - * @param key 缓存键 - * @return 数据值 - */ - default String bothGetString(final String hash, final String key) { - return bothGet(hash, key, String.class); - } - - /** - * 本地或远程获取字符串缓存数据, 过期返回null - * - * @param key 缓存键 - * @return 数据值 - */ - default String bothGetString(final String key) { - return bothGetString(DEFAULT_HASH, key); - } - - /** - * 本地或远程异步获取缓存数据, 过期返回null - * - * @param 泛型 - * @param hash 缓存hash - * @param key 缓存键 - * @param type 数据类型 - * @return 数据值 - */ - public CompletableFuture bothGetAsync(final String hash, final String key, final Type type); - - /** - * 本地或远程异步获取缓存数据, 过期返回null - * - * @param 泛型 - * @param key 缓存键 - * @param type 数据类型 - * @return 数据值 - */ - default CompletableFuture bothGetAsync(final String key, final Type type) { - return bothGetAsync(DEFAULT_HASH, key, type); - } - - /** - * 本地或远程异步获取字符串缓存数据, 过期返回null - * - * @param hash 缓存hash - * @param key 缓存键 - * @return 数据值 - */ - default CompletableFuture bothGetStringAsync(final String hash, final String key) { - return bothGetAsync(hash, key, String.class); - } - - /** - * 本地或远程异步获取字符串缓存数据, 过期返回null - * - * @param key 缓存键 - * @return 数据值 - */ - default CompletableFuture bothGetStringAsync(final String key) { - return bothGetStringAsync(DEFAULT_HASH, key); - } - - /** - * 本地或远程获取缓存数据, 过期返回null - * - * @param 泛型 - * @param hash 缓存hash - * @param key 缓存键 - * @param type 数据类型 - * @param nullable 是否缓存null值 - * @param localExpire 本地过期时长,Duration.ZERO为永不过期,为null表示不本地缓存 - * @param remoteExpire 远程过期时长,Duration.ZERO为永不过期,为null表示不远程缓存 - * @param supplier 数据函数 - * @return 数据值 - */ - public T bothGetSet( - String hash, - String key, - Type type, - boolean nullable, - Duration localExpire, - Duration remoteExpire, - ThrowSupplier supplier); - - /** - * 本地或远程获取缓存数据, 过期返回null - * - * @param 泛型 - * @param key 缓存键 - * @param type 数据类型 - * @param nullable 是否缓存null值 - * @param localExpire 本地过期时长,Duration.ZERO为永不过期,为null表示不本地缓存 - * @param remoteExpire 远程过期时长,Duration.ZERO为永不过期,为null表示不远程缓存 - * @param supplier 数据函数 - * @return 数据值 - */ - default T bothGetSet( - String key, - Type type, - boolean nullable, - Duration localExpire, - Duration remoteExpire, - ThrowSupplier supplier) { - return bothGetSet(DEFAULT_HASH, key, type, nullable, localExpire, remoteExpire, supplier); - } - - /** - * 本地或远程异步获取缓存数据, 过期返回null - * - * @param 泛型 - * @param hash 缓存hash - * @param key 缓存键 - * @param type 数据类型 - * @param nullable 是否缓存null值 - * @param localExpire 本地过期时长,Duration.ZERO为永不过期,为null表示不本地缓存 - * @param remoteExpire 远程过期时长,Duration.ZERO为永不过期,为null表示不远程缓存 - * @param supplier 数据函数 - * @return 数据值 - */ - public CompletableFuture bothGetSetAsync( - String hash, - String key, - Type type, - boolean nullable, - Duration localExpire, - Duration remoteExpire, - ThrowSupplier> supplier); - - /** - * 本地或远程异步获取缓存数据, 过期返回null - * - * @param 泛型 - * @param key 缓存键 - * @param type 数据类型 - * @param nullable 是否缓存null值 - * @param localExpire 本地过期时长,Duration.ZERO为永不过期,为null表示不本地缓存 - * @param remoteExpire 远程过期时长,Duration.ZERO为永不过期,为null表示不远程缓存 - * @param supplier 数据函数 - * @return 数据值 - */ - default CompletableFuture bothGetSetAsync( - String key, - Type type, - boolean nullable, - Duration localExpire, - Duration remoteExpire, - ThrowSupplier> supplier) { - return bothGetSetAsync(DEFAULT_HASH, key, type, nullable, localExpire, remoteExpire, supplier); - } - - /** - * 本地和远程缓存数据 - * - * @param 泛型 - * @param hash 缓存hash - * @param key 缓存键 - * @param type 数据类型 - * @param value 数据值 - * @param localExpire 本地过期时长,Duration.ZERO为永不过期,为null表示不本地缓存 - * @param remoteExpire 远程过期时长,Duration.ZERO为永不过期,为null表示不远程缓存 - */ - public void bothSet( - final String hash, - final String key, - final Type type, - final T value, - Duration localExpire, - Duration remoteExpire); - - /** - * 本地和远程缓存数据 - * - * @param 泛型 - * @param key 缓存键 - * @param type 数据类型 - * @param value 数据值 - * @param localExpire 本地过期时长,Duration.ZERO为永不过期,为null表示不本地缓存 - * @param remoteExpire 远程过期时长,Duration.ZERO为永不过期,为null表示不远程缓存 - */ - default void bothSet( - final String key, final Type type, final T value, Duration localExpire, Duration remoteExpire) { - bothSet(DEFAULT_HASH, key, type, value, localExpire, remoteExpire); - } - - /** - * 本地和远程缓存字符串数据 - * - * @param hash 缓存hash - * @param key 缓存键 - * @param value 数据值 - * @param localExpire 本地过期时长,Duration.ZERO为永不过期,为null表示不本地缓存 - * @param remoteExpire 远程过期时长,Duration.ZERO为永不过期,为null表示不远程缓存 - */ - default void bothSetString( - final String hash, final String key, final String value, Duration localExpire, Duration remoteExpire) { - bothSet(hash, key, String.class, value, localExpire, remoteExpire); - } - - /** - * 本地和远程缓存字符串数据 - * - * @param key 缓存键 - * @param value 数据值 - * @param localExpire 本地过期时长,Duration.ZERO为永不过期,为null表示不本地缓存 - * @param remoteExpire 远程过期时长,Duration.ZERO为永不过期,为null表示不远程缓存 - */ - default void bothSetString(final String key, final String value, Duration localExpire, Duration remoteExpire) { - bothSet(DEFAULT_HASH, key, String.class, value, localExpire, remoteExpire); - } - - /** - * 本地和远程异步缓存数据 - * - * @param 泛型 - * @param hash 缓存hash - * @param key 缓存键 - * @param type 数据类型 - * @param value 数据值 - * @param localExpire 本地过期时长,Duration.ZERO为永不过期,为null表示不本地缓存 - * @param remoteExpire 远程过期时长,Duration.ZERO为永不过期,为null表示不远程缓存 - * @return void - */ - public CompletableFuture bothSetAsync( - String hash, String key, Type type, T value, Duration localExpire, Duration remoteExpire); - - /** - * 本地和远程异步缓存数据 - * - * @param 泛型 - * @param key 缓存键 - * @param type 数据类型 - * @param value 数据值 - * @param localExpire 本地过期时长,Duration.ZERO为永不过期,为null表示不本地缓存 - * @param remoteExpire 远程过期时长,Duration.ZERO为永不过期,为null表示不远程缓存 - * @return void - */ - default CompletableFuture bothSetAsync( - String key, Type type, T value, Duration localExpire, Duration remoteExpire) { - return bothSetAsync(DEFAULT_HASH, key, type, value, localExpire, remoteExpire); - } - - /** - * 本地和远程异步缓存字符串数据 - * - * @param hash 缓存hash - * @param key 缓存键 - * @param value 数据值 - * @param localExpire 本地过期时长,Duration.ZERO为永不过期,为null表示不本地缓存 - * @param remoteExpire 远程过期时长,Duration.ZERO为永不过期,为null表示不远程缓存 - * @return void - */ - default CompletableFuture bothSetStringAsync( - String hash, String key, String value, Duration localExpire, Duration remoteExpire) { - return bothSetAsync(hash, key, String.class, value, localExpire, remoteExpire); - } - - /** - * 本地和远程异步缓存字符串数据 - * - * @param key 缓存键 - * @param value 数据值 - * @param localExpire 本地过期时长,Duration.ZERO为永不过期,为null表示不本地缓存 - * @param remoteExpire 远程过期时长,Duration.ZERO为永不过期,为null表示不远程缓存 - * @return void - */ - default CompletableFuture bothSetStringAsync( - String key, String value, Duration localExpire, Duration remoteExpire) { - return bothSetAsync(DEFAULT_HASH, key, String.class, value, localExpire, remoteExpire); - } - - /** - * 本地和远程删除缓存数据 - * - * @param hash 缓存hash - * @param key 缓存键 - * @return 删除数量 - */ - public long bothDel(String hash, String key); - - /** - * 本地和远程删除缓存数据 - * - * @param key 缓存键 - * @return 删除数量 - */ - default long bothDel(String key) { - return bothDel(DEFAULT_HASH, key); - } - - /** - * 本地和远程异步删除缓存数据 - * - * @param hash 缓存hash - * @param key 缓存键 - * @return 删除数量 - */ - public CompletableFuture bothDelAsync(String hash, String key); - - /** - * 本地和远程异步删除缓存数据 - * - * @param key 缓存键 - * @return 删除数量 - */ - default CompletableFuture bothDelAsync(String key) { - return bothDelAsync(DEFAULT_HASH, key); - } -} +/* + * + */ +package org.redkale.cache; + +import java.lang.reflect.Type; +import java.time.Duration; +import java.util.concurrent.CompletableFuture; +import org.redkale.util.ThrowSupplier; + +/** + * 缓存管理器 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public interface CacheManager { + + /** 默认的hash */ + public static final String DEFAULT_HASH = "cache-hash"; + + // -------------------------------------- 本地缓存 -------------------------------------- + /** + * 本地获取缓存数据, 过期返回null + * + * @param 泛型 + * @param hash 缓存hash + * @param key 缓存键 + * @param type 数据类型 + * @return 数据值 + */ + public T localGet(final String hash, final String key, final Type type); + + /** + * 本地获取缓存数据, 过期返回null + * + * @param 泛型 + * @param key 缓存键 + * @param type 数据类型 + * @return 数据值 + */ + default T localGet(final String key, final Type type) { + return localGet(DEFAULT_HASH, key, type); + } + + /** + * 本地获取字符串缓存数据, 过期返回null + * + * @param hash 缓存hash + * @param key 缓存键 + * @return 数据值 + */ + default String localGetString(final String hash, final String key) { + return localGet(hash, key, String.class); + } + + /** + * 本地获取字符串缓存数据, 过期返回null + * + * @param key 缓存键 + * @return 数据值 + */ + default String localGetString(final String key) { + return localGetString(DEFAULT_HASH, key); + } + + /** + * 本地获取缓存数据, 过期返回null + * + * @param 泛型 + * @param hash 缓存hash + * @param key 缓存键 + * @param type 数据类型 + * @param nullable 是否缓存null值 + * @param expire 过期时长,Duration.ZERO为永不过期 + * @param supplier 数据函数 + * @return 数据值 + */ + public T localGetSet( + final String hash, + final String key, + final Type type, + boolean nullable, + Duration expire, + ThrowSupplier supplier); + + /** + * 本地获取缓存数据, 过期返回null + * + * @param 泛型 + * @param key 缓存键 + * @param type 数据类型 + * @param nullable 是否缓存null值 + * @param expire 过期时长,Duration.ZERO为永不过期 + * @param supplier 数据函数 + * @return 数据值 + */ + default T localGetSet( + final String key, final Type type, boolean nullable, Duration expire, ThrowSupplier supplier) { + return localGetSet(DEFAULT_HASH, key, type, nullable, expire, supplier); + } + + /** + * 本地异步获取缓存数据, 过期返回null + * + * @param 泛型 + * @param hash 缓存hash + * @param key 缓存键 + * @param type 数据类型 + * @param nullable 是否缓存null值 + * @param expire 过期时长,Duration.ZERO为永不过期 + * @param supplier 数据函数 + * @return 数据值 + */ + public CompletableFuture localGetSetAsync( + String hash, + String key, + Type type, + boolean nullable, + Duration expire, + ThrowSupplier> supplier); + + /** + * 本地异步获取缓存数据, 过期返回null + * + * @param 泛型 + * @param key 缓存键 + * @param type 数据类型 + * @param nullable 是否缓存null值 + * @param expire 过期时长,Duration.ZERO为永不过期 + * @param supplier 数据函数 + * @return 数据值 + */ + default CompletableFuture localGetSetAsync( + String key, Type type, boolean nullable, Duration expire, ThrowSupplier> supplier) { + return localGetSetAsync(DEFAULT_HASH, key, type, nullable, expire, supplier); + } + + /** + * 本地缓存数据 + * + * @param 泛型 + * @param hash 缓存hash + * @param key 缓存键 + * @param type 数据类型 + * @param value 数据值 + * @param expire 过期时长,Duration.ZERO为永不过期 + */ + public void localSet(String hash, String key, Type type, T value, Duration expire); + + /** + * 本地缓存数据 + * + * @param 泛型 + * @param key 缓存键 + * @param type 数据类型 + * @param value 数据值 + * @param expire 过期时长,Duration.ZERO为永不过期 + */ + default void localSet(String key, Type type, T value, Duration expire) { + localSet(DEFAULT_HASH, key, type, value, expire); + } + + /** + * 本地缓存字符串数据 + * + * @param hash 缓存hash + * @param key 缓存键 + * @param value 数据值 + * @param expire 过期时长,Duration.ZERO为永不过期 + */ + default void localSetString(final String hash, final String key, final String value, Duration expire) { + localSet(hash, key, String.class, value, expire); + } + + /** + * 本地缓存字符串数据 + * + * @param key 缓存键 + * @param value 数据值 + * @param expire 过期时长,Duration.ZERO为永不过期 + */ + default void localSetString(final String key, final String value, Duration expire) { + localSetString(DEFAULT_HASH, key, value, expire); + } + + /** + * 本地删除缓存数据 + * + * @param hash 缓存hash + * @param key 缓存键 + * @return 删除数量 + */ + public long localDel(String hash, String key); + + /** + * 本地删除缓存数据 + * + * @param key 缓存键 + * @return 删除数量 + */ + default long localDel(String key) { + return localDel(DEFAULT_HASH, key); + } + + // -------------------------------------- 远程缓存 -------------------------------------- + /** + * 远程获取缓存数据, 过期返回null + * + * @param 泛型 + * @param hash 缓存hash + * @param key 缓存键 + * @param type 数据类型 + * @return 数据值 + */ + public T remoteGet(final String hash, final String key, final Type type); + + /** + * 远程获取缓存数据, 过期返回null + * + * @param 泛型 + * @param key 缓存键 + * @param type 数据类型 + * @return 数据值 + */ + default T remoteGet(final String key, final Type type) { + return remoteGet(DEFAULT_HASH, key, type); + } + + /** + * 远程获取字符串缓存数据, 过期返回null + * + * @param hash 缓存hash + * @param key 缓存键 + * @return 数据值 + */ + default String remoteGetString(final String hash, final String key) { + return remoteGet(hash, key, String.class); + } + + /** + * 远程获取字符串缓存数据, 过期返回null + * + * @param key 缓存键 + * @return 数据值 + */ + default String remoteGetString(final String key) { + return remoteGetString(DEFAULT_HASH, key); + } + + /** + * 远程异步获取缓存数据, 过期返回null + * + * @param 泛型 + * @param hash 缓存hash + * @param key 缓存键 + * @param type 数据类型 + * @return 数据值 + */ + public CompletableFuture remoteGetAsync(final String hash, final String key, final Type type); + + /** + * 远程异步获取缓存数据, 过期返回null + * + * @param 泛型 + * @param key 缓存键 + * @param type 数据类型 + * @return 数据值 + */ + default CompletableFuture remoteGetAsync(final String key, final Type type) { + return remoteGetAsync(DEFAULT_HASH, key, type); + } + + /** + * 远程异步获取字符串缓存数据, 过期返回null + * + * @param hash 缓存hash + * @param key 缓存键 + * @return 数据值 + */ + default CompletableFuture remoteGetStringAsync(final String hash, final String key) { + return remoteGetAsync(hash, key, String.class); + } + + /** + * 远程异步获取字符串缓存数据, 过期返回null + * + * @param key 缓存键 + * @return 数据值 + */ + default CompletableFuture remoteGetStringAsync(final String key) { + return remoteGetStringAsync(DEFAULT_HASH, key); + } + + /** + * 远程获取缓存数据, 过期返回null + * + * @param 泛型 + * @param hash 缓存hash + * @param key 缓存键 + * @param type 数据类型 + * @param nullable 是否缓存null值 + * @param expire 过期时长,Duration.ZERO为永不过期 + * @param supplier 数据函数 + * @return 数据值 + */ + public T remoteGetSet( + final String hash, + final String key, + final Type type, + boolean nullable, + Duration expire, + ThrowSupplier supplier); + + /** + * 远程获取缓存数据, 过期返回null + * + * @param 泛型 + * @param key 缓存键 + * @param type 数据类型 + * @param nullable 是否缓存null值 + * @param expire 过期时长,Duration.ZERO为永不过期 + * @param supplier 数据函数 + * @return 数据值 + */ + default T remoteGetSet( + final String key, final Type type, boolean nullable, Duration expire, ThrowSupplier supplier) { + return remoteGetSet(DEFAULT_HASH, key, type, nullable, expire, supplier); + } + + /** + * 远程异步获取缓存数据, 过期返回null + * + * @param 泛型 + * @param hash 缓存hash + * @param key 缓存键 + * @param type 数据类型 + * @param nullable 是否缓存null值 + * @param expire 过期时长,Duration.ZERO为永不过期 + * @param supplier 数据函数 + * @return 数据值 + */ + public CompletableFuture remoteGetSetAsync( + String hash, + String key, + Type type, + boolean nullable, + Duration expire, + ThrowSupplier> supplier); + + /** + * 远程异步获取缓存数据, 过期返回null + * + * @param 泛型 + * @param key 缓存键 + * @param type 数据类型 + * @param nullable 是否缓存null值 + * @param expire 过期时长,Duration.ZERO为永不过期 + * @param supplier 数据函数 + * @return 数据值 + */ + default CompletableFuture remoteGetSetAsync( + String key, Type type, boolean nullable, Duration expire, ThrowSupplier> supplier) { + return remoteGetSetAsync(DEFAULT_HASH, key, type, nullable, expire, supplier); + } + + /** + * 远程缓存数据 + * + * @param 泛型 + * @param hash 缓存hash + * @param key 缓存键 + * @param type 数据类型 + * @param value 数据值 + * @param expire 过期时长,Duration.ZERO为永不过期 + */ + public void remoteSet(final String hash, final String key, final Type type, final T value, Duration expire); + + /** + * 远程缓存数据 + * + * @param 泛型 + * @param key 缓存键 + * @param type 数据类型 + * @param value 数据值 + * @param expire 过期时长,Duration.ZERO为永不过期 + */ + default void remoteSet(final String key, final Type type, final T value, Duration expire) { + remoteSet(DEFAULT_HASH, key, type, value, expire); + } + + /** + * 远程缓存字符串数据 + * + * @param hash 缓存hash + * @param key 缓存键 + * @param value 数据值 + * @param expire 过期时长,Duration.ZERO为永不过期 + */ + default void remoteSetString(final String hash, final String key, final String value, Duration expire) { + remoteSet(hash, key, String.class, value, expire); + } + + /** + * 远程缓存字符串数据 + * + * @param key 缓存键 + * @param value 数据值 + * @param expire 过期时长,Duration.ZERO为永不过期 + */ + default void remoteSetString(final String key, final String value, Duration expire) { + remoteSetString(DEFAULT_HASH, key, value, expire); + } + + /** + * 远程异步缓存数据 + * + * @param 泛型 + * @param hash 缓存hash + * @param key 缓存键 + * @param type 数据类型 + * @param value 数据值 + * @param expire 过期时长,Duration.ZERO为永不过期 + * @return void + */ + public CompletableFuture remoteSetAsync(String hash, String key, Type type, T value, Duration expire); + + /** + * 远程异步缓存数据 + * + * @param 泛型 + * @param key 缓存键 + * @param type 数据类型 + * @param value 数据值 + * @param expire 过期时长,Duration.ZERO为永不过期 + * @return void + */ + default CompletableFuture remoteSetAsync(String key, Type type, T value, Duration expire) { + return remoteSetAsync(DEFAULT_HASH, key, type, value, expire); + } + + /** + * 远程异步缓存字符串数据 + * + * @param hash 缓存hash + * @param key 缓存键 + * @param value 数据值 + * @param expire 过期时长,Duration.ZERO为永不过期 + * @return void + */ + default CompletableFuture remoteSetStringAsync( + final String hash, final String key, final String value, Duration expire) { + return remoteSetAsync(hash, key, String.class, value, expire); + } + + /** + * 远程异步缓存字符串数据 + * + * @param key 缓存键 + * @param value 数据值 + * @param expire 过期时长,Duration.ZERO为永不过期 + * @return void + */ + default CompletableFuture remoteSetStringAsync(final String key, final String value, Duration expire) { + return remoteSetStringAsync(DEFAULT_HASH, key, value, expire); + } + + /** + * 远程删除缓存数据 + * + * @param hash 缓存hash + * @param key 缓存键 + * @return 删除数量 + */ + public long remoteDel(String hash, String key); + + /** + * 远程删除缓存数据 + * + * @param key 缓存键 + * @return 删除数量 + */ + default long remoteDel(String key) { + return remoteDel(DEFAULT_HASH, key); + } + + /** + * 远程异步删除缓存数据 + * + * @param hash 缓存hash + * @param key 缓存键 + * @return 删除数量 + */ + public CompletableFuture remoteDelAsync(String hash, String key); + + /** + * 远程异步删除缓存数据 + * + * @param key 缓存键 + * @return 删除数量 + */ + default CompletableFuture remoteDelAsync(String key) { + return remoteDelAsync(DEFAULT_HASH, key); + } + + // -------------------------------------- both缓存 -------------------------------------- + /** + * 本地或远程获取缓存数据, 过期返回null + * + * @param 泛型 + * @param hash 缓存hash + * @param key 缓存键 + * @param type 数据类型 + * @return 数据值 + */ + public T bothGet(final String hash, final String key, final Type type); + + /** + * 本地或远程获取缓存数据, 过期返回null + * + * @param 泛型 + * @param key 缓存键 + * @param type 数据类型 + * @return 数据值 + */ + default T bothGet(final String key, final Type type) { + return bothGet(DEFAULT_HASH, key, type); + } + + /** + * 本地或远程获取字符串缓存数据, 过期返回null + * + * @param hash 缓存hash + * @param key 缓存键 + * @return 数据值 + */ + default String bothGetString(final String hash, final String key) { + return bothGet(hash, key, String.class); + } + + /** + * 本地或远程获取字符串缓存数据, 过期返回null + * + * @param key 缓存键 + * @return 数据值 + */ + default String bothGetString(final String key) { + return bothGetString(DEFAULT_HASH, key); + } + + /** + * 本地或远程异步获取缓存数据, 过期返回null + * + * @param 泛型 + * @param hash 缓存hash + * @param key 缓存键 + * @param type 数据类型 + * @return 数据值 + */ + public CompletableFuture bothGetAsync(final String hash, final String key, final Type type); + + /** + * 本地或远程异步获取缓存数据, 过期返回null + * + * @param 泛型 + * @param key 缓存键 + * @param type 数据类型 + * @return 数据值 + */ + default CompletableFuture bothGetAsync(final String key, final Type type) { + return bothGetAsync(DEFAULT_HASH, key, type); + } + + /** + * 本地或远程异步获取字符串缓存数据, 过期返回null + * + * @param hash 缓存hash + * @param key 缓存键 + * @return 数据值 + */ + default CompletableFuture bothGetStringAsync(final String hash, final String key) { + return bothGetAsync(hash, key, String.class); + } + + /** + * 本地或远程异步获取字符串缓存数据, 过期返回null + * + * @param key 缓存键 + * @return 数据值 + */ + default CompletableFuture bothGetStringAsync(final String key) { + return bothGetStringAsync(DEFAULT_HASH, key); + } + + /** + * 本地或远程获取缓存数据, 过期返回null + * + * @param 泛型 + * @param hash 缓存hash + * @param key 缓存键 + * @param type 数据类型 + * @param nullable 是否缓存null值 + * @param localExpire 本地过期时长,Duration.ZERO为永不过期,为null表示不本地缓存 + * @param remoteExpire 远程过期时长,Duration.ZERO为永不过期,为null表示不远程缓存 + * @param supplier 数据函数 + * @return 数据值 + */ + public T bothGetSet( + String hash, + String key, + Type type, + boolean nullable, + Duration localExpire, + Duration remoteExpire, + ThrowSupplier supplier); + + /** + * 本地或远程获取缓存数据, 过期返回null + * + * @param 泛型 + * @param key 缓存键 + * @param type 数据类型 + * @param nullable 是否缓存null值 + * @param localExpire 本地过期时长,Duration.ZERO为永不过期,为null表示不本地缓存 + * @param remoteExpire 远程过期时长,Duration.ZERO为永不过期,为null表示不远程缓存 + * @param supplier 数据函数 + * @return 数据值 + */ + default T bothGetSet( + String key, + Type type, + boolean nullable, + Duration localExpire, + Duration remoteExpire, + ThrowSupplier supplier) { + return bothGetSet(DEFAULT_HASH, key, type, nullable, localExpire, remoteExpire, supplier); + } + + /** + * 本地或远程异步获取缓存数据, 过期返回null + * + * @param 泛型 + * @param hash 缓存hash + * @param key 缓存键 + * @param type 数据类型 + * @param nullable 是否缓存null值 + * @param localExpire 本地过期时长,Duration.ZERO为永不过期,为null表示不本地缓存 + * @param remoteExpire 远程过期时长,Duration.ZERO为永不过期,为null表示不远程缓存 + * @param supplier 数据函数 + * @return 数据值 + */ + public CompletableFuture bothGetSetAsync( + String hash, + String key, + Type type, + boolean nullable, + Duration localExpire, + Duration remoteExpire, + ThrowSupplier> supplier); + + /** + * 本地或远程异步获取缓存数据, 过期返回null + * + * @param 泛型 + * @param key 缓存键 + * @param type 数据类型 + * @param nullable 是否缓存null值 + * @param localExpire 本地过期时长,Duration.ZERO为永不过期,为null表示不本地缓存 + * @param remoteExpire 远程过期时长,Duration.ZERO为永不过期,为null表示不远程缓存 + * @param supplier 数据函数 + * @return 数据值 + */ + default CompletableFuture bothGetSetAsync( + String key, + Type type, + boolean nullable, + Duration localExpire, + Duration remoteExpire, + ThrowSupplier> supplier) { + return bothGetSetAsync(DEFAULT_HASH, key, type, nullable, localExpire, remoteExpire, supplier); + } + + /** + * 本地和远程缓存数据 + * + * @param 泛型 + * @param hash 缓存hash + * @param key 缓存键 + * @param type 数据类型 + * @param value 数据值 + * @param localExpire 本地过期时长,Duration.ZERO为永不过期,为null表示不本地缓存 + * @param remoteExpire 远程过期时长,Duration.ZERO为永不过期,为null表示不远程缓存 + */ + public void bothSet( + final String hash, + final String key, + final Type type, + final T value, + Duration localExpire, + Duration remoteExpire); + + /** + * 本地和远程缓存数据 + * + * @param 泛型 + * @param key 缓存键 + * @param type 数据类型 + * @param value 数据值 + * @param localExpire 本地过期时长,Duration.ZERO为永不过期,为null表示不本地缓存 + * @param remoteExpire 远程过期时长,Duration.ZERO为永不过期,为null表示不远程缓存 + */ + default void bothSet( + final String key, final Type type, final T value, Duration localExpire, Duration remoteExpire) { + bothSet(DEFAULT_HASH, key, type, value, localExpire, remoteExpire); + } + + /** + * 本地和远程缓存字符串数据 + * + * @param hash 缓存hash + * @param key 缓存键 + * @param value 数据值 + * @param localExpire 本地过期时长,Duration.ZERO为永不过期,为null表示不本地缓存 + * @param remoteExpire 远程过期时长,Duration.ZERO为永不过期,为null表示不远程缓存 + */ + default void bothSetString( + final String hash, final String key, final String value, Duration localExpire, Duration remoteExpire) { + bothSet(hash, key, String.class, value, localExpire, remoteExpire); + } + + /** + * 本地和远程缓存字符串数据 + * + * @param key 缓存键 + * @param value 数据值 + * @param localExpire 本地过期时长,Duration.ZERO为永不过期,为null表示不本地缓存 + * @param remoteExpire 远程过期时长,Duration.ZERO为永不过期,为null表示不远程缓存 + */ + default void bothSetString(final String key, final String value, Duration localExpire, Duration remoteExpire) { + bothSet(DEFAULT_HASH, key, String.class, value, localExpire, remoteExpire); + } + + /** + * 本地和远程异步缓存数据 + * + * @param 泛型 + * @param hash 缓存hash + * @param key 缓存键 + * @param type 数据类型 + * @param value 数据值 + * @param localExpire 本地过期时长,Duration.ZERO为永不过期,为null表示不本地缓存 + * @param remoteExpire 远程过期时长,Duration.ZERO为永不过期,为null表示不远程缓存 + * @return void + */ + public CompletableFuture bothSetAsync( + String hash, String key, Type type, T value, Duration localExpire, Duration remoteExpire); + + /** + * 本地和远程异步缓存数据 + * + * @param 泛型 + * @param key 缓存键 + * @param type 数据类型 + * @param value 数据值 + * @param localExpire 本地过期时长,Duration.ZERO为永不过期,为null表示不本地缓存 + * @param remoteExpire 远程过期时长,Duration.ZERO为永不过期,为null表示不远程缓存 + * @return void + */ + default CompletableFuture bothSetAsync( + String key, Type type, T value, Duration localExpire, Duration remoteExpire) { + return bothSetAsync(DEFAULT_HASH, key, type, value, localExpire, remoteExpire); + } + + /** + * 本地和远程异步缓存字符串数据 + * + * @param hash 缓存hash + * @param key 缓存键 + * @param value 数据值 + * @param localExpire 本地过期时长,Duration.ZERO为永不过期,为null表示不本地缓存 + * @param remoteExpire 远程过期时长,Duration.ZERO为永不过期,为null表示不远程缓存 + * @return void + */ + default CompletableFuture bothSetStringAsync( + String hash, String key, String value, Duration localExpire, Duration remoteExpire) { + return bothSetAsync(hash, key, String.class, value, localExpire, remoteExpire); + } + + /** + * 本地和远程异步缓存字符串数据 + * + * @param key 缓存键 + * @param value 数据值 + * @param localExpire 本地过期时长,Duration.ZERO为永不过期,为null表示不本地缓存 + * @param remoteExpire 远程过期时长,Duration.ZERO为永不过期,为null表示不远程缓存 + * @return void + */ + default CompletableFuture bothSetStringAsync( + String key, String value, Duration localExpire, Duration remoteExpire) { + return bothSetAsync(DEFAULT_HASH, key, String.class, value, localExpire, remoteExpire); + } + + /** + * 本地和远程删除缓存数据 + * + * @param hash 缓存hash + * @param key 缓存键 + * @return 删除数量 + */ + public long bothDel(String hash, String key); + + /** + * 本地和远程删除缓存数据 + * + * @param key 缓存键 + * @return 删除数量 + */ + default long bothDel(String key) { + return bothDel(DEFAULT_HASH, key); + } + + /** + * 本地和远程异步删除缓存数据 + * + * @param hash 缓存hash + * @param key 缓存键 + * @return 删除数量 + */ + public CompletableFuture bothDelAsync(String hash, String key); + + /** + * 本地和远程异步删除缓存数据 + * + * @param key 缓存键 + * @return 删除数量 + */ + default CompletableFuture bothDelAsync(String key) { + return bothDelAsync(DEFAULT_HASH, key); + } +} diff --git a/src/main/java/org/redkale/cache/Cached.java b/src/main/java/org/redkale/cache/Cached.java index 5883cbbd9..ab587a0c3 100644 --- a/src/main/java/org/redkale/cache/Cached.java +++ b/src/main/java/org/redkale/cache/Cached.java @@ -1,85 +1,85 @@ -/* - * - */ -package org.redkale.cache; - -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; -import java.util.concurrent.TimeUnit; -import org.redkale.service.LoadMode; - -/** - * 标记在Service的缓存接口, 方法有以下限制:
- * 1、方法返回类型不能是void/CompletableFuture<Void> 2、方法返回类型必须可json序列化 3、方法必须是protected/public 4、方法不能是final/static - * - * @since 2.8.0 - */ -@Documented -@Target(METHOD) -@Retention(RUNTIME) -public @interface Cached { - - /** - * 缓存的key,支持参数动态组合,比如"key_#{id}" - * - * @return 键 - */ - String key(); - - /** - * 缓存的hash, 不能含有':'、'#'、'@'字符 - * - * @return hash - */ - String hash() default CacheManager.DEFAULT_HASH; - - /** - * 本地缓存过期时长, 0表示永不过期, -1表示不作本地缓存。
- * 参数值支持方式:
- * 100: 设置数值 ${env.cache.expires}: 读取系统配置项 - * - * @return 过期时长 - */ - String localExpire() default "-1"; - - /** - * 远程缓存过期时长, 0表示永不过期, -1表示不作远程缓存。
- * 参数值支持方式:
- * 100: 设置数值 ${env.cache.expires}: 读取系统配置项 - * - * @return 过期时长 - */ - String remoteExpire() default "-1"; - - /** - * 是否可以缓存null值 - * - * @return 是否可以缓存null - */ - boolean nullable() default false; - - /** - * 过期时长的时间单位 - * - * @return 时间单位 - */ - TimeUnit timeUnit() default TimeUnit.SECONDS; - - /** - * 备注 - * - * @return 备注 - */ - String comment() default ""; - - /** - * Service加载模式 - * - * @return 模式 - */ - LoadMode mode() default LoadMode.ANY; -} +/* + * + */ +package org.redkale.cache; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; +import java.util.concurrent.TimeUnit; +import org.redkale.service.LoadMode; + +/** + * 标记在Service的缓存接口, 方法有以下限制:
+ * 1、方法返回类型不能是void/CompletableFuture<Void> 2、方法返回类型必须可json序列化 3、方法必须是protected/public 4、方法不能是final/static + * + * @since 2.8.0 + */ +@Documented +@Target(METHOD) +@Retention(RUNTIME) +public @interface Cached { + + /** + * 缓存的key,支持参数动态组合,比如"key_#{id}" + * + * @return 键 + */ + String key(); + + /** + * 缓存的hash, 不能含有':'、'#'、'@'字符 + * + * @return hash + */ + String hash() default CacheManager.DEFAULT_HASH; + + /** + * 本地缓存过期时长, 0表示永不过期, -1表示不作本地缓存。
+ * 参数值支持方式:
+ * 100: 设置数值 ${env.cache.expires}: 读取系统配置项 + * + * @return 过期时长 + */ + String localExpire() default "-1"; + + /** + * 远程缓存过期时长, 0表示永不过期, -1表示不作远程缓存。
+ * 参数值支持方式:
+ * 100: 设置数值 ${env.cache.expires}: 读取系统配置项 + * + * @return 过期时长 + */ + String remoteExpire() default "-1"; + + /** + * 是否可以缓存null值 + * + * @return 是否可以缓存null + */ + boolean nullable() default false; + + /** + * 过期时长的时间单位 + * + * @return 时间单位 + */ + TimeUnit timeUnit() default TimeUnit.SECONDS; + + /** + * 备注 + * + * @return 备注 + */ + String comment() default ""; + + /** + * Service加载模式 + * + * @return 模式 + */ + LoadMode mode() default LoadMode.ANY; +} diff --git a/src/main/java/org/redkale/cache/spi/CacheAction.java b/src/main/java/org/redkale/cache/spi/CacheAction.java index a3c63a530..8854e8ca4 100644 --- a/src/main/java/org/redkale/cache/spi/CacheAction.java +++ b/src/main/java/org/redkale/cache/spi/CacheAction.java @@ -1,156 +1,156 @@ -/* - * - */ -package org.redkale.cache.spi; - -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; -import java.time.Duration; -import java.util.Objects; -import java.util.concurrent.CompletableFuture; -import org.redkale.annotation.ClassDepends; -import org.redkale.annotation.Nullable; -import org.redkale.annotation.Resource; -import org.redkale.cache.CacheManager; -import org.redkale.convert.json.JsonConvert; -import org.redkale.util.Environment; -import org.redkale.util.MultiHashKey; -import org.redkale.util.ThrowSupplier; -import org.redkale.util.TypeToken; - -/** - * 缓存的方法对象 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -@ClassDepends -public class CacheAction { - - @Resource - private Environment environment; - - @Resource - private CacheManager manager; - - private final CacheEntry cached; - - // Supplier对象的类型 - private final Type resultType; - - // 缓存方法是否异步 - private final boolean async; - - // 是否可以缓存null - private final boolean nullable; - - // 宿主对象的类 - private final Class serviceClass; - - // 无法获取动态的Method,只能存方法名 - private final String methodName; - - // 获取动态的字段名 - private final String fieldName; - - // 方法参数类型 - @Nullable - private final Class[] paramTypes; - - // 方法参数名 - @Nullable - private final String[] paramNames; - - // 缓存的hash - private String hash; - - // 缓存的key - private MultiHashKey dynKey; - - // 本地缓存过期时长,Duration.ZERO为永不过期,为null表示不本地缓存 - private Duration localExpire; - - // 远程缓存过期时长,Duration.ZERO为永不过期,为null表示不远程缓存 - private Duration remoteExpire; - - CacheAction( - CacheEntry cached, - Type returnType, - Class serviceClass, - Class[] paramTypes, - String[] paramNames, - String methodName, - String fieldName) { - this.cached = cached; - this.nullable = cached.isNullable(); - this.serviceClass = Objects.requireNonNull(serviceClass); - this.paramTypes = paramTypes; - this.paramNames = paramNames; - this.methodName = Objects.requireNonNull(methodName); - this.fieldName = Objects.requireNonNull(fieldName); - this.async = CompletableFuture.class.isAssignableFrom(TypeToken.typeToClass(returnType)); - this.resultType = this.async ? ((ParameterizedType) returnType).getActualTypeArguments()[0] : returnType; - } - - void init() { - this.hash = cached.getHash().trim().isEmpty() || CacheManager.DEFAULT_HASH.equals(cached.getHash()) - ? CacheManager.DEFAULT_HASH - : environment.getPropertyValue(cached.getHash()); - String key = environment.getPropertyValue(cached.getKey()); - this.dynKey = MultiHashKey.create(paramNames, key); - this.localExpire = createDuration(cached.getLocalExpire()); - this.remoteExpire = createDuration(cached.getRemoteExpire()); - } - - @ClassDepends - public T get(ThrowSupplier supplier, Object... args) { - if (async) { - ThrowSupplier supplier0 = supplier; - return (T) manager.bothGetSetAsync( - hash, dynKey.keyFor(args), resultType, nullable, localExpire, remoteExpire, supplier0); - } else { - return manager.bothGetSet( - hash, dynKey.keyFor(args), resultType, nullable, localExpire, remoteExpire, supplier); - } - } - - private Duration createDuration(String val) { - String str = environment.getPropertyValue(val); - if ("-1".equals(str) || "null".equalsIgnoreCase(str)) { - return null; - } else if ("0".equals(str)) { - return Duration.ZERO; - } else if (str.indexOf('*') > -1) { - long rs = 1; - for (String v : str.split("\\*")) { - if (!v.trim().isEmpty()) { - rs *= Long.parseLong(v.trim()); - } - } - if (rs < 0) { - return null; - } else if (rs == 0) { - return Duration.ZERO; - } else { - return Duration.ofMillis(cached.getTimeUnit().toMillis(rs)); - } - } else { - return Duration.ofMillis(cached.getTimeUnit().toMillis(Long.parseLong(str))); - } - } - - @Override - public String toString() { - return "{" - + "\"serviceClass\":" + serviceClass.getName() - + ",\"methodName\":\"" + methodName + "\"" - + ",\"fieldName\":\"" + fieldName + "\"" - + ",\"paramTypes\":" + JsonConvert.root().convertTo(paramTypes) - + ",\"paramNames\":" + JsonConvert.root().convertTo(paramNames) - + ",\"resultType\":\"" + resultType + "\"" - + ",\"cache\":" + cached - + "}"; - } -} +/* + * + */ +package org.redkale.cache.spi; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.time.Duration; +import java.util.Objects; +import java.util.concurrent.CompletableFuture; +import org.redkale.annotation.ClassDepends; +import org.redkale.annotation.Nullable; +import org.redkale.annotation.Resource; +import org.redkale.cache.CacheManager; +import org.redkale.convert.json.JsonConvert; +import org.redkale.util.Environment; +import org.redkale.util.MultiHashKey; +import org.redkale.util.ThrowSupplier; +import org.redkale.util.TypeToken; + +/** + * 缓存的方法对象 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +@ClassDepends +public class CacheAction { + + @Resource + private Environment environment; + + @Resource + private CacheManager manager; + + private final CacheEntry cached; + + // Supplier对象的类型 + private final Type resultType; + + // 缓存方法是否异步 + private final boolean async; + + // 是否可以缓存null + private final boolean nullable; + + // 宿主对象的类 + private final Class serviceClass; + + // 无法获取动态的Method,只能存方法名 + private final String methodName; + + // 获取动态的字段名 + private final String fieldName; + + // 方法参数类型 + @Nullable + private final Class[] paramTypes; + + // 方法参数名 + @Nullable + private final String[] paramNames; + + // 缓存的hash + private String hash; + + // 缓存的key + private MultiHashKey dynKey; + + // 本地缓存过期时长,Duration.ZERO为永不过期,为null表示不本地缓存 + private Duration localExpire; + + // 远程缓存过期时长,Duration.ZERO为永不过期,为null表示不远程缓存 + private Duration remoteExpire; + + CacheAction( + CacheEntry cached, + Type returnType, + Class serviceClass, + Class[] paramTypes, + String[] paramNames, + String methodName, + String fieldName) { + this.cached = cached; + this.nullable = cached.isNullable(); + this.serviceClass = Objects.requireNonNull(serviceClass); + this.paramTypes = paramTypes; + this.paramNames = paramNames; + this.methodName = Objects.requireNonNull(methodName); + this.fieldName = Objects.requireNonNull(fieldName); + this.async = CompletableFuture.class.isAssignableFrom(TypeToken.typeToClass(returnType)); + this.resultType = this.async ? ((ParameterizedType) returnType).getActualTypeArguments()[0] : returnType; + } + + void init() { + this.hash = cached.getHash().trim().isEmpty() || CacheManager.DEFAULT_HASH.equals(cached.getHash()) + ? CacheManager.DEFAULT_HASH + : environment.getPropertyValue(cached.getHash()); + String key = environment.getPropertyValue(cached.getKey()); + this.dynKey = MultiHashKey.create(paramNames, key); + this.localExpire = createDuration(cached.getLocalExpire()); + this.remoteExpire = createDuration(cached.getRemoteExpire()); + } + + @ClassDepends + public T get(ThrowSupplier supplier, Object... args) { + if (async) { + ThrowSupplier supplier0 = supplier; + return (T) manager.bothGetSetAsync( + hash, dynKey.keyFor(args), resultType, nullable, localExpire, remoteExpire, supplier0); + } else { + return manager.bothGetSet( + hash, dynKey.keyFor(args), resultType, nullable, localExpire, remoteExpire, supplier); + } + } + + private Duration createDuration(String val) { + String str = environment.getPropertyValue(val); + if ("-1".equals(str) || "null".equalsIgnoreCase(str)) { + return null; + } else if ("0".equals(str)) { + return Duration.ZERO; + } else if (str.indexOf('*') > -1) { + long rs = 1; + for (String v : str.split("\\*")) { + if (!v.trim().isEmpty()) { + rs *= Long.parseLong(v.trim()); + } + } + if (rs < 0) { + return null; + } else if (rs == 0) { + return Duration.ZERO; + } else { + return Duration.ofMillis(cached.getTimeUnit().toMillis(rs)); + } + } else { + return Duration.ofMillis(cached.getTimeUnit().toMillis(Long.parseLong(str))); + } + } + + @Override + public String toString() { + return "{" + + "\"serviceClass\":" + serviceClass.getName() + + ",\"methodName\":\"" + methodName + "\"" + + ",\"fieldName\":\"" + fieldName + "\"" + + ",\"paramTypes\":" + JsonConvert.root().convertTo(paramTypes) + + ",\"paramNames\":" + JsonConvert.root().convertTo(paramNames) + + ",\"resultType\":\"" + resultType + "\"" + + ",\"cache\":" + cached + + "}"; + } +} diff --git a/src/main/java/org/redkale/cache/spi/CacheAsmMethodBoost.java b/src/main/java/org/redkale/cache/spi/CacheAsmMethodBoost.java index f20e2541e..94534647f 100644 --- a/src/main/java/org/redkale/cache/spi/CacheAsmMethodBoost.java +++ b/src/main/java/org/redkale/cache/spi/CacheAsmMethodBoost.java @@ -1,248 +1,248 @@ -/* - * - */ -package org.redkale.cache.spi; - -import static org.redkale.asm.Opcodes.*; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CompletableFuture; -import org.redkale.asm.AnnotationVisitor; -import org.redkale.asm.AsmMethodBean; -import org.redkale.asm.AsmMethodBoost; -import org.redkale.asm.Asms; -import org.redkale.asm.ClassWriter; -import org.redkale.asm.FieldVisitor; -import org.redkale.asm.Handle; -import org.redkale.asm.Label; -import org.redkale.asm.MethodVisitor; -import org.redkale.asm.Opcodes; -import org.redkale.asm.Type; -import org.redkale.cache.Cached; -import org.redkale.inject.ResourceFactory; -import org.redkale.service.LoadMode; -import org.redkale.util.RedkaleClassLoader; -import org.redkale.util.RedkaleException; -import org.redkale.util.ThrowSupplier; -import org.redkale.util.TypeToken; - -/** @author zhangjx */ -public class CacheAsmMethodBoost extends AsmMethodBoost { - - private static final java.lang.reflect.Type FUTURE_VOID = new TypeToken>() {}.getType(); - - private static final List> FILTER_ANN = List.of(Cached.class, DynForCache.class); - - private Map actionMap; - - public CacheAsmMethodBoost(boolean remote, Class serviceType) { - super(remote, serviceType); - } - - @Override - public List> filterMethodAnnotations(Method method) { - return FILTER_ANN; - } - - @Override - public String doMethod( - ClassLoader classLoader, - ClassWriter cw, - String newDynName, - String fieldPrefix, - List filterAnns, - Method method, - final String newMethodName) { - Map actions = this.actionMap; - if (actions == null) { - actions = new LinkedHashMap<>(); - this.actionMap = actions; - } - Cached cached = method.getAnnotation(Cached.class); - if (cached == null) { - return newMethodName; - } - if (!LoadMode.matches(remote, cached.mode())) { - return newMethodName; - } - if (method.getAnnotation(DynForCache.class) != null) { - return newMethodName; - } - if (Modifier.isFinal(method.getModifiers()) || Modifier.isStatic(method.getModifiers())) { - throw new RedkaleException( - "@" + Cached.class.getSimpleName() + " cannot on final or static method, but on " + method); - } - if (!Modifier.isProtected(method.getModifiers()) && !Modifier.isPublic(method.getModifiers())) { - throw new RedkaleException( - "@" + Cached.class.getSimpleName() + " must on protected or public method, but on " + method); - } - if (method.getReturnType() == void.class || FUTURE_VOID.equals(method.getGenericReturnType())) { - throw new RedkaleException("@" + Cached.class.getSimpleName() + " cannot on void method, but on " + method); - } - final int actionIndex = fieldIndex.incrementAndGet(); - final String rsMethodName = method.getName() + "_afterCache"; - final String dynFieldName = fieldPrefix + "_" + method.getName() + "CacheAction" + actionIndex; - final AsmMethodBean methodBean = getMethodBean(method); - { // 定义一个新方法调用 this.rsMethodName - final String cacheDynDesc = Type.getDescriptor(DynForCache.class); - final MethodVisitor mv = createMethodVisitor(cw, method, newMethodName, methodBean); - // mv.setDebug(true); - AnnotationVisitor av = mv.visitAnnotation(cacheDynDesc, true); - av.visit("dynField", dynFieldName); - Asms.visitAnnotation(av, cached); - visitRawAnnotation(method, newMethodName, mv, Cached.class, filterAnns); - - Label l0 = new Label(); - mv.visitLabel(l0); - mv.visitVarInsn(ALOAD, 0); - List insns = visitVarInsnParamTypes(mv, method, 0); - String dynDesc = methodBean.getDesc(); - dynDesc = "(L" + newDynName + ";" + dynDesc.substring(1, dynDesc.lastIndexOf(')') + 1) - + Type.getDescriptor(ThrowSupplier.class); - mv.visitInvokeDynamicInsn("get", dynDesc, Asms.createLambdaMetaHandle(), new Object[] { - org.redkale.asm.Type.getType("()Ljava/lang/Object;"), - new Handle(Opcodes.H_INVOKESPECIAL, newDynName, "lambda$" + actionIndex, methodBean.getDesc(), false), - org.redkale.asm.Type.getType("()" + Type.getDescriptor(method.getReturnType())) - }); - mv.visitVarInsn(ASTORE, 1 + method.getParameterCount()); - Label l1 = new Label(); - mv.visitLabel(l1); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, dynFieldName, Type.getDescriptor(CacheAction.class)); - - mv.visitVarInsn(ALOAD, 1 + method.getParameterCount()); - Asms.visitInsn(mv, method.getParameterCount()); - mv.visitTypeInsn(ANEWARRAY, "java/lang/Object"); - int insn = 0; - Class[] paramtypes = method.getParameterTypes(); - for (int j = 0; j < paramtypes.length; j++) { - final Class pt = paramtypes[j]; - mv.visitInsn(DUP); - insn++; - Asms.visitInsn(mv, j); - if (pt.isPrimitive()) { - if (pt == long.class) { - mv.visitVarInsn(LLOAD, insn++); - } else if (pt == float.class) { - mv.visitVarInsn(FLOAD, insn++); - } else if (pt == double.class) { - mv.visitVarInsn(DLOAD, insn++); - } else { - mv.visitVarInsn(ILOAD, insn); - } - Class bigclaz = TypeToken.primitiveToWrapper(pt); - mv.visitMethodInsn( - INVOKESTATIC, - bigclaz.getName().replace('.', '/'), - "valueOf", - "(" + Type.getDescriptor((Class) pt) + ")" + Type.getDescriptor(bigclaz), - false); - } else { - mv.visitVarInsn(ALOAD, insn); - } - mv.visitInsn(AASTORE); - } - String throwFuncDesc = Type.getDescriptor(ThrowSupplier.class); - mv.visitMethodInsn( - INVOKEVIRTUAL, - CacheAction.class.getName().replace('.', '/'), - "get", - "(" + throwFuncDesc + "[Ljava/lang/Object;)Ljava/lang/Object;", - false); - mv.visitTypeInsn(CHECKCAST, method.getReturnType().getName().replace('.', '/')); - mv.visitInsn(ARETURN); - Label l2 = new Label(); - mv.visitLabel(l2); - mv.visitLocalVariable("this", "L" + newDynName + ";", null, l0, l2, 0); - visitParamTypesLocalVariable(mv, method, l0, l2, insns, methodBean); - mv.visitLocalVariable("_redkale_supplier", Type.getDescriptor(ThrowSupplier.class), null, l1, l2, ++insn); - - mv.visitMaxs(20, 20); - mv.visitEnd(); - CacheAction action = new CacheAction( - new CacheEntry(cached), - method.getGenericReturnType(), - serviceType, - method.getParameterTypes(), - methodBean.fieldNameArray(), - method.getName(), - dynFieldName); - actions.put(dynFieldName, action); - } - { // ThrowSupplier - final MethodVisitor mv = cw.visitMethod( - ACC_PRIVATE + ACC_SYNTHETIC, "lambda$" + actionIndex, methodBean.getDesc(), null, new String[] { - "java/lang/Throwable" - }); - // mv.setDebug(true); - Label l0 = new Label(); - mv.visitLabel(l0); - mv.visitVarInsn(ALOAD, 0); - visitVarInsnParamTypes(mv, method, 0); - mv.visitMethodInsn(INVOKESPECIAL, newDynName, rsMethodName, methodBean.getDesc(), false); - mv.visitInsn(ARETURN); - Label l1 = new Label(); - mv.visitLabel(l1); - mv.visitLocalVariable("this", "L" + newDynName + ";", null, l0, l1, 0); - mv.visitMaxs(5, 5); - mv.visitEnd(); - } - { // 定义字段 - FieldVisitor fv = - cw.visitField(ACC_PRIVATE, dynFieldName, Type.getDescriptor(CacheAction.class), null, null); - fv.visitEnd(); - } - if (actions.size() == 1) { - cw.visitInnerClass( - "java/lang/invoke/MethodHandles$Lookup", - "java/lang/invoke/MethodHandles", - "Lookup", - ACC_PUBLIC + ACC_FINAL + ACC_STATIC); - } - return rsMethodName; - } - - @Override - public void doInstance(ResourceFactory resourceFactory, Object service) { - Class clazz = service.getClass(); - if (actionMap == null) { // 为null表示没有调用过doMethod, 动态类在编译是已经生成好了 - actionMap = new LinkedHashMap<>(); - Map methodBeans = AsmMethodBoost.getMethodBeans(clazz); - for (final Method method : clazz.getDeclaredMethods()) { - DynForCache cached = method.getAnnotation(DynForCache.class); - if (cached != null) { - String dynFieldName = cached.dynField(); - AsmMethodBean methodBean = AsmMethodBean.get(methodBeans, method); - CacheAction action = new CacheAction( - new CacheEntry(cached), - method.getGenericReturnType(), - serviceType, - method.getParameterTypes(), - methodBean.fieldNameArray(), - method.getName(), - dynFieldName); - actionMap.put(dynFieldName, action); - } - } - } - actionMap.forEach((field, action) -> { - try { - Field c = clazz.getDeclaredField(field); - c.setAccessible(true); - resourceFactory.inject(action); - action.init(); - c.set(service, action); - RedkaleClassLoader.putReflectionField(clazz.getName(), c); - } catch (Exception e) { - throw new RedkaleException("field (" + field + ") in " + clazz.getName() + " set error", e); - } - }); - // do nothing - } -} +/* + * + */ +package org.redkale.cache.spi; + +import static org.redkale.asm.Opcodes.*; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import org.redkale.asm.AnnotationVisitor; +import org.redkale.asm.AsmMethodBean; +import org.redkale.asm.AsmMethodBoost; +import org.redkale.asm.Asms; +import org.redkale.asm.ClassWriter; +import org.redkale.asm.FieldVisitor; +import org.redkale.asm.Handle; +import org.redkale.asm.Label; +import org.redkale.asm.MethodVisitor; +import org.redkale.asm.Opcodes; +import org.redkale.asm.Type; +import org.redkale.cache.Cached; +import org.redkale.inject.ResourceFactory; +import org.redkale.service.LoadMode; +import org.redkale.util.RedkaleClassLoader; +import org.redkale.util.RedkaleException; +import org.redkale.util.ThrowSupplier; +import org.redkale.util.TypeToken; + +/** @author zhangjx */ +public class CacheAsmMethodBoost extends AsmMethodBoost { + + private static final java.lang.reflect.Type FUTURE_VOID = new TypeToken>() {}.getType(); + + private static final List> FILTER_ANN = List.of(Cached.class, DynForCache.class); + + private Map actionMap; + + public CacheAsmMethodBoost(boolean remote, Class serviceType) { + super(remote, serviceType); + } + + @Override + public List> filterMethodAnnotations(Method method) { + return FILTER_ANN; + } + + @Override + public String doMethod( + ClassLoader classLoader, + ClassWriter cw, + String newDynName, + String fieldPrefix, + List filterAnns, + Method method, + final String newMethodName) { + Map actions = this.actionMap; + if (actions == null) { + actions = new LinkedHashMap<>(); + this.actionMap = actions; + } + Cached cached = method.getAnnotation(Cached.class); + if (cached == null) { + return newMethodName; + } + if (!LoadMode.matches(remote, cached.mode())) { + return newMethodName; + } + if (method.getAnnotation(DynForCache.class) != null) { + return newMethodName; + } + if (Modifier.isFinal(method.getModifiers()) || Modifier.isStatic(method.getModifiers())) { + throw new RedkaleException( + "@" + Cached.class.getSimpleName() + " cannot on final or static method, but on " + method); + } + if (!Modifier.isProtected(method.getModifiers()) && !Modifier.isPublic(method.getModifiers())) { + throw new RedkaleException( + "@" + Cached.class.getSimpleName() + " must on protected or public method, but on " + method); + } + if (method.getReturnType() == void.class || FUTURE_VOID.equals(method.getGenericReturnType())) { + throw new RedkaleException("@" + Cached.class.getSimpleName() + " cannot on void method, but on " + method); + } + final int actionIndex = fieldIndex.incrementAndGet(); + final String rsMethodName = method.getName() + "_afterCache"; + final String dynFieldName = fieldPrefix + "_" + method.getName() + "CacheAction" + actionIndex; + final AsmMethodBean methodBean = getMethodBean(method); + { // 定义一个新方法调用 this.rsMethodName + final String cacheDynDesc = Type.getDescriptor(DynForCache.class); + final MethodVisitor mv = createMethodVisitor(cw, method, newMethodName, methodBean); + // mv.setDebug(true); + AnnotationVisitor av = mv.visitAnnotation(cacheDynDesc, true); + av.visit("dynField", dynFieldName); + Asms.visitAnnotation(av, cached); + visitRawAnnotation(method, newMethodName, mv, Cached.class, filterAnns); + + Label l0 = new Label(); + mv.visitLabel(l0); + mv.visitVarInsn(ALOAD, 0); + List insns = visitVarInsnParamTypes(mv, method, 0); + String dynDesc = methodBean.getDesc(); + dynDesc = "(L" + newDynName + ";" + dynDesc.substring(1, dynDesc.lastIndexOf(')') + 1) + + Type.getDescriptor(ThrowSupplier.class); + mv.visitInvokeDynamicInsn("get", dynDesc, Asms.createLambdaMetaHandle(), new Object[] { + org.redkale.asm.Type.getType("()Ljava/lang/Object;"), + new Handle(Opcodes.H_INVOKESPECIAL, newDynName, "lambda$" + actionIndex, methodBean.getDesc(), false), + org.redkale.asm.Type.getType("()" + Type.getDescriptor(method.getReturnType())) + }); + mv.visitVarInsn(ASTORE, 1 + method.getParameterCount()); + Label l1 = new Label(); + mv.visitLabel(l1); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, dynFieldName, Type.getDescriptor(CacheAction.class)); + + mv.visitVarInsn(ALOAD, 1 + method.getParameterCount()); + Asms.visitInsn(mv, method.getParameterCount()); + mv.visitTypeInsn(ANEWARRAY, "java/lang/Object"); + int insn = 0; + Class[] paramtypes = method.getParameterTypes(); + for (int j = 0; j < paramtypes.length; j++) { + final Class pt = paramtypes[j]; + mv.visitInsn(DUP); + insn++; + Asms.visitInsn(mv, j); + if (pt.isPrimitive()) { + if (pt == long.class) { + mv.visitVarInsn(LLOAD, insn++); + } else if (pt == float.class) { + mv.visitVarInsn(FLOAD, insn++); + } else if (pt == double.class) { + mv.visitVarInsn(DLOAD, insn++); + } else { + mv.visitVarInsn(ILOAD, insn); + } + Class bigclaz = TypeToken.primitiveToWrapper(pt); + mv.visitMethodInsn( + INVOKESTATIC, + bigclaz.getName().replace('.', '/'), + "valueOf", + "(" + Type.getDescriptor((Class) pt) + ")" + Type.getDescriptor(bigclaz), + false); + } else { + mv.visitVarInsn(ALOAD, insn); + } + mv.visitInsn(AASTORE); + } + String throwFuncDesc = Type.getDescriptor(ThrowSupplier.class); + mv.visitMethodInsn( + INVOKEVIRTUAL, + CacheAction.class.getName().replace('.', '/'), + "get", + "(" + throwFuncDesc + "[Ljava/lang/Object;)Ljava/lang/Object;", + false); + mv.visitTypeInsn(CHECKCAST, method.getReturnType().getName().replace('.', '/')); + mv.visitInsn(ARETURN); + Label l2 = new Label(); + mv.visitLabel(l2); + mv.visitLocalVariable("this", "L" + newDynName + ";", null, l0, l2, 0); + visitParamTypesLocalVariable(mv, method, l0, l2, insns, methodBean); + mv.visitLocalVariable("_redkale_supplier", Type.getDescriptor(ThrowSupplier.class), null, l1, l2, ++insn); + + mv.visitMaxs(20, 20); + mv.visitEnd(); + CacheAction action = new CacheAction( + new CacheEntry(cached), + method.getGenericReturnType(), + serviceType, + method.getParameterTypes(), + methodBean.fieldNameArray(), + method.getName(), + dynFieldName); + actions.put(dynFieldName, action); + } + { // ThrowSupplier + final MethodVisitor mv = cw.visitMethod( + ACC_PRIVATE + ACC_SYNTHETIC, "lambda$" + actionIndex, methodBean.getDesc(), null, new String[] { + "java/lang/Throwable" + }); + // mv.setDebug(true); + Label l0 = new Label(); + mv.visitLabel(l0); + mv.visitVarInsn(ALOAD, 0); + visitVarInsnParamTypes(mv, method, 0); + mv.visitMethodInsn(INVOKESPECIAL, newDynName, rsMethodName, methodBean.getDesc(), false); + mv.visitInsn(ARETURN); + Label l1 = new Label(); + mv.visitLabel(l1); + mv.visitLocalVariable("this", "L" + newDynName + ";", null, l0, l1, 0); + mv.visitMaxs(5, 5); + mv.visitEnd(); + } + { // 定义字段 + FieldVisitor fv = + cw.visitField(ACC_PRIVATE, dynFieldName, Type.getDescriptor(CacheAction.class), null, null); + fv.visitEnd(); + } + if (actions.size() == 1) { + cw.visitInnerClass( + "java/lang/invoke/MethodHandles$Lookup", + "java/lang/invoke/MethodHandles", + "Lookup", + ACC_PUBLIC + ACC_FINAL + ACC_STATIC); + } + return rsMethodName; + } + + @Override + public void doInstance(ResourceFactory resourceFactory, Object service) { + Class clazz = service.getClass(); + if (actionMap == null) { // 为null表示没有调用过doMethod, 动态类在编译是已经生成好了 + actionMap = new LinkedHashMap<>(); + Map methodBeans = AsmMethodBoost.getMethodBeans(clazz); + for (final Method method : clazz.getDeclaredMethods()) { + DynForCache cached = method.getAnnotation(DynForCache.class); + if (cached != null) { + String dynFieldName = cached.dynField(); + AsmMethodBean methodBean = AsmMethodBean.get(methodBeans, method); + CacheAction action = new CacheAction( + new CacheEntry(cached), + method.getGenericReturnType(), + serviceType, + method.getParameterTypes(), + methodBean.fieldNameArray(), + method.getName(), + dynFieldName); + actionMap.put(dynFieldName, action); + } + } + } + actionMap.forEach((field, action) -> { + try { + Field c = clazz.getDeclaredField(field); + c.setAccessible(true); + resourceFactory.inject(action); + action.init(); + c.set(service, action); + RedkaleClassLoader.putReflectionField(clazz.getName(), c); + } catch (Exception e) { + throw new RedkaleException("field (" + field + ") in " + clazz.getName() + " set error", e); + } + }); + // do nothing + } +} diff --git a/src/main/java/org/redkale/cache/spi/CacheEntry.java b/src/main/java/org/redkale/cache/spi/CacheEntry.java index fff15c591..129745133 100644 --- a/src/main/java/org/redkale/cache/spi/CacheEntry.java +++ b/src/main/java/org/redkale/cache/spi/CacheEntry.java @@ -1,97 +1,97 @@ -/* - * - */ -package org.redkale.cache.spi; - -import java.util.concurrent.TimeUnit; -import org.redkale.cache.Cached; -import org.redkale.convert.json.JsonConvert; - -/** @author zhangjx */ -public class CacheEntry { - - private String key; - - private String hash; - - private String localExpire; - - private String remoteExpire; - - private TimeUnit timeUnit; - - private boolean nullable; - - public CacheEntry() {} - - public CacheEntry(DynForCache cached) { - this.key = cached.key(); - this.hash = cached.hash(); - this.localExpire = cached.localExpire(); - this.remoteExpire = cached.remoteExpire(); - this.timeUnit = cached.timeUnit(); - this.nullable = cached.nullable(); - } - - public CacheEntry(Cached cached) { - this.key = cached.key(); - this.hash = cached.hash(); - this.localExpire = cached.localExpire(); - this.remoteExpire = cached.remoteExpire(); - this.timeUnit = cached.timeUnit(); - this.nullable = cached.nullable(); - } - - public String getKey() { - return key; - } - - public void setKey(String key) { - this.key = key; - } - - public String getHash() { - return hash; - } - - public void setHash(String hash) { - this.hash = hash; - } - - public String getLocalExpire() { - return localExpire; - } - - public void setLocalExpire(String localExpire) { - this.localExpire = localExpire; - } - - public String getRemoteExpire() { - return remoteExpire; - } - - public void setRemoteExpire(String remoteExpire) { - this.remoteExpire = remoteExpire; - } - - public TimeUnit getTimeUnit() { - return timeUnit; - } - - public void setTimeUnit(TimeUnit timeUnit) { - this.timeUnit = timeUnit; - } - - public boolean isNullable() { - return nullable; - } - - public void setNullable(boolean nullable) { - this.nullable = nullable; - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } -} +/* + * + */ +package org.redkale.cache.spi; + +import java.util.concurrent.TimeUnit; +import org.redkale.cache.Cached; +import org.redkale.convert.json.JsonConvert; + +/** @author zhangjx */ +public class CacheEntry { + + private String key; + + private String hash; + + private String localExpire; + + private String remoteExpire; + + private TimeUnit timeUnit; + + private boolean nullable; + + public CacheEntry() {} + + public CacheEntry(DynForCache cached) { + this.key = cached.key(); + this.hash = cached.hash(); + this.localExpire = cached.localExpire(); + this.remoteExpire = cached.remoteExpire(); + this.timeUnit = cached.timeUnit(); + this.nullable = cached.nullable(); + } + + public CacheEntry(Cached cached) { + this.key = cached.key(); + this.hash = cached.hash(); + this.localExpire = cached.localExpire(); + this.remoteExpire = cached.remoteExpire(); + this.timeUnit = cached.timeUnit(); + this.nullable = cached.nullable(); + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public String getHash() { + return hash; + } + + public void setHash(String hash) { + this.hash = hash; + } + + public String getLocalExpire() { + return localExpire; + } + + public void setLocalExpire(String localExpire) { + this.localExpire = localExpire; + } + + public String getRemoteExpire() { + return remoteExpire; + } + + public void setRemoteExpire(String remoteExpire) { + this.remoteExpire = remoteExpire; + } + + public TimeUnit getTimeUnit() { + return timeUnit; + } + + public void setTimeUnit(TimeUnit timeUnit) { + this.timeUnit = timeUnit; + } + + public boolean isNullable() { + return nullable; + } + + public void setNullable(boolean nullable) { + this.nullable = nullable; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } +} diff --git a/src/main/java/org/redkale/cache/spi/CacheManagerProvider.java b/src/main/java/org/redkale/cache/spi/CacheManagerProvider.java index 823f5d937..cbf4bbe20 100644 --- a/src/main/java/org/redkale/cache/spi/CacheManagerProvider.java +++ b/src/main/java/org/redkale/cache/spi/CacheManagerProvider.java @@ -1,17 +1,17 @@ -/* - * - */ -package org.redkale.cache.spi; - -import org.redkale.cache.CacheManager; -import org.redkale.util.InstanceProvider; - -/** - * 自定义的CacheManager加载器, 如果标记@Priority加载器的优先级需要大于1000, 1000以下预留给官方加载器 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public interface CacheManagerProvider extends InstanceProvider {} +/* + * + */ +package org.redkale.cache.spi; + +import org.redkale.cache.CacheManager; +import org.redkale.util.InstanceProvider; + +/** + * 自定义的CacheManager加载器, 如果标记@Priority加载器的优先级需要大于1000, 1000以下预留给官方加载器 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public interface CacheManagerProvider extends InstanceProvider {} diff --git a/src/main/java/org/redkale/cache/spi/CacheManagerService.java b/src/main/java/org/redkale/cache/spi/CacheManagerService.java index e7cb7b571..cb61a093e 100644 --- a/src/main/java/org/redkale/cache/spi/CacheManagerService.java +++ b/src/main/java/org/redkale/cache/spi/CacheManagerService.java @@ -1,948 +1,948 @@ -/* - * - */ -package org.redkale.cache.spi; - -import java.lang.reflect.Type; -import java.time.Duration; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentSkipListSet; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.locks.ReentrantLock; -import java.util.function.Function; -import org.redkale.annotation.AutoLoad; -import org.redkale.annotation.Component; -import org.redkale.annotation.Nullable; -import org.redkale.annotation.Resource; -import org.redkale.annotation.ResourceType; -import org.redkale.boot.Application; -import org.redkale.cache.CacheManager; -import org.redkale.service.Local; -import org.redkale.service.Service; -import org.redkale.source.CacheMemorySource; -import org.redkale.source.CacheSource; -import org.redkale.util.AnyValue; -import org.redkale.util.RedkaleException; -import org.redkale.util.ThrowSupplier; -import org.redkale.util.TypeToken; -import org.redkale.util.Utility; - -/** - * 缓存管理器 - * - * @author zhangjx - */ -@Local -@Component -@AutoLoad(false) -@ResourceType(CacheManager.class) -public class CacheManagerService implements CacheManager, Service { - - // 是否开启缓存 - protected boolean enabled = true; - - // 配置 - protected AnyValue config; - - // 数据类型与CacheValue泛型的对应关系 - private final ConcurrentHashMap cacheValueTypes = new ConcurrentHashMap<>(); - - // 本地缓存Source - protected final CacheMemorySource localSource = new CacheMemorySource("cache-local"); - - // 缓存hash集合, 用于定时遍历删除过期数据 - protected final ConcurrentSkipListSet hashNames = new ConcurrentSkipListSet<>(); - - // 缓存无效时使用的同步锁 - private final ConcurrentHashMap syncLock = new ConcurrentHashMap<>(); - - // 缓存无效时使用的异步锁 - private final ConcurrentHashMap asyncLock = new ConcurrentHashMap<>(); - - @Resource(required = false) - protected Application application; - - // 远程缓存Source - protected CacheSource remoteSource; - - protected CacheManagerService(@Nullable CacheSource remoteSource) { - this.remoteSource = remoteSource; - } - - // 一般用于独立组件 - public static CacheManagerService create(@Nullable CacheSource remoteSource) { - return new CacheManagerService(remoteSource); - } - - public boolean enabled() { - return this.enabled; - } - - public CacheManagerService enabled(boolean val) { - this.enabled = val; - return this; - } - - @Override - public void init(AnyValue conf) { - this.config = conf; - if (conf == null) { - conf = AnyValue.create(); - } - this.enabled = conf.getBoolValue("enabled", true); - if (this.enabled) { - this.localSource.init(conf); - String remoteSourceName = conf.getValue("remote"); - if (Utility.isNotBlank(remoteSourceName)) { - CacheSource source = application.loadCacheSource(remoteSourceName, false); - if (source == null) { - throw new RedkaleException("Not found CacheSource '" + remoteSourceName + "'"); - } - this.remoteSource = source; - } - } - } - - @Override - public void destroy(AnyValue conf) { - if (this.enabled) { - this.localSource.destroy(conf); - } - } - - public boolean isEnabled() { - return enabled; - } - - public CacheManagerService addHash(String hash) { - this.hashNames.add(hash); - return this; - } - - // -------------------------------------- 本地缓存 -------------------------------------- - /** - * 本地获取缓存数据, 过期返回null - * - * @param 泛型 - * @param hash 缓存hash - * @param key 缓存键 - * @param type 数据类型 - * @return 数据值 - */ - @Override - public T localGet(final String hash, final String key, final Type type) { - checkEnable(); - return CacheValue.get(localSource.get(idFor(hash, key), loadCacheType(type))); - } - - /** - * 本地获取缓存数据, 过期返回null - * - * @param 泛型 - * @param hash 缓存hash - * @param key 缓存键 - * @param type 数据类型 - * @param nullable 是否缓存null值 - * @param expire 过期时长,Duration.ZERO为永不过期 - * @param supplier 数据函数 - * @return 数据值 - */ - @Override - public T localGetSet( - final String hash, - final String key, - final Type type, - boolean nullable, - Duration expire, - ThrowSupplier supplier) { - return getSet(localSource::get, this::localSetCache, hash, key, type, nullable, expire, supplier); - } - - /** - * 本地异步获取缓存数据, 过期返回null - * - * @param 泛型 - * @param hash 缓存hash - * @param key 缓存键 - * @param type 数据类型 - * @param nullable 是否缓存null值 - * @param expire 过期时长,Duration.ZERO为永不过期 - * @param supplier 数据函数 - * @return 数据值 - */ - @Override - public CompletableFuture localGetSetAsync( - String hash, - String key, - Type type, - boolean nullable, - Duration expire, - ThrowSupplier> supplier) { - return getSetAsync( - localSource::getAsync, this::localSetCacheAsync, hash, key, type, nullable, expire, supplier); - } - - /** - * 本地缓存数据 - * - * @param 泛型 - * @param hash 缓存hash - * @param key 缓存键 - * @param type 数据类型 - * @param value 数据值 - * @param expire 过期时长,Duration.ZERO为永不过期 - */ - @Override - public void localSet(String hash, String key, Type type, T value, Duration expire) { - setCache(localSource, hash, key, type, value, expire); - } - - /** - * 本地删除缓存数据 - * - * @param hash 缓存hash - * @param key 缓存键 - * @return 删除数量 - */ - @Override - public long localDel(String hash, String key) { - checkEnable(); - return localSource.del(idFor(hash, key)); - } - - // -------------------------------------- 远程缓存 -------------------------------------- - /** - * 远程获取缓存数据, 过期返回null - * - * @param 泛型 - * @param hash 缓存hash - * @param key 缓存键 - * @param type 数据类型 - * @return 数据值 - */ - @Override - public T remoteGet(final String hash, final String key, final Type type) { - checkEnable(); - return CacheValue.get(remoteSource.get(idFor(hash, key), loadCacheType(type))); - } - - /** - * 远程异步获取缓存数据, 过期返回null - * - * @param 泛型 - * @param hash 缓存hash - * @param key 缓存键 - * @param type 数据类型 - * @return 数据值 - */ - @Override - public CompletableFuture remoteGetAsync(final String hash, final String key, final Type type) { - checkEnable(); - CompletableFuture> future = remoteSource.getAsync(idFor(hash, key), loadCacheType(type)); - return future.thenApply(CacheValue::get); - } - - /** - * 远程获取缓存数据, 过期返回null - * - * @param 泛型 - * @param hash 缓存hash - * @param key 缓存键 - * @param type 数据类型 - * @param nullable 是否缓存null值 - * @param expire 过期时长,Duration.ZERO为永不过期 - * @param supplier 数据函数 - * @return 数据值 - */ - @Override - public T remoteGetSet( - final String hash, - final String key, - final Type type, - boolean nullable, - Duration expire, - ThrowSupplier supplier) { - return getSet(remoteSource::get, this::remoteSetCache, hash, key, type, nullable, expire, supplier); - } - - /** - * 远程异步获取缓存数据, 过期返回null - * - * @param 泛型 - * @param hash 缓存hash - * @param key 缓存键 - * @param type 数据类型 - * @param nullable 是否缓存null值 - * @param expire 过期时长,Duration.ZERO为永不过期 - * @param supplier 数据函数 - * @return 数据值 - */ - @Override - public CompletableFuture remoteGetSetAsync( - String hash, - String key, - Type type, - boolean nullable, - Duration expire, - ThrowSupplier> supplier) { - return getSetAsync( - remoteSource::getAsync, this::remoteSetCacheAsync, hash, key, type, nullable, expire, supplier); - } - - /** - * 远程缓存数据 - * - * @param 泛型 - * @param hash 缓存hash - * @param key 缓存键 - * @param type 数据类型 - * @param value 数据值 - * @param expire 过期时长,Duration.ZERO为永不过期 - */ - @Override - public void remoteSet(final String hash, final String key, final Type type, final T value, Duration expire) { - setCache(remoteSource, hash, key, type, value, expire); - } - - /** - * 远程异步缓存数据 - * - * @param 泛型 - * @param hash 缓存hash - * @param key 缓存键 - * @param type 数据类型 - * @param value 数据值 - * @param expire 过期时长,Duration.ZERO为永不过期 - */ - @Override - public CompletableFuture remoteSetAsync(String hash, String key, Type type, T value, Duration expire) { - return setCacheAsync(remoteSource, hash, key, type, value, expire); - } - - /** - * 远程删除缓存数据 - * - * @param hash 缓存hash - * @param key 缓存键 - * @return 删除数量 - */ - @Override - public long remoteDel(String hash, String key) { - checkEnable(); - return remoteSource.del(idFor(hash, key)); - } - - /** - * 远程异步删除缓存数据 - * - * @param hash 缓存hash - * @param key 缓存键 - * @return 删除数量 - */ - @Override - public CompletableFuture remoteDelAsync(String hash, String key) { - checkEnable(); - return remoteSource.delAsync(idFor(hash, key)); - } - - // -------------------------------------- both缓存 -------------------------------------- - /** - * 远程获取缓存数据, 过期返回null - * - * @param 泛型 - * @param hash 缓存hash - * @param key 缓存键 - * @param type 数据类型 - * @return 数据值 - */ - @Override - public T bothGet(final String hash, final String key, final Type type) { - return CacheValue.get(bothGetCache(hash, key, type)); - } - - /** - * 远程异步获取缓存数据, 过期返回null - * - * @param 泛型 - * @param hash 缓存hash - * @param key 缓存键 - * @param type 数据类型 - * @return 数据值 - */ - @Override - public CompletableFuture bothGetAsync(final String hash, final String key, final Type type) { - return bothGetCacheAsync(hash, key, type).thenApply(CacheValue::get); - } - - /** - * 远程获取缓存数据, 过期返回null - * - * @param 泛型 - * @param hash 缓存hash - * @param key 缓存键 - * @param type 数据类型 - * @param nullable 是否缓存null值 - * @param localExpire 本地过期时长,Duration.ZERO为永不过期,为null表示不本地缓存 - * @param remoteExpire 远程过期时长,Duration.ZERO为永不过期,为null表示不远程缓存 - * @param supplier 数据函数 - * @return 数据值 - */ - @Override - public T bothGetSet( - final String hash, - final String key, - final Type type, - boolean nullable, - Duration localExpire, - Duration remoteExpire, - ThrowSupplier supplier) { - if (!enabled) { - try { - return supplier.get(); - } catch (RuntimeException e) { - throw e; - } catch (Throwable t) { - throw new RedkaleException(t); - } - } - if (remoteExpire == null) { // 只有本地缓存 - Objects.requireNonNull(localExpire); - return localGetSet(hash, key, type, nullable, localExpire, supplier); - } - if (localExpire == null) { // 只有远程缓存 - Objects.requireNonNull(remoteExpire); - return remoteGetSet(hash, key, type, nullable, remoteExpire, supplier); - } - return getSet( - this::bothGetCache, - (i, e, t, v) -> { - localSetCache(i, localExpire, t, v); - if (remoteSource != null) { - remoteSetCache(i, remoteExpire, t, v); - } - }, - hash, - key, - type, - nullable, - localExpire, - supplier); - } - - /** - * 远程异步获取缓存数据, 过期返回null - * - * @param 泛型 - * @param hash 缓存hash - * @param key 缓存键 - * @param type 数据类型 - * @param nullable 是否缓存null值 - * @param localExpire 本地过期时长,Duration.ZERO为永不过期,为null表示不本地缓存 - * @param remoteExpire 远程过期时长,Duration.ZERO为永不过期,为null表示不远程缓存 - * @param supplier 数据函数 - * @return 数据值 - */ - @Override - public CompletableFuture bothGetSetAsync( - String hash, - String key, - Type type, - boolean nullable, - Duration localExpire, - Duration remoteExpire, - ThrowSupplier> supplier) { - if (!enabled) { - try { - return supplier.get(); - } catch (Throwable t) { - return CompletableFuture.failedFuture(t); - } - } - if (remoteExpire == null) { // 只有本地缓存 - Objects.requireNonNull(localExpire); - return localGetSetAsync(hash, key, type, nullable, localExpire, supplier); - } - if (localExpire == null) { // 只有远程缓存 - Objects.requireNonNull(remoteExpire); - return remoteGetSetAsync(hash, key, type, nullable, remoteExpire, supplier); - } - return getSetAsync( - this::bothGetCacheAsync, - (i, e, t, v) -> { - localSetCache(i, localExpire, t, v); - if (remoteSource != null) { - return remoteSetCacheAsync(i, remoteExpire, t, v); - } else { - return CompletableFuture.completedFuture(null); - } - }, - hash, - key, - type, - nullable, - localExpire, - supplier); - } - - /** - * 远程缓存数据 - * - * @param 泛型 - * @param hash 缓存hash - * @param key 缓存键 - * @param type 数据类型 - * @param value 数据值 - * @param localExpire 本地过期时长,Duration.ZERO为永不过期,为null表示不本地缓存 - * @param remoteExpire 远程过期时长,Duration.ZERO为永不过期,为null表示不远程缓存 - */ - @Override - public void bothSet( - final String hash, - final String key, - final Type type, - final T value, - Duration localExpire, - Duration remoteExpire) { - checkEnable(); - if (localExpire != null) { - setCache(localSource, hash, key, type, value, localExpire); - } - if (remoteSource != null && remoteExpire != null) { - setCache(remoteSource, hash, key, type, value, remoteExpire); - } - } - - /** - * 远程异步缓存数据 - * - * @param 泛型 - * @param hash 缓存hash - * @param key 缓存键 - * @param type 数据类型 - * @param value 数据值 - * @param localExpire 本地过期时长,Duration.ZERO为永不过期,为null表示不本地缓存 - * @param remoteExpire 远程过期时长,Duration.ZERO为永不过期,为null表示不远程缓存 - * @return void - */ - @Override - public CompletableFuture bothSetAsync( - String hash, String key, Type type, T value, Duration localExpire, Duration remoteExpire) { - checkEnable(); - if (localExpire != null) { - setCache(localSource, hash, key, type, value, localExpire); - } - if (remoteSource != null && remoteExpire != null) { - return setCacheAsync(remoteSource, hash, key, type, value, remoteExpire); - } else { - return CompletableFuture.completedFuture(null); - } - } - - /** - * 远程删除缓存数据 - * - * @param hash 缓存hash - * @param key 缓存键 - * @return 删除数量 - */ - @Override - public long bothDel(String hash, String key) { - checkEnable(); - String id = idFor(hash, key); - long v = localSource.del(id); - if (remoteSource != null) { - return remoteSource.del(id); - } else { - return v; - } - } - - /** - * 远程异步删除缓存数据 - * - * @param hash 缓存hash - * @param key 缓存键 - * @return 删除数量 - */ - @Override - public CompletableFuture bothDelAsync(String hash, String key) { - checkEnable(); - String id = idFor(hash, key); - long v = localSource.del(id); // 内存操作,无需异步 - if (remoteSource != null) { - return remoteSource.delAsync(id); - } else { - return CompletableFuture.completedFuture(v); - } - } - - // -------------------------------------- 内部方法 -------------------------------------- - /** - * 获取缓存数据, 过期返回null - * - * @param 泛型 - * @param getter 获取数据函数 - * @param setter 设置数据函数 - * @param hash 缓存hash - * @param key 缓存键 - * @param type 数据类型 - * @param nullable 是否缓存null值 - * @param expire 过期时长,Duration.ZERO为永不过期 - * @param supplier 数据函数 - * @return 数据值 - */ - protected T getSet( - GetterFunc> getter, - SetterSyncFunc setter, - String hash, - String key, - Type type, - boolean nullable, - Duration expire, - ThrowSupplier supplier) { - checkEnable(); - Objects.requireNonNull(expire); - Objects.requireNonNull(supplier); - final Type cacheType = loadCacheType(type); - final String id = idFor(hash, key); - CacheValue cacheVal = getter.get(id, cacheType); - if (CacheValue.isValid(cacheVal)) { - return cacheVal.getVal(); - } - Function func = k -> { - CacheValue oldCacheVal = getter.get(id, cacheType); - if (CacheValue.isValid(oldCacheVal)) { - return oldCacheVal; - } - CacheValue newCacheVal; - try { - newCacheVal = toCacheSupplier(nullable, supplier).get(); - } catch (RuntimeException e) { - throw e; - } catch (Throwable t) { - throw new RedkaleException(t); - } - if (CacheValue.isValid(newCacheVal)) { - setter.set(id, expire, cacheType, newCacheVal); - } - return newCacheVal; - }; - cacheVal = syncLock.computeIfAbsent(id, func); - try { - return CacheValue.get(cacheVal); - } finally { - syncLock.remove(id); - } - } - - /** - * 异步获取缓存数据, 过期返回null - * - * @param 泛型 - * @param getter 获取数据函数 - * @param setter 设置数据函数 - * @param hash 缓存hash - * @param key 缓存键 - * @param type 数据类型 - * @param nullable 是否缓存null值 - * @param expire 过期时长,Duration.ZERO为永不过期 - * @param supplier 数据函数 - * @return 数据值 - */ - protected CompletableFuture getSetAsync( - GetterFunc>> getter, - SetterAsyncFunc setter, - String hash, - String key, - Type type, - boolean nullable, - Duration expire, - ThrowSupplier> supplier) { - checkEnable(); - Objects.requireNonNull(supplier); - final Type cacheType = loadCacheType(type); - final String id = idFor(hash, key); - CompletableFuture> sourceFuture = getter.get(id, cacheType); - return sourceFuture.thenCompose(val -> { - if (CacheValue.isValid(val)) { - return CompletableFuture.completedFuture(val.getVal()); - } - final CacheAsyncEntry entry = asyncLock.computeIfAbsent(id, CacheAsyncEntry::new); - CompletableFuture future = new CompletableFuture<>(); - if (entry.compareAddFuture(future)) { - try { - supplier.get().whenComplete((v, e) -> { - if (e != null) { - entry.fail(e); - } - CacheValue cacheVal = toCacheValue(nullable, v); - if (CacheValue.isValid(cacheVal)) { - setter.set(id, expire, cacheType, cacheVal) - .whenComplete((v2, e2) -> entry.success(CacheValue.get(cacheVal))); - } else { - entry.success(CacheValue.get(cacheVal)); - } - }); - } catch (Throwable e) { - entry.fail(e); - } - } - return future; - }); - } - - protected CompletableFuture localSetCacheAsync( - String id, Duration expire, Type cacheType, CacheValue cacheVal) { - return setCacheAsync(localSource, id, expire, cacheType, cacheVal); - } - - protected CompletableFuture remoteSetCacheAsync( - String id, Duration expire, Type cacheType, CacheValue cacheVal) { - return setCacheAsync(remoteSource, id, expire, cacheType, cacheVal); - } - - protected void localSetCache(String id, Duration expire, Type cacheType, CacheValue cacheVal) { - setCache(localSource, id, expire, cacheType, cacheVal); - } - - protected void remoteSetCache(String id, Duration expire, Type cacheType, CacheValue cacheVal) { - setCache(remoteSource, id, expire, cacheType, cacheVal); - } - - protected void setCache( - CacheSource source, String id, Duration expire, Type cacheType, CacheValue cacheVal) { - checkEnable(); - Objects.requireNonNull(expire); - long millis = expire.toMillis(); - if (millis > 0) { - source.psetex(id, millis, cacheType, cacheVal); - } else { - source.set(id, cacheType, cacheVal); - } - } - - protected CompletableFuture setCacheAsync( - CacheSource source, String id, Duration expire, Type cacheType, CacheValue cacheVal) { - checkEnable(); - Objects.requireNonNull(expire); - long millis = expire.toMillis(); - if (millis > 0) { - return source.psetexAsync(id, millis, cacheType, cacheVal); - } else { - return source.setAsync(id, cacheType, cacheVal); - } - } - - protected void setCache(CacheSource source, String hash, String key, Type type, T value, Duration expire) { - setCache(source, idFor(hash, key), expire, loadCacheType(type, value), CacheValue.create(value)); - } - - protected CompletableFuture setCacheAsync( - CacheSource source, String hash, String key, Type type, T value, Duration expire) { - return setCacheAsync(source, idFor(hash, key), expire, loadCacheType(type, value), CacheValue.create(value)); - } - - protected CacheValue bothGetCache(final String hash, final String key, final Type type) { - return bothGetCache(idFor(hash, key), loadCacheType(type)); - } - - /** - * 远程异步获取缓存数据, 过期返回null - * - * @param 泛型 - * @param hash 缓存hash - * @param key 缓存键 - * @param type 数据类型 - * @return 数据值 - */ - protected CompletableFuture> bothGetCacheAsync( - final String hash, final String key, final Type type) { - return bothGetCacheAsync(idFor(hash, key), loadCacheType(type)); - } - - protected CacheValue bothGetCache(final String id, final Type cacheType) { - checkEnable(); - CacheValue cacheVal = localSource.get(id, cacheType); - if (CacheValue.isValid(cacheVal)) { - return cacheVal; - } - if (remoteSource != null) { - return remoteSource.get(id, cacheType); - } else { - return null; - } - } - - /** - * 远程异步获取缓存数据, 过期返回null - * - * @param 泛型 - * @param id 缓存键 - * @param cacheType 数据类型 - * @return 数据值 - */ - protected CompletableFuture> bothGetCacheAsync(final String id, final Type cacheType) { - checkEnable(); - CacheValue val = localSource.get(id, cacheType); // 内存操作,无需异步 - if (CacheValue.isValid(val)) { - return CompletableFuture.completedFuture(val); - } - if (remoteSource != null) { - return remoteSource.getAsync(id, cacheType); - } else { - return CompletableFuture.completedFuture(null); - } - } - - protected void checkEnable() { - if (!enabled) { - throw new RedkaleException(CacheManager.class.getSimpleName() + " is disabled"); - } - } - - /** - * 创建一个锁key - * - * @param hash 缓存hash - * @param key 缓存键 - * @return key - */ - protected String idFor(String hash, String key) { - return hash + ':' + key; - } - - /** - * 将原始数据函数转换成获取CacheValue数据函数 - * - * @param 泛型 - * @param nullable 是否缓存null值 - * @param value 缓存值 - * @return CacheValue函数 - */ - protected CacheValue toCacheValue(boolean nullable, T value) { - if (value == null) { - return nullable ? CacheValue.create(value) : null; - } - return CacheValue.create(value); - } - - /** - * 将原始数据函数转换成获取CacheValue数据函数 - * - * @param 泛型 - * @param nullable 是否缓存null值 - * @param supplier 数据函数 - * @return CacheValue函数 - */ - protected ThrowSupplier> toCacheSupplier(boolean nullable, ThrowSupplier supplier) { - return () -> toCacheValue(nullable, supplier.get()); - } - - /** - * 创建数据类型创建对应CacheValue泛型 - * - * @param type 数据类型,为null则取value的类型 - * @param value 数据值 - * @return CacheValue泛型 - */ - protected Type loadCacheType(Type type, final Object value) { - return loadCacheType(type == null ? value.getClass() : type); - } - - /** - * 创建数据类型创建对应CacheValue泛型 - * - * @param type 数据类型 - * @return CacheValue泛型 - */ - protected Type loadCacheType(Type type) { - return cacheValueTypes.computeIfAbsent( - type, t -> TypeToken.createParameterizedType(null, CacheValue.class, type)); - } - - private static final Object NIL = new Object(); - - protected static interface GetterFunc { - - public R get(String id, Type cacheType); - } - - protected static interface SetterSyncFunc { - - public void set(String id, Duration expire, Type cacheType, CacheValue cacheVal); - } - - protected static interface SetterAsyncFunc { - - public CompletableFuture set(String id, Duration expire, Type cacheType, CacheValue cacheVal); - } - - protected class CacheAsyncEntry { - - private final AtomicBoolean state = new AtomicBoolean(); - - private final List futures = new ArrayList<>(); - - private final ReentrantLock lock = new ReentrantLock(); - - private final String lockId; - - private Object resultObj = NIL; - - private Throwable resultExp; - - public CacheAsyncEntry(String lockId) { - this.lockId = lockId; - } - - public boolean compareAddFuture(CompletableFuture future) { - lock.lock(); - try { - if (resultObj != NIL) { - future.complete(resultObj); - return false; - } else if (resultExp != null) { - future.completeExceptionally(resultExp); - return false; - } - boolean rs = state.compareAndSet(false, true); - this.futures.add(future); - return rs; - } finally { - lock.unlock(); - } - } - - public void fail(Throwable t) { - lock.lock(); - try { - this.resultExp = t; - for (CompletableFuture future : futures) { - future.completeExceptionally(t); - } - this.futures.clear(); - } finally { - asyncLock.remove(lockId); - lock.unlock(); - } - } - - public void success(T val) { - lock.lock(); - try { - this.resultObj = val; - for (CompletableFuture future : futures) { - future.complete(val); - } - this.futures.clear(); - } finally { - asyncLock.remove(lockId); - lock.unlock(); - } - } - } -} +/* + * + */ +package org.redkale.cache.spi; + +import java.lang.reflect.Type; +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentSkipListSet; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.locks.ReentrantLock; +import java.util.function.Function; +import org.redkale.annotation.AutoLoad; +import org.redkale.annotation.Component; +import org.redkale.annotation.Nullable; +import org.redkale.annotation.Resource; +import org.redkale.annotation.ResourceType; +import org.redkale.boot.Application; +import org.redkale.cache.CacheManager; +import org.redkale.service.Local; +import org.redkale.service.Service; +import org.redkale.source.CacheMemorySource; +import org.redkale.source.CacheSource; +import org.redkale.util.AnyValue; +import org.redkale.util.RedkaleException; +import org.redkale.util.ThrowSupplier; +import org.redkale.util.TypeToken; +import org.redkale.util.Utility; + +/** + * 缓存管理器 + * + * @author zhangjx + */ +@Local +@Component +@AutoLoad(false) +@ResourceType(CacheManager.class) +public class CacheManagerService implements CacheManager, Service { + + // 是否开启缓存 + protected boolean enabled = true; + + // 配置 + protected AnyValue config; + + // 数据类型与CacheValue泛型的对应关系 + private final ConcurrentHashMap cacheValueTypes = new ConcurrentHashMap<>(); + + // 本地缓存Source + protected final CacheMemorySource localSource = new CacheMemorySource("cache-local"); + + // 缓存hash集合, 用于定时遍历删除过期数据 + protected final ConcurrentSkipListSet hashNames = new ConcurrentSkipListSet<>(); + + // 缓存无效时使用的同步锁 + private final ConcurrentHashMap syncLock = new ConcurrentHashMap<>(); + + // 缓存无效时使用的异步锁 + private final ConcurrentHashMap asyncLock = new ConcurrentHashMap<>(); + + @Resource(required = false) + protected Application application; + + // 远程缓存Source + protected CacheSource remoteSource; + + protected CacheManagerService(@Nullable CacheSource remoteSource) { + this.remoteSource = remoteSource; + } + + // 一般用于独立组件 + public static CacheManagerService create(@Nullable CacheSource remoteSource) { + return new CacheManagerService(remoteSource); + } + + public boolean enabled() { + return this.enabled; + } + + public CacheManagerService enabled(boolean val) { + this.enabled = val; + return this; + } + + @Override + public void init(AnyValue conf) { + this.config = conf; + if (conf == null) { + conf = AnyValue.create(); + } + this.enabled = conf.getBoolValue("enabled", true); + if (this.enabled) { + this.localSource.init(conf); + String remoteSourceName = conf.getValue("remote"); + if (Utility.isNotBlank(remoteSourceName)) { + CacheSource source = application.loadCacheSource(remoteSourceName, false); + if (source == null) { + throw new RedkaleException("Not found CacheSource '" + remoteSourceName + "'"); + } + this.remoteSource = source; + } + } + } + + @Override + public void destroy(AnyValue conf) { + if (this.enabled) { + this.localSource.destroy(conf); + } + } + + public boolean isEnabled() { + return enabled; + } + + public CacheManagerService addHash(String hash) { + this.hashNames.add(hash); + return this; + } + + // -------------------------------------- 本地缓存 -------------------------------------- + /** + * 本地获取缓存数据, 过期返回null + * + * @param 泛型 + * @param hash 缓存hash + * @param key 缓存键 + * @param type 数据类型 + * @return 数据值 + */ + @Override + public T localGet(final String hash, final String key, final Type type) { + checkEnable(); + return CacheValue.get(localSource.get(idFor(hash, key), loadCacheType(type))); + } + + /** + * 本地获取缓存数据, 过期返回null + * + * @param 泛型 + * @param hash 缓存hash + * @param key 缓存键 + * @param type 数据类型 + * @param nullable 是否缓存null值 + * @param expire 过期时长,Duration.ZERO为永不过期 + * @param supplier 数据函数 + * @return 数据值 + */ + @Override + public T localGetSet( + final String hash, + final String key, + final Type type, + boolean nullable, + Duration expire, + ThrowSupplier supplier) { + return getSet(localSource::get, this::localSetCache, hash, key, type, nullable, expire, supplier); + } + + /** + * 本地异步获取缓存数据, 过期返回null + * + * @param 泛型 + * @param hash 缓存hash + * @param key 缓存键 + * @param type 数据类型 + * @param nullable 是否缓存null值 + * @param expire 过期时长,Duration.ZERO为永不过期 + * @param supplier 数据函数 + * @return 数据值 + */ + @Override + public CompletableFuture localGetSetAsync( + String hash, + String key, + Type type, + boolean nullable, + Duration expire, + ThrowSupplier> supplier) { + return getSetAsync( + localSource::getAsync, this::localSetCacheAsync, hash, key, type, nullable, expire, supplier); + } + + /** + * 本地缓存数据 + * + * @param 泛型 + * @param hash 缓存hash + * @param key 缓存键 + * @param type 数据类型 + * @param value 数据值 + * @param expire 过期时长,Duration.ZERO为永不过期 + */ + @Override + public void localSet(String hash, String key, Type type, T value, Duration expire) { + setCache(localSource, hash, key, type, value, expire); + } + + /** + * 本地删除缓存数据 + * + * @param hash 缓存hash + * @param key 缓存键 + * @return 删除数量 + */ + @Override + public long localDel(String hash, String key) { + checkEnable(); + return localSource.del(idFor(hash, key)); + } + + // -------------------------------------- 远程缓存 -------------------------------------- + /** + * 远程获取缓存数据, 过期返回null + * + * @param 泛型 + * @param hash 缓存hash + * @param key 缓存键 + * @param type 数据类型 + * @return 数据值 + */ + @Override + public T remoteGet(final String hash, final String key, final Type type) { + checkEnable(); + return CacheValue.get(remoteSource.get(idFor(hash, key), loadCacheType(type))); + } + + /** + * 远程异步获取缓存数据, 过期返回null + * + * @param 泛型 + * @param hash 缓存hash + * @param key 缓存键 + * @param type 数据类型 + * @return 数据值 + */ + @Override + public CompletableFuture remoteGetAsync(final String hash, final String key, final Type type) { + checkEnable(); + CompletableFuture> future = remoteSource.getAsync(idFor(hash, key), loadCacheType(type)); + return future.thenApply(CacheValue::get); + } + + /** + * 远程获取缓存数据, 过期返回null + * + * @param 泛型 + * @param hash 缓存hash + * @param key 缓存键 + * @param type 数据类型 + * @param nullable 是否缓存null值 + * @param expire 过期时长,Duration.ZERO为永不过期 + * @param supplier 数据函数 + * @return 数据值 + */ + @Override + public T remoteGetSet( + final String hash, + final String key, + final Type type, + boolean nullable, + Duration expire, + ThrowSupplier supplier) { + return getSet(remoteSource::get, this::remoteSetCache, hash, key, type, nullable, expire, supplier); + } + + /** + * 远程异步获取缓存数据, 过期返回null + * + * @param 泛型 + * @param hash 缓存hash + * @param key 缓存键 + * @param type 数据类型 + * @param nullable 是否缓存null值 + * @param expire 过期时长,Duration.ZERO为永不过期 + * @param supplier 数据函数 + * @return 数据值 + */ + @Override + public CompletableFuture remoteGetSetAsync( + String hash, + String key, + Type type, + boolean nullable, + Duration expire, + ThrowSupplier> supplier) { + return getSetAsync( + remoteSource::getAsync, this::remoteSetCacheAsync, hash, key, type, nullable, expire, supplier); + } + + /** + * 远程缓存数据 + * + * @param 泛型 + * @param hash 缓存hash + * @param key 缓存键 + * @param type 数据类型 + * @param value 数据值 + * @param expire 过期时长,Duration.ZERO为永不过期 + */ + @Override + public void remoteSet(final String hash, final String key, final Type type, final T value, Duration expire) { + setCache(remoteSource, hash, key, type, value, expire); + } + + /** + * 远程异步缓存数据 + * + * @param 泛型 + * @param hash 缓存hash + * @param key 缓存键 + * @param type 数据类型 + * @param value 数据值 + * @param expire 过期时长,Duration.ZERO为永不过期 + */ + @Override + public CompletableFuture remoteSetAsync(String hash, String key, Type type, T value, Duration expire) { + return setCacheAsync(remoteSource, hash, key, type, value, expire); + } + + /** + * 远程删除缓存数据 + * + * @param hash 缓存hash + * @param key 缓存键 + * @return 删除数量 + */ + @Override + public long remoteDel(String hash, String key) { + checkEnable(); + return remoteSource.del(idFor(hash, key)); + } + + /** + * 远程异步删除缓存数据 + * + * @param hash 缓存hash + * @param key 缓存键 + * @return 删除数量 + */ + @Override + public CompletableFuture remoteDelAsync(String hash, String key) { + checkEnable(); + return remoteSource.delAsync(idFor(hash, key)); + } + + // -------------------------------------- both缓存 -------------------------------------- + /** + * 远程获取缓存数据, 过期返回null + * + * @param 泛型 + * @param hash 缓存hash + * @param key 缓存键 + * @param type 数据类型 + * @return 数据值 + */ + @Override + public T bothGet(final String hash, final String key, final Type type) { + return CacheValue.get(bothGetCache(hash, key, type)); + } + + /** + * 远程异步获取缓存数据, 过期返回null + * + * @param 泛型 + * @param hash 缓存hash + * @param key 缓存键 + * @param type 数据类型 + * @return 数据值 + */ + @Override + public CompletableFuture bothGetAsync(final String hash, final String key, final Type type) { + return bothGetCacheAsync(hash, key, type).thenApply(CacheValue::get); + } + + /** + * 远程获取缓存数据, 过期返回null + * + * @param 泛型 + * @param hash 缓存hash + * @param key 缓存键 + * @param type 数据类型 + * @param nullable 是否缓存null值 + * @param localExpire 本地过期时长,Duration.ZERO为永不过期,为null表示不本地缓存 + * @param remoteExpire 远程过期时长,Duration.ZERO为永不过期,为null表示不远程缓存 + * @param supplier 数据函数 + * @return 数据值 + */ + @Override + public T bothGetSet( + final String hash, + final String key, + final Type type, + boolean nullable, + Duration localExpire, + Duration remoteExpire, + ThrowSupplier supplier) { + if (!enabled) { + try { + return supplier.get(); + } catch (RuntimeException e) { + throw e; + } catch (Throwable t) { + throw new RedkaleException(t); + } + } + if (remoteExpire == null) { // 只有本地缓存 + Objects.requireNonNull(localExpire); + return localGetSet(hash, key, type, nullable, localExpire, supplier); + } + if (localExpire == null) { // 只有远程缓存 + Objects.requireNonNull(remoteExpire); + return remoteGetSet(hash, key, type, nullable, remoteExpire, supplier); + } + return getSet( + this::bothGetCache, + (i, e, t, v) -> { + localSetCache(i, localExpire, t, v); + if (remoteSource != null) { + remoteSetCache(i, remoteExpire, t, v); + } + }, + hash, + key, + type, + nullable, + localExpire, + supplier); + } + + /** + * 远程异步获取缓存数据, 过期返回null + * + * @param 泛型 + * @param hash 缓存hash + * @param key 缓存键 + * @param type 数据类型 + * @param nullable 是否缓存null值 + * @param localExpire 本地过期时长,Duration.ZERO为永不过期,为null表示不本地缓存 + * @param remoteExpire 远程过期时长,Duration.ZERO为永不过期,为null表示不远程缓存 + * @param supplier 数据函数 + * @return 数据值 + */ + @Override + public CompletableFuture bothGetSetAsync( + String hash, + String key, + Type type, + boolean nullable, + Duration localExpire, + Duration remoteExpire, + ThrowSupplier> supplier) { + if (!enabled) { + try { + return supplier.get(); + } catch (Throwable t) { + return CompletableFuture.failedFuture(t); + } + } + if (remoteExpire == null) { // 只有本地缓存 + Objects.requireNonNull(localExpire); + return localGetSetAsync(hash, key, type, nullable, localExpire, supplier); + } + if (localExpire == null) { // 只有远程缓存 + Objects.requireNonNull(remoteExpire); + return remoteGetSetAsync(hash, key, type, nullable, remoteExpire, supplier); + } + return getSetAsync( + this::bothGetCacheAsync, + (i, e, t, v) -> { + localSetCache(i, localExpire, t, v); + if (remoteSource != null) { + return remoteSetCacheAsync(i, remoteExpire, t, v); + } else { + return CompletableFuture.completedFuture(null); + } + }, + hash, + key, + type, + nullable, + localExpire, + supplier); + } + + /** + * 远程缓存数据 + * + * @param 泛型 + * @param hash 缓存hash + * @param key 缓存键 + * @param type 数据类型 + * @param value 数据值 + * @param localExpire 本地过期时长,Duration.ZERO为永不过期,为null表示不本地缓存 + * @param remoteExpire 远程过期时长,Duration.ZERO为永不过期,为null表示不远程缓存 + */ + @Override + public void bothSet( + final String hash, + final String key, + final Type type, + final T value, + Duration localExpire, + Duration remoteExpire) { + checkEnable(); + if (localExpire != null) { + setCache(localSource, hash, key, type, value, localExpire); + } + if (remoteSource != null && remoteExpire != null) { + setCache(remoteSource, hash, key, type, value, remoteExpire); + } + } + + /** + * 远程异步缓存数据 + * + * @param 泛型 + * @param hash 缓存hash + * @param key 缓存键 + * @param type 数据类型 + * @param value 数据值 + * @param localExpire 本地过期时长,Duration.ZERO为永不过期,为null表示不本地缓存 + * @param remoteExpire 远程过期时长,Duration.ZERO为永不过期,为null表示不远程缓存 + * @return void + */ + @Override + public CompletableFuture bothSetAsync( + String hash, String key, Type type, T value, Duration localExpire, Duration remoteExpire) { + checkEnable(); + if (localExpire != null) { + setCache(localSource, hash, key, type, value, localExpire); + } + if (remoteSource != null && remoteExpire != null) { + return setCacheAsync(remoteSource, hash, key, type, value, remoteExpire); + } else { + return CompletableFuture.completedFuture(null); + } + } + + /** + * 远程删除缓存数据 + * + * @param hash 缓存hash + * @param key 缓存键 + * @return 删除数量 + */ + @Override + public long bothDel(String hash, String key) { + checkEnable(); + String id = idFor(hash, key); + long v = localSource.del(id); + if (remoteSource != null) { + return remoteSource.del(id); + } else { + return v; + } + } + + /** + * 远程异步删除缓存数据 + * + * @param hash 缓存hash + * @param key 缓存键 + * @return 删除数量 + */ + @Override + public CompletableFuture bothDelAsync(String hash, String key) { + checkEnable(); + String id = idFor(hash, key); + long v = localSource.del(id); // 内存操作,无需异步 + if (remoteSource != null) { + return remoteSource.delAsync(id); + } else { + return CompletableFuture.completedFuture(v); + } + } + + // -------------------------------------- 内部方法 -------------------------------------- + /** + * 获取缓存数据, 过期返回null + * + * @param 泛型 + * @param getter 获取数据函数 + * @param setter 设置数据函数 + * @param hash 缓存hash + * @param key 缓存键 + * @param type 数据类型 + * @param nullable 是否缓存null值 + * @param expire 过期时长,Duration.ZERO为永不过期 + * @param supplier 数据函数 + * @return 数据值 + */ + protected T getSet( + GetterFunc> getter, + SetterSyncFunc setter, + String hash, + String key, + Type type, + boolean nullable, + Duration expire, + ThrowSupplier supplier) { + checkEnable(); + Objects.requireNonNull(expire); + Objects.requireNonNull(supplier); + final Type cacheType = loadCacheType(type); + final String id = idFor(hash, key); + CacheValue cacheVal = getter.get(id, cacheType); + if (CacheValue.isValid(cacheVal)) { + return cacheVal.getVal(); + } + Function func = k -> { + CacheValue oldCacheVal = getter.get(id, cacheType); + if (CacheValue.isValid(oldCacheVal)) { + return oldCacheVal; + } + CacheValue newCacheVal; + try { + newCacheVal = toCacheSupplier(nullable, supplier).get(); + } catch (RuntimeException e) { + throw e; + } catch (Throwable t) { + throw new RedkaleException(t); + } + if (CacheValue.isValid(newCacheVal)) { + setter.set(id, expire, cacheType, newCacheVal); + } + return newCacheVal; + }; + cacheVal = syncLock.computeIfAbsent(id, func); + try { + return CacheValue.get(cacheVal); + } finally { + syncLock.remove(id); + } + } + + /** + * 异步获取缓存数据, 过期返回null + * + * @param 泛型 + * @param getter 获取数据函数 + * @param setter 设置数据函数 + * @param hash 缓存hash + * @param key 缓存键 + * @param type 数据类型 + * @param nullable 是否缓存null值 + * @param expire 过期时长,Duration.ZERO为永不过期 + * @param supplier 数据函数 + * @return 数据值 + */ + protected CompletableFuture getSetAsync( + GetterFunc>> getter, + SetterAsyncFunc setter, + String hash, + String key, + Type type, + boolean nullable, + Duration expire, + ThrowSupplier> supplier) { + checkEnable(); + Objects.requireNonNull(supplier); + final Type cacheType = loadCacheType(type); + final String id = idFor(hash, key); + CompletableFuture> sourceFuture = getter.get(id, cacheType); + return sourceFuture.thenCompose(val -> { + if (CacheValue.isValid(val)) { + return CompletableFuture.completedFuture(val.getVal()); + } + final CacheAsyncEntry entry = asyncLock.computeIfAbsent(id, CacheAsyncEntry::new); + CompletableFuture future = new CompletableFuture<>(); + if (entry.compareAddFuture(future)) { + try { + supplier.get().whenComplete((v, e) -> { + if (e != null) { + entry.fail(e); + } + CacheValue cacheVal = toCacheValue(nullable, v); + if (CacheValue.isValid(cacheVal)) { + setter.set(id, expire, cacheType, cacheVal) + .whenComplete((v2, e2) -> entry.success(CacheValue.get(cacheVal))); + } else { + entry.success(CacheValue.get(cacheVal)); + } + }); + } catch (Throwable e) { + entry.fail(e); + } + } + return future; + }); + } + + protected CompletableFuture localSetCacheAsync( + String id, Duration expire, Type cacheType, CacheValue cacheVal) { + return setCacheAsync(localSource, id, expire, cacheType, cacheVal); + } + + protected CompletableFuture remoteSetCacheAsync( + String id, Duration expire, Type cacheType, CacheValue cacheVal) { + return setCacheAsync(remoteSource, id, expire, cacheType, cacheVal); + } + + protected void localSetCache(String id, Duration expire, Type cacheType, CacheValue cacheVal) { + setCache(localSource, id, expire, cacheType, cacheVal); + } + + protected void remoteSetCache(String id, Duration expire, Type cacheType, CacheValue cacheVal) { + setCache(remoteSource, id, expire, cacheType, cacheVal); + } + + protected void setCache( + CacheSource source, String id, Duration expire, Type cacheType, CacheValue cacheVal) { + checkEnable(); + Objects.requireNonNull(expire); + long millis = expire.toMillis(); + if (millis > 0) { + source.psetex(id, millis, cacheType, cacheVal); + } else { + source.set(id, cacheType, cacheVal); + } + } + + protected CompletableFuture setCacheAsync( + CacheSource source, String id, Duration expire, Type cacheType, CacheValue cacheVal) { + checkEnable(); + Objects.requireNonNull(expire); + long millis = expire.toMillis(); + if (millis > 0) { + return source.psetexAsync(id, millis, cacheType, cacheVal); + } else { + return source.setAsync(id, cacheType, cacheVal); + } + } + + protected void setCache(CacheSource source, String hash, String key, Type type, T value, Duration expire) { + setCache(source, idFor(hash, key), expire, loadCacheType(type, value), CacheValue.create(value)); + } + + protected CompletableFuture setCacheAsync( + CacheSource source, String hash, String key, Type type, T value, Duration expire) { + return setCacheAsync(source, idFor(hash, key), expire, loadCacheType(type, value), CacheValue.create(value)); + } + + protected CacheValue bothGetCache(final String hash, final String key, final Type type) { + return bothGetCache(idFor(hash, key), loadCacheType(type)); + } + + /** + * 远程异步获取缓存数据, 过期返回null + * + * @param 泛型 + * @param hash 缓存hash + * @param key 缓存键 + * @param type 数据类型 + * @return 数据值 + */ + protected CompletableFuture> bothGetCacheAsync( + final String hash, final String key, final Type type) { + return bothGetCacheAsync(idFor(hash, key), loadCacheType(type)); + } + + protected CacheValue bothGetCache(final String id, final Type cacheType) { + checkEnable(); + CacheValue cacheVal = localSource.get(id, cacheType); + if (CacheValue.isValid(cacheVal)) { + return cacheVal; + } + if (remoteSource != null) { + return remoteSource.get(id, cacheType); + } else { + return null; + } + } + + /** + * 远程异步获取缓存数据, 过期返回null + * + * @param 泛型 + * @param id 缓存键 + * @param cacheType 数据类型 + * @return 数据值 + */ + protected CompletableFuture> bothGetCacheAsync(final String id, final Type cacheType) { + checkEnable(); + CacheValue val = localSource.get(id, cacheType); // 内存操作,无需异步 + if (CacheValue.isValid(val)) { + return CompletableFuture.completedFuture(val); + } + if (remoteSource != null) { + return remoteSource.getAsync(id, cacheType); + } else { + return CompletableFuture.completedFuture(null); + } + } + + protected void checkEnable() { + if (!enabled) { + throw new RedkaleException(CacheManager.class.getSimpleName() + " is disabled"); + } + } + + /** + * 创建一个锁key + * + * @param hash 缓存hash + * @param key 缓存键 + * @return key + */ + protected String idFor(String hash, String key) { + return hash + ':' + key; + } + + /** + * 将原始数据函数转换成获取CacheValue数据函数 + * + * @param 泛型 + * @param nullable 是否缓存null值 + * @param value 缓存值 + * @return CacheValue函数 + */ + protected CacheValue toCacheValue(boolean nullable, T value) { + if (value == null) { + return nullable ? CacheValue.create(value) : null; + } + return CacheValue.create(value); + } + + /** + * 将原始数据函数转换成获取CacheValue数据函数 + * + * @param 泛型 + * @param nullable 是否缓存null值 + * @param supplier 数据函数 + * @return CacheValue函数 + */ + protected ThrowSupplier> toCacheSupplier(boolean nullable, ThrowSupplier supplier) { + return () -> toCacheValue(nullable, supplier.get()); + } + + /** + * 创建数据类型创建对应CacheValue泛型 + * + * @param type 数据类型,为null则取value的类型 + * @param value 数据值 + * @return CacheValue泛型 + */ + protected Type loadCacheType(Type type, final Object value) { + return loadCacheType(type == null ? value.getClass() : type); + } + + /** + * 创建数据类型创建对应CacheValue泛型 + * + * @param type 数据类型 + * @return CacheValue泛型 + */ + protected Type loadCacheType(Type type) { + return cacheValueTypes.computeIfAbsent( + type, t -> TypeToken.createParameterizedType(null, CacheValue.class, type)); + } + + private static final Object NIL = new Object(); + + protected static interface GetterFunc { + + public R get(String id, Type cacheType); + } + + protected static interface SetterSyncFunc { + + public void set(String id, Duration expire, Type cacheType, CacheValue cacheVal); + } + + protected static interface SetterAsyncFunc { + + public CompletableFuture set(String id, Duration expire, Type cacheType, CacheValue cacheVal); + } + + protected class CacheAsyncEntry { + + private final AtomicBoolean state = new AtomicBoolean(); + + private final List futures = new ArrayList<>(); + + private final ReentrantLock lock = new ReentrantLock(); + + private final String lockId; + + private Object resultObj = NIL; + + private Throwable resultExp; + + public CacheAsyncEntry(String lockId) { + this.lockId = lockId; + } + + public boolean compareAddFuture(CompletableFuture future) { + lock.lock(); + try { + if (resultObj != NIL) { + future.complete(resultObj); + return false; + } else if (resultExp != null) { + future.completeExceptionally(resultExp); + return false; + } + boolean rs = state.compareAndSet(false, true); + this.futures.add(future); + return rs; + } finally { + lock.unlock(); + } + } + + public void fail(Throwable t) { + lock.lock(); + try { + this.resultExp = t; + for (CompletableFuture future : futures) { + future.completeExceptionally(t); + } + this.futures.clear(); + } finally { + asyncLock.remove(lockId); + lock.unlock(); + } + } + + public void success(T val) { + lock.lock(); + try { + this.resultObj = val; + for (CompletableFuture future : futures) { + future.complete(val); + } + this.futures.clear(); + } finally { + asyncLock.remove(lockId); + lock.unlock(); + } + } + } +} diff --git a/src/main/java/org/redkale/cache/spi/CacheModuleEngine.java b/src/main/java/org/redkale/cache/spi/CacheModuleEngine.java index 0c90acf43..bd8568f8a 100644 --- a/src/main/java/org/redkale/cache/spi/CacheModuleEngine.java +++ b/src/main/java/org/redkale/cache/spi/CacheModuleEngine.java @@ -1,101 +1,101 @@ -/* - * - */ -package org.redkale.cache.spi; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.ServiceLoader; -import org.redkale.asm.AsmMethodBoost; -import org.redkale.boot.Application; -import org.redkale.boot.ModuleEngine; -import org.redkale.cache.CacheManager; -import org.redkale.service.Service; -import org.redkale.util.AnyValue; -import org.redkale.util.InstanceProvider; -import org.redkale.util.RedkaleClassLoader; - -/** @author zhangjx */ -public class CacheModuleEngine extends ModuleEngine { - - // 全局缓存管理器 - private CacheManager cacheManager; - - private AnyValue config; - - public CacheModuleEngine(Application application) { - super(application); - } - - /** - * 判断模块的配置项合并策略, 返回null表示模块不识别此配置项 - * - * @param path 配置项路径 - * @param key 配置项名称 - * @param val1 配置项原值 - * @param val2 配置项新值 - * @return MergeEnum - */ - @Override - public AnyValue.MergeEnum mergeAppConfigStrategy(String path, String key, AnyValue val1, AnyValue val2) { - if ("".equals(path) && "cache".equals(key)) { - return AnyValue.MergeEnum.REPLACE; - } - return null; - } - - /** - * 动态扩展类的方法 - * - * @param remote 是否远程模式 - * @param serviceClass 类 - * @return 方法动态扩展器 - */ - @Override - public AsmMethodBoost createAsmMethodBoost(boolean remote, Class serviceClass) { - return new CacheAsmMethodBoost(remote, serviceClass); - } - - /** 结束Application.init方法前被调用 */ - @Override - public void onAppPostInit() { - // 设置缓存管理器 - this.config = application.getAppConfig().getAnyValue("cache"); - this.cacheManager = createManager(this.config); - if (!application.isCompileMode()) { - this.resourceFactory.inject(this.cacheManager); - if (this.cacheManager instanceof Service) { - ((Service) this.cacheManager).init(this.config); - } - } - this.resourceFactory.register("", CacheManager.class, this.cacheManager); - } - - /** 进入Application.shutdown方法被调用 */ - @Override - public void onAppPreShutdown() { - if (!application.isCompileMode() && this.cacheManager instanceof Service) { - ((Service) this.cacheManager).destroy(this.config); - } - } - - private CacheManager createManager(AnyValue conf) { - Iterator it = ServiceLoader.load(CacheManagerProvider.class, application.getClassLoader()) - .iterator(); - RedkaleClassLoader.putServiceLoader(CacheManagerProvider.class); - List providers = new ArrayList<>(); - while (it.hasNext()) { - CacheManagerProvider provider = it.next(); - if (provider != null && provider.acceptsConf(conf)) { - RedkaleClassLoader.putReflectionPublicConstructors( - provider.getClass(), provider.getClass().getName()); - providers.add(provider); - } - } - for (CacheManagerProvider provider : InstanceProvider.sort(providers)) { - return provider.createInstance(); - } - return CacheManagerService.create(null).enabled(false); - } -} +/* + * + */ +package org.redkale.cache.spi; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.ServiceLoader; +import org.redkale.asm.AsmMethodBoost; +import org.redkale.boot.Application; +import org.redkale.boot.ModuleEngine; +import org.redkale.cache.CacheManager; +import org.redkale.service.Service; +import org.redkale.util.AnyValue; +import org.redkale.util.InstanceProvider; +import org.redkale.util.RedkaleClassLoader; + +/** @author zhangjx */ +public class CacheModuleEngine extends ModuleEngine { + + // 全局缓存管理器 + private CacheManager cacheManager; + + private AnyValue config; + + public CacheModuleEngine(Application application) { + super(application); + } + + /** + * 判断模块的配置项合并策略, 返回null表示模块不识别此配置项 + * + * @param path 配置项路径 + * @param key 配置项名称 + * @param val1 配置项原值 + * @param val2 配置项新值 + * @return MergeEnum + */ + @Override + public AnyValue.MergeEnum mergeAppConfigStrategy(String path, String key, AnyValue val1, AnyValue val2) { + if ("".equals(path) && "cache".equals(key)) { + return AnyValue.MergeEnum.REPLACE; + } + return null; + } + + /** + * 动态扩展类的方法 + * + * @param remote 是否远程模式 + * @param serviceClass 类 + * @return 方法动态扩展器 + */ + @Override + public AsmMethodBoost createAsmMethodBoost(boolean remote, Class serviceClass) { + return new CacheAsmMethodBoost(remote, serviceClass); + } + + /** 结束Application.init方法前被调用 */ + @Override + public void onAppPostInit() { + // 设置缓存管理器 + this.config = application.getAppConfig().getAnyValue("cache"); + this.cacheManager = createManager(this.config); + if (!application.isCompileMode()) { + this.resourceFactory.inject(this.cacheManager); + if (this.cacheManager instanceof Service) { + ((Service) this.cacheManager).init(this.config); + } + } + this.resourceFactory.register("", CacheManager.class, this.cacheManager); + } + + /** 进入Application.shutdown方法被调用 */ + @Override + public void onAppPreShutdown() { + if (!application.isCompileMode() && this.cacheManager instanceof Service) { + ((Service) this.cacheManager).destroy(this.config); + } + } + + private CacheManager createManager(AnyValue conf) { + Iterator it = ServiceLoader.load(CacheManagerProvider.class, application.getClassLoader()) + .iterator(); + RedkaleClassLoader.putServiceLoader(CacheManagerProvider.class); + List providers = new ArrayList<>(); + while (it.hasNext()) { + CacheManagerProvider provider = it.next(); + if (provider != null && provider.acceptsConf(conf)) { + RedkaleClassLoader.putReflectionPublicConstructors( + provider.getClass(), provider.getClass().getName()); + providers.add(provider); + } + } + for (CacheManagerProvider provider : InstanceProvider.sort(providers)) { + return provider.createInstance(); + } + return CacheManagerService.create(null).enabled(false); + } +} diff --git a/src/main/java/org/redkale/cache/spi/CacheValue.java b/src/main/java/org/redkale/cache/spi/CacheValue.java index 20c37c639..321621c08 100644 --- a/src/main/java/org/redkale/cache/spi/CacheValue.java +++ b/src/main/java/org/redkale/cache/spi/CacheValue.java @@ -1,53 +1,53 @@ -/* - * - */ -package org.redkale.cache.spi; - -import org.redkale.convert.ConvertColumn; -import org.redkale.convert.json.JsonConvert; - -/** - * 内部缓存对象 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @param 泛型 - * @since 2.8.0 - */ -public class CacheValue { - - @ConvertColumn(index = 1) - private T val; - - public CacheValue() {} - - protected CacheValue(T value) { - this.val = value; - } - - public static CacheValue create(T value) { - return new CacheValue(value); - } - - public static boolean isValid(CacheValue val) { - return val != null; - } - - public static T get(CacheValue val) { - return isValid(val) ? (T) val.getVal() : null; - } - - public T getVal() { - return val; - } - - public void setVal(T val) { - this.val = val; - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } -} +/* + * + */ +package org.redkale.cache.spi; + +import org.redkale.convert.ConvertColumn; +import org.redkale.convert.json.JsonConvert; + +/** + * 内部缓存对象 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @param 泛型 + * @since 2.8.0 + */ +public class CacheValue { + + @ConvertColumn(index = 1) + private T val; + + public CacheValue() {} + + protected CacheValue(T value) { + this.val = value; + } + + public static CacheValue create(T value) { + return new CacheValue(value); + } + + public static boolean isValid(CacheValue val) { + return val != null; + } + + public static T get(CacheValue val) { + return isValid(val) ? (T) val.getVal() : null; + } + + public T getVal() { + return val; + } + + public void setVal(T val) { + this.val = val; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } +} diff --git a/src/main/java/org/redkale/cache/spi/DynForCache.java b/src/main/java/org/redkale/cache/spi/DynForCache.java index 836ab1e8d..2122dcb95 100644 --- a/src/main/java/org/redkale/cache/spi/DynForCache.java +++ b/src/main/java/org/redkale/cache/spi/DynForCache.java @@ -1,41 +1,41 @@ -/* - * - */ -package org.redkale.cache.spi; - -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; -import java.util.concurrent.TimeUnit; -import org.redkale.service.LoadMode; - -/** - * {@link org.redkale.cache.Cached}注解的动态扩展版,会多一个字段信息 用于识别方法是否已经动态处理过 - * - * @author zhangjx - * @since 2.8.0 - */ -@Documented -@Target({METHOD}) -@Retention(RUNTIME) -public @interface DynForCache { - - String dynField(); - - String key(); - - String hash(); - - String localExpire(); - - String remoteExpire(); - - TimeUnit timeUnit(); - - boolean nullable(); - - LoadMode mode() default LoadMode.ANY; -} +/* + * + */ +package org.redkale.cache.spi; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; +import java.util.concurrent.TimeUnit; +import org.redkale.service.LoadMode; + +/** + * {@link org.redkale.cache.Cached}注解的动态扩展版,会多一个字段信息 用于识别方法是否已经动态处理过 + * + * @author zhangjx + * @since 2.8.0 + */ +@Documented +@Target({METHOD}) +@Retention(RUNTIME) +public @interface DynForCache { + + String dynField(); + + String key(); + + String hash(); + + String localExpire(); + + String remoteExpire(); + + TimeUnit timeUnit(); + + boolean nullable(); + + LoadMode mode() default LoadMode.ANY; +} diff --git a/src/main/java/org/redkale/cluster/ClusterRpcClient.java b/src/main/java/org/redkale/cluster/ClusterRpcClient.java index 1a074014a..cc06ea40c 100644 --- a/src/main/java/org/redkale/cluster/ClusterRpcClient.java +++ b/src/main/java/org/redkale/cluster/ClusterRpcClient.java @@ -1,35 +1,35 @@ -/* - * - */ -package org.redkale.cluster; - -import java.util.concurrent.CompletableFuture; - -/** - * cluster模式下的rpc client - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @param message - * @param

result - * @since 2.8.0 - */ -public interface ClusterRpcClient { - - /** - * 发送消息,需要响应 - * - * @param message 消息体 - * @return 应答消息 - */ - public CompletableFuture

sendMessage(final R message); - - /** - * 发送消息,无需响应 - * - * @param message 消息体 - * @return 应答 - */ - public CompletableFuture produceMessage(R message); -} +/* + * + */ +package org.redkale.cluster; + +import java.util.concurrent.CompletableFuture; + +/** + * cluster模式下的rpc client + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @param message + * @param

result + * @since 2.8.0 + */ +public interface ClusterRpcClient { + + /** + * 发送消息,需要响应 + * + * @param message 消息体 + * @return 应答消息 + */ + public CompletableFuture

sendMessage(final R message); + + /** + * 发送消息,无需响应 + * + * @param message 消息体 + * @return 应答 + */ + public CompletableFuture produceMessage(R message); +} diff --git a/src/main/java/org/redkale/cluster/spi/ClusterModuleEngine.java b/src/main/java/org/redkale/cluster/spi/ClusterModuleEngine.java index 63fb44e11..b6ba023ca 100644 --- a/src/main/java/org/redkale/cluster/spi/ClusterModuleEngine.java +++ b/src/main/java/org/redkale/cluster/spi/ClusterModuleEngine.java @@ -1,253 +1,253 @@ -/* - * - */ -package org.redkale.cluster.spi; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Objects; -import java.util.Properties; -import java.util.ServiceLoader; -import java.util.Set; -import java.util.logging.Level; -import org.redkale.boot.Application; -import org.redkale.boot.ModuleEngine; -import org.redkale.inject.ResourceEvent; -import org.redkale.source.SourceManager; -import org.redkale.util.AnyValue; -import org.redkale.util.AnyValueWriter; -import org.redkale.util.RedkaleClassLoader; - -/** @author zhangjx */ -public class ClusterModuleEngine extends ModuleEngine { - - // 第三方服务配置资源 - // @since 2.8.0 - private Properties clusterProperties = new Properties(); - - // 第三方服务发现管理接口 - // @since 2.1.0 - private ClusterAgent clusterAgent; - - public ClusterModuleEngine(Application application) { - super(application); - } - - /** 结束Application.init方法前被调用 */ - @Override - public void onAppPostInit() { - ClusterAgent cluster = null; - AnyValue clusterConf = application.getAppConfig().getAnyValue("cluster"); - if (clusterConf != null) { - try { - String classVal = environment.getPropertyValue( - clusterConf.getValue("type", clusterConf.getValue("value"))); // 兼容value字段 - if (classVal == null - || classVal.isEmpty() - || classVal.indexOf('.') < 0) { // 不包含.表示非类名,比如值: consul, nacos - Iterator it = ServiceLoader.load( - ClusterAgentProvider.class, application.getClassLoader()) - .iterator(); - RedkaleClassLoader.putServiceLoader(ClusterAgentProvider.class); - while (it.hasNext()) { - ClusterAgentProvider provider = it.next(); - if (provider != null) { - RedkaleClassLoader.putReflectionPublicConstructors( - provider.getClass(), provider.getClass().getName()); // loader class - } - if (provider != null && provider.acceptsConf(clusterConf)) { - cluster = provider.createInstance(); - cluster.setConfig(clusterConf); - break; - } - } - if (cluster == null) { - ClusterAgent cacheClusterAgent = new CacheClusterAgent(); - if (cacheClusterAgent.acceptsConf(clusterConf)) { - cluster = cacheClusterAgent; - cluster.setConfig(clusterConf); - } - } - if (cluster == null) { - logger.log( - Level.SEVERE, - "load application cluster resource, but not found name='type' value error: " - + clusterConf); - } - } else { - Class type = application.getClassLoader().loadClass(classVal); - if (!ClusterAgent.class.isAssignableFrom(type)) { - logger.log( - Level.SEVERE, - "load application cluster resource, but not found " + ClusterAgent.class.getSimpleName() - + " implements class error: " + clusterConf); - } else { - RedkaleClassLoader.putReflectionDeclaredConstructors(type, type.getName()); - cluster = (ClusterAgent) type.getDeclaredConstructor().newInstance(); - cluster.setConfig(clusterConf); - } - } - // 此时不能执行cluster.init,因内置的对象可能依赖config.properties配置项 - } catch (Exception e) { - logger.log(Level.SEVERE, "load application cluster resource error: " + clusterConf, e); - } - } - this.clusterAgent = cluster; - - if (this.clusterAgent != null) { - if (logger.isLoggable(Level.FINER)) { - logger.log( - Level.FINER, - "ClusterAgent (type = " + this.clusterAgent.getClass().getSimpleName() + ") initing"); - } - long s = System.currentTimeMillis(); - if (this.clusterAgent instanceof CacheClusterAgent) { - String sourceName = - ((CacheClusterAgent) clusterAgent).getSourceName(); // 必须在inject前调用,需要赋值Resourcable.name - SourceManager sourceManager = application.getResourceFactory().find(SourceManager.class); - sourceManager.loadCacheSource(sourceName, false); - } - this.resourceFactory.inject(clusterAgent); - clusterAgent.init(clusterAgent.getConfig()); - this.resourceFactory.register(ClusterAgent.class, clusterAgent); - logger.info("ClusterAgent (type = " + this.clusterAgent.getClass().getSimpleName() + ") init in " - + (System.currentTimeMillis() - s) + " ms"); - } - } - - /** 配置项加载后被调用 */ - @Override - public void onEnvironmentLoaded(Properties allProps) { - allProps.forEach((key, val) -> { - if (key.toString().startsWith("redkale.cluster.")) { - this.clusterProperties.put(key, val); - } - }); - } - - /** - * 配置项变更时被调用 - * - * @param namespace 命名空间 - * @param events 变更项 - */ - @Override - public void onEnvironmentChanged(String namespace, List events) { - Set clusterRemovedKeys = new HashSet<>(); - Properties clusterChangedProps = new Properties(); - - for (ResourceEvent event : events) { - if (event.name().startsWith("redkale.cluster.")) { - if (!Objects.equals(event.newValue(), this.clusterProperties.getProperty(event.name()))) { - if (event.newValue() == null) { - if (this.clusterProperties.containsKey(event.name())) { - clusterRemovedKeys.add(event.name()); - } - } else { - clusterChangedProps.put(event.name(), event.newValue()); - } - } - } - } - // 第三方服务注册配置项的变更 - if (!clusterChangedProps.isEmpty() || !clusterRemovedKeys.isEmpty()) { - if (this.clusterAgent != null) { - final AnyValueWriter old = - (AnyValueWriter) application.getAppConfig().getAnyValue("cluster"); - Properties newProps = new Properties(); - newProps.putAll(clusterProperties); - List changeEvents = new ArrayList<>(); - clusterChangedProps.forEach((k, v) -> { - final String key = k.toString(); - newProps.put(k, v); - changeEvents.add(ResourceEvent.create( - key.substring("redkale.cluster.".length()), v, this.clusterProperties.getProperty(key))); - }); - clusterRemovedKeys.forEach(k -> { - final String key = k; - newProps.remove(k); - changeEvents.add(ResourceEvent.create( - key.substring("redkale.cluster.".length()), null, this.clusterProperties.getProperty(key))); - }); - if (!changeEvents.isEmpty()) { - AnyValueWriter back = old.copy(); - try { - old.replace(AnyValue.loadFromProperties(newProps) - .getAnyValue("redkale") - .getAnyValue("cluster")); - clusterAgent.onResourceChange(changeEvents.toArray(new ResourceEvent[changeEvents.size()])); - } catch (RuntimeException e) { - old.replace(back); // 还原配置 - throw e; - } - } - } else { - StringBuilder sb = new StringBuilder(); - clusterChangedProps.forEach((k, v) -> { - sb.append(ClusterAgent.class.getSimpleName()) - .append(" skip change '") - .append(k) - .append("'\r\n"); - }); - clusterRemovedKeys.forEach(k -> { - sb.append(ClusterAgent.class.getSimpleName()) - .append(" skip change '") - .append(k) - .append("'\r\n"); - }); - if (sb.length() > 0) { - logger.log(Level.INFO, sb.toString()); - } - } - clusterRemovedKeys.forEach(k -> this.clusterProperties.remove(k)); - this.clusterProperties.putAll(clusterChangedProps); - } - } - - /** - * 判断模块的配置项合并策略, 返回null表示模块不识别此配置项 - * - * @param path 配置项路径 - * @param key 配置项名称 - * @param val1 配置项原值 - * @param val2 配置项新值 - * @return MergeEnum - */ - @Override - public AnyValue.MergeEnum mergeAppConfigStrategy(String path, String key, AnyValue val1, AnyValue val2) { - if ("".equals(path) && "cluster".equals(key)) { - return AnyValue.MergeEnum.REPLACE; - } - return null; - } - - /** 进入Application.start方法被调用 */ - @Override - public void onAppPreStart() { - if (!application.isSingletonMode() && !application.isCompileMode() && this.clusterAgent != null) { - this.clusterAgent.register(application); - } - } - - /** 服务全部启动后被调用 */ - public void onServersPostStart() { - if (this.clusterAgent != null) { - this.clusterAgent.start(); - } - } - - /** 服务全部停掉后被调用 */ - public void onServersPostStop() { - if (!application.isCompileMode() && clusterAgent != null) { - if (logger.isLoggable(Level.FINER)) { - logger.log(Level.FINER, "ClusterAgent destroying"); - } - long s = System.currentTimeMillis(); - clusterAgent.deregister(application); - clusterAgent.destroy(clusterAgent.getConfig()); - logger.info("ClusterAgent destroy in " + (System.currentTimeMillis() - s) + " ms"); - } - } -} +/* + * + */ +package org.redkale.cluster.spi; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Objects; +import java.util.Properties; +import java.util.ServiceLoader; +import java.util.Set; +import java.util.logging.Level; +import org.redkale.boot.Application; +import org.redkale.boot.ModuleEngine; +import org.redkale.inject.ResourceEvent; +import org.redkale.source.SourceManager; +import org.redkale.util.AnyValue; +import org.redkale.util.AnyValueWriter; +import org.redkale.util.RedkaleClassLoader; + +/** @author zhangjx */ +public class ClusterModuleEngine extends ModuleEngine { + + // 第三方服务配置资源 + // @since 2.8.0 + private Properties clusterProperties = new Properties(); + + // 第三方服务发现管理接口 + // @since 2.1.0 + private ClusterAgent clusterAgent; + + public ClusterModuleEngine(Application application) { + super(application); + } + + /** 结束Application.init方法前被调用 */ + @Override + public void onAppPostInit() { + ClusterAgent cluster = null; + AnyValue clusterConf = application.getAppConfig().getAnyValue("cluster"); + if (clusterConf != null) { + try { + String classVal = environment.getPropertyValue( + clusterConf.getValue("type", clusterConf.getValue("value"))); // 兼容value字段 + if (classVal == null + || classVal.isEmpty() + || classVal.indexOf('.') < 0) { // 不包含.表示非类名,比如值: consul, nacos + Iterator it = ServiceLoader.load( + ClusterAgentProvider.class, application.getClassLoader()) + .iterator(); + RedkaleClassLoader.putServiceLoader(ClusterAgentProvider.class); + while (it.hasNext()) { + ClusterAgentProvider provider = it.next(); + if (provider != null) { + RedkaleClassLoader.putReflectionPublicConstructors( + provider.getClass(), provider.getClass().getName()); // loader class + } + if (provider != null && provider.acceptsConf(clusterConf)) { + cluster = provider.createInstance(); + cluster.setConfig(clusterConf); + break; + } + } + if (cluster == null) { + ClusterAgent cacheClusterAgent = new CacheClusterAgent(); + if (cacheClusterAgent.acceptsConf(clusterConf)) { + cluster = cacheClusterAgent; + cluster.setConfig(clusterConf); + } + } + if (cluster == null) { + logger.log( + Level.SEVERE, + "load application cluster resource, but not found name='type' value error: " + + clusterConf); + } + } else { + Class type = application.getClassLoader().loadClass(classVal); + if (!ClusterAgent.class.isAssignableFrom(type)) { + logger.log( + Level.SEVERE, + "load application cluster resource, but not found " + ClusterAgent.class.getSimpleName() + + " implements class error: " + clusterConf); + } else { + RedkaleClassLoader.putReflectionDeclaredConstructors(type, type.getName()); + cluster = (ClusterAgent) type.getDeclaredConstructor().newInstance(); + cluster.setConfig(clusterConf); + } + } + // 此时不能执行cluster.init,因内置的对象可能依赖config.properties配置项 + } catch (Exception e) { + logger.log(Level.SEVERE, "load application cluster resource error: " + clusterConf, e); + } + } + this.clusterAgent = cluster; + + if (this.clusterAgent != null) { + if (logger.isLoggable(Level.FINER)) { + logger.log( + Level.FINER, + "ClusterAgent (type = " + this.clusterAgent.getClass().getSimpleName() + ") initing"); + } + long s = System.currentTimeMillis(); + if (this.clusterAgent instanceof CacheClusterAgent) { + String sourceName = + ((CacheClusterAgent) clusterAgent).getSourceName(); // 必须在inject前调用,需要赋值Resourcable.name + SourceManager sourceManager = application.getResourceFactory().find(SourceManager.class); + sourceManager.loadCacheSource(sourceName, false); + } + this.resourceFactory.inject(clusterAgent); + clusterAgent.init(clusterAgent.getConfig()); + this.resourceFactory.register(ClusterAgent.class, clusterAgent); + logger.info("ClusterAgent (type = " + this.clusterAgent.getClass().getSimpleName() + ") init in " + + (System.currentTimeMillis() - s) + " ms"); + } + } + + /** 配置项加载后被调用 */ + @Override + public void onEnvironmentLoaded(Properties allProps) { + allProps.forEach((key, val) -> { + if (key.toString().startsWith("redkale.cluster.")) { + this.clusterProperties.put(key, val); + } + }); + } + + /** + * 配置项变更时被调用 + * + * @param namespace 命名空间 + * @param events 变更项 + */ + @Override + public void onEnvironmentChanged(String namespace, List events) { + Set clusterRemovedKeys = new HashSet<>(); + Properties clusterChangedProps = new Properties(); + + for (ResourceEvent event : events) { + if (event.name().startsWith("redkale.cluster.")) { + if (!Objects.equals(event.newValue(), this.clusterProperties.getProperty(event.name()))) { + if (event.newValue() == null) { + if (this.clusterProperties.containsKey(event.name())) { + clusterRemovedKeys.add(event.name()); + } + } else { + clusterChangedProps.put(event.name(), event.newValue()); + } + } + } + } + // 第三方服务注册配置项的变更 + if (!clusterChangedProps.isEmpty() || !clusterRemovedKeys.isEmpty()) { + if (this.clusterAgent != null) { + final AnyValueWriter old = + (AnyValueWriter) application.getAppConfig().getAnyValue("cluster"); + Properties newProps = new Properties(); + newProps.putAll(clusterProperties); + List changeEvents = new ArrayList<>(); + clusterChangedProps.forEach((k, v) -> { + final String key = k.toString(); + newProps.put(k, v); + changeEvents.add(ResourceEvent.create( + key.substring("redkale.cluster.".length()), v, this.clusterProperties.getProperty(key))); + }); + clusterRemovedKeys.forEach(k -> { + final String key = k; + newProps.remove(k); + changeEvents.add(ResourceEvent.create( + key.substring("redkale.cluster.".length()), null, this.clusterProperties.getProperty(key))); + }); + if (!changeEvents.isEmpty()) { + AnyValueWriter back = old.copy(); + try { + old.replace(AnyValue.loadFromProperties(newProps) + .getAnyValue("redkale") + .getAnyValue("cluster")); + clusterAgent.onResourceChange(changeEvents.toArray(new ResourceEvent[changeEvents.size()])); + } catch (RuntimeException e) { + old.replace(back); // 还原配置 + throw e; + } + } + } else { + StringBuilder sb = new StringBuilder(); + clusterChangedProps.forEach((k, v) -> { + sb.append(ClusterAgent.class.getSimpleName()) + .append(" skip change '") + .append(k) + .append("'\r\n"); + }); + clusterRemovedKeys.forEach(k -> { + sb.append(ClusterAgent.class.getSimpleName()) + .append(" skip change '") + .append(k) + .append("'\r\n"); + }); + if (sb.length() > 0) { + logger.log(Level.INFO, sb.toString()); + } + } + clusterRemovedKeys.forEach(k -> this.clusterProperties.remove(k)); + this.clusterProperties.putAll(clusterChangedProps); + } + } + + /** + * 判断模块的配置项合并策略, 返回null表示模块不识别此配置项 + * + * @param path 配置项路径 + * @param key 配置项名称 + * @param val1 配置项原值 + * @param val2 配置项新值 + * @return MergeEnum + */ + @Override + public AnyValue.MergeEnum mergeAppConfigStrategy(String path, String key, AnyValue val1, AnyValue val2) { + if ("".equals(path) && "cluster".equals(key)) { + return AnyValue.MergeEnum.REPLACE; + } + return null; + } + + /** 进入Application.start方法被调用 */ + @Override + public void onAppPreStart() { + if (!application.isSingletonMode() && !application.isCompileMode() && this.clusterAgent != null) { + this.clusterAgent.register(application); + } + } + + /** 服务全部启动后被调用 */ + public void onServersPostStart() { + if (this.clusterAgent != null) { + this.clusterAgent.start(); + } + } + + /** 服务全部停掉后被调用 */ + public void onServersPostStop() { + if (!application.isCompileMode() && clusterAgent != null) { + if (logger.isLoggable(Level.FINER)) { + logger.log(Level.FINER, "ClusterAgent destroying"); + } + long s = System.currentTimeMillis(); + clusterAgent.deregister(application); + clusterAgent.destroy(clusterAgent.getConfig()); + logger.info("ClusterAgent destroy in " + (System.currentTimeMillis() - s) + " ms"); + } + } +} diff --git a/src/main/java/org/redkale/cluster/spi/HttpClusterRpcClient.java b/src/main/java/org/redkale/cluster/spi/HttpClusterRpcClient.java index d142c4a73..3c485de0c 100644 --- a/src/main/java/org/redkale/cluster/spi/HttpClusterRpcClient.java +++ b/src/main/java/org/redkale/cluster/spi/HttpClusterRpcClient.java @@ -1,228 +1,228 @@ -package org.redkale.cluster.spi; - -import static org.redkale.util.Utility.isEmpty; -import static org.redkale.util.Utility.isNotEmpty; - -import java.io.Serializable; -import java.net.*; -import java.nio.charset.StandardCharsets; -import java.time.Duration; -import java.util.*; -import java.util.concurrent.*; -import java.util.logging.Level; -import java.util.logging.Logger; -import org.redkale.annotation.Resource; -import org.redkale.boot.Application; -import org.redkale.cluster.HttpRpcClient; -import org.redkale.net.http.*; -import org.redkale.util.Traces; -import org.redkale.util.Utility; - -/** - * 没有配置MQ的情况下依赖ClusterAgent实现的默认HttpRpcClient实例 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.1.0 - */ -public class HttpClusterRpcClient extends HttpRpcClient { - - // jdk.internal.net.http.common.Utils.DISALLOWED_HEADERS_SET - private static final Set DISALLOWED_HEADERS_SET = Utility.ofSet( - "connection", - "content-length", - "date", - "expect", - "from", - "host", - "origin", - "referer", - "upgrade", - "via", - "warning"); - - protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); - - protected final HttpLocalRpcClient localClient; - - protected final ConcurrentHashMap topicServletMap = new ConcurrentHashMap<>(); - - protected ClusterAgent clusterAgent; - - @Resource(name = "cluster.httpClient", required = false) - protected WebClient webClient; - - @Resource(name = "cluster.httpClient", required = false) - protected java.net.http.HttpClient httpClient; - - public HttpClusterRpcClient(Application application, String resourceName, ClusterAgent clusterAgent) { - Objects.requireNonNull(clusterAgent); - this.localClient = new HttpLocalRpcClient(application, resourceName); - this.clusterAgent = clusterAgent; - } - - @Override - protected String getNodeid() { - return localClient.getNodeid(); - } - - @Override - public CompletableFuture> sendMessage( - String topic, Serializable userid, String groupid, WebRequest request) { - if (topicServletMap.computeIfAbsent(topic, t -> localClient.findHttpServlet(t) != null)) { - return localClient.sendMessage(topic, userid, groupid, request); - } else { - return httpAsync(false, userid, request); - } - } - - @Override - public CompletableFuture produceMessage( - String topic, Serializable userid, String groupid, WebRequest request) { - if (topicServletMap.computeIfAbsent(topic, t -> localClient.findHttpServlet(t) != null)) { - return localClient.produceMessage(topic, userid, groupid, request); - } else { - return httpAsync(true, userid, request).thenApply(v -> null); - } - } - - private CompletableFuture> httpAsync(boolean produce, Serializable userid, WebRequest req) { - req.setTraceid(Traces.computeIfAbsent(req.getTraceid(), Traces.currentTraceid())); - String module = req.getPath(); - module = module.substring(1, module.indexOf('/', 1)); - HttpHeaders headers = req.getHeaders(); - String resname = req.getHeader(Rest.REST_HEADER_RESNAME, ""); - final String localModule = module; - if (logger.isLoggable(Level.FINEST)) { - logger.log(Level.FINEST, "httpAsync.queryHttpAddress: module=" + localModule + ", resname=" + resname); - } - return clusterAgent.queryHttpAddress("http", module, resname).thenCompose(addrs -> { - Traces.currentTraceid(req.getTraceid()); - if (isEmpty(addrs)) { - if (logger.isLoggable(Level.WARNING)) { - logger.log( - Level.WARNING, - "httpAsync." + (produce ? "produceMessage" : "sendMessage") + " failed, module=" - + localModule + ", resname=" + resname + ", address is empty"); - } - return new HttpResult().status(404).toFuture(); - } - final HttpHeaders clientHeaders = HttpHeaders.create(); - if (headers != null) { - boolean ws = headers.contains("Sec-WebSocket-Key"); - headers.forEach((n, v) -> { - if (!DISALLOWED_HEADERS_SET.contains(n.toLowerCase()) - && (!ws - || (!"Connection".equals(n) - && !"Sec-WebSocket-Key".equals(n) - && !"Sec-WebSocket-Version".equals(n)))) { - clientHeaders.add(n, v); - } - }); - } - clientHeaders.set("Content-Type", "x-www-form-urlencoded"); - if (req.isRpc()) { - clientHeaders.set(Rest.REST_HEADER_RPC, "true"); - } - if (isNotEmpty(req.getTraceid())) { - clientHeaders.set(Rest.REST_HEADER_TRACEID, req.getTraceid()); - } - if (userid != null) { - clientHeaders.set(Rest.REST_HEADER_CURRUSERID, String.valueOf(userid)); - } - if (req.getReqConvertType() != null) { - clientHeaders.set( - Rest.REST_HEADER_REQ_CONVERT, req.getReqConvertType().toString()); - } - if (req.getRespConvertType() != null) { - clientHeaders.set( - Rest.REST_HEADER_RESP_CONVERT, req.getRespConvertType().toString()); - } - - if (webClient != null) { - WebRequest newReq = req.copy().headers(clientHeaders); - InetSocketAddress addr = randomAddress(newReq, addrs); - if (logger.isLoggable(Level.FINEST)) { - logger.log( - Level.FINEST, - "httpAsync: module=" + localModule + ", resname=" + resname + ", addr=" + addr); - } - return (CompletableFuture) webClient.sendAsync(addr, newReq); - } - byte[] clientBody = null; - if (isNotEmpty(req.getBody())) { - String paramstr = req.getParametersToString(); - if (paramstr != null) { - if (req.getPath().indexOf('?') > 0) { - req.setPath(req.getPath() + "&" + paramstr); - } else { - req.setPath(req.getPath() + "?" + paramstr); - } - } - clientBody = req.getBody(); - } else { - String paramstr = req.getParametersToString(); - if (paramstr != null) { - clientBody = paramstr.getBytes(StandardCharsets.UTF_8); - } - } - if (logger.isLoggable(Level.FINEST)) { - logger.log( - Level.FINEST, - "httpAsync: module=" + localModule + ", resname=" + resname + ", enter sendEachAddressAsync"); - } - return sendEachAddressAsync(req, req.requestPath(), clientHeaders, clientBody, addrs.iterator()); - }); - } - - protected InetSocketAddress randomAddress(WebRequest req, Set addrs) { - InetSocketAddress[] array = addrs.toArray(new InetSocketAddress[addrs.size()]); - return array[ThreadLocalRandom.current().nextInt(array.length)]; - } - - protected CompletableFuture> sendEachAddressAsync( - WebRequest req, - String requestPath, - final HttpHeaders clientHeaders, - byte[] clientBody, - Iterator it) { - if (!it.hasNext()) { - return new HttpResult().status(404).toFuture(); - } - InetSocketAddress addr = it.next(); - String host = addr.getPort() > 0 && addr.getPort() != 80 - ? (addr.getHostString() + ":" + addr.getPort()) - : addr.getHostString(); - String url = "http://" + host + requestPath; - if (logger.isLoggable(Level.FINER)) { - logger.log( - Level.FINER, - "sendEachAddressAsync: url: " + url + ", body: " - + (clientBody != null ? new String(clientBody, StandardCharsets.UTF_8) : "") + ", headers: " - + clientHeaders); - } - java.net.http.HttpRequest.Builder builder = java.net.http.HttpRequest.newBuilder() - .uri(URI.create(url)) - .timeout(Duration.ofMillis(10_000)) - // 存在sendHeader后不发送body数据的问题, java.net.http.HttpRequest的bug? - .method("POST", createBodyPublisher(clientBody)); - clientHeaders.forEach(builder::header); - return httpClient - .sendAsync(builder.build(), java.net.http.HttpResponse.BodyHandlers.ofByteArray()) - .thenApply((java.net.http.HttpResponse resp) -> { - Traces.currentTraceid(req.getTraceid()); - final int rs = resp.statusCode(); - if (rs != 200) { - return new HttpResult().status(rs); - } - return new HttpResult<>(resp.body()); - }); - } - - private static java.net.http.HttpRequest.BodyPublisher createBodyPublisher(byte[] clientBody) { - return clientBody == null - ? java.net.http.HttpRequest.BodyPublishers.noBody() - : java.net.http.HttpRequest.BodyPublishers.ofByteArray(clientBody); - } -} +package org.redkale.cluster.spi; + +import static org.redkale.util.Utility.isEmpty; +import static org.redkale.util.Utility.isNotEmpty; + +import java.io.Serializable; +import java.net.*; +import java.nio.charset.StandardCharsets; +import java.time.Duration; +import java.util.*; +import java.util.concurrent.*; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.redkale.annotation.Resource; +import org.redkale.boot.Application; +import org.redkale.cluster.HttpRpcClient; +import org.redkale.net.http.*; +import org.redkale.util.Traces; +import org.redkale.util.Utility; + +/** + * 没有配置MQ的情况下依赖ClusterAgent实现的默认HttpRpcClient实例 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.1.0 + */ +public class HttpClusterRpcClient extends HttpRpcClient { + + // jdk.internal.net.http.common.Utils.DISALLOWED_HEADERS_SET + private static final Set DISALLOWED_HEADERS_SET = Utility.ofSet( + "connection", + "content-length", + "date", + "expect", + "from", + "host", + "origin", + "referer", + "upgrade", + "via", + "warning"); + + protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); + + protected final HttpLocalRpcClient localClient; + + protected final ConcurrentHashMap topicServletMap = new ConcurrentHashMap<>(); + + protected ClusterAgent clusterAgent; + + @Resource(name = "cluster.httpClient", required = false) + protected WebClient webClient; + + @Resource(name = "cluster.httpClient", required = false) + protected java.net.http.HttpClient httpClient; + + public HttpClusterRpcClient(Application application, String resourceName, ClusterAgent clusterAgent) { + Objects.requireNonNull(clusterAgent); + this.localClient = new HttpLocalRpcClient(application, resourceName); + this.clusterAgent = clusterAgent; + } + + @Override + protected String getNodeid() { + return localClient.getNodeid(); + } + + @Override + public CompletableFuture> sendMessage( + String topic, Serializable userid, String groupid, WebRequest request) { + if (topicServletMap.computeIfAbsent(topic, t -> localClient.findHttpServlet(t) != null)) { + return localClient.sendMessage(topic, userid, groupid, request); + } else { + return httpAsync(false, userid, request); + } + } + + @Override + public CompletableFuture produceMessage( + String topic, Serializable userid, String groupid, WebRequest request) { + if (topicServletMap.computeIfAbsent(topic, t -> localClient.findHttpServlet(t) != null)) { + return localClient.produceMessage(topic, userid, groupid, request); + } else { + return httpAsync(true, userid, request).thenApply(v -> null); + } + } + + private CompletableFuture> httpAsync(boolean produce, Serializable userid, WebRequest req) { + req.setTraceid(Traces.computeIfAbsent(req.getTraceid(), Traces.currentTraceid())); + String module = req.getPath(); + module = module.substring(1, module.indexOf('/', 1)); + HttpHeaders headers = req.getHeaders(); + String resname = req.getHeader(Rest.REST_HEADER_RESNAME, ""); + final String localModule = module; + if (logger.isLoggable(Level.FINEST)) { + logger.log(Level.FINEST, "httpAsync.queryHttpAddress: module=" + localModule + ", resname=" + resname); + } + return clusterAgent.queryHttpAddress("http", module, resname).thenCompose(addrs -> { + Traces.currentTraceid(req.getTraceid()); + if (isEmpty(addrs)) { + if (logger.isLoggable(Level.WARNING)) { + logger.log( + Level.WARNING, + "httpAsync." + (produce ? "produceMessage" : "sendMessage") + " failed, module=" + + localModule + ", resname=" + resname + ", address is empty"); + } + return new HttpResult().status(404).toFuture(); + } + final HttpHeaders clientHeaders = HttpHeaders.create(); + if (headers != null) { + boolean ws = headers.contains("Sec-WebSocket-Key"); + headers.forEach((n, v) -> { + if (!DISALLOWED_HEADERS_SET.contains(n.toLowerCase()) + && (!ws + || (!"Connection".equals(n) + && !"Sec-WebSocket-Key".equals(n) + && !"Sec-WebSocket-Version".equals(n)))) { + clientHeaders.add(n, v); + } + }); + } + clientHeaders.set("Content-Type", "x-www-form-urlencoded"); + if (req.isRpc()) { + clientHeaders.set(Rest.REST_HEADER_RPC, "true"); + } + if (isNotEmpty(req.getTraceid())) { + clientHeaders.set(Rest.REST_HEADER_TRACEID, req.getTraceid()); + } + if (userid != null) { + clientHeaders.set(Rest.REST_HEADER_CURRUSERID, String.valueOf(userid)); + } + if (req.getReqConvertType() != null) { + clientHeaders.set( + Rest.REST_HEADER_REQ_CONVERT, req.getReqConvertType().toString()); + } + if (req.getRespConvertType() != null) { + clientHeaders.set( + Rest.REST_HEADER_RESP_CONVERT, req.getRespConvertType().toString()); + } + + if (webClient != null) { + WebRequest newReq = req.copy().headers(clientHeaders); + InetSocketAddress addr = randomAddress(newReq, addrs); + if (logger.isLoggable(Level.FINEST)) { + logger.log( + Level.FINEST, + "httpAsync: module=" + localModule + ", resname=" + resname + ", addr=" + addr); + } + return (CompletableFuture) webClient.sendAsync(addr, newReq); + } + byte[] clientBody = null; + if (isNotEmpty(req.getBody())) { + String paramstr = req.getParametersToString(); + if (paramstr != null) { + if (req.getPath().indexOf('?') > 0) { + req.setPath(req.getPath() + "&" + paramstr); + } else { + req.setPath(req.getPath() + "?" + paramstr); + } + } + clientBody = req.getBody(); + } else { + String paramstr = req.getParametersToString(); + if (paramstr != null) { + clientBody = paramstr.getBytes(StandardCharsets.UTF_8); + } + } + if (logger.isLoggable(Level.FINEST)) { + logger.log( + Level.FINEST, + "httpAsync: module=" + localModule + ", resname=" + resname + ", enter sendEachAddressAsync"); + } + return sendEachAddressAsync(req, req.requestPath(), clientHeaders, clientBody, addrs.iterator()); + }); + } + + protected InetSocketAddress randomAddress(WebRequest req, Set addrs) { + InetSocketAddress[] array = addrs.toArray(new InetSocketAddress[addrs.size()]); + return array[ThreadLocalRandom.current().nextInt(array.length)]; + } + + protected CompletableFuture> sendEachAddressAsync( + WebRequest req, + String requestPath, + final HttpHeaders clientHeaders, + byte[] clientBody, + Iterator it) { + if (!it.hasNext()) { + return new HttpResult().status(404).toFuture(); + } + InetSocketAddress addr = it.next(); + String host = addr.getPort() > 0 && addr.getPort() != 80 + ? (addr.getHostString() + ":" + addr.getPort()) + : addr.getHostString(); + String url = "http://" + host + requestPath; + if (logger.isLoggable(Level.FINER)) { + logger.log( + Level.FINER, + "sendEachAddressAsync: url: " + url + ", body: " + + (clientBody != null ? new String(clientBody, StandardCharsets.UTF_8) : "") + ", headers: " + + clientHeaders); + } + java.net.http.HttpRequest.Builder builder = java.net.http.HttpRequest.newBuilder() + .uri(URI.create(url)) + .timeout(Duration.ofMillis(10_000)) + // 存在sendHeader后不发送body数据的问题, java.net.http.HttpRequest的bug? + .method("POST", createBodyPublisher(clientBody)); + clientHeaders.forEach(builder::header); + return httpClient + .sendAsync(builder.build(), java.net.http.HttpResponse.BodyHandlers.ofByteArray()) + .thenApply((java.net.http.HttpResponse resp) -> { + Traces.currentTraceid(req.getTraceid()); + final int rs = resp.statusCode(); + if (rs != 200) { + return new HttpResult().status(rs); + } + return new HttpResult<>(resp.body()); + }); + } + + private static java.net.http.HttpRequest.BodyPublisher createBodyPublisher(byte[] clientBody) { + return clientBody == null + ? java.net.http.HttpRequest.BodyPublishers.noBody() + : java.net.http.HttpRequest.BodyPublishers.ofByteArray(clientBody); + } +} diff --git a/src/main/java/org/redkale/convert/ConvertImpl.java b/src/main/java/org/redkale/convert/ConvertImpl.java index 8a084323b..23ead4148 100644 --- a/src/main/java/org/redkale/convert/ConvertImpl.java +++ b/src/main/java/org/redkale/convert/ConvertImpl.java @@ -1,65 +1,65 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package org.redkale.convert; - -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.*; - -/** - * 用于序列化时接口或抽象类的默认实现类, 被标记的类必须是接口或抽象类
- * 使用场景:
- * - *

- * - *
- * @ConvertImpl(OneImpl.class)
- * public interface OneEntity {
- *     public String getName();
- * }
- *
- *
- * public class OneImpl implements OneEntity {
- *     private String name;
- *     public String getName(){return name;}
- *     public void setName(String name){this.name=name;}
- * }
- *
- *
- * String json = "{'name':'hello'}";
- * OneEntity one = JsonConvert.root().convertFrom(OneEntity.class, json);
- * //one instanceof OneImpl
- *
- * 
- * - *
- * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.5.0 - */ -// 一定不能标记Inherited -@Documented -@Target({TYPE}) -@Retention(RUNTIME) -public @interface ConvertImpl { - - /** - * 默认的实现类 - * - * @return String - */ - Class value() default Object.class; - - /** - * 实现类的集合 - * - * @return Class[] - */ - Class[] types() default {}; -} +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert; + +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.*; + +/** + * 用于序列化时接口或抽象类的默认实现类, 被标记的类必须是接口或抽象类
+ * 使用场景:
+ * + *

+ * + *
+ * @ConvertImpl(OneImpl.class)
+ * public interface OneEntity {
+ *     public String getName();
+ * }
+ *
+ *
+ * public class OneImpl implements OneEntity {
+ *     private String name;
+ *     public String getName(){return name;}
+ *     public void setName(String name){this.name=name;}
+ * }
+ *
+ *
+ * String json = "{'name':'hello'}";
+ * OneEntity one = JsonConvert.root().convertFrom(OneEntity.class, json);
+ * //one instanceof OneImpl
+ *
+ * 
+ * + *
+ * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.5.0 + */ +// 一定不能标记Inherited +@Documented +@Target({TYPE}) +@Retention(RUNTIME) +public @interface ConvertImpl { + + /** + * 默认的实现类 + * + * @return String + */ + Class value() default Object.class; + + /** + * 实现类的集合 + * + * @return Class[] + */ + Class[] types() default {}; +} diff --git a/src/main/java/org/redkale/convert/StreamDecoder.java b/src/main/java/org/redkale/convert/StreamDecoder.java index 898f94108..44dd1df14 100644 --- a/src/main/java/org/redkale/convert/StreamDecoder.java +++ b/src/main/java/org/redkale/convert/StreamDecoder.java @@ -1,137 +1,137 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package org.redkale.convert; - -import java.lang.reflect.*; -import java.util.*; -import java.util.concurrent.locks.*; -import java.util.stream.Stream; - -/** - * Stream的反序列化操作类
- * 支持一定程度的泛型。
- * - *

详情见: https://redkale.org - * - * @author zhangjx - * @param 反解析的集合元素类型 - */ -@SuppressWarnings("unchecked") -public class StreamDecoder implements Decodeable> { - - protected final Type type; - - protected final Type componentType; - - protected final Decodeable componentDecoder; - - protected volatile boolean inited = false; - - private final ReentrantLock lock = new ReentrantLock(); - - private final Condition condition = lock.newCondition(); - - public StreamDecoder(final ConvertFactory factory, final Type type) { - this.type = type; - try { - if (type instanceof ParameterizedType) { - final ParameterizedType pt = (ParameterizedType) type; - this.componentType = pt.getActualTypeArguments()[0]; - factory.register(type, this); - this.componentDecoder = factory.loadDecoder(this.componentType); - } else { - throw new ConvertException("StreamDecoder not support the type (" + type + ")"); - } - } finally { - inited = true; - lock.lock(); - try { - condition.signalAll(); - } finally { - lock.unlock(); - } - } - } - - @Override - public Stream convertFrom(Reader in) { - return convertFrom(in, null); - } - - public Stream convertFrom(Reader in, DeMember member) { - byte[] typevals = new byte[1]; - int len = in.readArrayB(member, typevals, this.componentDecoder); - int contentLength = -1; - if (len == Reader.SIGN_NULL) { - return null; - } - if (len == Reader.SIGN_NOLENBUTBYTES) { - contentLength = in.readMemberContentLength(member, this.componentDecoder); - len = Reader.SIGN_NOLENGTH; - } - if (this.componentDecoder == null) { - if (!this.inited) { - lock.lock(); - try { - condition.await(); - } catch (Exception e) { - // do nothing - } finally { - lock.unlock(); - } - } - } - final Decodeable localdecoder = getComponentDecoder(this.componentDecoder, typevals); - final List result = new ArrayList(); - boolean first = true; - if (len == Reader.SIGN_NOLENGTH) { - int startPosition = in.position(); - while (hasNext(in, member, startPosition, contentLength, first)) { - Reader itemReader = getItemReader(in, member, first); - if (itemReader == null) { - break; - } - result.add(readMemberValue(itemReader, member, localdecoder, first)); - first = false; - } - } else { - for (int i = 0; i < len; i++) { - result.add(localdecoder.convertFrom(in)); - } - } - in.readArrayE(); - return result.stream(); - } - - protected boolean hasNext(Reader in, DeMember member, int startPosition, int contentLength, boolean first) { - return in.hasNext(startPosition, contentLength); - } - - protected Decodeable getComponentDecoder(Decodeable decoder, byte[] typevals) { - return decoder; - } - - protected Reader getItemReader(Reader in, DeMember member, boolean first) { - return in; - } - - protected T readMemberValue(Reader in, DeMember member, Decodeable decoder, boolean first) { - return decoder.convertFrom(in); - } - - @Override - public Type getType() { - return type; - } - - public Type getComponentType() { - return componentType; - } - - public Decodeable getComponentDecoder() { - return componentDecoder; - } -} +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert; + +import java.lang.reflect.*; +import java.util.*; +import java.util.concurrent.locks.*; +import java.util.stream.Stream; + +/** + * Stream的反序列化操作类
+ * 支持一定程度的泛型。
+ * + *

详情见: https://redkale.org + * + * @author zhangjx + * @param 反解析的集合元素类型 + */ +@SuppressWarnings("unchecked") +public class StreamDecoder implements Decodeable> { + + protected final Type type; + + protected final Type componentType; + + protected final Decodeable componentDecoder; + + protected volatile boolean inited = false; + + private final ReentrantLock lock = new ReentrantLock(); + + private final Condition condition = lock.newCondition(); + + public StreamDecoder(final ConvertFactory factory, final Type type) { + this.type = type; + try { + if (type instanceof ParameterizedType) { + final ParameterizedType pt = (ParameterizedType) type; + this.componentType = pt.getActualTypeArguments()[0]; + factory.register(type, this); + this.componentDecoder = factory.loadDecoder(this.componentType); + } else { + throw new ConvertException("StreamDecoder not support the type (" + type + ")"); + } + } finally { + inited = true; + lock.lock(); + try { + condition.signalAll(); + } finally { + lock.unlock(); + } + } + } + + @Override + public Stream convertFrom(Reader in) { + return convertFrom(in, null); + } + + public Stream convertFrom(Reader in, DeMember member) { + byte[] typevals = new byte[1]; + int len = in.readArrayB(member, typevals, this.componentDecoder); + int contentLength = -1; + if (len == Reader.SIGN_NULL) { + return null; + } + if (len == Reader.SIGN_NOLENBUTBYTES) { + contentLength = in.readMemberContentLength(member, this.componentDecoder); + len = Reader.SIGN_NOLENGTH; + } + if (this.componentDecoder == null) { + if (!this.inited) { + lock.lock(); + try { + condition.await(); + } catch (Exception e) { + // do nothing + } finally { + lock.unlock(); + } + } + } + final Decodeable localdecoder = getComponentDecoder(this.componentDecoder, typevals); + final List result = new ArrayList(); + boolean first = true; + if (len == Reader.SIGN_NOLENGTH) { + int startPosition = in.position(); + while (hasNext(in, member, startPosition, contentLength, first)) { + Reader itemReader = getItemReader(in, member, first); + if (itemReader == null) { + break; + } + result.add(readMemberValue(itemReader, member, localdecoder, first)); + first = false; + } + } else { + for (int i = 0; i < len; i++) { + result.add(localdecoder.convertFrom(in)); + } + } + in.readArrayE(); + return result.stream(); + } + + protected boolean hasNext(Reader in, DeMember member, int startPosition, int contentLength, boolean first) { + return in.hasNext(startPosition, contentLength); + } + + protected Decodeable getComponentDecoder(Decodeable decoder, byte[] typevals) { + return decoder; + } + + protected Reader getItemReader(Reader in, DeMember member, boolean first) { + return in; + } + + protected T readMemberValue(Reader in, DeMember member, Decodeable decoder, boolean first) { + return decoder.convertFrom(in); + } + + @Override + public Type getType() { + return type; + } + + public Type getComponentType() { + return componentType; + } + + public Decodeable getComponentDecoder() { + return componentDecoder; + } +} diff --git a/src/main/java/org/redkale/convert/ext/EnumSimpledCoder.java b/src/main/java/org/redkale/convert/ext/EnumSimpledCoder.java index 6dd134d5e..3f536091d 100644 --- a/src/main/java/org/redkale/convert/ext/EnumSimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/EnumSimpledCoder.java @@ -1,98 +1,98 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package org.redkale.convert.ext; - -import java.lang.reflect.*; -import java.util.*; -import org.redkale.convert.*; -import org.redkale.util.RedkaleClassLoader; - -/** - * 枚举 的SimpledCoder实现 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @param Reader输入的子类型 - * @param Writer输出的子类型 - * @param Enum的子类 - */ -public final class EnumSimpledCoder extends SimpledCoder { - - private final Encodeable valueEncoder; - - private final Map enumToValues; - - private final Map valueToEnums; - - public EnumSimpledCoder(final ConvertFactory factory, Class type) { - this.type = type; - ConvertEnumValue cev = type.getAnnotation(ConvertEnumValue.class); - if (cev == null) { - this.valueEncoder = null; - this.enumToValues = null; - this.valueToEnums = null; - } else { - try { - String fieldName = cev.value(); - Field field = type.getDeclaredField(fieldName); - RedkaleClassLoader.putReflectionField(fieldName, field); - char[] chs = fieldName.toCharArray(); - chs[0] = Character.toUpperCase(chs[0]); - String methodName = "get" + new String(chs); - Method method = null; - try { - method = type.getMethod(methodName); - } catch (NoSuchMethodException | SecurityException me) { - method = type.getMethod(fieldName); - methodName = fieldName; - } - RedkaleClassLoader.putReflectionMethod(methodName, method); - Map map1 = new HashMap<>(); - Map map2 = new HashMap<>(); - for (E e : type.getEnumConstants()) { - map1.put(e, method.invoke(e)); - map2.put(method.invoke(e).toString(), e); - } - this.valueEncoder = factory.loadEncoder(field.getType()); - this.enumToValues = map1; - this.valueToEnums = map2; - } catch (Exception e) { - throw new ConvertException(e); - } - } - } - - @Override - public void convertTo(final W out, final E value) { - if (value == null) { - out.writeNull(); - } else if (valueEncoder != null) { - valueEncoder.convertTo(out, enumToValues.get(value)); - } else { - out.writeSmallString(value.toString()); - } - } - - @Override - @SuppressWarnings("unchecked") - public E convertFrom(final R in) { - String value = in.readSmallString(); - if (value == null) { - return null; - } - if (valueToEnums != null) { - return valueToEnums.get(value); - } else { - return (E) Enum.valueOf((Class) type, value); - } - } - - @Override - public Class getType() { - return (Class) type; - } -} +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.ext; + +import java.lang.reflect.*; +import java.util.*; +import org.redkale.convert.*; +import org.redkale.util.RedkaleClassLoader; + +/** + * 枚举 的SimpledCoder实现 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @param Reader输入的子类型 + * @param Writer输出的子类型 + * @param Enum的子类 + */ +public final class EnumSimpledCoder extends SimpledCoder { + + private final Encodeable valueEncoder; + + private final Map enumToValues; + + private final Map valueToEnums; + + public EnumSimpledCoder(final ConvertFactory factory, Class type) { + this.type = type; + ConvertEnumValue cev = type.getAnnotation(ConvertEnumValue.class); + if (cev == null) { + this.valueEncoder = null; + this.enumToValues = null; + this.valueToEnums = null; + } else { + try { + String fieldName = cev.value(); + Field field = type.getDeclaredField(fieldName); + RedkaleClassLoader.putReflectionField(fieldName, field); + char[] chs = fieldName.toCharArray(); + chs[0] = Character.toUpperCase(chs[0]); + String methodName = "get" + new String(chs); + Method method = null; + try { + method = type.getMethod(methodName); + } catch (NoSuchMethodException | SecurityException me) { + method = type.getMethod(fieldName); + methodName = fieldName; + } + RedkaleClassLoader.putReflectionMethod(methodName, method); + Map map1 = new HashMap<>(); + Map map2 = new HashMap<>(); + for (E e : type.getEnumConstants()) { + map1.put(e, method.invoke(e)); + map2.put(method.invoke(e).toString(), e); + } + this.valueEncoder = factory.loadEncoder(field.getType()); + this.enumToValues = map1; + this.valueToEnums = map2; + } catch (Exception e) { + throw new ConvertException(e); + } + } + } + + @Override + public void convertTo(final W out, final E value) { + if (value == null) { + out.writeNull(); + } else if (valueEncoder != null) { + valueEncoder.convertTo(out, enumToValues.get(value)); + } else { + out.writeSmallString(value.toString()); + } + } + + @Override + @SuppressWarnings("unchecked") + public E convertFrom(final R in) { + String value = in.readSmallString(); + if (value == null) { + return null; + } + if (valueToEnums != null) { + return valueToEnums.get(value); + } else { + return (E) Enum.valueOf((Class) type, value); + } + } + + @Override + public Class getType() { + return (Class) type; + } +} diff --git a/src/main/java/org/redkale/convert/ext/InstantSimpledCoder.java b/src/main/java/org/redkale/convert/ext/InstantSimpledCoder.java index 0d883dab1..31d19a6a5 100644 --- a/src/main/java/org/redkale/convert/ext/InstantSimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/InstantSimpledCoder.java @@ -1,59 +1,59 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package org.redkale.convert.ext; - -import java.time.Instant; -import org.redkale.convert.*; -import org.redkale.convert.json.*; - -/** - * java.time.Instant 的SimpledCoder实现 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @param Reader输入的子类型 - * @param Writer输出的子类型 - */ -public class InstantSimpledCoder extends SimpledCoder { - - public static final InstantSimpledCoder instance = new InstantSimpledCoder(); - - @Override - public void convertTo(W out, Instant value) { - out.writeLong(value == null ? -1L : value.toEpochMilli()); - } - - @Override - public Instant convertFrom(R in) { - long t = in.readLong(); - return t == -1 ? null : Instant.ofEpochMilli(t); - } - - public static final class InstantJsonSimpledCoder - extends SimpledCoder { - - public static final InstantJsonSimpledCoder instance = new InstantJsonSimpledCoder(); - - @Override - public void convertTo(final W out, final Instant value) { - if (value == null) { - out.writeNull(); - } else { - out.writeSmallString(value.toString()); - } - } - - @Override - public Instant convertFrom(R in) { - final String str = in.readSmallString(); - if (str == null) { - return null; - } - return Instant.parse(str); - } - } -} +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.ext; + +import java.time.Instant; +import org.redkale.convert.*; +import org.redkale.convert.json.*; + +/** + * java.time.Instant 的SimpledCoder实现 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @param Reader输入的子类型 + * @param Writer输出的子类型 + */ +public class InstantSimpledCoder extends SimpledCoder { + + public static final InstantSimpledCoder instance = new InstantSimpledCoder(); + + @Override + public void convertTo(W out, Instant value) { + out.writeLong(value == null ? -1L : value.toEpochMilli()); + } + + @Override + public Instant convertFrom(R in) { + long t = in.readLong(); + return t == -1 ? null : Instant.ofEpochMilli(t); + } + + public static final class InstantJsonSimpledCoder + extends SimpledCoder { + + public static final InstantJsonSimpledCoder instance = new InstantJsonSimpledCoder(); + + @Override + public void convertTo(final W out, final Instant value) { + if (value == null) { + out.writeNull(); + } else { + out.writeSmallString(value.toString()); + } + } + + @Override + public Instant convertFrom(R in) { + final String str = in.readSmallString(); + if (str == null) { + return null; + } + return Instant.parse(str); + } + } +} diff --git a/src/main/java/org/redkale/convert/ext/LocalDateSimpledCoder.java b/src/main/java/org/redkale/convert/ext/LocalDateSimpledCoder.java index 16de4b899..3b3cd555f 100644 --- a/src/main/java/org/redkale/convert/ext/LocalDateSimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/LocalDateSimpledCoder.java @@ -1,75 +1,75 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package org.redkale.convert.ext; - -import java.time.LocalDate; -import org.redkale.convert.*; -import org.redkale.convert.json.*; - -/** - * java.time.LocalDate 的SimpledCoder实现 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @param Reader输入的子类型 - * @param Writer输出的子类型 - */ -public final class LocalDateSimpledCoder extends SimpledCoder { - - public static final LocalDateSimpledCoder instance = new LocalDateSimpledCoder(); - - @Override - public void convertTo(W out, LocalDate value) { - out.writeInt( - value == null ? -1 : value.getYear() * 100_00 + value.getMonthValue() * 100 + value.getDayOfMonth()); - } - - @Override - public LocalDate convertFrom(R in) { - int t = in.readInt(); - return t == -1 ? null : LocalDate.of(t / 100_00, t % 100_00 / 100, t % 100); - } - - // public static void main(String[] args) throws Throwable { - // LocalDate now = LocalDate.now(); - // System.out.println(now); - // BsonWriter writer = new BsonWriter(); - // LocalDateSimpledCoder.instance.convertTo(writer, now); - // System.out.println(new ByteArray(writer).getInt(0)); - // BsonReader reader = new BsonReader(writer.toArray()); - // System.out.println(LocalDateSimpledCoder.instance.convertFrom(reader)); - // } - /** - * java.time.LocalDate 的JsonSimpledCoder实现 - * - * @param Reader输入的子类型 - * @param Writer输出的子类型 - */ - public static final class LocalDateJsonSimpledCoder - extends SimpledCoder { - - public static final LocalDateJsonSimpledCoder instance = new LocalDateJsonSimpledCoder(); - - @Override - public void convertTo(final W out, final LocalDate value) { - if (value == null) { - out.writeNull(); - } else { - out.writeSmallString(value.toString()); - } - } - - @Override - public LocalDate convertFrom(R in) { - final String str = in.readSmallString(); - if (str == null) { - return null; - } - return LocalDate.parse(str); - } - } -} +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.ext; + +import java.time.LocalDate; +import org.redkale.convert.*; +import org.redkale.convert.json.*; + +/** + * java.time.LocalDate 的SimpledCoder实现 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @param Reader输入的子类型 + * @param Writer输出的子类型 + */ +public final class LocalDateSimpledCoder extends SimpledCoder { + + public static final LocalDateSimpledCoder instance = new LocalDateSimpledCoder(); + + @Override + public void convertTo(W out, LocalDate value) { + out.writeInt( + value == null ? -1 : value.getYear() * 100_00 + value.getMonthValue() * 100 + value.getDayOfMonth()); + } + + @Override + public LocalDate convertFrom(R in) { + int t = in.readInt(); + return t == -1 ? null : LocalDate.of(t / 100_00, t % 100_00 / 100, t % 100); + } + + // public static void main(String[] args) throws Throwable { + // LocalDate now = LocalDate.now(); + // System.out.println(now); + // BsonWriter writer = new BsonWriter(); + // LocalDateSimpledCoder.instance.convertTo(writer, now); + // System.out.println(new ByteArray(writer).getInt(0)); + // BsonReader reader = new BsonReader(writer.toArray()); + // System.out.println(LocalDateSimpledCoder.instance.convertFrom(reader)); + // } + /** + * java.time.LocalDate 的JsonSimpledCoder实现 + * + * @param Reader输入的子类型 + * @param Writer输出的子类型 + */ + public static final class LocalDateJsonSimpledCoder + extends SimpledCoder { + + public static final LocalDateJsonSimpledCoder instance = new LocalDateJsonSimpledCoder(); + + @Override + public void convertTo(final W out, final LocalDate value) { + if (value == null) { + out.writeNull(); + } else { + out.writeSmallString(value.toString()); + } + } + + @Override + public LocalDate convertFrom(R in) { + final String str = in.readSmallString(); + if (str == null) { + return null; + } + return LocalDate.parse(str); + } + } +} diff --git a/src/main/java/org/redkale/convert/ext/LocalDateTimeSimpledCoder.java b/src/main/java/org/redkale/convert/ext/LocalDateTimeSimpledCoder.java index 490d6df2b..ea0303010 100644 --- a/src/main/java/org/redkale/convert/ext/LocalDateTimeSimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/LocalDateTimeSimpledCoder.java @@ -1,108 +1,108 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package org.redkale.convert.ext; - -import java.time.*; -import org.redkale.convert.*; -import org.redkale.convert.json.*; - -/** - * java.time.LocalDateTime 的SimpledCoder实现 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @param Reader输入的子类型 - * @param Writer输出的子类型 - */ -public final class LocalDateTimeSimpledCoder - extends SimpledCoder { - - private static final ByteArraySimpledCoder bsSimpledCoder = ByteArraySimpledCoder.instance; - - public static final LocalDateTimeSimpledCoder instance = new LocalDateTimeSimpledCoder(); - - @Override - public void convertTo(W out, LocalDateTime value) { - if (value == null) { - bsSimpledCoder.convertTo(out, null); - } else { - long v1 = value.toEpochSecond(ZoneOffset.UTC); - int v2 = value.getNano(); - byte[] bs = new byte[] { - (byte) (v1 >> 56), - (byte) (v1 >> 48), - (byte) (v1 >> 40), - (byte) (v1 >> 32), - (byte) (v1 >> 24), - (byte) (v1 >> 16), - (byte) (v1 >> 8), - (byte) v1, - (byte) (v2 >> 24), - (byte) (v2 >> 16), - (byte) (v2 >> 8), - (byte) v2 - }; - bsSimpledCoder.convertTo(out, bs); - } - } - - @Override - public LocalDateTime convertFrom(R in) { - byte[] bs = bsSimpledCoder.convertFrom(in); - if (bs == null) { - return null; - } - long v1 = (((long) bs[0] & 0xff) << 56) - | (((long) bs[1] & 0xff) << 48) - | (((long) bs[2] & 0xff) << 40) - | (((long) bs[3] & 0xff) << 32) - | (((long) bs[4] & 0xff) << 24) - | (((long) bs[5] & 0xff) << 16) - | (((long) bs[6] & 0xff) << 8) - | ((long) bs[7] & 0xff); - int v2 = ((bs[8] & 0xff) << 24) | ((bs[9] & 0xff) << 16) | ((bs[10] & 0xff) << 8) | (bs[11] & 0xff); - return LocalDateTime.ofEpochSecond(v1, v2, ZoneOffset.UTC); - } - - // public static void main(String[] args) throws Throwable { - // LocalDateTime now = LocalDateTime.now(); - // System.out.println(now); - // BsonWriter writer = new BsonWriter(); - // LocalDateTimeSimpledCoder.instance.convertTo(writer, now); - // BsonReader reader = new BsonReader(writer.toArray()); - // System.out.println(LocalDateTimeSimpledCoder.instance.convertFrom(reader)); - // } - /** - * java.time.LocalDateTime 的JsonSimpledCoder实现 - * - * @param Reader输入的子类型 - * @param Writer输出的子类型 - */ - public static final class LocalDateTimeJsonSimpledCoder - extends SimpledCoder { - - public static final LocalDateTimeJsonSimpledCoder instance = new LocalDateTimeJsonSimpledCoder(); - - @Override - public void convertTo(final W out, final LocalDateTime value) { - if (value == null) { - out.writeNull(); - } else { - out.writeSmallString(value.toString()); - } - } - - @Override - public LocalDateTime convertFrom(R in) { - final String str = in.readSmallString(); - if (str == null) { - return null; - } - return LocalDateTime.parse(str); - } - } -} +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.ext; + +import java.time.*; +import org.redkale.convert.*; +import org.redkale.convert.json.*; + +/** + * java.time.LocalDateTime 的SimpledCoder实现 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @param Reader输入的子类型 + * @param Writer输出的子类型 + */ +public final class LocalDateTimeSimpledCoder + extends SimpledCoder { + + private static final ByteArraySimpledCoder bsSimpledCoder = ByteArraySimpledCoder.instance; + + public static final LocalDateTimeSimpledCoder instance = new LocalDateTimeSimpledCoder(); + + @Override + public void convertTo(W out, LocalDateTime value) { + if (value == null) { + bsSimpledCoder.convertTo(out, null); + } else { + long v1 = value.toEpochSecond(ZoneOffset.UTC); + int v2 = value.getNano(); + byte[] bs = new byte[] { + (byte) (v1 >> 56), + (byte) (v1 >> 48), + (byte) (v1 >> 40), + (byte) (v1 >> 32), + (byte) (v1 >> 24), + (byte) (v1 >> 16), + (byte) (v1 >> 8), + (byte) v1, + (byte) (v2 >> 24), + (byte) (v2 >> 16), + (byte) (v2 >> 8), + (byte) v2 + }; + bsSimpledCoder.convertTo(out, bs); + } + } + + @Override + public LocalDateTime convertFrom(R in) { + byte[] bs = bsSimpledCoder.convertFrom(in); + if (bs == null) { + return null; + } + long v1 = (((long) bs[0] & 0xff) << 56) + | (((long) bs[1] & 0xff) << 48) + | (((long) bs[2] & 0xff) << 40) + | (((long) bs[3] & 0xff) << 32) + | (((long) bs[4] & 0xff) << 24) + | (((long) bs[5] & 0xff) << 16) + | (((long) bs[6] & 0xff) << 8) + | ((long) bs[7] & 0xff); + int v2 = ((bs[8] & 0xff) << 24) | ((bs[9] & 0xff) << 16) | ((bs[10] & 0xff) << 8) | (bs[11] & 0xff); + return LocalDateTime.ofEpochSecond(v1, v2, ZoneOffset.UTC); + } + + // public static void main(String[] args) throws Throwable { + // LocalDateTime now = LocalDateTime.now(); + // System.out.println(now); + // BsonWriter writer = new BsonWriter(); + // LocalDateTimeSimpledCoder.instance.convertTo(writer, now); + // BsonReader reader = new BsonReader(writer.toArray()); + // System.out.println(LocalDateTimeSimpledCoder.instance.convertFrom(reader)); + // } + /** + * java.time.LocalDateTime 的JsonSimpledCoder实现 + * + * @param Reader输入的子类型 + * @param Writer输出的子类型 + */ + public static final class LocalDateTimeJsonSimpledCoder + extends SimpledCoder { + + public static final LocalDateTimeJsonSimpledCoder instance = new LocalDateTimeJsonSimpledCoder(); + + @Override + public void convertTo(final W out, final LocalDateTime value) { + if (value == null) { + out.writeNull(); + } else { + out.writeSmallString(value.toString()); + } + } + + @Override + public LocalDateTime convertFrom(R in) { + final String str = in.readSmallString(); + if (str == null) { + return null; + } + return LocalDateTime.parse(str); + } + } +} diff --git a/src/main/java/org/redkale/convert/ext/LocalTimeSimpledCoder.java b/src/main/java/org/redkale/convert/ext/LocalTimeSimpledCoder.java index deb137b9f..7916ef86e 100644 --- a/src/main/java/org/redkale/convert/ext/LocalTimeSimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/LocalTimeSimpledCoder.java @@ -1,73 +1,73 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package org.redkale.convert.ext; - -import java.time.LocalTime; -import org.redkale.convert.*; -import org.redkale.convert.json.*; - -/** - * java.time.LocalTime 的SimpledCoder实现 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @param Reader输入的子类型 - * @param Writer输出的子类型 - */ -public final class LocalTimeSimpledCoder extends SimpledCoder { - - public static final LocalTimeSimpledCoder instance = new LocalTimeSimpledCoder(); - - @Override - public void convertTo(W out, LocalTime value) { - out.writeLong(value == null ? -1L : value.toNanoOfDay()); - } - - @Override - public LocalTime convertFrom(R in) { - long t = in.readLong(); - return t == -1 ? null : LocalTime.ofNanoOfDay(t); - } - - // public static void main(String[] args) throws Throwable { - // LocalTime now = LocalTime.now(); - // System.out.println(now); - // BsonWriter writer = new BsonWriter(); - // LocalTimeSimpledCoder.instance.convertTo(writer, now); - // BsonReader reader = new BsonReader(writer.toArray()); - // System.out.println(LocalTimeSimpledCoder.instance.convertFrom(reader)); - // } - /** - * java.time.LocalTime 的JsonSimpledCoder实现 - * - * @param Reader输入的子类型 - * @param Writer输出的子类型 - */ - public static final class LocalTimeJsonSimpledCoder - extends SimpledCoder { - - public static final LocalTimeJsonSimpledCoder instance = new LocalTimeJsonSimpledCoder(); - - @Override - public void convertTo(final W out, final LocalTime value) { - if (value == null) { - out.writeNull(); - } else { - out.writeSmallString(value.toString()); - } - } - - @Override - public LocalTime convertFrom(R in) { - final String str = in.readSmallString(); - if (str == null) { - return null; - } - return LocalTime.parse(str); - } - } -} +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.ext; + +import java.time.LocalTime; +import org.redkale.convert.*; +import org.redkale.convert.json.*; + +/** + * java.time.LocalTime 的SimpledCoder实现 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @param Reader输入的子类型 + * @param Writer输出的子类型 + */ +public final class LocalTimeSimpledCoder extends SimpledCoder { + + public static final LocalTimeSimpledCoder instance = new LocalTimeSimpledCoder(); + + @Override + public void convertTo(W out, LocalTime value) { + out.writeLong(value == null ? -1L : value.toNanoOfDay()); + } + + @Override + public LocalTime convertFrom(R in) { + long t = in.readLong(); + return t == -1 ? null : LocalTime.ofNanoOfDay(t); + } + + // public static void main(String[] args) throws Throwable { + // LocalTime now = LocalTime.now(); + // System.out.println(now); + // BsonWriter writer = new BsonWriter(); + // LocalTimeSimpledCoder.instance.convertTo(writer, now); + // BsonReader reader = new BsonReader(writer.toArray()); + // System.out.println(LocalTimeSimpledCoder.instance.convertFrom(reader)); + // } + /** + * java.time.LocalTime 的JsonSimpledCoder实现 + * + * @param Reader输入的子类型 + * @param Writer输出的子类型 + */ + public static final class LocalTimeJsonSimpledCoder + extends SimpledCoder { + + public static final LocalTimeJsonSimpledCoder instance = new LocalTimeJsonSimpledCoder(); + + @Override + public void convertTo(final W out, final LocalTime value) { + if (value == null) { + out.writeNull(); + } else { + out.writeSmallString(value.toString()); + } + } + + @Override + public LocalTime convertFrom(R in) { + final String str = in.readSmallString(); + if (str == null) { + return null; + } + return LocalTime.parse(str); + } + } +} diff --git a/src/main/java/org/redkale/convert/ext/LongAdderSimpledCoder.java b/src/main/java/org/redkale/convert/ext/LongAdderSimpledCoder.java index 6fd9421a6..ce0f586fb 100644 --- a/src/main/java/org/redkale/convert/ext/LongAdderSimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/LongAdderSimpledCoder.java @@ -1,35 +1,35 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package org.redkale.convert.ext; - -import java.util.concurrent.atomic.LongAdder; -import org.redkale.convert.*; - -/** - * LongAdder 的SimpledCoder实现 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @param Reader输入的子类型 - * @param Writer输出的子类型 - */ -public final class LongAdderSimpledCoder extends SimpledCoder { - - public static final LongAdderSimpledCoder instance = new LongAdderSimpledCoder(); - - @Override - public void convertTo(W out, LongAdder value) { - out.writeLong(value == null ? 0L : value.longValue()); - } - - @Override - public LongAdder convertFrom(R in) { - LongAdder la = new LongAdder(); - la.add(in.readLong()); - return la; - } -} +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.ext; + +import java.util.concurrent.atomic.LongAdder; +import org.redkale.convert.*; + +/** + * LongAdder 的SimpledCoder实现 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @param Reader输入的子类型 + * @param Writer输出的子类型 + */ +public final class LongAdderSimpledCoder extends SimpledCoder { + + public static final LongAdderSimpledCoder instance = new LongAdderSimpledCoder(); + + @Override + public void convertTo(W out, LongAdder value) { + out.writeLong(value == null ? 0L : value.longValue()); + } + + @Override + public LongAdder convertFrom(R in) { + LongAdder la = new LongAdder(); + la.add(in.readLong()); + return la; + } +} diff --git a/src/main/java/org/redkale/convert/json/JsonArray.java b/src/main/java/org/redkale/convert/json/JsonArray.java index 48d021a3c..0b0822e88 100644 --- a/src/main/java/org/redkale/convert/json/JsonArray.java +++ b/src/main/java/org/redkale/convert/json/JsonArray.java @@ -1,388 +1,388 @@ -/* - * - */ -package org.redkale.convert.json; - -import java.lang.reflect.Type; -import java.math.*; -import java.util.*; -import org.redkale.annotation.Nullable; -import org.redkale.convert.ConvertDisabled; -import org.redkale.util.*; - -/** - * 常规json数组 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public class JsonArray extends ArrayList implements JsonElement { - - public JsonArray() {} - - public JsonArray(Collection collection) { - super(collection); - } - - public JsonArray(Object... array) { - super(Arrays.asList(array)); - } - - public static JsonArray convertFrom(String text) { - return convertFrom(Utility.charArray(text)); - } - - public static JsonArray convertFrom(char[] text) { - return convertFrom(text, 0, text.length); - } - - public static JsonArray convertFrom(char[] text, int offset, int length) { - return JsonConvert.root().convertFrom(JsonArray.class, text, offset, length); - } - - public static JsonArray create() { - return new JsonArray(); - } - - public List toList(Type componentType) { - Type listType = TypeToken.createParameterizedType(null, ArrayList.class, componentType); - return (List) - JsonConvert.root().convertFrom(listType, JsonConvert.root().convertTo(this)); - } - - public JsonArray append(Object value) { - super.add(value); - return this; - } - - public JsonArray append(int index, Object value) { - super.set(index, value); - return this; - } - - public boolean isNull(int index) { - return get(index) == null; - } - - public boolean isJsonObject(int index) { - return get(index) instanceof JsonObject; - } - - public boolean isJsonArray(int index) { - return get(index) instanceof JsonArray; - } - - public JsonObject getJsonObject(int index) { - Object val = get(index); - if (val instanceof JsonObject) { - return (JsonObject) val; - } - if (val instanceof Map) { - return new JsonObject((Map) val); - } - throw new RedkaleException("val [" + val + "] is not a valid JsonObject."); - } - - public JsonArray getJsonArray(int index) { - Object val = get(index); - if (val instanceof JsonArray) { - return (JsonArray) val; - } - if (val instanceof Collection) { - return new JsonArray((Collection) val); - } - throw new RedkaleException("val [" + val + "] is not a valid JsonArray."); - } - - public String getString(int index) { - final Object val = get(index); - if (val == null) { - return null; - } - return val.toString(); - } - - public String getString(int index, String defValue) { - final Object val = get(index); - if (val == null) { - return defValue; - } - return val.toString(); - } - - public BigDecimal getBigDecimal(int index) { - final Object val = get(index); - if (val == null) { - return null; - } - if (val instanceof BigDecimal) { - return (BigDecimal) val; - } - return new BigDecimal(val.toString()); - } - - public BigDecimal getBigDecimal(int index, BigDecimal defValue) { - final Object val = get(index); - if (val == null) { - return defValue; - } - if (val instanceof BigDecimal) { - return (BigDecimal) val; - } - try { - return new BigDecimal(val.toString()); - } catch (Exception e) { - return defValue; - } - } - - public BigInteger getBigInteger(int index) { - final Object val = get(index); - if (val == null) { - return null; - } - if (val instanceof BigInteger) { - return (BigInteger) val; - } - return new BigInteger(val.toString()); - } - - public BigInteger getBigInteger(int index, BigInteger defValue) { - final Object val = get(index); - if (val == null) { - return defValue; - } - if (val instanceof BigInteger) { - return (BigInteger) val; - } - try { - return new BigInteger(val.toString()); - } catch (Exception e) { - return defValue; - } - } - - public Number getNumber(int index) { - Object val = get(index); - if (val == null) { - return null; - } - if (val instanceof Number) { - return (Number) val; - } - return JsonObject.stringToNumber(val.toString()); - } - - public Number getNumber(int index, Number defValue) { - Object val = get(index); - if (val == null) { - return defValue; - } - if (val instanceof Number) { - return (Number) val; - } - try { - return JsonObject.stringToNumber(val.toString()); - } catch (Exception e) { - return defValue; - } - } - - public Double getDouble(int index) { - final Object val = get(index); - if (val == null) { - return null; - } - if (val instanceof Number) { - return ((Number) val).doubleValue(); - } - return Double.parseDouble(val.toString()); - } - - public double getDouble(int index, double defValue) { - final Object val = get(index); - if (val == null) { - return defValue; - } - if (val instanceof Number) { - return ((Number) val).doubleValue(); - } - try { - return Double.parseDouble(val.toString()); - } catch (Exception e) { - return defValue; - } - } - - public Long getLong(int index) { - final Object val = get(index); - if (val == null) { - return null; - } - if (val instanceof Number) { - return ((Number) val).longValue(); - } - return Long.parseLong(val.toString()); - } - - public long getLong(int index, long defValue) { - final Object val = get(index); - if (val == null) { - return defValue; - } - if (val instanceof Number) { - return ((Number) val).longValue(); - } - try { - return Long.parseLong(val.toString()); - } catch (Exception e) { - return defValue; - } - } - - public Float getFloat(int index) { - final Object val = get(index); - if (val == null) { - return null; - } - if (val instanceof Number) { - return ((Number) val).floatValue(); - } - return Float.parseFloat(val.toString()); - } - - public float getFloat(int index, float defValue) { - final Object val = get(index); - if (val == null) { - return defValue; - } - if (val instanceof Number) { - return ((Number) val).floatValue(); - } - try { - return Float.parseFloat(val.toString()); - } catch (Exception e) { - return defValue; - } - } - - public Integer getInt(int index) { - final Object val = get(index); - if (val == null) { - return null; - } - if (val instanceof Number) { - return ((Number) val).intValue(); - } - return Integer.parseInt(val.toString()); - } - - public int getInt(int index, int defValue) { - final Object val = get(index); - if (val == null) { - return defValue; - } - if (val instanceof Number) { - return ((Number) val).intValue(); - } - try { - return Integer.parseInt(val.toString()); - } catch (Exception e) { - return defValue; - } - } - - public Short getShort(int index) { - final Object val = get(index); - if (val == null) { - return null; - } - if (val instanceof Number) { - return ((Number) val).shortValue(); - } - return Short.parseShort(val.toString()); - } - - public short getShort(int index, short defValue) { - final Object val = get(index); - if (val == null) { - return defValue; - } - if (val instanceof Number) { - return ((Number) val).shortValue(); - } - try { - return Short.parseShort(val.toString()); - } catch (Exception e) { - return defValue; - } - } - - public Byte getByte(int index) { - final Object val = get(index); - if (val == null) { - return null; - } - if (val instanceof Number) { - return ((Number) val).byteValue(); - } - return Byte.parseByte(val.toString()); - } - - public byte getByte(int index, byte defValue) { - final Object val = get(index); - if (val == null) { - return defValue; - } - if (val instanceof Number) { - return ((Number) val).byteValue(); - } - try { - return Byte.parseByte(val.toString()); - } catch (Exception e) { - return defValue; - } - } - - @Nullable - public Boolean getBoolean(int index) { - final Object val = get(index); - if (val == null) { - return null; - } - return "true".equalsIgnoreCase(val.toString()); - } - - public boolean getBoolean(int index, boolean defValue) { - final Object val = get(index); - if (val == null) { - return defValue; - } - return "true".equalsIgnoreCase(val.toString()); - } - - @Override - @ConvertDisabled - public final boolean isObject() { - return false; - } - - @Override - @ConvertDisabled - public final boolean isArray() { - return true; - } - - @Override - @ConvertDisabled - public final boolean isString() { - return false; - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } -} +/* + * + */ +package org.redkale.convert.json; + +import java.lang.reflect.Type; +import java.math.*; +import java.util.*; +import org.redkale.annotation.Nullable; +import org.redkale.convert.ConvertDisabled; +import org.redkale.util.*; + +/** + * 常规json数组 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public class JsonArray extends ArrayList implements JsonElement { + + public JsonArray() {} + + public JsonArray(Collection collection) { + super(collection); + } + + public JsonArray(Object... array) { + super(Arrays.asList(array)); + } + + public static JsonArray convertFrom(String text) { + return convertFrom(Utility.charArray(text)); + } + + public static JsonArray convertFrom(char[] text) { + return convertFrom(text, 0, text.length); + } + + public static JsonArray convertFrom(char[] text, int offset, int length) { + return JsonConvert.root().convertFrom(JsonArray.class, text, offset, length); + } + + public static JsonArray create() { + return new JsonArray(); + } + + public List toList(Type componentType) { + Type listType = TypeToken.createParameterizedType(null, ArrayList.class, componentType); + return (List) + JsonConvert.root().convertFrom(listType, JsonConvert.root().convertTo(this)); + } + + public JsonArray append(Object value) { + super.add(value); + return this; + } + + public JsonArray append(int index, Object value) { + super.set(index, value); + return this; + } + + public boolean isNull(int index) { + return get(index) == null; + } + + public boolean isJsonObject(int index) { + return get(index) instanceof JsonObject; + } + + public boolean isJsonArray(int index) { + return get(index) instanceof JsonArray; + } + + public JsonObject getJsonObject(int index) { + Object val = get(index); + if (val instanceof JsonObject) { + return (JsonObject) val; + } + if (val instanceof Map) { + return new JsonObject((Map) val); + } + throw new RedkaleException("val [" + val + "] is not a valid JsonObject."); + } + + public JsonArray getJsonArray(int index) { + Object val = get(index); + if (val instanceof JsonArray) { + return (JsonArray) val; + } + if (val instanceof Collection) { + return new JsonArray((Collection) val); + } + throw new RedkaleException("val [" + val + "] is not a valid JsonArray."); + } + + public String getString(int index) { + final Object val = get(index); + if (val == null) { + return null; + } + return val.toString(); + } + + public String getString(int index, String defValue) { + final Object val = get(index); + if (val == null) { + return defValue; + } + return val.toString(); + } + + public BigDecimal getBigDecimal(int index) { + final Object val = get(index); + if (val == null) { + return null; + } + if (val instanceof BigDecimal) { + return (BigDecimal) val; + } + return new BigDecimal(val.toString()); + } + + public BigDecimal getBigDecimal(int index, BigDecimal defValue) { + final Object val = get(index); + if (val == null) { + return defValue; + } + if (val instanceof BigDecimal) { + return (BigDecimal) val; + } + try { + return new BigDecimal(val.toString()); + } catch (Exception e) { + return defValue; + } + } + + public BigInteger getBigInteger(int index) { + final Object val = get(index); + if (val == null) { + return null; + } + if (val instanceof BigInteger) { + return (BigInteger) val; + } + return new BigInteger(val.toString()); + } + + public BigInteger getBigInteger(int index, BigInteger defValue) { + final Object val = get(index); + if (val == null) { + return defValue; + } + if (val instanceof BigInteger) { + return (BigInteger) val; + } + try { + return new BigInteger(val.toString()); + } catch (Exception e) { + return defValue; + } + } + + public Number getNumber(int index) { + Object val = get(index); + if (val == null) { + return null; + } + if (val instanceof Number) { + return (Number) val; + } + return JsonObject.stringToNumber(val.toString()); + } + + public Number getNumber(int index, Number defValue) { + Object val = get(index); + if (val == null) { + return defValue; + } + if (val instanceof Number) { + return (Number) val; + } + try { + return JsonObject.stringToNumber(val.toString()); + } catch (Exception e) { + return defValue; + } + } + + public Double getDouble(int index) { + final Object val = get(index); + if (val == null) { + return null; + } + if (val instanceof Number) { + return ((Number) val).doubleValue(); + } + return Double.parseDouble(val.toString()); + } + + public double getDouble(int index, double defValue) { + final Object val = get(index); + if (val == null) { + return defValue; + } + if (val instanceof Number) { + return ((Number) val).doubleValue(); + } + try { + return Double.parseDouble(val.toString()); + } catch (Exception e) { + return defValue; + } + } + + public Long getLong(int index) { + final Object val = get(index); + if (val == null) { + return null; + } + if (val instanceof Number) { + return ((Number) val).longValue(); + } + return Long.parseLong(val.toString()); + } + + public long getLong(int index, long defValue) { + final Object val = get(index); + if (val == null) { + return defValue; + } + if (val instanceof Number) { + return ((Number) val).longValue(); + } + try { + return Long.parseLong(val.toString()); + } catch (Exception e) { + return defValue; + } + } + + public Float getFloat(int index) { + final Object val = get(index); + if (val == null) { + return null; + } + if (val instanceof Number) { + return ((Number) val).floatValue(); + } + return Float.parseFloat(val.toString()); + } + + public float getFloat(int index, float defValue) { + final Object val = get(index); + if (val == null) { + return defValue; + } + if (val instanceof Number) { + return ((Number) val).floatValue(); + } + try { + return Float.parseFloat(val.toString()); + } catch (Exception e) { + return defValue; + } + } + + public Integer getInt(int index) { + final Object val = get(index); + if (val == null) { + return null; + } + if (val instanceof Number) { + return ((Number) val).intValue(); + } + return Integer.parseInt(val.toString()); + } + + public int getInt(int index, int defValue) { + final Object val = get(index); + if (val == null) { + return defValue; + } + if (val instanceof Number) { + return ((Number) val).intValue(); + } + try { + return Integer.parseInt(val.toString()); + } catch (Exception e) { + return defValue; + } + } + + public Short getShort(int index) { + final Object val = get(index); + if (val == null) { + return null; + } + if (val instanceof Number) { + return ((Number) val).shortValue(); + } + return Short.parseShort(val.toString()); + } + + public short getShort(int index, short defValue) { + final Object val = get(index); + if (val == null) { + return defValue; + } + if (val instanceof Number) { + return ((Number) val).shortValue(); + } + try { + return Short.parseShort(val.toString()); + } catch (Exception e) { + return defValue; + } + } + + public Byte getByte(int index) { + final Object val = get(index); + if (val == null) { + return null; + } + if (val instanceof Number) { + return ((Number) val).byteValue(); + } + return Byte.parseByte(val.toString()); + } + + public byte getByte(int index, byte defValue) { + final Object val = get(index); + if (val == null) { + return defValue; + } + if (val instanceof Number) { + return ((Number) val).byteValue(); + } + try { + return Byte.parseByte(val.toString()); + } catch (Exception e) { + return defValue; + } + } + + @Nullable + public Boolean getBoolean(int index) { + final Object val = get(index); + if (val == null) { + return null; + } + return "true".equalsIgnoreCase(val.toString()); + } + + public boolean getBoolean(int index, boolean defValue) { + final Object val = get(index); + if (val == null) { + return defValue; + } + return "true".equalsIgnoreCase(val.toString()); + } + + @Override + @ConvertDisabled + public final boolean isObject() { + return false; + } + + @Override + @ConvertDisabled + public final boolean isArray() { + return true; + } + + @Override + @ConvertDisabled + public final boolean isString() { + return false; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } +} diff --git a/src/main/java/org/redkale/convert/json/JsonElement.java b/src/main/java/org/redkale/convert/json/JsonElement.java index 52dac92fc..f2ef6b398 100644 --- a/src/main/java/org/redkale/convert/json/JsonElement.java +++ b/src/main/java/org/redkale/convert/json/JsonElement.java @@ -1,39 +1,39 @@ -/* - * - */ -package org.redkale.convert.json; - -import org.redkale.util.Utility; - -/** - * 常规json实体 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public interface JsonElement extends java.io.Serializable { - - public boolean isObject(); - - public boolean isArray(); - - public boolean isString(); - - public static JsonElement convertFrom(String text) { - return convertFrom(Utility.charArray(text)); - } - - public static JsonElement convertFrom(char[] text) { - return convertFrom(text, 0, text.length); - } - - public static JsonElement convertFrom(char[] text, final int offset, final int length) { - Object val = JsonConvert.root().convertFrom(JsonElement.class, text, offset, length); - if (val instanceof CharSequence) { - return new JsonString(val.toString()); - } - return (JsonElement) val; - } -} +/* + * + */ +package org.redkale.convert.json; + +import org.redkale.util.Utility; + +/** + * 常规json实体 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public interface JsonElement extends java.io.Serializable { + + public boolean isObject(); + + public boolean isArray(); + + public boolean isString(); + + public static JsonElement convertFrom(String text) { + return convertFrom(Utility.charArray(text)); + } + + public static JsonElement convertFrom(char[] text) { + return convertFrom(text, 0, text.length); + } + + public static JsonElement convertFrom(char[] text, final int offset, final int length) { + Object val = JsonConvert.root().convertFrom(JsonElement.class, text, offset, length); + if (val instanceof CharSequence) { + return new JsonString(val.toString()); + } + return (JsonElement) val; + } +} diff --git a/src/main/java/org/redkale/convert/json/JsonElementDecoder.java b/src/main/java/org/redkale/convert/json/JsonElementDecoder.java index 3e46a47ce..6cc93dcb3 100644 --- a/src/main/java/org/redkale/convert/json/JsonElementDecoder.java +++ b/src/main/java/org/redkale/convert/json/JsonElementDecoder.java @@ -1,40 +1,40 @@ -/* - * - */ -package org.redkale.convert.json; - -import java.lang.reflect.Type; -import java.util.*; -import org.redkale.convert.AnyDecoder; -import org.redkale.convert.ext.StringSimpledCoder; -import org.redkale.util.*; - -/** - * 常规json - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -class JsonElementDecoder extends AnyDecoder { - - private static final Type arrayType = new TypeToken>() {}.getType(); - - private static final Type objectType = new TypeToken>() {}.getType(); - - private static final Creator arrayCreator = t -> new JsonArray(); - - private static final Creator objectCreator = t -> new JsonObject(); - - public static final JsonElementDecoder instance = new JsonElementDecoder(); - - public JsonElementDecoder() { - super(objectCreator, objectType, arrayCreator, arrayType, StringSimpledCoder.instance); - } - - @Override - public Type getType() { - return JsonElement.class; - } -} +/* + * + */ +package org.redkale.convert.json; + +import java.lang.reflect.Type; +import java.util.*; +import org.redkale.convert.AnyDecoder; +import org.redkale.convert.ext.StringSimpledCoder; +import org.redkale.util.*; + +/** + * 常规json + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +class JsonElementDecoder extends AnyDecoder { + + private static final Type arrayType = new TypeToken>() {}.getType(); + + private static final Type objectType = new TypeToken>() {}.getType(); + + private static final Creator arrayCreator = t -> new JsonArray(); + + private static final Creator objectCreator = t -> new JsonObject(); + + public static final JsonElementDecoder instance = new JsonElementDecoder(); + + public JsonElementDecoder() { + super(objectCreator, objectType, arrayCreator, arrayType, StringSimpledCoder.instance); + } + + @Override + public Type getType() { + return JsonElement.class; + } +} diff --git a/src/main/java/org/redkale/convert/json/JsonObject.java b/src/main/java/org/redkale/convert/json/JsonObject.java index 5dac36f1d..5eae27aa5 100644 --- a/src/main/java/org/redkale/convert/json/JsonObject.java +++ b/src/main/java/org/redkale/convert/json/JsonObject.java @@ -1,471 +1,471 @@ -/* - * - */ -package org.redkale.convert.json; - -import java.lang.reflect.Type; -import java.math.*; -import java.util.*; -import org.redkale.annotation.Nullable; -import org.redkale.convert.ConvertDisabled; -import org.redkale.util.*; - -/** - * 常规json对象 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public class JsonObject extends LinkedHashMap implements JsonElement { - - public JsonObject() {} - - public JsonObject(Map map) { - super(map); - } - - public static JsonObject convertFrom(String text) { - return convertFrom(Utility.charArray(text)); - } - - public static JsonObject convertFrom(char[] text) { - return convertFrom(text, 0, text.length); - } - - public static JsonObject convertFrom(char[] text, int offset, int length) { - return JsonConvert.root().convertFrom(JsonObject.class, text, offset, length); - } - - public static JsonObject create() { - return new JsonObject(); - } - - public static JsonObject of(Object bean) { - if (bean instanceof CharSequence) { - return convertFrom(bean.toString()); - } - if (bean instanceof JsonObject) { - return (JsonObject) bean; - } - if (bean instanceof Map) { - return new JsonObject((Map) bean); - } - return convertFrom(JsonConvert.root().convertTo(bean)); - } - - public T toObject(Type type) { - return (T) JsonConvert.root().convertFrom(type, JsonConvert.root().convertTo(this)); - } - - public JsonObject append(String key, Object value) { - super.put(key, value); - return this; - } - - public JsonObject append(String key, Collection value) { - super.put(key, value == null || value instanceof JsonArray ? value : new JsonArray(value)); - return this; - } - - public JsonObject putObject(String key) { - JsonObject val = new JsonObject(); - super.put(key, val); - return val; - } - - public JsonArray putArray(String key) { - JsonArray val = new JsonArray(); - super.put(key, val); - return val; - } - - public boolean has(String key) { - return containsKey(key); - } - - public boolean isNull(String key) { - return get(key) == null; - } - - public boolean isJsonObject(String key) { - return get(key) instanceof JsonObject; - } - - public boolean isJsonArray(String key) { - return get(key) instanceof JsonArray; - } - - public JsonObject getJsonObject(String key) { - Object val = get(key); - if (val instanceof JsonObject) { - return (JsonObject) val; - } - if (val instanceof Map) { - return new JsonObject((Map) val); - } - throw new RedkaleException("val [" + val + "] is not a valid JsonObject."); - } - - public JsonArray getJsonArray(String key) { - Object val = get(key); - if (val instanceof JsonArray) { - return (JsonArray) val; - } - if (val instanceof Collection) { - return new JsonArray((Collection) val); - } - throw new RedkaleException("val [" + val + "] is not a valid JsonArray."); - } - - public String getString(String key) { - final Object val = get(key); - if (val == null) { - return null; - } - return val.toString(); - } - - public String getString(String key, String defValue) { - final Object val = get(key); - if (val == null) { - return defValue; - } - return val.toString(); - } - - public BigDecimal getBigDecimal(String key) { - final Object val = get(key); - if (val == null) { - return null; - } - if (val instanceof BigDecimal) { - return (BigDecimal) val; - } - return new BigDecimal(val.toString()); - } - - public BigDecimal getBigDecimal(String key, BigDecimal defValue) { - final Object val = get(key); - if (val == null) { - return defValue; - } - if (val instanceof BigDecimal) { - return (BigDecimal) val; - } - try { - return new BigDecimal(val.toString()); - } catch (Exception e) { - return defValue; - } - } - - public BigInteger getBigInteger(String key) { - final Object val = get(key); - if (val == null) { - return null; - } - if (val instanceof BigInteger) { - return (BigInteger) val; - } - return new BigInteger(val.toString()); - } - - public BigInteger getBigInteger(String key, BigInteger defValue) { - final Object val = get(key); - if (val == null) { - return defValue; - } - if (val instanceof BigInteger) { - return (BigInteger) val; - } - try { - return new BigInteger(val.toString()); - } catch (Exception e) { - return defValue; - } - } - - public Number getNumber(String key) { - Object val = get(key); - if (val == null) { - return null; - } - if (val instanceof Number) { - return (Number) val; - } - return stringToNumber(val.toString()); - } - - public Number getNumber(String key, Number defValue) { - Object val = get(key); - if (val == null) { - return defValue; - } - if (val instanceof Number) { - return (Number) val; - } - try { - return stringToNumber(val.toString()); - } catch (Exception e) { - return defValue; - } - } - - public Double getDouble(String key) { - final Object val = get(key); - if (val == null) { - return null; - } - if (val instanceof Number) { - return ((Number) val).doubleValue(); - } - return Double.parseDouble(val.toString()); - } - - public double getDouble(String key, double defValue) { - final Object val = get(key); - if (val == null) { - return defValue; - } - if (val instanceof Number) { - return ((Number) val).doubleValue(); - } - try { - return Double.parseDouble(val.toString()); - } catch (Exception e) { - return defValue; - } - } - - public Long getLong(String key) { - final Object val = get(key); - if (val == null) { - return null; - } - if (val instanceof Number) { - return ((Number) val).longValue(); - } - return Long.parseLong(val.toString()); - } - - public long getLong(String key, long defValue) { - final Object val = get(key); - if (val == null) { - return defValue; - } - if (val instanceof Number) { - return ((Number) val).longValue(); - } - try { - return Long.parseLong(val.toString()); - } catch (Exception e) { - return defValue; - } - } - - public Float getFloat(String key) { - final Object val = get(key); - if (val == null) { - return null; - } - if (val instanceof Number) { - return ((Number) val).floatValue(); - } - return Float.parseFloat(val.toString()); - } - - public float getFloat(String key, float defValue) { - final Object val = get(key); - if (val == null) { - return defValue; - } - if (val instanceof Number) { - return ((Number) val).floatValue(); - } - try { - return Float.parseFloat(val.toString()); - } catch (Exception e) { - return defValue; - } - } - - public Integer getInt(String key) { - final Object val = get(key); - if (val == null) { - return null; - } - if (val instanceof Number) { - return ((Number) val).intValue(); - } - return Integer.parseInt(val.toString()); - } - - public int getInt(String key, int defValue) { - final Object val = get(key); - if (val == null) { - return defValue; - } - if (val instanceof Number) { - return ((Number) val).intValue(); - } - try { - return Integer.parseInt(val.toString()); - } catch (Exception e) { - return defValue; - } - } - - public Short getShort(String key) { - final Object val = get(key); - if (val == null) { - return null; - } - if (val instanceof Number) { - return ((Number) val).shortValue(); - } - return Short.parseShort(val.toString()); - } - - public short getShort(String key, short defValue) { - final Object val = get(key); - if (val == null) { - return defValue; - } - if (val instanceof Number) { - return ((Number) val).shortValue(); - } - try { - return Short.parseShort(val.toString()); - } catch (Exception e) { - return defValue; - } - } - - public Byte getByte(String key) { - final Object val = get(key); - if (val == null) { - return null; - } - if (val instanceof Number) { - return ((Number) val).byteValue(); - } - return Byte.parseByte(val.toString()); - } - - public byte getByte(String key, byte defValue) { - final Object val = get(key); - if (val == null) { - return defValue; - } - if (val instanceof Number) { - return ((Number) val).byteValue(); - } - try { - return Byte.parseByte(val.toString()); - } catch (Exception e) { - return defValue; - } - } - - @Nullable - public Boolean getBoolean(String key) { - final Object val = get(key); - if (val == null) { - return null; - } - return "true".equalsIgnoreCase(val.toString()); - } - - public boolean getBoolean(String key, boolean defValue) { - final Object val = get(key); - if (val == null) { - return defValue; - } - return "true".equalsIgnoreCase(val.toString()); - } - - protected static Number stringToNumber(String val) { - char initial = val.charAt(0); - if ((initial >= '0' && initial <= '9') || initial == '-') { - // decimal representation - if (val.indexOf('.') > -1 || val.indexOf('e') > -1 || val.indexOf('E') > -1 || "-0".equals(val)) { - // Use a BigDecimal all the time so we keep the original - // representation. BigDecimal doesn't support -0.0, ensure we - // keep that by forcing a decimal. - try { - BigDecimal bd = new BigDecimal(val); - if (initial == '-' && BigDecimal.ZERO.compareTo(bd) == 0) { - return -0.0; - } - return bd; - } catch (NumberFormatException retryAsDouble) { - // this is to support "Hex Floats" like this: 0x1.0P-1074 - try { - Double d = Double.valueOf(val); - if (d.isNaN() || d.isInfinite()) { - throw new NumberFormatException("val [" + val + "] is not a valid number."); - } - return d; - } catch (NumberFormatException ignore) { - throw new NumberFormatException("val [" + val + "] is not a valid number."); - } - } - } - // block items like 00 01 etc. Java number parsers treat these as Octal. - if (initial == '0' && val.length() > 1) { - char at1 = val.charAt(1); - if (at1 >= '0' && at1 <= '9') { - throw new NumberFormatException("val [" + val + "] is not a valid number."); - } - } else if (initial == '-' && val.length() > 2) { - char at1 = val.charAt(1); - char at2 = val.charAt(2); - if (at1 == '0' && at2 >= '0' && at2 <= '9') { - throw new NumberFormatException("val [" + val + "] is not a valid number."); - } - } - // integer representation. - // This will narrow any values to the smallest reasonable Object representation - // (Integer, Long, or BigInteger) - - // BigInteger down conversion: We use a similar bitLength compare as - // BigInteger#intValueExact uses. Increases GC, but objects hold - // only what they need. i.e. Less runtime overhead if the value is - // long lived. - BigInteger bi = new BigInteger(val); - if (bi.bitLength() <= 31) { - return bi.intValue(); - } - if (bi.bitLength() <= 63) { - return bi.longValue(); - } - return bi; - } - return null; - } - - @Override - @ConvertDisabled - public final boolean isObject() { - return true; - } - - @Override - @ConvertDisabled - public final boolean isArray() { - return false; - } - - @Override - @ConvertDisabled - public final boolean isString() { - return false; - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } -} +/* + * + */ +package org.redkale.convert.json; + +import java.lang.reflect.Type; +import java.math.*; +import java.util.*; +import org.redkale.annotation.Nullable; +import org.redkale.convert.ConvertDisabled; +import org.redkale.util.*; + +/** + * 常规json对象 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public class JsonObject extends LinkedHashMap implements JsonElement { + + public JsonObject() {} + + public JsonObject(Map map) { + super(map); + } + + public static JsonObject convertFrom(String text) { + return convertFrom(Utility.charArray(text)); + } + + public static JsonObject convertFrom(char[] text) { + return convertFrom(text, 0, text.length); + } + + public static JsonObject convertFrom(char[] text, int offset, int length) { + return JsonConvert.root().convertFrom(JsonObject.class, text, offset, length); + } + + public static JsonObject create() { + return new JsonObject(); + } + + public static JsonObject of(Object bean) { + if (bean instanceof CharSequence) { + return convertFrom(bean.toString()); + } + if (bean instanceof JsonObject) { + return (JsonObject) bean; + } + if (bean instanceof Map) { + return new JsonObject((Map) bean); + } + return convertFrom(JsonConvert.root().convertTo(bean)); + } + + public T toObject(Type type) { + return (T) JsonConvert.root().convertFrom(type, JsonConvert.root().convertTo(this)); + } + + public JsonObject append(String key, Object value) { + super.put(key, value); + return this; + } + + public JsonObject append(String key, Collection value) { + super.put(key, value == null || value instanceof JsonArray ? value : new JsonArray(value)); + return this; + } + + public JsonObject putObject(String key) { + JsonObject val = new JsonObject(); + super.put(key, val); + return val; + } + + public JsonArray putArray(String key) { + JsonArray val = new JsonArray(); + super.put(key, val); + return val; + } + + public boolean has(String key) { + return containsKey(key); + } + + public boolean isNull(String key) { + return get(key) == null; + } + + public boolean isJsonObject(String key) { + return get(key) instanceof JsonObject; + } + + public boolean isJsonArray(String key) { + return get(key) instanceof JsonArray; + } + + public JsonObject getJsonObject(String key) { + Object val = get(key); + if (val instanceof JsonObject) { + return (JsonObject) val; + } + if (val instanceof Map) { + return new JsonObject((Map) val); + } + throw new RedkaleException("val [" + val + "] is not a valid JsonObject."); + } + + public JsonArray getJsonArray(String key) { + Object val = get(key); + if (val instanceof JsonArray) { + return (JsonArray) val; + } + if (val instanceof Collection) { + return new JsonArray((Collection) val); + } + throw new RedkaleException("val [" + val + "] is not a valid JsonArray."); + } + + public String getString(String key) { + final Object val = get(key); + if (val == null) { + return null; + } + return val.toString(); + } + + public String getString(String key, String defValue) { + final Object val = get(key); + if (val == null) { + return defValue; + } + return val.toString(); + } + + public BigDecimal getBigDecimal(String key) { + final Object val = get(key); + if (val == null) { + return null; + } + if (val instanceof BigDecimal) { + return (BigDecimal) val; + } + return new BigDecimal(val.toString()); + } + + public BigDecimal getBigDecimal(String key, BigDecimal defValue) { + final Object val = get(key); + if (val == null) { + return defValue; + } + if (val instanceof BigDecimal) { + return (BigDecimal) val; + } + try { + return new BigDecimal(val.toString()); + } catch (Exception e) { + return defValue; + } + } + + public BigInteger getBigInteger(String key) { + final Object val = get(key); + if (val == null) { + return null; + } + if (val instanceof BigInteger) { + return (BigInteger) val; + } + return new BigInteger(val.toString()); + } + + public BigInteger getBigInteger(String key, BigInteger defValue) { + final Object val = get(key); + if (val == null) { + return defValue; + } + if (val instanceof BigInteger) { + return (BigInteger) val; + } + try { + return new BigInteger(val.toString()); + } catch (Exception e) { + return defValue; + } + } + + public Number getNumber(String key) { + Object val = get(key); + if (val == null) { + return null; + } + if (val instanceof Number) { + return (Number) val; + } + return stringToNumber(val.toString()); + } + + public Number getNumber(String key, Number defValue) { + Object val = get(key); + if (val == null) { + return defValue; + } + if (val instanceof Number) { + return (Number) val; + } + try { + return stringToNumber(val.toString()); + } catch (Exception e) { + return defValue; + } + } + + public Double getDouble(String key) { + final Object val = get(key); + if (val == null) { + return null; + } + if (val instanceof Number) { + return ((Number) val).doubleValue(); + } + return Double.parseDouble(val.toString()); + } + + public double getDouble(String key, double defValue) { + final Object val = get(key); + if (val == null) { + return defValue; + } + if (val instanceof Number) { + return ((Number) val).doubleValue(); + } + try { + return Double.parseDouble(val.toString()); + } catch (Exception e) { + return defValue; + } + } + + public Long getLong(String key) { + final Object val = get(key); + if (val == null) { + return null; + } + if (val instanceof Number) { + return ((Number) val).longValue(); + } + return Long.parseLong(val.toString()); + } + + public long getLong(String key, long defValue) { + final Object val = get(key); + if (val == null) { + return defValue; + } + if (val instanceof Number) { + return ((Number) val).longValue(); + } + try { + return Long.parseLong(val.toString()); + } catch (Exception e) { + return defValue; + } + } + + public Float getFloat(String key) { + final Object val = get(key); + if (val == null) { + return null; + } + if (val instanceof Number) { + return ((Number) val).floatValue(); + } + return Float.parseFloat(val.toString()); + } + + public float getFloat(String key, float defValue) { + final Object val = get(key); + if (val == null) { + return defValue; + } + if (val instanceof Number) { + return ((Number) val).floatValue(); + } + try { + return Float.parseFloat(val.toString()); + } catch (Exception e) { + return defValue; + } + } + + public Integer getInt(String key) { + final Object val = get(key); + if (val == null) { + return null; + } + if (val instanceof Number) { + return ((Number) val).intValue(); + } + return Integer.parseInt(val.toString()); + } + + public int getInt(String key, int defValue) { + final Object val = get(key); + if (val == null) { + return defValue; + } + if (val instanceof Number) { + return ((Number) val).intValue(); + } + try { + return Integer.parseInt(val.toString()); + } catch (Exception e) { + return defValue; + } + } + + public Short getShort(String key) { + final Object val = get(key); + if (val == null) { + return null; + } + if (val instanceof Number) { + return ((Number) val).shortValue(); + } + return Short.parseShort(val.toString()); + } + + public short getShort(String key, short defValue) { + final Object val = get(key); + if (val == null) { + return defValue; + } + if (val instanceof Number) { + return ((Number) val).shortValue(); + } + try { + return Short.parseShort(val.toString()); + } catch (Exception e) { + return defValue; + } + } + + public Byte getByte(String key) { + final Object val = get(key); + if (val == null) { + return null; + } + if (val instanceof Number) { + return ((Number) val).byteValue(); + } + return Byte.parseByte(val.toString()); + } + + public byte getByte(String key, byte defValue) { + final Object val = get(key); + if (val == null) { + return defValue; + } + if (val instanceof Number) { + return ((Number) val).byteValue(); + } + try { + return Byte.parseByte(val.toString()); + } catch (Exception e) { + return defValue; + } + } + + @Nullable + public Boolean getBoolean(String key) { + final Object val = get(key); + if (val == null) { + return null; + } + return "true".equalsIgnoreCase(val.toString()); + } + + public boolean getBoolean(String key, boolean defValue) { + final Object val = get(key); + if (val == null) { + return defValue; + } + return "true".equalsIgnoreCase(val.toString()); + } + + protected static Number stringToNumber(String val) { + char initial = val.charAt(0); + if ((initial >= '0' && initial <= '9') || initial == '-') { + // decimal representation + if (val.indexOf('.') > -1 || val.indexOf('e') > -1 || val.indexOf('E') > -1 || "-0".equals(val)) { + // Use a BigDecimal all the time so we keep the original + // representation. BigDecimal doesn't support -0.0, ensure we + // keep that by forcing a decimal. + try { + BigDecimal bd = new BigDecimal(val); + if (initial == '-' && BigDecimal.ZERO.compareTo(bd) == 0) { + return -0.0; + } + return bd; + } catch (NumberFormatException retryAsDouble) { + // this is to support "Hex Floats" like this: 0x1.0P-1074 + try { + Double d = Double.valueOf(val); + if (d.isNaN() || d.isInfinite()) { + throw new NumberFormatException("val [" + val + "] is not a valid number."); + } + return d; + } catch (NumberFormatException ignore) { + throw new NumberFormatException("val [" + val + "] is not a valid number."); + } + } + } + // block items like 00 01 etc. Java number parsers treat these as Octal. + if (initial == '0' && val.length() > 1) { + char at1 = val.charAt(1); + if (at1 >= '0' && at1 <= '9') { + throw new NumberFormatException("val [" + val + "] is not a valid number."); + } + } else if (initial == '-' && val.length() > 2) { + char at1 = val.charAt(1); + char at2 = val.charAt(2); + if (at1 == '0' && at2 >= '0' && at2 <= '9') { + throw new NumberFormatException("val [" + val + "] is not a valid number."); + } + } + // integer representation. + // This will narrow any values to the smallest reasonable Object representation + // (Integer, Long, or BigInteger) + + // BigInteger down conversion: We use a similar bitLength compare as + // BigInteger#intValueExact uses. Increases GC, but objects hold + // only what they need. i.e. Less runtime overhead if the value is + // long lived. + BigInteger bi = new BigInteger(val); + if (bi.bitLength() <= 31) { + return bi.intValue(); + } + if (bi.bitLength() <= 63) { + return bi.longValue(); + } + return bi; + } + return null; + } + + @Override + @ConvertDisabled + public final boolean isObject() { + return true; + } + + @Override + @ConvertDisabled + public final boolean isArray() { + return false; + } + + @Override + @ConvertDisabled + public final boolean isString() { + return false; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } +} diff --git a/src/main/java/org/redkale/convert/json/JsonString.java b/src/main/java/org/redkale/convert/json/JsonString.java index cda2df9d3..67a6e1a1a 100644 --- a/src/main/java/org/redkale/convert/json/JsonString.java +++ b/src/main/java/org/redkale/convert/json/JsonString.java @@ -1,83 +1,83 @@ -/* - * - */ -package org.redkale.convert.json; - -import org.redkale.convert.ConvertDisabled; - -/** - * 常规json字符串 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public class JsonString implements CharSequence, JsonElement, Comparable { - - private String value; - - public JsonString() {} - - public JsonString(String value) { - this.value = value; - } - - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } - - @ConvertDisabled - public boolean isNull() { - return value == null; - } - - @Override - public int length() { - return value.length(); - } - - @Override - public char charAt(int index) { - return value.charAt(index); - } - - @Override - public CharSequence subSequence(int start, int end) { - return value.substring(end, end); - } - - @Override - public int compareTo(JsonString o) { - return o == null || o.value == null - ? (value == null ? 0 : 1) - : (this.value == null ? -1 : this.value.compareTo(o.value)); - } - - @Override - @ConvertDisabled - public final boolean isObject() { - return false; - } - - @Override - @ConvertDisabled - public final boolean isArray() { - return false; - } - - @Override - @ConvertDisabled - public final boolean isString() { - return true; - } - - @Override - public String toString() { - return value; - } -} +/* + * + */ +package org.redkale.convert.json; + +import org.redkale.convert.ConvertDisabled; + +/** + * 常规json字符串 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public class JsonString implements CharSequence, JsonElement, Comparable { + + private String value; + + public JsonString() {} + + public JsonString(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + @ConvertDisabled + public boolean isNull() { + return value == null; + } + + @Override + public int length() { + return value.length(); + } + + @Override + public char charAt(int index) { + return value.charAt(index); + } + + @Override + public CharSequence subSequence(int start, int end) { + return value.substring(end, end); + } + + @Override + public int compareTo(JsonString o) { + return o == null || o.value == null + ? (value == null ? 0 : 1) + : (this.value == null ? -1 : this.value.compareTo(o.value)); + } + + @Override + @ConvertDisabled + public final boolean isObject() { + return false; + } + + @Override + @ConvertDisabled + public final boolean isArray() { + return false; + } + + @Override + @ConvertDisabled + public final boolean isString() { + return true; + } + + @Override + public String toString() { + return value; + } +} diff --git a/src/main/java/org/redkale/convert/proto/ProtobufArrayDecoder.java b/src/main/java/org/redkale/convert/proto/ProtobufArrayDecoder.java index d989c7764..bfb892b59 100644 --- a/src/main/java/org/redkale/convert/proto/ProtobufArrayDecoder.java +++ b/src/main/java/org/redkale/convert/proto/ProtobufArrayDecoder.java @@ -1,45 +1,45 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package org.redkale.convert.proto; - -import java.lang.reflect.Type; -import java.util.concurrent.atomic.*; -import org.redkale.convert.*; - -/** - * @author zhangjx - * @param T - */ -public class ProtobufArrayDecoder extends ArrayDecoder { - - protected final boolean simple; - - private final boolean string; - - private final boolean enumtostring; - - public ProtobufArrayDecoder(ConvertFactory factory, Type type) { - super(factory, type); - this.enumtostring = ((ProtobufFactory) factory).enumtostring; - Type comtype = this.getComponentType(); - this.string = String.class == comtype; - this.simple = Boolean.class == comtype - || Short.class == comtype - || Character.class == comtype - || Integer.class == comtype - || Float.class == comtype - || Long.class == comtype - || Double.class == comtype - || AtomicInteger.class == comtype - || AtomicLong.class == comtype; - } - - @Override - protected Reader getItemReader(Reader in, DeMember member, boolean first) { - if (simple) return in; - return ProtobufFactory.getItemReader(string, simple, in, member, enumtostring, first); - } -} +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.proto; + +import java.lang.reflect.Type; +import java.util.concurrent.atomic.*; +import org.redkale.convert.*; + +/** + * @author zhangjx + * @param T + */ +public class ProtobufArrayDecoder extends ArrayDecoder { + + protected final boolean simple; + + private final boolean string; + + private final boolean enumtostring; + + public ProtobufArrayDecoder(ConvertFactory factory, Type type) { + super(factory, type); + this.enumtostring = ((ProtobufFactory) factory).enumtostring; + Type comtype = this.getComponentType(); + this.string = String.class == comtype; + this.simple = Boolean.class == comtype + || Short.class == comtype + || Character.class == comtype + || Integer.class == comtype + || Float.class == comtype + || Long.class == comtype + || Double.class == comtype + || AtomicInteger.class == comtype + || AtomicLong.class == comtype; + } + + @Override + protected Reader getItemReader(Reader in, DeMember member, boolean first) { + if (simple) return in; + return ProtobufFactory.getItemReader(string, simple, in, member, enumtostring, first); + } +} diff --git a/src/main/java/org/redkale/convert/proto/ProtobufArrayEncoder.java b/src/main/java/org/redkale/convert/proto/ProtobufArrayEncoder.java index eb10853db..ffff24790 100644 --- a/src/main/java/org/redkale/convert/proto/ProtobufArrayEncoder.java +++ b/src/main/java/org/redkale/convert/proto/ProtobufArrayEncoder.java @@ -1,58 +1,58 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package org.redkale.convert.proto; - -import java.lang.reflect.Type; -import java.util.concurrent.atomic.*; -import org.redkale.convert.*; - -/** - * @author zhangjx - * @param T - */ -public class ProtobufArrayEncoder extends ArrayEncoder { - - protected final boolean simple; - - public ProtobufArrayEncoder(ConvertFactory factory, Type type) { - super(factory, type); - Type comtype = this.getComponentType(); - this.simple = Boolean.class == comtype - || Short.class == comtype - || Character.class == comtype - || Integer.class == comtype - || Float.class == comtype - || Long.class == comtype - || Double.class == comtype - || AtomicInteger.class == comtype - || AtomicLong.class == comtype; - } - - @Override - protected void writeMemberValue( - Writer out, EnMember member, Encodeable encoder, Object item, int index) { - if (simple) { - if (item == null) { - ((ProtobufWriter) out).writeUInt32(0); - } else { - componentEncoder.convertTo(out, item); - } - return; - } - if (member != null) out.writeFieldName(member); - if (item == null) { - ((ProtobufWriter) out).writeUInt32(0); - } else if (item instanceof CharSequence) { - encoder.convertTo(out, item); - } else { - ProtobufWriter tmp = new ProtobufWriter().configFieldFunc(out); - encoder.convertTo(tmp, item); - int length = tmp.count(); - ((ProtobufWriter) out).writeUInt32(length); - ((ProtobufWriter) out).writeTo(tmp.toArray()); - } - } -} +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.proto; + +import java.lang.reflect.Type; +import java.util.concurrent.atomic.*; +import org.redkale.convert.*; + +/** + * @author zhangjx + * @param T + */ +public class ProtobufArrayEncoder extends ArrayEncoder { + + protected final boolean simple; + + public ProtobufArrayEncoder(ConvertFactory factory, Type type) { + super(factory, type); + Type comtype = this.getComponentType(); + this.simple = Boolean.class == comtype + || Short.class == comtype + || Character.class == comtype + || Integer.class == comtype + || Float.class == comtype + || Long.class == comtype + || Double.class == comtype + || AtomicInteger.class == comtype + || AtomicLong.class == comtype; + } + + @Override + protected void writeMemberValue( + Writer out, EnMember member, Encodeable encoder, Object item, int index) { + if (simple) { + if (item == null) { + ((ProtobufWriter) out).writeUInt32(0); + } else { + componentEncoder.convertTo(out, item); + } + return; + } + if (member != null) out.writeFieldName(member); + if (item == null) { + ((ProtobufWriter) out).writeUInt32(0); + } else if (item instanceof CharSequence) { + encoder.convertTo(out, item); + } else { + ProtobufWriter tmp = new ProtobufWriter().configFieldFunc(out); + encoder.convertTo(tmp, item); + int length = tmp.count(); + ((ProtobufWriter) out).writeUInt32(length); + ((ProtobufWriter) out).writeTo(tmp.toArray()); + } + } +} diff --git a/src/main/java/org/redkale/convert/proto/ProtobufByteBufferReader.java b/src/main/java/org/redkale/convert/proto/ProtobufByteBufferReader.java index 743b2ed53..c6eb3a924 100644 --- a/src/main/java/org/redkale/convert/proto/ProtobufByteBufferReader.java +++ b/src/main/java/org/redkale/convert/proto/ProtobufByteBufferReader.java @@ -1,198 +1,198 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package org.redkale.convert.proto; - -import java.nio.ByteBuffer; - -/** @author zhangjx */ -public class ProtobufByteBufferReader extends ProtobufReader { - - private ByteBuffer[] buffers; - - private int currentIndex = 0; - - private ByteBuffer currentBuffer; - - protected ProtobufByteBufferReader(ByteBuffer... buffers) { - this.buffers = buffers; - if (buffers != null && buffers.length > 0) this.currentBuffer = buffers[currentIndex]; - } - - @Override - protected boolean recycle() { - super.recycle(); // this.position 初始化值为-1 - this.currentIndex = 0; - this.currentBuffer = null; - this.buffers = null; - return false; - } - - @Override - protected byte currentByte() { - return currentBuffer.get(currentBuffer.position()); - } - - protected byte nextByte() { - if (this.currentBuffer.hasRemaining()) { - this.position++; - return this.currentBuffer.get(); - } - for (; ; ) { - this.currentBuffer = this.buffers[++this.currentIndex]; - if (this.currentBuffer.hasRemaining()) { - this.position++; - return this.currentBuffer.get(); - } - } - } - // - // //------------------------------------------------------------ - // /** - // * 判断对象是否存在下一个属性或者数组是否存在下一个元素 - // * - // * @param startPosition 起始位置 - // * @param contentLength 内容大小, 不确定的传-1 - // * - // * @return 是否存在 - // */ - // @Override - // public boolean hasNext(int startPosition, int contentLength) { - // //("-------------: " + startPosition + ", " + contentLength + ", " + this.position); - // if (startPosition >= 0 && contentLength >= 0) { - // return (this.position) < (startPosition + contentLength); - // } - // return (this.position + 1) < this.content.length; - // } - // - // @Override - // public byte[] readByteArray() { - // final int size = readRawVarint32(); - // byte[] bs = new byte[size]; - // System.arraycopy(content, position + 1, bs, 0, size); - // position += size; - // return bs; - // } - // - // protected int readRawVarint32() { //readUInt32 - // fastpath: - // { - // int tempPos = this.position; - // if ((tempPos + 1) == content.length) break fastpath; - // - // int x; - // if ((x = content[++tempPos]) >= 0) { - // this.position = tempPos; - // return x; - // } else if (content.length - (tempPos + 1) < 9) { - // break fastpath; - // } else if ((x ^= (content[++tempPos] << 7)) < 0) { - // x ^= (~0 << 7); - // } else if ((x ^= (content[++tempPos] << 14)) >= 0) { - // x ^= (~0 << 7) ^ (~0 << 14); - // } else if ((x ^= (content[++tempPos] << 21)) < 0) { - // x ^= (~0 << 7) ^ (~0 << 14) ^ (~0 << 21); - // } else { - // int y = content[++tempPos]; - // x ^= y << 28; - // x ^= (~0 << 7) ^ (~0 << 14) ^ (~0 << 21) ^ (~0 << 28); - // if (y < 0 - // && content[++tempPos] < 0 - // && content[++tempPos] < 0 - // && content[++tempPos] < 0 - // && content[++tempPos] < 0 - // && content[++tempPos] < 0) { - // break fastpath; // Will throw malformedVarint() - // } - // } - // this.position = tempPos; - // return x; - // } - // return (int) readRawVarint64SlowPath(); - // } - // - // protected long readRawVarint64() { - // fastpath: - // { - // int tempPos = this.position; - // if ((tempPos + 1) == content.length) break fastpath; - // - // long x; - // int y; - // if ((y = content[++tempPos]) >= 0) { - // this.position = tempPos; - // return y; - // } else if (content.length - (tempPos + 1) < 9) { - // break fastpath; - // } else if ((y ^= (content[++tempPos] << 7)) < 0) { - // x = y ^ (~0 << 7); - // } else if ((y ^= (content[++tempPos] << 14)) >= 0) { - // x = y ^ ((~0 << 7) ^ (~0 << 14)); - // } else if ((y ^= (content[++tempPos] << 21)) < 0) { - // x = y ^ ((~0 << 7) ^ (~0 << 14) ^ (~0 << 21)); - // } else if ((x = y ^ ((long) content[++tempPos] << 28)) >= 0L) { - // x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28); - // } else if ((x ^= ((long) content[++tempPos] << 35)) < 0L) { - // x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35); - // } else if ((x ^= ((long) content[++tempPos] << 42)) >= 0L) { - // x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35) ^ (~0L << 42); - // } else if ((x ^= ((long) content[++tempPos] << 49)) < 0L) { - // x ^= (~0L << 7) - // ^ (~0L << 14) - // ^ (~0L << 21) - // ^ (~0L << 28) - // ^ (~0L << 35) - // ^ (~0L << 42) - // ^ (~0L << 49); - // } else { - // x ^= ((long) content[++tempPos] << 56); - // x ^= (~0L << 7) - // ^ (~0L << 14) - // ^ (~0L << 21) - // ^ (~0L << 28) - // ^ (~0L << 35) - // ^ (~0L << 42) - // ^ (~0L << 49) - // ^ (~0L << 56); - // if (x < 0L) { - // if (content[++tempPos] < 0L) { - // break fastpath; // Will throw malformedVarint() - // } - // } - // } - // this.position = tempPos; - // return x; - // } - // return readRawVarint64SlowPath(); - // } - // - // protected long readRawVarint64SlowPath() { - // long result = 0; - // for (int shift = 0; shift < 64; shift += 7) { - // final byte b = content[++this.position]; - // result |= (long) (b & 0x7F) << shift; - // if ((b & 0x80) == 0) return result; - // } - // throw new ConvertException("readRawVarint64SlowPath error"); - // } - // - // protected int readRawLittleEndian32() { - // return ((content[++this.position] & 0xff) - // | ((content[++this.position] & 0xff) << 8) - // | ((content[++this.position] & 0xff) << 16) - // | ((content[++this.position] & 0xff) << 24)); - // } - // - // protected long readRawLittleEndian64() { - // return ((content[++this.position] & 0xffL) - // | ((content[++this.position] & 0xffL) << 8) - // | ((content[++this.position] & 0xffL) << 16) - // | ((content[++this.position] & 0xffL) << 24) - // | ((content[++this.position] & 0xffL) << 32) - // | ((content[++this.position] & 0xffL) << 40) - // | ((content[++this.position] & 0xffL) << 48) - // | ((content[++this.position] & 0xffL) << 56)); - // } -} +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.proto; + +import java.nio.ByteBuffer; + +/** @author zhangjx */ +public class ProtobufByteBufferReader extends ProtobufReader { + + private ByteBuffer[] buffers; + + private int currentIndex = 0; + + private ByteBuffer currentBuffer; + + protected ProtobufByteBufferReader(ByteBuffer... buffers) { + this.buffers = buffers; + if (buffers != null && buffers.length > 0) this.currentBuffer = buffers[currentIndex]; + } + + @Override + protected boolean recycle() { + super.recycle(); // this.position 初始化值为-1 + this.currentIndex = 0; + this.currentBuffer = null; + this.buffers = null; + return false; + } + + @Override + protected byte currentByte() { + return currentBuffer.get(currentBuffer.position()); + } + + protected byte nextByte() { + if (this.currentBuffer.hasRemaining()) { + this.position++; + return this.currentBuffer.get(); + } + for (; ; ) { + this.currentBuffer = this.buffers[++this.currentIndex]; + if (this.currentBuffer.hasRemaining()) { + this.position++; + return this.currentBuffer.get(); + } + } + } + // + // //------------------------------------------------------------ + // /** + // * 判断对象是否存在下一个属性或者数组是否存在下一个元素 + // * + // * @param startPosition 起始位置 + // * @param contentLength 内容大小, 不确定的传-1 + // * + // * @return 是否存在 + // */ + // @Override + // public boolean hasNext(int startPosition, int contentLength) { + // //("-------------: " + startPosition + ", " + contentLength + ", " + this.position); + // if (startPosition >= 0 && contentLength >= 0) { + // return (this.position) < (startPosition + contentLength); + // } + // return (this.position + 1) < this.content.length; + // } + // + // @Override + // public byte[] readByteArray() { + // final int size = readRawVarint32(); + // byte[] bs = new byte[size]; + // System.arraycopy(content, position + 1, bs, 0, size); + // position += size; + // return bs; + // } + // + // protected int readRawVarint32() { //readUInt32 + // fastpath: + // { + // int tempPos = this.position; + // if ((tempPos + 1) == content.length) break fastpath; + // + // int x; + // if ((x = content[++tempPos]) >= 0) { + // this.position = tempPos; + // return x; + // } else if (content.length - (tempPos + 1) < 9) { + // break fastpath; + // } else if ((x ^= (content[++tempPos] << 7)) < 0) { + // x ^= (~0 << 7); + // } else if ((x ^= (content[++tempPos] << 14)) >= 0) { + // x ^= (~0 << 7) ^ (~0 << 14); + // } else if ((x ^= (content[++tempPos] << 21)) < 0) { + // x ^= (~0 << 7) ^ (~0 << 14) ^ (~0 << 21); + // } else { + // int y = content[++tempPos]; + // x ^= y << 28; + // x ^= (~0 << 7) ^ (~0 << 14) ^ (~0 << 21) ^ (~0 << 28); + // if (y < 0 + // && content[++tempPos] < 0 + // && content[++tempPos] < 0 + // && content[++tempPos] < 0 + // && content[++tempPos] < 0 + // && content[++tempPos] < 0) { + // break fastpath; // Will throw malformedVarint() + // } + // } + // this.position = tempPos; + // return x; + // } + // return (int) readRawVarint64SlowPath(); + // } + // + // protected long readRawVarint64() { + // fastpath: + // { + // int tempPos = this.position; + // if ((tempPos + 1) == content.length) break fastpath; + // + // long x; + // int y; + // if ((y = content[++tempPos]) >= 0) { + // this.position = tempPos; + // return y; + // } else if (content.length - (tempPos + 1) < 9) { + // break fastpath; + // } else if ((y ^= (content[++tempPos] << 7)) < 0) { + // x = y ^ (~0 << 7); + // } else if ((y ^= (content[++tempPos] << 14)) >= 0) { + // x = y ^ ((~0 << 7) ^ (~0 << 14)); + // } else if ((y ^= (content[++tempPos] << 21)) < 0) { + // x = y ^ ((~0 << 7) ^ (~0 << 14) ^ (~0 << 21)); + // } else if ((x = y ^ ((long) content[++tempPos] << 28)) >= 0L) { + // x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28); + // } else if ((x ^= ((long) content[++tempPos] << 35)) < 0L) { + // x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35); + // } else if ((x ^= ((long) content[++tempPos] << 42)) >= 0L) { + // x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35) ^ (~0L << 42); + // } else if ((x ^= ((long) content[++tempPos] << 49)) < 0L) { + // x ^= (~0L << 7) + // ^ (~0L << 14) + // ^ (~0L << 21) + // ^ (~0L << 28) + // ^ (~0L << 35) + // ^ (~0L << 42) + // ^ (~0L << 49); + // } else { + // x ^= ((long) content[++tempPos] << 56); + // x ^= (~0L << 7) + // ^ (~0L << 14) + // ^ (~0L << 21) + // ^ (~0L << 28) + // ^ (~0L << 35) + // ^ (~0L << 42) + // ^ (~0L << 49) + // ^ (~0L << 56); + // if (x < 0L) { + // if (content[++tempPos] < 0L) { + // break fastpath; // Will throw malformedVarint() + // } + // } + // } + // this.position = tempPos; + // return x; + // } + // return readRawVarint64SlowPath(); + // } + // + // protected long readRawVarint64SlowPath() { + // long result = 0; + // for (int shift = 0; shift < 64; shift += 7) { + // final byte b = content[++this.position]; + // result |= (long) (b & 0x7F) << shift; + // if ((b & 0x80) == 0) return result; + // } + // throw new ConvertException("readRawVarint64SlowPath error"); + // } + // + // protected int readRawLittleEndian32() { + // return ((content[++this.position] & 0xff) + // | ((content[++this.position] & 0xff) << 8) + // | ((content[++this.position] & 0xff) << 16) + // | ((content[++this.position] & 0xff) << 24)); + // } + // + // protected long readRawLittleEndian64() { + // return ((content[++this.position] & 0xffL) + // | ((content[++this.position] & 0xffL) << 8) + // | ((content[++this.position] & 0xffL) << 16) + // | ((content[++this.position] & 0xffL) << 24) + // | ((content[++this.position] & 0xffL) << 32) + // | ((content[++this.position] & 0xffL) << 40) + // | ((content[++this.position] & 0xffL) << 48) + // | ((content[++this.position] & 0xffL) << 56)); + // } +} diff --git a/src/main/java/org/redkale/convert/proto/ProtobufByteBufferWriter.java b/src/main/java/org/redkale/convert/proto/ProtobufByteBufferWriter.java index 31baeea01..58584156e 100644 --- a/src/main/java/org/redkale/convert/proto/ProtobufByteBufferWriter.java +++ b/src/main/java/org/redkale/convert/proto/ProtobufByteBufferWriter.java @@ -1,144 +1,144 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package org.redkale.convert.proto; - -import java.nio.ByteBuffer; -import java.util.function.Supplier; -import org.redkale.util.Utility; - -/** @author zhangjx */ -public class ProtobufByteBufferWriter extends ProtobufWriter { - - private final Supplier supplier; - - private ByteBuffer[] buffers; - - private int index; - - public ProtobufByteBufferWriter(int features, boolean enumtostring, Supplier supplier) { - super((byte[]) null); - this.features = features; - this.enumtostring = enumtostring; - this.supplier = supplier; - } - - @Override - protected boolean recycle() { - super.recycle(); - this.buffers = null; - this.index = 0; - return false; - } - - @Override - public ByteBuffer[] toBuffers() { - if (buffers == null) { - return new ByteBuffer[0]; - } - for (int i = index; i < this.buffers.length; i++) { - ByteBuffer buf = this.buffers[i]; - if (buf.position() != 0) { - buf.flip(); - } - } - return this.buffers; - } - - @Override - public byte[] toArray() { - if (buffers == null) { - return new byte[0]; - } - int pos = 0; - byte[] bytes = new byte[this.count]; - for (ByteBuffer buf : toBuffers()) { - int r = buf.remaining(); - buf.get(bytes, pos, r); - buf.flip(); - pos += r; - } - return bytes; - } - - @Override - public String toString() { - return this.getClass().getSimpleName() + "[count=" + this.count + "]"; - } - - @Override - protected int expand(final int byteLength) { - if (this.buffers == null) { - this.index = 0; - this.buffers = new ByteBuffer[] {supplier.get()}; - } - ByteBuffer buffer = this.buffers[index]; - if (!buffer.hasRemaining()) { - buffer.flip(); - buffer = supplier.get(); - this.buffers = Utility.append(this.buffers, buffer); - this.index++; - } - int len = buffer.remaining(); - int size = 0; - while (len < byteLength) { - buffer = supplier.get(); - this.buffers = Utility.append(this.buffers, buffer); - len += buffer.remaining(); - size++; - } - return size; - } - - @Override - public void writeTo(final byte[] chs, final int start, final int len) { - if (expand(len) == 0) { - this.buffers[index].put(chs, start, len); - } else { - ByteBuffer buffer = this.buffers[index]; - final int end = start + len; - int remain = len; // 还剩多少没有写 - while (remain > 0) { - final int br = buffer.remaining(); - if (remain > br) { // 一个buffer写不完 - buffer.put(chs, end - remain, br); - buffer = nextByteBuffer(); - remain -= br; - } else { - buffer.put(chs, end - remain, remain); - remain = 0; - } - } - } - this.count += len; - } - - private ByteBuffer nextByteBuffer() { - this.buffers[this.index].flip(); - return this.buffers[++this.index]; - } - - @Override - public void writeTo(final byte ch) { - expand(1); - this.buffers[index].put(ch); - count++; - } - - @Override - public byte[] content() { - throw new UnsupportedOperationException("Not supported yet."); // 无需实现 - } - - @Override - public int offset() { - throw new UnsupportedOperationException("Not supported yet."); // 无需实现 - } - - @Override - public int length() { - throw new UnsupportedOperationException("Not supported yet."); // 无需实现 - } -} +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.proto; + +import java.nio.ByteBuffer; +import java.util.function.Supplier; +import org.redkale.util.Utility; + +/** @author zhangjx */ +public class ProtobufByteBufferWriter extends ProtobufWriter { + + private final Supplier supplier; + + private ByteBuffer[] buffers; + + private int index; + + public ProtobufByteBufferWriter(int features, boolean enumtostring, Supplier supplier) { + super((byte[]) null); + this.features = features; + this.enumtostring = enumtostring; + this.supplier = supplier; + } + + @Override + protected boolean recycle() { + super.recycle(); + this.buffers = null; + this.index = 0; + return false; + } + + @Override + public ByteBuffer[] toBuffers() { + if (buffers == null) { + return new ByteBuffer[0]; + } + for (int i = index; i < this.buffers.length; i++) { + ByteBuffer buf = this.buffers[i]; + if (buf.position() != 0) { + buf.flip(); + } + } + return this.buffers; + } + + @Override + public byte[] toArray() { + if (buffers == null) { + return new byte[0]; + } + int pos = 0; + byte[] bytes = new byte[this.count]; + for (ByteBuffer buf : toBuffers()) { + int r = buf.remaining(); + buf.get(bytes, pos, r); + buf.flip(); + pos += r; + } + return bytes; + } + + @Override + public String toString() { + return this.getClass().getSimpleName() + "[count=" + this.count + "]"; + } + + @Override + protected int expand(final int byteLength) { + if (this.buffers == null) { + this.index = 0; + this.buffers = new ByteBuffer[] {supplier.get()}; + } + ByteBuffer buffer = this.buffers[index]; + if (!buffer.hasRemaining()) { + buffer.flip(); + buffer = supplier.get(); + this.buffers = Utility.append(this.buffers, buffer); + this.index++; + } + int len = buffer.remaining(); + int size = 0; + while (len < byteLength) { + buffer = supplier.get(); + this.buffers = Utility.append(this.buffers, buffer); + len += buffer.remaining(); + size++; + } + return size; + } + + @Override + public void writeTo(final byte[] chs, final int start, final int len) { + if (expand(len) == 0) { + this.buffers[index].put(chs, start, len); + } else { + ByteBuffer buffer = this.buffers[index]; + final int end = start + len; + int remain = len; // 还剩多少没有写 + while (remain > 0) { + final int br = buffer.remaining(); + if (remain > br) { // 一个buffer写不完 + buffer.put(chs, end - remain, br); + buffer = nextByteBuffer(); + remain -= br; + } else { + buffer.put(chs, end - remain, remain); + remain = 0; + } + } + } + this.count += len; + } + + private ByteBuffer nextByteBuffer() { + this.buffers[this.index].flip(); + return this.buffers[++this.index]; + } + + @Override + public void writeTo(final byte ch) { + expand(1); + this.buffers[index].put(ch); + count++; + } + + @Override + public byte[] content() { + throw new UnsupportedOperationException("Not supported yet."); // 无需实现 + } + + @Override + public int offset() { + throw new UnsupportedOperationException("Not supported yet."); // 无需实现 + } + + @Override + public int length() { + throw new UnsupportedOperationException("Not supported yet."); // 无需实现 + } +} diff --git a/src/main/java/org/redkale/convert/proto/ProtobufCollectionDecoder.java b/src/main/java/org/redkale/convert/proto/ProtobufCollectionDecoder.java index 8634bb056..58e26487b 100644 --- a/src/main/java/org/redkale/convert/proto/ProtobufCollectionDecoder.java +++ b/src/main/java/org/redkale/convert/proto/ProtobufCollectionDecoder.java @@ -1,45 +1,45 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package org.redkale.convert.proto; - -import java.lang.reflect.Type; -import java.util.concurrent.atomic.*; -import org.redkale.convert.*; - -/** - * @author zhangjx - * @param T - */ -public class ProtobufCollectionDecoder extends CollectionDecoder { - - protected final boolean simple; - - private final boolean string; - - private final boolean enumtostring; - - public ProtobufCollectionDecoder(ConvertFactory factory, Type type) { - super(factory, type); - this.enumtostring = ((ProtobufFactory) factory).enumtostring; - Type comtype = this.getComponentType(); - this.string = String.class == comtype; - this.simple = Boolean.class == comtype - || Short.class == comtype - || Character.class == comtype - || Integer.class == comtype - || Float.class == comtype - || Long.class == comtype - || Double.class == comtype - || AtomicInteger.class == comtype - || AtomicLong.class == comtype; - } - - @Override - protected Reader getItemReader(Reader in, DeMember member, boolean first) { - if (simple) return in; - return ProtobufFactory.getItemReader(string, simple, in, member, enumtostring, first); - } -} +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.proto; + +import java.lang.reflect.Type; +import java.util.concurrent.atomic.*; +import org.redkale.convert.*; + +/** + * @author zhangjx + * @param T + */ +public class ProtobufCollectionDecoder extends CollectionDecoder { + + protected final boolean simple; + + private final boolean string; + + private final boolean enumtostring; + + public ProtobufCollectionDecoder(ConvertFactory factory, Type type) { + super(factory, type); + this.enumtostring = ((ProtobufFactory) factory).enumtostring; + Type comtype = this.getComponentType(); + this.string = String.class == comtype; + this.simple = Boolean.class == comtype + || Short.class == comtype + || Character.class == comtype + || Integer.class == comtype + || Float.class == comtype + || Long.class == comtype + || Double.class == comtype + || AtomicInteger.class == comtype + || AtomicLong.class == comtype; + } + + @Override + protected Reader getItemReader(Reader in, DeMember member, boolean first) { + if (simple) return in; + return ProtobufFactory.getItemReader(string, simple, in, member, enumtostring, first); + } +} diff --git a/src/main/java/org/redkale/convert/proto/ProtobufCollectionEncoder.java b/src/main/java/org/redkale/convert/proto/ProtobufCollectionEncoder.java index 6e50a62d7..0de960154 100644 --- a/src/main/java/org/redkale/convert/proto/ProtobufCollectionEncoder.java +++ b/src/main/java/org/redkale/convert/proto/ProtobufCollectionEncoder.java @@ -1,57 +1,57 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package org.redkale.convert.proto; - -import java.lang.reflect.Type; -import java.util.concurrent.atomic.*; -import org.redkale.convert.*; - -/** - * @author zhangjx - * @param T - */ -public class ProtobufCollectionEncoder extends CollectionEncoder { - - protected final boolean simple; - - public ProtobufCollectionEncoder(ConvertFactory factory, Type type) { - super(factory, type); - Type comtype = this.getComponentType(); - this.simple = Boolean.class == comtype - || Short.class == comtype - || Character.class == comtype - || Integer.class == comtype - || Float.class == comtype - || Long.class == comtype - || Double.class == comtype - || AtomicInteger.class == comtype - || AtomicLong.class == comtype; - } - - @Override - protected void writeMemberValue(Writer out, EnMember member, Object item, boolean first) { - if (simple) { - if (item == null) { - ((ProtobufWriter) out).writeUInt32(0); - } else { - componentEncoder.convertTo(out, item); - } - return; - } - if (member != null) out.writeFieldName(member); - if (item == null) { - ((ProtobufWriter) out).writeUInt32(0); - } else if (item instanceof CharSequence) { - componentEncoder.convertTo(out, item); - } else { - ProtobufWriter tmp = new ProtobufWriter().configFieldFunc(out); - componentEncoder.convertTo(tmp, item); - int length = tmp.count(); - ((ProtobufWriter) out).writeUInt32(length); - ((ProtobufWriter) out).writeTo(tmp.toArray()); - } - } -} +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.proto; + +import java.lang.reflect.Type; +import java.util.concurrent.atomic.*; +import org.redkale.convert.*; + +/** + * @author zhangjx + * @param T + */ +public class ProtobufCollectionEncoder extends CollectionEncoder { + + protected final boolean simple; + + public ProtobufCollectionEncoder(ConvertFactory factory, Type type) { + super(factory, type); + Type comtype = this.getComponentType(); + this.simple = Boolean.class == comtype + || Short.class == comtype + || Character.class == comtype + || Integer.class == comtype + || Float.class == comtype + || Long.class == comtype + || Double.class == comtype + || AtomicInteger.class == comtype + || AtomicLong.class == comtype; + } + + @Override + protected void writeMemberValue(Writer out, EnMember member, Object item, boolean first) { + if (simple) { + if (item == null) { + ((ProtobufWriter) out).writeUInt32(0); + } else { + componentEncoder.convertTo(out, item); + } + return; + } + if (member != null) out.writeFieldName(member); + if (item == null) { + ((ProtobufWriter) out).writeUInt32(0); + } else if (item instanceof CharSequence) { + componentEncoder.convertTo(out, item); + } else { + ProtobufWriter tmp = new ProtobufWriter().configFieldFunc(out); + componentEncoder.convertTo(tmp, item); + int length = tmp.count(); + ((ProtobufWriter) out).writeUInt32(length); + ((ProtobufWriter) out).writeTo(tmp.toArray()); + } + } +} diff --git a/src/main/java/org/redkale/convert/proto/ProtobufConvert.java b/src/main/java/org/redkale/convert/proto/ProtobufConvert.java index 80b237e97..b6edb34d5 100644 --- a/src/main/java/org/redkale/convert/proto/ProtobufConvert.java +++ b/src/main/java/org/redkale/convert/proto/ProtobufConvert.java @@ -1,870 +1,870 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package org.redkale.convert.proto; - -import java.io.*; -import java.lang.reflect.*; -import java.nio.ByteBuffer; -import java.util.*; -import java.util.function.*; -import org.redkale.convert.*; -import org.redkale.convert.ext.StringArraySimpledCoder; -import org.redkale.util.*; - -/** - * protobuf的Convert实现
- * 注意:
- * 1、 只实现proto3版本
- * 2、 int统一使用sint32, long统一使用sint64
- * 3、 集合统一 packed repeated
- * 4、 目前使用的基础数据类型为:bool、sint32、sint64、float、double、bytes、string、map、Any
- * - * @author zhangjx - */ -public class ProtobufConvert extends BinaryConvert { - - private final ThreadLocal writerPool = Utility.withInitialThreadLocal(ProtobufWriter::new); - - private final Consumer writerConsumer = w -> offerWriter(w); - - private final ThreadLocal readerPool = Utility.withInitialThreadLocal(ProtobufReader::new); - - private Encodeable lastConvertEncodeable; - - private Decodeable lastConvertDecodeable; - - protected ProtobufConvert(ConvertFactory factory, int features) { - super(factory, features); - } - - @Override - public ProtobufFactory getFactory() { - return (ProtobufFactory) factory; - } - - public static ProtobufConvert root() { - return ProtobufFactory.root().getConvert(); - } - - @Override - public ProtobufConvert newConvert(final BiFunction objFieldFunc) { - return newConvert(objFieldFunc, null, null); - } - - @Override - public ProtobufConvert newConvert( - final BiFunction objFieldFunc, BiFunction mapFieldFunc) { - return newConvert(objFieldFunc, mapFieldFunc, null); - } - - @Override - public ProtobufConvert newConvert( - final BiFunction objFieldFunc, Function objExtFunc) { - return newConvert(objFieldFunc, null, objExtFunc); - } - - @Override - public ProtobufConvert newConvert( - final BiFunction fieldFunc, - BiFunction mapFieldFunc, - Function objExtFunc) { - return new ProtobufConvert(getFactory(), features) { - @Override - protected S configWrite(S writer) { - super.configWrite(writer); - return fieldFunc(writer, fieldFunc, mapFieldFunc, objExtFunc); - } - }; - } - - @Override - public ProtobufReader pollReader() { - ProtobufReader reader = readerPool.get(); - if (reader == null) { - reader = new ProtobufReader(); - } else { - readerPool.set(null); - } - return reader; - } - - @Override - public void offerReader(final ProtobufReader in) { - if (in != null) { - in.recycle(); - readerPool.set(in); - } - } - - // ------------------------------ writer ----------------------------------------------------------- - @Override - protected S configWrite(S writer) { - writer.initOffset = writer.count; - return writer; - } - - public ProtobufByteBufferWriter pollProtobufWriter(final Supplier supplier) { - return configWrite(new ProtobufByteBufferWriter(features, ((ProtobufFactory) factory).enumtostring, supplier)); - } - - public ProtobufWriter pollProtobufWriter(final OutputStream out) { - return configWrite(new ProtobufStreamWriter(features, ((ProtobufFactory) factory).enumtostring, out)); - } - - @Override - public ProtobufWriter pollWriter() { - ProtobufWriter writer = writerPool.get(); - if (writer == null) { - writer = new ProtobufWriter(); - } else { - writerPool.set(null); - } - return configWrite(writer.withFeatures(features).enumtostring(((ProtobufFactory) factory).enumtostring)); - } - - @Override - public void offerWriter(final ProtobufWriter out) { - if (out != null) { - out.recycle(); - writerPool.set(out); - } - } - - /** - * 请求参数的类型 - * - * @param type 请求参数的类型 - * @return String - */ - public String getJsonDecodeDescriptor(Type type) { - StringBuilder sb = new StringBuilder(); - defineJsonDecodeDescriptor(null, new ArrayList<>(), type, sb, "", null); - return sb.toString(); - } - - public String getJsonDecodeDescriptor(Type type, BiFunction func) { - StringBuilder sb = new StringBuilder(); - defineJsonDecodeDescriptor(null, new ArrayList<>(), type, sb, "", func); - return sb.toString(); - } - - protected String getJsonDecodeDescriptor( - Type parent, List list, Type type, BiFunction func) { - StringBuilder sb = new StringBuilder(); - defineJsonDecodeDescriptor(parent, list, type, sb, "", func); - return sb.toString(); - } - - protected void defineJsonDecodeDescriptor( - Type parent, - List list, - Type type, - StringBuilder sb, - String prefix, - BiFunction excludeFunc) { - Decodeable decoder = factory.loadDecoder(type); - boolean dot = sb.length() > 0; - if (decoder instanceof ObjectDecoder) { - if (sb.length() > 0) { - if (list.contains(parent + "" + defineTypeName(type))) { - return; - } - list.add(parent + "" + defineTypeName(type)); - sb.append(prefix) - .append("\"message ") - .append(defineTypeName(type)) - .append("\" : {\r\n"); - } else { - sb.append("{\r\n"); - } - DeMember[] ems = ((ObjectDecoder) decoder).getMembers(); - List members = new ArrayList<>(); - for (DeMember member : ems) { - if (excludeFunc != null && excludeFunc.apply(type, member)) { - continue; - } - members.add(member); - } - for (DeMember member : members) { - Type mtype = member.getDecoder().getType(); - if (!(mtype instanceof Class)) { - if (mtype instanceof ParameterizedType) { - final ParameterizedType pt = (ParameterizedType) mtype; - if (pt.getActualTypeArguments().length == 1 - && (pt.getActualTypeArguments()[0] instanceof Class)) { - defineJsonDecodeDescriptor(parent, list, mtype, sb, prefix + " ", excludeFunc); - } - } else if (mtype instanceof GenericArrayType) { - final GenericArrayType gt = (GenericArrayType) mtype; - if (!gt.getGenericComponentType().toString().startsWith("java") - && !gt.getGenericComponentType().toString().startsWith("class java") - && gt.getGenericComponentType().toString().indexOf('.') > 0) { - defineJsonDecodeDescriptor( - parent, list, gt.getGenericComponentType(), sb, prefix + " ", excludeFunc); - } - } - continue; - } - Class mclz = (Class) member.getDecoder().getType(); - if (!mclz.isArray() - && !mclz.isEnum() - && !mclz.isPrimitive() - && !mclz.getName().startsWith("java")) { - defineJsonDecodeDescriptor(parent, list, mclz, sb, prefix + " ", excludeFunc); - } else if (mclz.isArray() - && !mclz.getComponentType().getName().startsWith("java") - && !mclz.getComponentType().isPrimitive() - && !mclz.getComponentType().isArray() - && !mclz.getComponentType().getName().equals("boolean") - && !mclz.getComponentType().getName().equals("byte") - && !mclz.getComponentType().getName().equals("char") - && !mclz.getComponentType().getName().equals("short") - && !mclz.getComponentType().getName().equals("int") - && !mclz.getComponentType().getName().equals("long") - && !mclz.getComponentType().getName().equals("float") - && !mclz.getComponentType().getName().equals("double")) { - defineJsonDecodeDescriptor(parent, list, mclz.getComponentType(), sb, prefix + " ", excludeFunc); - } - } - for (int i = 0; i < members.size(); i++) { - DeMember member = members.get(i); - try { - sb.append(prefix) - .append(" \"") - .append(ProtobufFactory.wireTypeString( - member.getDecoder().getType(), ((ProtobufFactory) factory).enumtostring)) - .append(" ") - .append(member.getAttribute().field()) - .append("\" : ") - .append(member.getPosition()) - .append(i == members.size() - 1 ? "\r\n" : ",\r\n"); - } catch (RuntimeException e) { - System.err.println("member = " + member); - throw e; - } - } - sb.append(prefix).append(dot ? "}," : "}").append("\r\n"); - } else if ((!(type instanceof Class) - || !((Class) type).isArray() - || !((Class) type).getComponentType().getName().startsWith("java")) - && (decoder instanceof ProtobufArrayDecoder || decoder instanceof ProtobufCollectionDecoder)) { - Type mtype = decoder instanceof ProtobufArrayDecoder - ? ((ProtobufArrayDecoder) decoder).getComponentType() - : ((ProtobufCollectionDecoder) decoder).getComponentType(); - if (!mtype.toString().startsWith("java") - && !mtype.toString().startsWith("class java") - && mtype.toString().indexOf('.') > 0) { - defineJsonDecodeDescriptor(parent, list, mtype, sb, prefix, excludeFunc); - } - } else if (sb.length() == 0) { - if (decoder instanceof SimpledCoder - || decoder instanceof StringArraySimpledCoder - || (decoder instanceof ProtobufArrayDecoder - && ((ProtobufArrayDecoder) decoder).getComponentDecoder() instanceof SimpledCoder) - || (decoder instanceof ProtobufCollectionDecoder - && ((ProtobufCollectionDecoder) decoder).getComponentDecoder() instanceof SimpledCoder)) { - sb.append(prefix).append("{\r\n"); - sb.append(prefix) - .append(" \"") - .append(ProtobufFactory.wireTypeString(type, ((ProtobufFactory) factory).enumtostring)) - .append(" 0\" : 0\r\n"); - sb.append(prefix).append(dot ? "}," : "}").append("\r\n"); - } else if (decoder instanceof MapDecoder) { - sb.append(prefix).append("{\r\n"); - sb.append(prefix) - .append(" \"") - .append(ProtobufFactory.wireTypeString(type, ((ProtobufFactory) factory).enumtostring)) - .append(" 0\" : 0\r\n"); - sb.append(prefix).append(dot ? "}," : "}").append("\r\n"); - } else { - throw new ConvertException("Not support type (" + type + ")"); - } - } else { - throw new ConvertException("Not support the type (" + type + ")"); - } - } - - /** - * 输出结果的类型 - * - * @param type 输出结果的类型 - * @return String - */ - public String getJsonEncodeDescriptor(Type type) { - StringBuilder sb = new StringBuilder(); - defineJsonEncodeDescriptor(null, new ArrayList<>(), type, sb, "", null); - return sb.toString(); - } - - public String getJsonEncodeDescriptor(Type type, BiFunction func) { - StringBuilder sb = new StringBuilder(); - defineJsonEncodeDescriptor(null, new ArrayList<>(), type, sb, "", func); - return sb.toString(); - } - - protected String getJsonEncodeDescriptor( - Type parent, List list, Type type, BiFunction func) { - StringBuilder sb = new StringBuilder(); - defineJsonEncodeDescriptor(parent, list, type, sb, "", func); - return sb.toString(); - } - - protected void defineJsonEncodeDescriptor( - Type parent, - List list, - Type type, - StringBuilder sb, - String prefix, - BiFunction excludeFunc) { - Encodeable encoder = factory.loadEncoder(type); - boolean dot = sb.length() > 0; - if (encoder instanceof ObjectEncoder) { - if (sb.length() > 0) { - if (list.contains(parent + "" + defineTypeName(type))) { - return; - } - list.add(parent + "" + defineTypeName(type)); - sb.append(prefix) - .append("\"message ") - .append(defineTypeName(type)) - .append("\" : {\r\n"); - } else { - sb.append("{\r\n"); - } - EnMember[] ems = ((ObjectEncoder) encoder).getMembers(); - List members = new ArrayList<>(); - for (EnMember member : ems) { - if (excludeFunc != null && excludeFunc.apply(type, member)) { - continue; - } - members.add(member); - } - for (EnMember member : members) { - Type mtype = member.getEncoder().getType(); - if (!(mtype instanceof Class)) { - if (mtype instanceof ParameterizedType) { - final ParameterizedType pt = (ParameterizedType) mtype; - if (pt.getActualTypeArguments().length == 1 - && (pt.getActualTypeArguments()[0] instanceof Class)) { - defineJsonEncodeDescriptor(parent, list, mtype, sb, prefix + " ", excludeFunc); - } - } else if (mtype instanceof GenericArrayType) { - final GenericArrayType gt = (GenericArrayType) mtype; - if (!gt.getGenericComponentType().toString().startsWith("java") - && !gt.getGenericComponentType().toString().startsWith("class java") - && gt.getGenericComponentType().toString().indexOf('.') > 0) { - defineJsonEncodeDescriptor( - parent, list, gt.getGenericComponentType(), sb, prefix + " ", excludeFunc); - } - } - continue; - } - Class mclz = (Class) member.getEncoder().getType(); - if (!mclz.isArray() && !mclz.isEnum() && !mclz.getName().startsWith("java")) { - defineJsonEncodeDescriptor(parent, list, mclz, sb, prefix + " ", excludeFunc); - } else if (mclz.isArray() - && !mclz.getComponentType().getName().startsWith("java") - && !mclz.getComponentType().getName().equals("boolean") - && !mclz.getComponentType().getName().equals("byte") - && !mclz.getComponentType().getName().equals("char") - && !mclz.getComponentType().getName().equals("short") - && !mclz.getComponentType().getName().equals("int") - && !mclz.getComponentType().getName().equals("long") - && !mclz.getComponentType().getName().equals("float") - && !mclz.getComponentType().getName().equals("double")) { - defineJsonEncodeDescriptor(parent, list, mclz.getComponentType(), sb, prefix + " ", excludeFunc); - } - } - for (int i = 0; i < members.size(); i++) { - EnMember member = members.get(i); - try { - sb.append(prefix) - .append(" \"") - .append(ProtobufFactory.wireTypeString( - member.getEncoder().getType(), ((ProtobufFactory) factory).enumtostring)) - .append(" ") - .append(member.getAttribute().field()) - .append("\" : ") - .append(member.getPosition()) - .append(i == members.size() - 1 ? "\r\n" : ",\r\n"); - } catch (RuntimeException e) { - System.err.println("member = " + member); - throw e; - } - } - sb.append(prefix).append(dot ? "}," : "}").append("\r\n"); - } else if (encoder instanceof ProtobufArrayEncoder || encoder instanceof ProtobufCollectionEncoder) { - Type mtype = encoder instanceof ProtobufArrayEncoder - ? ((ProtobufArrayEncoder) encoder).getComponentType() - : ((ProtobufCollectionEncoder) encoder).getComponentType(); - if (!mtype.toString().startsWith("java") - && !mtype.toString().startsWith("class java") - && mtype.toString().indexOf('.') > 0) { - defineJsonEncodeDescriptor(parent, list, mtype, sb, prefix, excludeFunc); - } - } else if (sb.length() == 0) { - if (encoder instanceof SimpledCoder - || (encoder instanceof ProtobufArrayEncoder - && ((ProtobufArrayEncoder) encoder).getComponentEncoder() instanceof SimpledCoder) - || (encoder instanceof ProtobufCollectionEncoder - && ((ProtobufCollectionEncoder) encoder).getComponentEncoder() instanceof SimpledCoder)) { - sb.append(prefix).append("{\r\n"); - sb.append(prefix) - .append(" \"") - .append(ProtobufFactory.wireTypeString(type, ((ProtobufFactory) factory).enumtostring)) - .append(" 0\" : 0\r\n"); - sb.append(prefix).append(dot ? "}," : "}").append("\r\n"); - } else if (encoder instanceof MapEncoder) { - sb.append(prefix).append("{\r\n"); - sb.append(prefix) - .append(" \"") - .append(ProtobufFactory.wireTypeString(type, ((ProtobufFactory) factory).enumtostring)) - .append(" 0\" : 0\r\n"); - sb.append(prefix).append(dot ? "}," : "}").append("\r\n"); - } else { - throw new ConvertException("Not support the type (" + type + ")"); - } - } else { - throw new ConvertException("Not support the type (" + type + ")"); - } - } - - public String getProtoDescriptor(Type type) { - StringBuilder sb = new StringBuilder(); - Class clazz = TypeToken.typeToClass(type); - sb.append("//java ") - .append(clazz.isArray() ? (clazz.getComponentType().getName() + "[]") : clazz.getName()) - .append("\r\n\r\n"); - if (type instanceof Class) { - sb.append("option java_package = \"") - .append(clazz.getPackage().getName()) - .append("\";\r\n\r\n"); - } - sb.append("syntax = \"proto3\";\r\n\r\n"); - // defineProtoDescriptor(type, sb, ""); - defineProtoDescriptor(null, new ArrayList<>(), type, sb, "", null); - return sb.toString(); - } - - protected String defineProtoDescriptor( - Type parent, List list, Type type, BiFunction func) { - StringBuilder sb = new StringBuilder(); - defineProtoDescriptor(parent, list, type, sb, "", func); - return sb.toString(); - } - - protected void defineProtoDescriptor( - Type parent, - List list, - Type type, - StringBuilder sb, - String prefix, - BiFunction excludeFunc) { - Encodeable encoder = factory.loadEncoder(type); - if (encoder instanceof ObjectEncoder) { - if (list.contains(parent + "" + defineTypeName(type))) { - return; - } - list.add(parent + "" + defineTypeName(type)); - - List members = new ArrayList<>(); - EnMember[] ems = ((ObjectEncoder) encoder).getMembers(); - for (EnMember member : ems) { - if (excludeFunc != null && excludeFunc.apply(type, member)) { - continue; - } - members.add(member); - } - final List sblist = new ArrayList<>(); - for (EnMember member : members) { - Type mtype = member.getEncoder().getType(); - if (!(mtype instanceof Class)) { - if (mtype instanceof ParameterizedType) { - final ParameterizedType pt = (ParameterizedType) mtype; - if (pt.getActualTypeArguments().length == 1 - && (pt.getActualTypeArguments()[0] instanceof Class)) { - StringBuilder innersb = new StringBuilder(); - defineProtoDescriptor(parent, list, mtype, innersb, prefix, excludeFunc); - sblist.add(innersb); - } - } else if (mtype instanceof GenericArrayType) { - final GenericArrayType gt = (GenericArrayType) mtype; - if (!gt.getGenericComponentType().toString().startsWith("java") - && !gt.getGenericComponentType().toString().startsWith("class java") - && gt.getGenericComponentType().toString().indexOf('.') > 0) { - StringBuilder innersb = new StringBuilder(); - defineProtoDescriptor( - parent, list, gt.getGenericComponentType(), innersb, prefix, excludeFunc); - sblist.add(innersb); - } - } - continue; - } - Class mclz = (Class) member.getEncoder().getType(); - if (!mclz.isArray() && !mclz.isEnum() && !mclz.getName().startsWith("java")) { - StringBuilder innersb = new StringBuilder(); - defineProtoDescriptor(parent, list, mclz, innersb, prefix, excludeFunc); - sblist.add(innersb); - } else if (mclz.isArray() - && !mclz.getComponentType().getName().startsWith("java") - && !mclz.getComponentType().getName().equals("boolean") - && !mclz.getComponentType().getName().equals("byte") - && !mclz.getComponentType().getName().equals("char") - && !mclz.getComponentType().getName().equals("short") - && !mclz.getComponentType().getName().equals("int") - && !mclz.getComponentType().getName().equals("long") - && !mclz.getComponentType().getName().equals("float") - && !mclz.getComponentType().getName().equals("double")) { - StringBuilder innersb = new StringBuilder(); - defineProtoDescriptor(parent, list, mclz.getComponentType(), innersb, prefix, excludeFunc); - sblist.add(innersb); - } - } - for (StringBuilder sbitem : sblist) { - if (sbitem.length() < 1) { - continue; - } - sb.append(sbitem.toString().trim()).append("\r\n\r\n"); - } - sb.append(prefix).append("message ").append(defineTypeName(type)).append(" {\r\n"); - for (int i = 0; i < members.size(); i++) { - EnMember member = members.get(i); - try { - sb.append(prefix) - .append(" ") - .append(ProtobufFactory.wireTypeString( - member.getEncoder().getType(), ((ProtobufFactory) factory).enumtostring)) - .append(" ") - .append(member.getAttribute().field()) - .append(" = ") - .append(member.getPosition()) - .append(member.getComment().isEmpty() ? ";\r\n" : ("; //" + member.getComment() + " \r\n")); - } catch (RuntimeException e) { - System.err.println("member = " + member); - throw e; - } - } - sb.append(prefix).append("}").append("\r\n"); - } else if (encoder instanceof ProtobufArrayEncoder || encoder instanceof ProtobufCollectionEncoder) { - Type mtype = encoder instanceof ProtobufArrayEncoder - ? ((ProtobufArrayEncoder) encoder).getComponentType() - : ((ProtobufCollectionEncoder) encoder).getComponentType(); - if (!mtype.toString().startsWith("java") - && !mtype.toString().startsWith("class java") - && mtype.toString().indexOf('.') > 0) { - defineProtoDescriptor(parent, list, mtype, sb, prefix, excludeFunc); - } - } else { - throw new ConvertException("Not support the type (" + type + ")"); - } - } - - protected StringBuilder defineTypeName(Type type) { - StringBuilder sb = new StringBuilder(); - if (type instanceof Class) { - sb.append(((Class) type).getSimpleName().replace("[]", "_Array")); - } else if (type instanceof ParameterizedType) { - Type raw = ((ParameterizedType) type).getRawType(); - sb.append(((Class) raw).getSimpleName().replace("[]", "_Array")); - Type[] ts = ((ParameterizedType) type).getActualTypeArguments(); - if (ts != null) { - for (Type t : ts) { - if (t != null) { - sb.append('_').append(defineTypeName(t)); - } - } - } - } - return sb; - } - - // ------------------------------ convertFrom ----------------------------------------------------------- - @Override - public T convertFrom(final Type type, final byte[] bytes) { - if (bytes == null) { - return null; - } - return convertFrom(type, bytes, 0, bytes.length); - } - - @Override - @SuppressWarnings("unchecked") - public T convertFrom(final Type type, final byte[] bytes, final int offset, final int len) { - if (type == null) { - return null; - } - final ProtobufReader reader = new ProtobufReader(bytes, offset, len); - Decodeable decoder = this.lastConvertDecodeable; - if (decoder == null || decoder.getType() != type) { - decoder = factory.loadDecoder(type); - this.lastConvertDecodeable = decoder; - } - if (!(decoder instanceof ObjectDecoder) && !(decoder instanceof SimpledCoder)) { - throw new ConvertException(this.getClass().getSimpleName() + " not supported type(" + type + ")"); - } - T rs = (T) decoder.convertFrom(reader); - return rs; - } - - @SuppressWarnings("unchecked") - public T convertFrom(final Type type, final InputStream in) { - if (true) { - throw new ConvertException(this.getClass().getSimpleName() + " not supported convertFrom InputStream"); - } - if (type == null || in == null) { - return null; - } - Decodeable decoder = this.lastConvertDecodeable; - if (decoder == null || decoder.getType() != type) { - decoder = factory.loadDecoder(type); - this.lastConvertDecodeable = decoder; - } - if (!(decoder instanceof ObjectDecoder)) { - throw new ConvertException(this.getClass().getSimpleName() + " not supported type(" + type + ")"); - } - return (T) decoder.convertFrom(new ProtobufStreamReader(in)); - } - - @Override - @SuppressWarnings("unchecked") - public T convertFrom(final Type type, final ByteBuffer... buffers) { - if (true) { - throw new ConvertException(this.getClass().getSimpleName() + " not supported convertFrom ByteBuffer"); - } - if (type == null || buffers.length < 1) { - return null; - } - Decodeable decoder = this.lastConvertDecodeable; - if (decoder == null || decoder.getType() != type) { - decoder = factory.loadDecoder(type); - this.lastConvertDecodeable = decoder; - } - if (!(decoder instanceof ObjectDecoder)) { - throw new ConvertException(this.getClass().getSimpleName() + " not supported type(" + type + ")"); - } - return (T) decoder.convertFrom(new ProtobufByteBufferReader(buffers)); - } - - @Override - @SuppressWarnings("unchecked") - public T convertFrom(final Type type, final ProtobufReader reader) { - if (type == null) { - return null; - } - Decodeable decoder = this.lastConvertDecodeable; - if (decoder == null || decoder.getType() != type) { - decoder = factory.loadDecoder(type); - this.lastConvertDecodeable = decoder; - } - if (!(decoder instanceof ObjectDecoder)) { - throw new ConvertException(this.getClass().getSimpleName() + " not supported type(" + type + ")"); - } - T rs = (T) decoder.convertFrom(reader); - return rs; - } - - // ------------------------------ convertTo ----------------------------------------------------------- - @Override - public byte[] convertTo(final Type type, final Object value) { - if (value == null) { - final ProtobufWriter writer = pollWriter(); - writer.writeNull(); - byte[] result = writer.toArray(); - offerWriter(writer); - return result; - } - final Type t = type == null ? value.getClass() : type; - final ProtobufWriter writer = pollWriter(); - Encodeable encoder = this.lastConvertEncodeable; - if (encoder == null || encoder.getType() != t) { - encoder = factory.loadEncoder(t); - this.lastConvertEncodeable = encoder; - } - if (encoder.specifyable()) { - writer.specificObjectType(t); - } - if (!(encoder instanceof ObjectEncoder) && !(encoder instanceof SimpledCoder)) { - throw new ConvertException(this.getClass().getSimpleName() + " not supported type(" + t + ")"); - } - encoder.convertTo(writer, value); - byte[] result = writer.toArray(); - offerWriter(writer); - return result; - } - - public byte[] convertTo(final Object value, int tag, byte... appends) { - return convertTo(value.getClass(), value, tag, appends); - } - - public byte[] convertTo(final Type type, final Object value, int tag, byte... appends) { - if (type == null) { - return null; - } - final ProtobufWriter writer = pollWriter(); - Encodeable encoder = this.lastConvertEncodeable; - if (encoder == null || encoder.getType() != type) { - encoder = factory.loadEncoder(type); - this.lastConvertEncodeable = encoder; - } - if (encoder.specifyable()) { - writer.specificObjectType(type); - } - if (!(encoder instanceof ObjectEncoder) && !(encoder instanceof SimpledCoder)) { - throw new ConvertException(this.getClass().getSimpleName() + " not supported type(" + type + ")"); - } - encoder.convertTo(writer, value); - writer.writeUInt32(tag); - writer.writeUInt32(appends.length); - writer.writeTo(appends); - byte[] result = writer.toArray(); - offerWriter(writer); - return result; - } - - @Override - public byte[] convertToBytes(final Type type, final Object value) { - return convertTo(type, value); - } - - @Override - public void convertToBytes(final Type type, final Object value, final ConvertBytesHandler handler) { - final ProtobufWriter writer = pollWriter(); - if (value == null) { - writer.writeNull(); - } else { - final Type t = type == null ? value.getClass() : type; - Encodeable encoder = this.lastConvertEncodeable; - if (encoder == null || encoder.getType() != t) { - encoder = factory.loadEncoder(t); - this.lastConvertEncodeable = encoder; - } - if (encoder.specifyable()) { - writer.specificObjectType(t); - } - if (!(encoder instanceof ObjectEncoder) && !(encoder instanceof SimpledCoder)) { - throw new ConvertException(this.getClass().getSimpleName() + " not supported type(" + t + ")"); - } - encoder.convertTo(writer, value); - } - writer.completed(handler, writerConsumer); - } - - @Override - public void convertToBytes(final ByteArray array, final Type type, final Object value) { - Objects.requireNonNull(array); - final ProtobufWriter writer = configWrite(new ProtobufWriter(array) - .withFeatures(features) - .enumtostring(((ProtobufFactory) factory).enumtostring)); - if (value == null) { - writer.writeNull(); - } else { - final Type t = type == null ? value.getClass() : type; - Encodeable encoder = this.lastConvertEncodeable; - if (encoder == null || encoder.getType() != t) { - encoder = factory.loadEncoder(t); - this.lastConvertEncodeable = encoder; - } - if (encoder.specifyable()) { - writer.specificObjectType(t); - } - if (!(encoder instanceof ObjectEncoder) && !(encoder instanceof SimpledCoder)) { - throw new ConvertException(this.getClass().getSimpleName() + " not supported type(" + t + ")"); - } - encoder.convertTo(writer, value); - } - writer.directTo(array); - } - - public void convertTo(final OutputStream out, final Type type, final Object value) { - if (true) { - throw new ConvertException(this.getClass().getSimpleName() + " not supported convertTo OutputStream"); - } - ProtobufWriter writer = pollProtobufWriter(out); - if (value == null) { - writer.writeNull(); - } else { - final Type t = type == null ? value.getClass() : type; - Encodeable encoder = this.lastConvertEncodeable; - if (encoder == null || encoder.getType() != t) { - encoder = factory.loadEncoder(t); - this.lastConvertEncodeable = encoder; - } - if (encoder.specifyable()) { - writer.specificObjectType(t); - } - if (!(encoder instanceof ObjectEncoder)) { - throw new ConvertException(this.getClass().getSimpleName() + " not supported type(" + t + ")"); - } - encoder.convertTo(writer, value); - } - } - - @Override - public ByteBuffer[] convertTo(final Supplier supplier, final Type type, final Object value) { - // if (true) throw new ConvertException(this.getClass().getSimpleName() + " not supported convertTo - // ByteBuffer"); - Objects.requireNonNull(supplier); - ProtobufByteBufferWriter writer = pollProtobufWriter(supplier); - if (value == null) { - writer.writeNull(); - } else { - final Type t = type == null ? value.getClass() : type; - Encodeable encoder = this.lastConvertEncodeable; - if (encoder == null || encoder.getType() != t) { - encoder = factory.loadEncoder(t); - this.lastConvertEncodeable = encoder; - } - if (encoder.specifyable()) { - writer.specificObjectType(t); - } - if (!(encoder instanceof ObjectEncoder)) { - throw new ConvertException(this.getClass().getSimpleName() + " not supported type(" + t + ")"); - } - encoder.convertTo(writer, value); - } - return writer.toBuffers(); - } - - @Override - public void convertTo(final ProtobufWriter writer, final Type type, final Object value) { - if (value == null) { - writer.writeNull(); - return; - } - writer.initOffset = writer.count; - final Type t = type == null ? value.getClass() : type; - Encodeable encoder = this.lastConvertEncodeable; - if (encoder == null || encoder.getType() != t) { - encoder = factory.loadEncoder(t); - this.lastConvertEncodeable = encoder; - } - if (encoder.specifyable()) { - writer.specificObjectType(t); - } - encoder.convertTo(writer, value); - } - - public ProtobufWriter convertToWriter(final Type type, final Object value) { - if (value == null) { - return null; - } - final ProtobufWriter writer = pollWriter(); - final Type t = type == null ? value.getClass() : type; - Encodeable encoder = this.lastConvertEncodeable; - if (encoder == null || encoder.getType() != t) { - encoder = factory.loadEncoder(t); - this.lastConvertEncodeable = encoder; - } - if (encoder.specifyable()) { - writer.specificObjectType(t); - } - if (!(encoder instanceof ObjectEncoder)) { - throw new ConvertException(this.getClass().getSimpleName() + " not supported type(" + t + ")"); - } - encoder.convertTo(writer, value); - return writer; - } -} +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.proto; + +import java.io.*; +import java.lang.reflect.*; +import java.nio.ByteBuffer; +import java.util.*; +import java.util.function.*; +import org.redkale.convert.*; +import org.redkale.convert.ext.StringArraySimpledCoder; +import org.redkale.util.*; + +/** + * protobuf的Convert实现
+ * 注意:
+ * 1、 只实现proto3版本
+ * 2、 int统一使用sint32, long统一使用sint64
+ * 3、 集合统一 packed repeated
+ * 4、 目前使用的基础数据类型为:bool、sint32、sint64、float、double、bytes、string、map、Any
+ * + * @author zhangjx + */ +public class ProtobufConvert extends BinaryConvert { + + private final ThreadLocal writerPool = Utility.withInitialThreadLocal(ProtobufWriter::new); + + private final Consumer writerConsumer = w -> offerWriter(w); + + private final ThreadLocal readerPool = Utility.withInitialThreadLocal(ProtobufReader::new); + + private Encodeable lastConvertEncodeable; + + private Decodeable lastConvertDecodeable; + + protected ProtobufConvert(ConvertFactory factory, int features) { + super(factory, features); + } + + @Override + public ProtobufFactory getFactory() { + return (ProtobufFactory) factory; + } + + public static ProtobufConvert root() { + return ProtobufFactory.root().getConvert(); + } + + @Override + public ProtobufConvert newConvert(final BiFunction objFieldFunc) { + return newConvert(objFieldFunc, null, null); + } + + @Override + public ProtobufConvert newConvert( + final BiFunction objFieldFunc, BiFunction mapFieldFunc) { + return newConvert(objFieldFunc, mapFieldFunc, null); + } + + @Override + public ProtobufConvert newConvert( + final BiFunction objFieldFunc, Function objExtFunc) { + return newConvert(objFieldFunc, null, objExtFunc); + } + + @Override + public ProtobufConvert newConvert( + final BiFunction fieldFunc, + BiFunction mapFieldFunc, + Function objExtFunc) { + return new ProtobufConvert(getFactory(), features) { + @Override + protected S configWrite(S writer) { + super.configWrite(writer); + return fieldFunc(writer, fieldFunc, mapFieldFunc, objExtFunc); + } + }; + } + + @Override + public ProtobufReader pollReader() { + ProtobufReader reader = readerPool.get(); + if (reader == null) { + reader = new ProtobufReader(); + } else { + readerPool.set(null); + } + return reader; + } + + @Override + public void offerReader(final ProtobufReader in) { + if (in != null) { + in.recycle(); + readerPool.set(in); + } + } + + // ------------------------------ writer ----------------------------------------------------------- + @Override + protected S configWrite(S writer) { + writer.initOffset = writer.count; + return writer; + } + + public ProtobufByteBufferWriter pollProtobufWriter(final Supplier supplier) { + return configWrite(new ProtobufByteBufferWriter(features, ((ProtobufFactory) factory).enumtostring, supplier)); + } + + public ProtobufWriter pollProtobufWriter(final OutputStream out) { + return configWrite(new ProtobufStreamWriter(features, ((ProtobufFactory) factory).enumtostring, out)); + } + + @Override + public ProtobufWriter pollWriter() { + ProtobufWriter writer = writerPool.get(); + if (writer == null) { + writer = new ProtobufWriter(); + } else { + writerPool.set(null); + } + return configWrite(writer.withFeatures(features).enumtostring(((ProtobufFactory) factory).enumtostring)); + } + + @Override + public void offerWriter(final ProtobufWriter out) { + if (out != null) { + out.recycle(); + writerPool.set(out); + } + } + + /** + * 请求参数的类型 + * + * @param type 请求参数的类型 + * @return String + */ + public String getJsonDecodeDescriptor(Type type) { + StringBuilder sb = new StringBuilder(); + defineJsonDecodeDescriptor(null, new ArrayList<>(), type, sb, "", null); + return sb.toString(); + } + + public String getJsonDecodeDescriptor(Type type, BiFunction func) { + StringBuilder sb = new StringBuilder(); + defineJsonDecodeDescriptor(null, new ArrayList<>(), type, sb, "", func); + return sb.toString(); + } + + protected String getJsonDecodeDescriptor( + Type parent, List list, Type type, BiFunction func) { + StringBuilder sb = new StringBuilder(); + defineJsonDecodeDescriptor(parent, list, type, sb, "", func); + return sb.toString(); + } + + protected void defineJsonDecodeDescriptor( + Type parent, + List list, + Type type, + StringBuilder sb, + String prefix, + BiFunction excludeFunc) { + Decodeable decoder = factory.loadDecoder(type); + boolean dot = sb.length() > 0; + if (decoder instanceof ObjectDecoder) { + if (sb.length() > 0) { + if (list.contains(parent + "" + defineTypeName(type))) { + return; + } + list.add(parent + "" + defineTypeName(type)); + sb.append(prefix) + .append("\"message ") + .append(defineTypeName(type)) + .append("\" : {\r\n"); + } else { + sb.append("{\r\n"); + } + DeMember[] ems = ((ObjectDecoder) decoder).getMembers(); + List members = new ArrayList<>(); + for (DeMember member : ems) { + if (excludeFunc != null && excludeFunc.apply(type, member)) { + continue; + } + members.add(member); + } + for (DeMember member : members) { + Type mtype = member.getDecoder().getType(); + if (!(mtype instanceof Class)) { + if (mtype instanceof ParameterizedType) { + final ParameterizedType pt = (ParameterizedType) mtype; + if (pt.getActualTypeArguments().length == 1 + && (pt.getActualTypeArguments()[0] instanceof Class)) { + defineJsonDecodeDescriptor(parent, list, mtype, sb, prefix + " ", excludeFunc); + } + } else if (mtype instanceof GenericArrayType) { + final GenericArrayType gt = (GenericArrayType) mtype; + if (!gt.getGenericComponentType().toString().startsWith("java") + && !gt.getGenericComponentType().toString().startsWith("class java") + && gt.getGenericComponentType().toString().indexOf('.') > 0) { + defineJsonDecodeDescriptor( + parent, list, gt.getGenericComponentType(), sb, prefix + " ", excludeFunc); + } + } + continue; + } + Class mclz = (Class) member.getDecoder().getType(); + if (!mclz.isArray() + && !mclz.isEnum() + && !mclz.isPrimitive() + && !mclz.getName().startsWith("java")) { + defineJsonDecodeDescriptor(parent, list, mclz, sb, prefix + " ", excludeFunc); + } else if (mclz.isArray() + && !mclz.getComponentType().getName().startsWith("java") + && !mclz.getComponentType().isPrimitive() + && !mclz.getComponentType().isArray() + && !mclz.getComponentType().getName().equals("boolean") + && !mclz.getComponentType().getName().equals("byte") + && !mclz.getComponentType().getName().equals("char") + && !mclz.getComponentType().getName().equals("short") + && !mclz.getComponentType().getName().equals("int") + && !mclz.getComponentType().getName().equals("long") + && !mclz.getComponentType().getName().equals("float") + && !mclz.getComponentType().getName().equals("double")) { + defineJsonDecodeDescriptor(parent, list, mclz.getComponentType(), sb, prefix + " ", excludeFunc); + } + } + for (int i = 0; i < members.size(); i++) { + DeMember member = members.get(i); + try { + sb.append(prefix) + .append(" \"") + .append(ProtobufFactory.wireTypeString( + member.getDecoder().getType(), ((ProtobufFactory) factory).enumtostring)) + .append(" ") + .append(member.getAttribute().field()) + .append("\" : ") + .append(member.getPosition()) + .append(i == members.size() - 1 ? "\r\n" : ",\r\n"); + } catch (RuntimeException e) { + System.err.println("member = " + member); + throw e; + } + } + sb.append(prefix).append(dot ? "}," : "}").append("\r\n"); + } else if ((!(type instanceof Class) + || !((Class) type).isArray() + || !((Class) type).getComponentType().getName().startsWith("java")) + && (decoder instanceof ProtobufArrayDecoder || decoder instanceof ProtobufCollectionDecoder)) { + Type mtype = decoder instanceof ProtobufArrayDecoder + ? ((ProtobufArrayDecoder) decoder).getComponentType() + : ((ProtobufCollectionDecoder) decoder).getComponentType(); + if (!mtype.toString().startsWith("java") + && !mtype.toString().startsWith("class java") + && mtype.toString().indexOf('.') > 0) { + defineJsonDecodeDescriptor(parent, list, mtype, sb, prefix, excludeFunc); + } + } else if (sb.length() == 0) { + if (decoder instanceof SimpledCoder + || decoder instanceof StringArraySimpledCoder + || (decoder instanceof ProtobufArrayDecoder + && ((ProtobufArrayDecoder) decoder).getComponentDecoder() instanceof SimpledCoder) + || (decoder instanceof ProtobufCollectionDecoder + && ((ProtobufCollectionDecoder) decoder).getComponentDecoder() instanceof SimpledCoder)) { + sb.append(prefix).append("{\r\n"); + sb.append(prefix) + .append(" \"") + .append(ProtobufFactory.wireTypeString(type, ((ProtobufFactory) factory).enumtostring)) + .append(" 0\" : 0\r\n"); + sb.append(prefix).append(dot ? "}," : "}").append("\r\n"); + } else if (decoder instanceof MapDecoder) { + sb.append(prefix).append("{\r\n"); + sb.append(prefix) + .append(" \"") + .append(ProtobufFactory.wireTypeString(type, ((ProtobufFactory) factory).enumtostring)) + .append(" 0\" : 0\r\n"); + sb.append(prefix).append(dot ? "}," : "}").append("\r\n"); + } else { + throw new ConvertException("Not support type (" + type + ")"); + } + } else { + throw new ConvertException("Not support the type (" + type + ")"); + } + } + + /** + * 输出结果的类型 + * + * @param type 输出结果的类型 + * @return String + */ + public String getJsonEncodeDescriptor(Type type) { + StringBuilder sb = new StringBuilder(); + defineJsonEncodeDescriptor(null, new ArrayList<>(), type, sb, "", null); + return sb.toString(); + } + + public String getJsonEncodeDescriptor(Type type, BiFunction func) { + StringBuilder sb = new StringBuilder(); + defineJsonEncodeDescriptor(null, new ArrayList<>(), type, sb, "", func); + return sb.toString(); + } + + protected String getJsonEncodeDescriptor( + Type parent, List list, Type type, BiFunction func) { + StringBuilder sb = new StringBuilder(); + defineJsonEncodeDescriptor(parent, list, type, sb, "", func); + return sb.toString(); + } + + protected void defineJsonEncodeDescriptor( + Type parent, + List list, + Type type, + StringBuilder sb, + String prefix, + BiFunction excludeFunc) { + Encodeable encoder = factory.loadEncoder(type); + boolean dot = sb.length() > 0; + if (encoder instanceof ObjectEncoder) { + if (sb.length() > 0) { + if (list.contains(parent + "" + defineTypeName(type))) { + return; + } + list.add(parent + "" + defineTypeName(type)); + sb.append(prefix) + .append("\"message ") + .append(defineTypeName(type)) + .append("\" : {\r\n"); + } else { + sb.append("{\r\n"); + } + EnMember[] ems = ((ObjectEncoder) encoder).getMembers(); + List members = new ArrayList<>(); + for (EnMember member : ems) { + if (excludeFunc != null && excludeFunc.apply(type, member)) { + continue; + } + members.add(member); + } + for (EnMember member : members) { + Type mtype = member.getEncoder().getType(); + if (!(mtype instanceof Class)) { + if (mtype instanceof ParameterizedType) { + final ParameterizedType pt = (ParameterizedType) mtype; + if (pt.getActualTypeArguments().length == 1 + && (pt.getActualTypeArguments()[0] instanceof Class)) { + defineJsonEncodeDescriptor(parent, list, mtype, sb, prefix + " ", excludeFunc); + } + } else if (mtype instanceof GenericArrayType) { + final GenericArrayType gt = (GenericArrayType) mtype; + if (!gt.getGenericComponentType().toString().startsWith("java") + && !gt.getGenericComponentType().toString().startsWith("class java") + && gt.getGenericComponentType().toString().indexOf('.') > 0) { + defineJsonEncodeDescriptor( + parent, list, gt.getGenericComponentType(), sb, prefix + " ", excludeFunc); + } + } + continue; + } + Class mclz = (Class) member.getEncoder().getType(); + if (!mclz.isArray() && !mclz.isEnum() && !mclz.getName().startsWith("java")) { + defineJsonEncodeDescriptor(parent, list, mclz, sb, prefix + " ", excludeFunc); + } else if (mclz.isArray() + && !mclz.getComponentType().getName().startsWith("java") + && !mclz.getComponentType().getName().equals("boolean") + && !mclz.getComponentType().getName().equals("byte") + && !mclz.getComponentType().getName().equals("char") + && !mclz.getComponentType().getName().equals("short") + && !mclz.getComponentType().getName().equals("int") + && !mclz.getComponentType().getName().equals("long") + && !mclz.getComponentType().getName().equals("float") + && !mclz.getComponentType().getName().equals("double")) { + defineJsonEncodeDescriptor(parent, list, mclz.getComponentType(), sb, prefix + " ", excludeFunc); + } + } + for (int i = 0; i < members.size(); i++) { + EnMember member = members.get(i); + try { + sb.append(prefix) + .append(" \"") + .append(ProtobufFactory.wireTypeString( + member.getEncoder().getType(), ((ProtobufFactory) factory).enumtostring)) + .append(" ") + .append(member.getAttribute().field()) + .append("\" : ") + .append(member.getPosition()) + .append(i == members.size() - 1 ? "\r\n" : ",\r\n"); + } catch (RuntimeException e) { + System.err.println("member = " + member); + throw e; + } + } + sb.append(prefix).append(dot ? "}," : "}").append("\r\n"); + } else if (encoder instanceof ProtobufArrayEncoder || encoder instanceof ProtobufCollectionEncoder) { + Type mtype = encoder instanceof ProtobufArrayEncoder + ? ((ProtobufArrayEncoder) encoder).getComponentType() + : ((ProtobufCollectionEncoder) encoder).getComponentType(); + if (!mtype.toString().startsWith("java") + && !mtype.toString().startsWith("class java") + && mtype.toString().indexOf('.') > 0) { + defineJsonEncodeDescriptor(parent, list, mtype, sb, prefix, excludeFunc); + } + } else if (sb.length() == 0) { + if (encoder instanceof SimpledCoder + || (encoder instanceof ProtobufArrayEncoder + && ((ProtobufArrayEncoder) encoder).getComponentEncoder() instanceof SimpledCoder) + || (encoder instanceof ProtobufCollectionEncoder + && ((ProtobufCollectionEncoder) encoder).getComponentEncoder() instanceof SimpledCoder)) { + sb.append(prefix).append("{\r\n"); + sb.append(prefix) + .append(" \"") + .append(ProtobufFactory.wireTypeString(type, ((ProtobufFactory) factory).enumtostring)) + .append(" 0\" : 0\r\n"); + sb.append(prefix).append(dot ? "}," : "}").append("\r\n"); + } else if (encoder instanceof MapEncoder) { + sb.append(prefix).append("{\r\n"); + sb.append(prefix) + .append(" \"") + .append(ProtobufFactory.wireTypeString(type, ((ProtobufFactory) factory).enumtostring)) + .append(" 0\" : 0\r\n"); + sb.append(prefix).append(dot ? "}," : "}").append("\r\n"); + } else { + throw new ConvertException("Not support the type (" + type + ")"); + } + } else { + throw new ConvertException("Not support the type (" + type + ")"); + } + } + + public String getProtoDescriptor(Type type) { + StringBuilder sb = new StringBuilder(); + Class clazz = TypeToken.typeToClass(type); + sb.append("//java ") + .append(clazz.isArray() ? (clazz.getComponentType().getName() + "[]") : clazz.getName()) + .append("\r\n\r\n"); + if (type instanceof Class) { + sb.append("option java_package = \"") + .append(clazz.getPackage().getName()) + .append("\";\r\n\r\n"); + } + sb.append("syntax = \"proto3\";\r\n\r\n"); + // defineProtoDescriptor(type, sb, ""); + defineProtoDescriptor(null, new ArrayList<>(), type, sb, "", null); + return sb.toString(); + } + + protected String defineProtoDescriptor( + Type parent, List list, Type type, BiFunction func) { + StringBuilder sb = new StringBuilder(); + defineProtoDescriptor(parent, list, type, sb, "", func); + return sb.toString(); + } + + protected void defineProtoDescriptor( + Type parent, + List list, + Type type, + StringBuilder sb, + String prefix, + BiFunction excludeFunc) { + Encodeable encoder = factory.loadEncoder(type); + if (encoder instanceof ObjectEncoder) { + if (list.contains(parent + "" + defineTypeName(type))) { + return; + } + list.add(parent + "" + defineTypeName(type)); + + List members = new ArrayList<>(); + EnMember[] ems = ((ObjectEncoder) encoder).getMembers(); + for (EnMember member : ems) { + if (excludeFunc != null && excludeFunc.apply(type, member)) { + continue; + } + members.add(member); + } + final List sblist = new ArrayList<>(); + for (EnMember member : members) { + Type mtype = member.getEncoder().getType(); + if (!(mtype instanceof Class)) { + if (mtype instanceof ParameterizedType) { + final ParameterizedType pt = (ParameterizedType) mtype; + if (pt.getActualTypeArguments().length == 1 + && (pt.getActualTypeArguments()[0] instanceof Class)) { + StringBuilder innersb = new StringBuilder(); + defineProtoDescriptor(parent, list, mtype, innersb, prefix, excludeFunc); + sblist.add(innersb); + } + } else if (mtype instanceof GenericArrayType) { + final GenericArrayType gt = (GenericArrayType) mtype; + if (!gt.getGenericComponentType().toString().startsWith("java") + && !gt.getGenericComponentType().toString().startsWith("class java") + && gt.getGenericComponentType().toString().indexOf('.') > 0) { + StringBuilder innersb = new StringBuilder(); + defineProtoDescriptor( + parent, list, gt.getGenericComponentType(), innersb, prefix, excludeFunc); + sblist.add(innersb); + } + } + continue; + } + Class mclz = (Class) member.getEncoder().getType(); + if (!mclz.isArray() && !mclz.isEnum() && !mclz.getName().startsWith("java")) { + StringBuilder innersb = new StringBuilder(); + defineProtoDescriptor(parent, list, mclz, innersb, prefix, excludeFunc); + sblist.add(innersb); + } else if (mclz.isArray() + && !mclz.getComponentType().getName().startsWith("java") + && !mclz.getComponentType().getName().equals("boolean") + && !mclz.getComponentType().getName().equals("byte") + && !mclz.getComponentType().getName().equals("char") + && !mclz.getComponentType().getName().equals("short") + && !mclz.getComponentType().getName().equals("int") + && !mclz.getComponentType().getName().equals("long") + && !mclz.getComponentType().getName().equals("float") + && !mclz.getComponentType().getName().equals("double")) { + StringBuilder innersb = new StringBuilder(); + defineProtoDescriptor(parent, list, mclz.getComponentType(), innersb, prefix, excludeFunc); + sblist.add(innersb); + } + } + for (StringBuilder sbitem : sblist) { + if (sbitem.length() < 1) { + continue; + } + sb.append(sbitem.toString().trim()).append("\r\n\r\n"); + } + sb.append(prefix).append("message ").append(defineTypeName(type)).append(" {\r\n"); + for (int i = 0; i < members.size(); i++) { + EnMember member = members.get(i); + try { + sb.append(prefix) + .append(" ") + .append(ProtobufFactory.wireTypeString( + member.getEncoder().getType(), ((ProtobufFactory) factory).enumtostring)) + .append(" ") + .append(member.getAttribute().field()) + .append(" = ") + .append(member.getPosition()) + .append(member.getComment().isEmpty() ? ";\r\n" : ("; //" + member.getComment() + " \r\n")); + } catch (RuntimeException e) { + System.err.println("member = " + member); + throw e; + } + } + sb.append(prefix).append("}").append("\r\n"); + } else if (encoder instanceof ProtobufArrayEncoder || encoder instanceof ProtobufCollectionEncoder) { + Type mtype = encoder instanceof ProtobufArrayEncoder + ? ((ProtobufArrayEncoder) encoder).getComponentType() + : ((ProtobufCollectionEncoder) encoder).getComponentType(); + if (!mtype.toString().startsWith("java") + && !mtype.toString().startsWith("class java") + && mtype.toString().indexOf('.') > 0) { + defineProtoDescriptor(parent, list, mtype, sb, prefix, excludeFunc); + } + } else { + throw new ConvertException("Not support the type (" + type + ")"); + } + } + + protected StringBuilder defineTypeName(Type type) { + StringBuilder sb = new StringBuilder(); + if (type instanceof Class) { + sb.append(((Class) type).getSimpleName().replace("[]", "_Array")); + } else if (type instanceof ParameterizedType) { + Type raw = ((ParameterizedType) type).getRawType(); + sb.append(((Class) raw).getSimpleName().replace("[]", "_Array")); + Type[] ts = ((ParameterizedType) type).getActualTypeArguments(); + if (ts != null) { + for (Type t : ts) { + if (t != null) { + sb.append('_').append(defineTypeName(t)); + } + } + } + } + return sb; + } + + // ------------------------------ convertFrom ----------------------------------------------------------- + @Override + public T convertFrom(final Type type, final byte[] bytes) { + if (bytes == null) { + return null; + } + return convertFrom(type, bytes, 0, bytes.length); + } + + @Override + @SuppressWarnings("unchecked") + public T convertFrom(final Type type, final byte[] bytes, final int offset, final int len) { + if (type == null) { + return null; + } + final ProtobufReader reader = new ProtobufReader(bytes, offset, len); + Decodeable decoder = this.lastConvertDecodeable; + if (decoder == null || decoder.getType() != type) { + decoder = factory.loadDecoder(type); + this.lastConvertDecodeable = decoder; + } + if (!(decoder instanceof ObjectDecoder) && !(decoder instanceof SimpledCoder)) { + throw new ConvertException(this.getClass().getSimpleName() + " not supported type(" + type + ")"); + } + T rs = (T) decoder.convertFrom(reader); + return rs; + } + + @SuppressWarnings("unchecked") + public T convertFrom(final Type type, final InputStream in) { + if (true) { + throw new ConvertException(this.getClass().getSimpleName() + " not supported convertFrom InputStream"); + } + if (type == null || in == null) { + return null; + } + Decodeable decoder = this.lastConvertDecodeable; + if (decoder == null || decoder.getType() != type) { + decoder = factory.loadDecoder(type); + this.lastConvertDecodeable = decoder; + } + if (!(decoder instanceof ObjectDecoder)) { + throw new ConvertException(this.getClass().getSimpleName() + " not supported type(" + type + ")"); + } + return (T) decoder.convertFrom(new ProtobufStreamReader(in)); + } + + @Override + @SuppressWarnings("unchecked") + public T convertFrom(final Type type, final ByteBuffer... buffers) { + if (true) { + throw new ConvertException(this.getClass().getSimpleName() + " not supported convertFrom ByteBuffer"); + } + if (type == null || buffers.length < 1) { + return null; + } + Decodeable decoder = this.lastConvertDecodeable; + if (decoder == null || decoder.getType() != type) { + decoder = factory.loadDecoder(type); + this.lastConvertDecodeable = decoder; + } + if (!(decoder instanceof ObjectDecoder)) { + throw new ConvertException(this.getClass().getSimpleName() + " not supported type(" + type + ")"); + } + return (T) decoder.convertFrom(new ProtobufByteBufferReader(buffers)); + } + + @Override + @SuppressWarnings("unchecked") + public T convertFrom(final Type type, final ProtobufReader reader) { + if (type == null) { + return null; + } + Decodeable decoder = this.lastConvertDecodeable; + if (decoder == null || decoder.getType() != type) { + decoder = factory.loadDecoder(type); + this.lastConvertDecodeable = decoder; + } + if (!(decoder instanceof ObjectDecoder)) { + throw new ConvertException(this.getClass().getSimpleName() + " not supported type(" + type + ")"); + } + T rs = (T) decoder.convertFrom(reader); + return rs; + } + + // ------------------------------ convertTo ----------------------------------------------------------- + @Override + public byte[] convertTo(final Type type, final Object value) { + if (value == null) { + final ProtobufWriter writer = pollWriter(); + writer.writeNull(); + byte[] result = writer.toArray(); + offerWriter(writer); + return result; + } + final Type t = type == null ? value.getClass() : type; + final ProtobufWriter writer = pollWriter(); + Encodeable encoder = this.lastConvertEncodeable; + if (encoder == null || encoder.getType() != t) { + encoder = factory.loadEncoder(t); + this.lastConvertEncodeable = encoder; + } + if (encoder.specifyable()) { + writer.specificObjectType(t); + } + if (!(encoder instanceof ObjectEncoder) && !(encoder instanceof SimpledCoder)) { + throw new ConvertException(this.getClass().getSimpleName() + " not supported type(" + t + ")"); + } + encoder.convertTo(writer, value); + byte[] result = writer.toArray(); + offerWriter(writer); + return result; + } + + public byte[] convertTo(final Object value, int tag, byte... appends) { + return convertTo(value.getClass(), value, tag, appends); + } + + public byte[] convertTo(final Type type, final Object value, int tag, byte... appends) { + if (type == null) { + return null; + } + final ProtobufWriter writer = pollWriter(); + Encodeable encoder = this.lastConvertEncodeable; + if (encoder == null || encoder.getType() != type) { + encoder = factory.loadEncoder(type); + this.lastConvertEncodeable = encoder; + } + if (encoder.specifyable()) { + writer.specificObjectType(type); + } + if (!(encoder instanceof ObjectEncoder) && !(encoder instanceof SimpledCoder)) { + throw new ConvertException(this.getClass().getSimpleName() + " not supported type(" + type + ")"); + } + encoder.convertTo(writer, value); + writer.writeUInt32(tag); + writer.writeUInt32(appends.length); + writer.writeTo(appends); + byte[] result = writer.toArray(); + offerWriter(writer); + return result; + } + + @Override + public byte[] convertToBytes(final Type type, final Object value) { + return convertTo(type, value); + } + + @Override + public void convertToBytes(final Type type, final Object value, final ConvertBytesHandler handler) { + final ProtobufWriter writer = pollWriter(); + if (value == null) { + writer.writeNull(); + } else { + final Type t = type == null ? value.getClass() : type; + Encodeable encoder = this.lastConvertEncodeable; + if (encoder == null || encoder.getType() != t) { + encoder = factory.loadEncoder(t); + this.lastConvertEncodeable = encoder; + } + if (encoder.specifyable()) { + writer.specificObjectType(t); + } + if (!(encoder instanceof ObjectEncoder) && !(encoder instanceof SimpledCoder)) { + throw new ConvertException(this.getClass().getSimpleName() + " not supported type(" + t + ")"); + } + encoder.convertTo(writer, value); + } + writer.completed(handler, writerConsumer); + } + + @Override + public void convertToBytes(final ByteArray array, final Type type, final Object value) { + Objects.requireNonNull(array); + final ProtobufWriter writer = configWrite(new ProtobufWriter(array) + .withFeatures(features) + .enumtostring(((ProtobufFactory) factory).enumtostring)); + if (value == null) { + writer.writeNull(); + } else { + final Type t = type == null ? value.getClass() : type; + Encodeable encoder = this.lastConvertEncodeable; + if (encoder == null || encoder.getType() != t) { + encoder = factory.loadEncoder(t); + this.lastConvertEncodeable = encoder; + } + if (encoder.specifyable()) { + writer.specificObjectType(t); + } + if (!(encoder instanceof ObjectEncoder) && !(encoder instanceof SimpledCoder)) { + throw new ConvertException(this.getClass().getSimpleName() + " not supported type(" + t + ")"); + } + encoder.convertTo(writer, value); + } + writer.directTo(array); + } + + public void convertTo(final OutputStream out, final Type type, final Object value) { + if (true) { + throw new ConvertException(this.getClass().getSimpleName() + " not supported convertTo OutputStream"); + } + ProtobufWriter writer = pollProtobufWriter(out); + if (value == null) { + writer.writeNull(); + } else { + final Type t = type == null ? value.getClass() : type; + Encodeable encoder = this.lastConvertEncodeable; + if (encoder == null || encoder.getType() != t) { + encoder = factory.loadEncoder(t); + this.lastConvertEncodeable = encoder; + } + if (encoder.specifyable()) { + writer.specificObjectType(t); + } + if (!(encoder instanceof ObjectEncoder)) { + throw new ConvertException(this.getClass().getSimpleName() + " not supported type(" + t + ")"); + } + encoder.convertTo(writer, value); + } + } + + @Override + public ByteBuffer[] convertTo(final Supplier supplier, final Type type, final Object value) { + // if (true) throw new ConvertException(this.getClass().getSimpleName() + " not supported convertTo + // ByteBuffer"); + Objects.requireNonNull(supplier); + ProtobufByteBufferWriter writer = pollProtobufWriter(supplier); + if (value == null) { + writer.writeNull(); + } else { + final Type t = type == null ? value.getClass() : type; + Encodeable encoder = this.lastConvertEncodeable; + if (encoder == null || encoder.getType() != t) { + encoder = factory.loadEncoder(t); + this.lastConvertEncodeable = encoder; + } + if (encoder.specifyable()) { + writer.specificObjectType(t); + } + if (!(encoder instanceof ObjectEncoder)) { + throw new ConvertException(this.getClass().getSimpleName() + " not supported type(" + t + ")"); + } + encoder.convertTo(writer, value); + } + return writer.toBuffers(); + } + + @Override + public void convertTo(final ProtobufWriter writer, final Type type, final Object value) { + if (value == null) { + writer.writeNull(); + return; + } + writer.initOffset = writer.count; + final Type t = type == null ? value.getClass() : type; + Encodeable encoder = this.lastConvertEncodeable; + if (encoder == null || encoder.getType() != t) { + encoder = factory.loadEncoder(t); + this.lastConvertEncodeable = encoder; + } + if (encoder.specifyable()) { + writer.specificObjectType(t); + } + encoder.convertTo(writer, value); + } + + public ProtobufWriter convertToWriter(final Type type, final Object value) { + if (value == null) { + return null; + } + final ProtobufWriter writer = pollWriter(); + final Type t = type == null ? value.getClass() : type; + Encodeable encoder = this.lastConvertEncodeable; + if (encoder == null || encoder.getType() != t) { + encoder = factory.loadEncoder(t); + this.lastConvertEncodeable = encoder; + } + if (encoder.specifyable()) { + writer.specificObjectType(t); + } + if (!(encoder instanceof ObjectEncoder)) { + throw new ConvertException(this.getClass().getSimpleName() + " not supported type(" + t + ")"); + } + encoder.convertTo(writer, value); + return writer; + } +} diff --git a/src/main/java/org/redkale/convert/proto/ProtobufEnumSimpledCoder.java b/src/main/java/org/redkale/convert/proto/ProtobufEnumSimpledCoder.java index c9bda7d40..970f951ea 100644 --- a/src/main/java/org/redkale/convert/proto/ProtobufEnumSimpledCoder.java +++ b/src/main/java/org/redkale/convert/proto/ProtobufEnumSimpledCoder.java @@ -1,71 +1,71 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package org.redkale.convert.proto; - -import java.lang.reflect.Method; -import java.util.*; -import org.redkale.convert.*; -import org.redkale.util.RedkaleClassLoader; - -/** - * 枚举 的SimpledCoder实现 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @param Reader输入的子类型 - * @param Writer输出的子类型 - * @param Enum的子类 - */ -public class ProtobufEnumSimpledCoder - extends SimpledCoder { - - private final Map values = new HashMap<>(); - - private final boolean enumtostring; - - public ProtobufEnumSimpledCoder(Class type, boolean enumtostring) { - this.type = type; - this.enumtostring = enumtostring; - try { - final Method method = type.getMethod("values"); - RedkaleClassLoader.putReflectionMethod(type.getName(), method); - for (E item : (E[]) method.invoke(null)) { - values.put(item.ordinal(), item); - } - } catch (Exception e) { - throw new ConvertException(e); - } - } - - @Override - public void convertTo(final W out, final E value) { - if (value == null) { - out.writeNull(); - } else if (enumtostring) { - out.writeSmallString(value.toString()); - } else { - ((ProtobufWriter) out).writeUInt32(value.ordinal()); - } - } - - @Override - @SuppressWarnings("unchecked") - public E convertFrom(final R in) { - if (enumtostring) { - String value = in.readSmallString(); - if (value == null) return null; - return (E) Enum.valueOf((Class) type, value); - } - int value = ((ProtobufReader) in).readRawVarint32(); - return values.get(value); - } - - @Override - public Class getType() { - return (Class) type; - } -} +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.proto; + +import java.lang.reflect.Method; +import java.util.*; +import org.redkale.convert.*; +import org.redkale.util.RedkaleClassLoader; + +/** + * 枚举 的SimpledCoder实现 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @param Reader输入的子类型 + * @param Writer输出的子类型 + * @param Enum的子类 + */ +public class ProtobufEnumSimpledCoder + extends SimpledCoder { + + private final Map values = new HashMap<>(); + + private final boolean enumtostring; + + public ProtobufEnumSimpledCoder(Class type, boolean enumtostring) { + this.type = type; + this.enumtostring = enumtostring; + try { + final Method method = type.getMethod("values"); + RedkaleClassLoader.putReflectionMethod(type.getName(), method); + for (E item : (E[]) method.invoke(null)) { + values.put(item.ordinal(), item); + } + } catch (Exception e) { + throw new ConvertException(e); + } + } + + @Override + public void convertTo(final W out, final E value) { + if (value == null) { + out.writeNull(); + } else if (enumtostring) { + out.writeSmallString(value.toString()); + } else { + ((ProtobufWriter) out).writeUInt32(value.ordinal()); + } + } + + @Override + @SuppressWarnings("unchecked") + public E convertFrom(final R in) { + if (enumtostring) { + String value = in.readSmallString(); + if (value == null) return null; + return (E) Enum.valueOf((Class) type, value); + } + int value = ((ProtobufReader) in).readRawVarint32(); + return values.get(value); + } + + @Override + public Class getType() { + return (Class) type; + } +} diff --git a/src/main/java/org/redkale/convert/proto/ProtobufFactory.java b/src/main/java/org/redkale/convert/proto/ProtobufFactory.java index baf747029..ac0007001 100644 --- a/src/main/java/org/redkale/convert/proto/ProtobufFactory.java +++ b/src/main/java/org/redkale/convert/proto/ProtobufFactory.java @@ -1,345 +1,345 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package org.redkale.convert.proto; - -import java.io.Serializable; -import java.lang.reflect.*; -import java.util.*; -import java.util.concurrent.atomic.*; -import java.util.stream.Stream; -import org.redkale.convert.*; -import org.redkale.util.AnyValue; -import org.redkale.util.AnyValueWriter; - -/** @author zhangjx */ -public class ProtobufFactory extends ConvertFactory { - - private static final ProtobufFactory instance = new ProtobufFactory( - null, - getSystemPropertyInt("redkale.convert.protobuf.tiny", "redkale.convert.tiny", true, Convert.FEATURE_TINY) - | getSystemPropertyInt( - "redkale.convert.protobuf.nullable", - "redkale.convert.nullable", - false, - Convert.FEATURE_NULLABLE), - Boolean.parseBoolean(System.getProperty("redkale.convert.protobuf.enumtostring", "true"))); - - static final Decodeable objectDecoder = instance.loadDecoder(Object.class); - - static final Encodeable objectEncoder = instance.loadEncoder(Object.class); - - protected final boolean enumtostring; - - protected boolean reversible = false; - - static { - instance.register(Serializable.class, objectDecoder); - instance.register(Serializable.class, objectEncoder); - - instance.register(AnyValue.class, instance.loadDecoder(AnyValueWriter.class)); - instance.register(AnyValue.class, instance.loadEncoder(AnyValueWriter.class)); - } - - @SuppressWarnings("OverridableMethodCallInConstructor") - private ProtobufFactory(ProtobufFactory parent, int features, boolean enumtostring) { - super(parent, features); - this.enumtostring = enumtostring; - if (parent == null) { // root - this.register(String[].class, this.createArrayDecoder(String[].class)); - this.register(String[].class, this.createArrayEncoder(String[].class)); - } - } - - public static ProtobufFactory root() { - return instance; - } - - @Override - public ProtobufFactory withFeatures(int features) { - return super.withFeatures(features); - } - - @Override - public ProtobufFactory addFeature(int feature) { - return super.addFeature(feature); - } - - @Override - public ProtobufFactory removeFeature(int feature) { - return super.removeFeature(feature); - } - - @Override - public ProtobufFactory withTinyFeature(boolean tiny) { - return super.withTinyFeature(tiny); - } - - @Override - public ProtobufFactory withNullableFeature(boolean nullable) { - return super.withNullableFeature(nullable); - } - - public static ProtobufFactory create() { - return new ProtobufFactory(null, instance.features, instance.enumtostring); - } - - @Override - protected SimpledCoder createEnumSimpledCoder(Class enumClass) { - return new ProtobufEnumSimpledCoder(enumClass, this.enumtostring); - } - - @Override - protected ObjectDecoder createObjectDecoder(Type type) { - return new ProtobufObjectDecoder(type); - } - - @Override - protected ObjectEncoder createObjectEncoder(Type type) { - return new ProtobufObjectEncoder(type); - } - - @Override - protected Decodeable createMapDecoder(Type type) { - return new ProtobufMapDecoder(this, type); - } - - @Override - protected Encodeable createMapEncoder(Type type) { - return new ProtobufMapEncoder(this, type); - } - - @Override - protected Decodeable createArrayDecoder(Type type) { - return new ProtobufArrayDecoder(this, type); - } - - @Override - protected Encodeable createArrayEncoder(Type type) { - return new ProtobufArrayEncoder(this, type); - } - - @Override - protected Decodeable createCollectionDecoder(Type type) { - return new ProtobufCollectionDecoder(this, type); - } - - @Override - protected Encodeable createCollectionEncoder(Type type) { - return new ProtobufCollectionEncoder(this, type); - } - - @Override - protected Decodeable createStreamDecoder(Type type) { - return new ProtobufStreamDecoder(this, type); - } - - @Override - protected Encodeable createStreamEncoder(Type type) { - return new ProtobufStreamEncoder(this, type); - } - - @Override - public final ProtobufConvert getConvert() { - if (convert == null) { - convert = new ProtobufConvert(this, features); - } - return (ProtobufConvert) convert; - } - - @Override - public ProtobufFactory createChild() { - return new ProtobufFactory(this, features, this.enumtostring); - } - - @Override - public ProtobufFactory createChild(int features) { - return new ProtobufFactory(this, features, this.enumtostring); - } - - @Override - public ConvertType getConvertType() { - return ConvertType.PROTOBUF; - } - - public ProtobufFactory reversible(boolean reversible) { - this.reversible = reversible; - return this; - } - - @Override - public boolean isReversible() { - return reversible; - } - - @Override - public boolean isFieldSort() { - return true; - } - - protected static Reader getItemReader( - boolean string, boolean simple, Reader in, DeMember member, boolean enumtostring, boolean first) { - if (string) { - if (member == null || first) { - return in; - } - ProtobufReader reader = (ProtobufReader) in; - int tag = reader.readTag(); - if (tag != member.getTag()) { - reader.backTag(tag); - return null; - } - return in; - } else { - ProtobufReader reader = (ProtobufReader) in; - if (!first && member != null) { - int tag = reader.readTag(); - if (tag != member.getTag()) { - reader.backTag(tag); - return null; - } - } - byte[] bs = reader.readByteArray(); - return new ProtobufReader(bs); - } - } - - public static int getTag(String fieldName, Type fieldType, int fieldPos, boolean enumtostring) { - int wiretype = ProtobufFactory.wireType(fieldType, enumtostring); - return (fieldPos << 3 | wiretype); - } - - public static int getTag(DeMember member, boolean enumtostring) { - int wiretype = ProtobufFactory.wireType(member.getAttribute().type(), enumtostring); - return (member.getPosition() << 3 | wiretype); - } - - public static int wireType(Type javaType, boolean enumtostring) { - if (javaType == double.class || javaType == Double.class) { - return 1; - } - if (javaType == float.class || javaType == Float.class) { - return 5; - } - if (javaType == boolean.class || javaType == Boolean.class) { - return 0; - } - if (javaType instanceof Class) { - Class javaClazz = (Class) javaType; - if (javaClazz.isEnum()) { - return enumtostring ? 2 : 0; - } - if (javaClazz.isPrimitive() || Number.class.isAssignableFrom(javaClazz)) { - return 0; - } - } - return 2; - } - - public static String wireTypeString(Type javaType, boolean enumtostring) { - if (javaType == double.class || javaType == Double.class) { - return "double"; - } - if (javaType == long.class || javaType == Long.class) { - return "sint64"; - } - if (javaType == float.class || javaType == Float.class) { - return "float"; - } - if (javaType == int.class || javaType == Integer.class) { - return "sint32"; - } - if (javaType == short.class || javaType == Short.class) { - return "sint32"; - } - if (javaType == char.class || javaType == Character.class) { - return "sint32"; - } - if (javaType == byte.class || javaType == Byte.class) { - return "sint32"; - } - if (javaType == boolean.class || javaType == Boolean.class) { - return "bool"; - } - if (javaType == AtomicLong.class) { - return "sint64"; - } - if (javaType == AtomicInteger.class) { - return "sint32"; - } - if (javaType == AtomicBoolean.class) { - return "bool"; - } - - if (javaType == double[].class || javaType == Double[].class) { - return "repeated double"; - } - if (javaType == long[].class || javaType == Long[].class) { - return "repeated sint64"; - } - if (javaType == float[].class || javaType == Float[].class) { - return "repeated float"; - } - if (javaType == int[].class || javaType == Integer[].class) { - return "repeated sint32"; - } - if (javaType == short[].class || javaType == Short[].class) { - return "repeated sint32"; - } - if (javaType == char[].class || javaType == Character[].class) { - return "repeated sint32"; - } - if (javaType == byte[].class || javaType == Byte[].class) { - return "bytes"; - } - if (javaType == boolean[].class || javaType == Boolean[].class) { - return "repeated bool"; - } - if (javaType == AtomicLong[].class) { - return "repeated sint64"; - } - if (javaType == AtomicInteger[].class) { - return "repeated sint32"; - } - if (javaType == AtomicBoolean[].class) { - return "repeated bool"; - } - - if (javaType == java.util.Properties.class) { - return "map"; - } - if (javaType instanceof Class) { - Class javaClazz = (Class) javaType; - if (javaClazz.isArray()) { - return "repeated " + wireTypeString(javaClazz.getComponentType(), enumtostring); - } - if (javaClazz.isEnum()) { - return enumtostring ? "string" : javaClazz.getSimpleName(); - } - if (CharSequence.class.isAssignableFrom(javaClazz)) { - return "string"; - } - return javaClazz == Object.class ? "Any" : javaClazz.getSimpleName(); - } else if (javaType instanceof ParameterizedType) { // Collection、Stream、Map 必须是泛型 - final ParameterizedType pt = (ParameterizedType) javaType; - final Class rawType = (Class) pt.getRawType(); - if (Map.class.isAssignableFrom(rawType)) { - Type keyType = pt.getActualTypeArguments()[0]; - Type valueType = pt.getActualTypeArguments()[1]; - return "map<" + wireTypeString(keyType, enumtostring) + "," + wireTypeString(valueType, enumtostring) - + ">"; - } else if (Collection.class.isAssignableFrom(rawType) - || Stream.class.isAssignableFrom(rawType) - || rawType.isArray()) { - return "repeated " + wireTypeString(pt.getActualTypeArguments()[0], enumtostring); - } else if (pt.getActualTypeArguments().length == 1 && (pt.getActualTypeArguments()[0] instanceof Class)) { - return rawType.getSimpleName() + "_" + ((Class) pt.getActualTypeArguments()[0]).getSimpleName(); - } - } else if (javaType instanceof GenericArrayType) { - return "repeated " + wireTypeString(((GenericArrayType) javaType).getGenericComponentType(), enumtostring); - } - throw new UnsupportedOperationException("ProtobufConvert not supported type(" + javaType + ")"); - } -} +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.proto; + +import java.io.Serializable; +import java.lang.reflect.*; +import java.util.*; +import java.util.concurrent.atomic.*; +import java.util.stream.Stream; +import org.redkale.convert.*; +import org.redkale.util.AnyValue; +import org.redkale.util.AnyValueWriter; + +/** @author zhangjx */ +public class ProtobufFactory extends ConvertFactory { + + private static final ProtobufFactory instance = new ProtobufFactory( + null, + getSystemPropertyInt("redkale.convert.protobuf.tiny", "redkale.convert.tiny", true, Convert.FEATURE_TINY) + | getSystemPropertyInt( + "redkale.convert.protobuf.nullable", + "redkale.convert.nullable", + false, + Convert.FEATURE_NULLABLE), + Boolean.parseBoolean(System.getProperty("redkale.convert.protobuf.enumtostring", "true"))); + + static final Decodeable objectDecoder = instance.loadDecoder(Object.class); + + static final Encodeable objectEncoder = instance.loadEncoder(Object.class); + + protected final boolean enumtostring; + + protected boolean reversible = false; + + static { + instance.register(Serializable.class, objectDecoder); + instance.register(Serializable.class, objectEncoder); + + instance.register(AnyValue.class, instance.loadDecoder(AnyValueWriter.class)); + instance.register(AnyValue.class, instance.loadEncoder(AnyValueWriter.class)); + } + + @SuppressWarnings("OverridableMethodCallInConstructor") + private ProtobufFactory(ProtobufFactory parent, int features, boolean enumtostring) { + super(parent, features); + this.enumtostring = enumtostring; + if (parent == null) { // root + this.register(String[].class, this.createArrayDecoder(String[].class)); + this.register(String[].class, this.createArrayEncoder(String[].class)); + } + } + + public static ProtobufFactory root() { + return instance; + } + + @Override + public ProtobufFactory withFeatures(int features) { + return super.withFeatures(features); + } + + @Override + public ProtobufFactory addFeature(int feature) { + return super.addFeature(feature); + } + + @Override + public ProtobufFactory removeFeature(int feature) { + return super.removeFeature(feature); + } + + @Override + public ProtobufFactory withTinyFeature(boolean tiny) { + return super.withTinyFeature(tiny); + } + + @Override + public ProtobufFactory withNullableFeature(boolean nullable) { + return super.withNullableFeature(nullable); + } + + public static ProtobufFactory create() { + return new ProtobufFactory(null, instance.features, instance.enumtostring); + } + + @Override + protected SimpledCoder createEnumSimpledCoder(Class enumClass) { + return new ProtobufEnumSimpledCoder(enumClass, this.enumtostring); + } + + @Override + protected ObjectDecoder createObjectDecoder(Type type) { + return new ProtobufObjectDecoder(type); + } + + @Override + protected ObjectEncoder createObjectEncoder(Type type) { + return new ProtobufObjectEncoder(type); + } + + @Override + protected Decodeable createMapDecoder(Type type) { + return new ProtobufMapDecoder(this, type); + } + + @Override + protected Encodeable createMapEncoder(Type type) { + return new ProtobufMapEncoder(this, type); + } + + @Override + protected Decodeable createArrayDecoder(Type type) { + return new ProtobufArrayDecoder(this, type); + } + + @Override + protected Encodeable createArrayEncoder(Type type) { + return new ProtobufArrayEncoder(this, type); + } + + @Override + protected Decodeable createCollectionDecoder(Type type) { + return new ProtobufCollectionDecoder(this, type); + } + + @Override + protected Encodeable createCollectionEncoder(Type type) { + return new ProtobufCollectionEncoder(this, type); + } + + @Override + protected Decodeable createStreamDecoder(Type type) { + return new ProtobufStreamDecoder(this, type); + } + + @Override + protected Encodeable createStreamEncoder(Type type) { + return new ProtobufStreamEncoder(this, type); + } + + @Override + public final ProtobufConvert getConvert() { + if (convert == null) { + convert = new ProtobufConvert(this, features); + } + return (ProtobufConvert) convert; + } + + @Override + public ProtobufFactory createChild() { + return new ProtobufFactory(this, features, this.enumtostring); + } + + @Override + public ProtobufFactory createChild(int features) { + return new ProtobufFactory(this, features, this.enumtostring); + } + + @Override + public ConvertType getConvertType() { + return ConvertType.PROTOBUF; + } + + public ProtobufFactory reversible(boolean reversible) { + this.reversible = reversible; + return this; + } + + @Override + public boolean isReversible() { + return reversible; + } + + @Override + public boolean isFieldSort() { + return true; + } + + protected static Reader getItemReader( + boolean string, boolean simple, Reader in, DeMember member, boolean enumtostring, boolean first) { + if (string) { + if (member == null || first) { + return in; + } + ProtobufReader reader = (ProtobufReader) in; + int tag = reader.readTag(); + if (tag != member.getTag()) { + reader.backTag(tag); + return null; + } + return in; + } else { + ProtobufReader reader = (ProtobufReader) in; + if (!first && member != null) { + int tag = reader.readTag(); + if (tag != member.getTag()) { + reader.backTag(tag); + return null; + } + } + byte[] bs = reader.readByteArray(); + return new ProtobufReader(bs); + } + } + + public static int getTag(String fieldName, Type fieldType, int fieldPos, boolean enumtostring) { + int wiretype = ProtobufFactory.wireType(fieldType, enumtostring); + return (fieldPos << 3 | wiretype); + } + + public static int getTag(DeMember member, boolean enumtostring) { + int wiretype = ProtobufFactory.wireType(member.getAttribute().type(), enumtostring); + return (member.getPosition() << 3 | wiretype); + } + + public static int wireType(Type javaType, boolean enumtostring) { + if (javaType == double.class || javaType == Double.class) { + return 1; + } + if (javaType == float.class || javaType == Float.class) { + return 5; + } + if (javaType == boolean.class || javaType == Boolean.class) { + return 0; + } + if (javaType instanceof Class) { + Class javaClazz = (Class) javaType; + if (javaClazz.isEnum()) { + return enumtostring ? 2 : 0; + } + if (javaClazz.isPrimitive() || Number.class.isAssignableFrom(javaClazz)) { + return 0; + } + } + return 2; + } + + public static String wireTypeString(Type javaType, boolean enumtostring) { + if (javaType == double.class || javaType == Double.class) { + return "double"; + } + if (javaType == long.class || javaType == Long.class) { + return "sint64"; + } + if (javaType == float.class || javaType == Float.class) { + return "float"; + } + if (javaType == int.class || javaType == Integer.class) { + return "sint32"; + } + if (javaType == short.class || javaType == Short.class) { + return "sint32"; + } + if (javaType == char.class || javaType == Character.class) { + return "sint32"; + } + if (javaType == byte.class || javaType == Byte.class) { + return "sint32"; + } + if (javaType == boolean.class || javaType == Boolean.class) { + return "bool"; + } + if (javaType == AtomicLong.class) { + return "sint64"; + } + if (javaType == AtomicInteger.class) { + return "sint32"; + } + if (javaType == AtomicBoolean.class) { + return "bool"; + } + + if (javaType == double[].class || javaType == Double[].class) { + return "repeated double"; + } + if (javaType == long[].class || javaType == Long[].class) { + return "repeated sint64"; + } + if (javaType == float[].class || javaType == Float[].class) { + return "repeated float"; + } + if (javaType == int[].class || javaType == Integer[].class) { + return "repeated sint32"; + } + if (javaType == short[].class || javaType == Short[].class) { + return "repeated sint32"; + } + if (javaType == char[].class || javaType == Character[].class) { + return "repeated sint32"; + } + if (javaType == byte[].class || javaType == Byte[].class) { + return "bytes"; + } + if (javaType == boolean[].class || javaType == Boolean[].class) { + return "repeated bool"; + } + if (javaType == AtomicLong[].class) { + return "repeated sint64"; + } + if (javaType == AtomicInteger[].class) { + return "repeated sint32"; + } + if (javaType == AtomicBoolean[].class) { + return "repeated bool"; + } + + if (javaType == java.util.Properties.class) { + return "map"; + } + if (javaType instanceof Class) { + Class javaClazz = (Class) javaType; + if (javaClazz.isArray()) { + return "repeated " + wireTypeString(javaClazz.getComponentType(), enumtostring); + } + if (javaClazz.isEnum()) { + return enumtostring ? "string" : javaClazz.getSimpleName(); + } + if (CharSequence.class.isAssignableFrom(javaClazz)) { + return "string"; + } + return javaClazz == Object.class ? "Any" : javaClazz.getSimpleName(); + } else if (javaType instanceof ParameterizedType) { // Collection、Stream、Map 必须是泛型 + final ParameterizedType pt = (ParameterizedType) javaType; + final Class rawType = (Class) pt.getRawType(); + if (Map.class.isAssignableFrom(rawType)) { + Type keyType = pt.getActualTypeArguments()[0]; + Type valueType = pt.getActualTypeArguments()[1]; + return "map<" + wireTypeString(keyType, enumtostring) + "," + wireTypeString(valueType, enumtostring) + + ">"; + } else if (Collection.class.isAssignableFrom(rawType) + || Stream.class.isAssignableFrom(rawType) + || rawType.isArray()) { + return "repeated " + wireTypeString(pt.getActualTypeArguments()[0], enumtostring); + } else if (pt.getActualTypeArguments().length == 1 && (pt.getActualTypeArguments()[0] instanceof Class)) { + return rawType.getSimpleName() + "_" + ((Class) pt.getActualTypeArguments()[0]).getSimpleName(); + } + } else if (javaType instanceof GenericArrayType) { + return "repeated " + wireTypeString(((GenericArrayType) javaType).getGenericComponentType(), enumtostring); + } + throw new UnsupportedOperationException("ProtobufConvert not supported type(" + javaType + ")"); + } +} diff --git a/src/main/java/org/redkale/convert/proto/ProtobufMapDecoder.java b/src/main/java/org/redkale/convert/proto/ProtobufMapDecoder.java index acbaa0dc1..860af725e 100644 --- a/src/main/java/org/redkale/convert/proto/ProtobufMapDecoder.java +++ b/src/main/java/org/redkale/convert/proto/ProtobufMapDecoder.java @@ -1,52 +1,52 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package org.redkale.convert.proto; - -import java.lang.reflect.Type; -import org.redkale.convert.*; - -/** - * @author zhangjx - * @param K - * @param V - */ -public class ProtobufMapDecoder extends MapDecoder { - - private final boolean enumtostring; - - public ProtobufMapDecoder(ConvertFactory factory, Type type) { - super(factory, type); - this.enumtostring = ((ProtobufFactory) factory).enumtostring; - } - - @Override - protected Reader getEntryReader(Reader in, DeMember member, boolean first) { - ProtobufReader reader = (ProtobufReader) in; - if (!first && member != null) { - int tag = reader.readTag(); - if (tag != member.getTag()) { - reader.backTag(tag); - return null; - } - } - byte[] bs = reader.readByteArray(); - return new ProtobufReader(bs); - } - - @Override - protected K readKeyMember(Reader in, DeMember member, Decodeable decoder, boolean first) { - ProtobufReader reader = (ProtobufReader) in; - reader.readTag(); - return decoder.convertFrom(in); - } - - @Override - protected V readValueMember(Reader in, DeMember member, Decodeable decoder, boolean first) { - ProtobufReader reader = (ProtobufReader) in; - reader.readTag(); - return decoder.convertFrom(in); - } -} +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.proto; + +import java.lang.reflect.Type; +import org.redkale.convert.*; + +/** + * @author zhangjx + * @param K + * @param V + */ +public class ProtobufMapDecoder extends MapDecoder { + + private final boolean enumtostring; + + public ProtobufMapDecoder(ConvertFactory factory, Type type) { + super(factory, type); + this.enumtostring = ((ProtobufFactory) factory).enumtostring; + } + + @Override + protected Reader getEntryReader(Reader in, DeMember member, boolean first) { + ProtobufReader reader = (ProtobufReader) in; + if (!first && member != null) { + int tag = reader.readTag(); + if (tag != member.getTag()) { + reader.backTag(tag); + return null; + } + } + byte[] bs = reader.readByteArray(); + return new ProtobufReader(bs); + } + + @Override + protected K readKeyMember(Reader in, DeMember member, Decodeable decoder, boolean first) { + ProtobufReader reader = (ProtobufReader) in; + reader.readTag(); + return decoder.convertFrom(in); + } + + @Override + protected V readValueMember(Reader in, DeMember member, Decodeable decoder, boolean first) { + ProtobufReader reader = (ProtobufReader) in; + reader.readTag(); + return decoder.convertFrom(in); + } +} diff --git a/src/main/java/org/redkale/convert/proto/ProtobufMapEncoder.java b/src/main/java/org/redkale/convert/proto/ProtobufMapEncoder.java index cfa8d1e0d..3846a8cd5 100644 --- a/src/main/java/org/redkale/convert/proto/ProtobufMapEncoder.java +++ b/src/main/java/org/redkale/convert/proto/ProtobufMapEncoder.java @@ -1,37 +1,37 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package org.redkale.convert.proto; - -import java.lang.reflect.Type; -import org.redkale.convert.*; - -/** - * @author zhangjx - * @param K - * @param V - */ -public class ProtobufMapEncoder extends MapEncoder { - - private final boolean enumtostring; - - public ProtobufMapEncoder(ConvertFactory factory, Type type) { - super(factory, type); - this.enumtostring = ((ProtobufFactory) factory).enumtostring; - } - - @Override - protected void writeMemberValue(Writer out, EnMember member, K key, V value, boolean first) { - ProtobufWriter tmp = new ProtobufWriter().configFieldFunc(out); - if (member != null) out.writeFieldName(member); - tmp.writeUInt32(1 << 3 | ProtobufFactory.wireType(keyEncoder.getType(), enumtostring)); - keyEncoder.convertTo(tmp, key); - tmp.writeUInt32(2 << 3 | ProtobufFactory.wireType(valueEncoder.getType(), enumtostring)); - valueEncoder.convertTo(tmp, value); - int length = tmp.count(); - ((ProtobufWriter) out).writeUInt32(length); - ((ProtobufWriter) out).writeTo(tmp.toArray()); - } -} +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.proto; + +import java.lang.reflect.Type; +import org.redkale.convert.*; + +/** + * @author zhangjx + * @param K + * @param V + */ +public class ProtobufMapEncoder extends MapEncoder { + + private final boolean enumtostring; + + public ProtobufMapEncoder(ConvertFactory factory, Type type) { + super(factory, type); + this.enumtostring = ((ProtobufFactory) factory).enumtostring; + } + + @Override + protected void writeMemberValue(Writer out, EnMember member, K key, V value, boolean first) { + ProtobufWriter tmp = new ProtobufWriter().configFieldFunc(out); + if (member != null) out.writeFieldName(member); + tmp.writeUInt32(1 << 3 | ProtobufFactory.wireType(keyEncoder.getType(), enumtostring)); + keyEncoder.convertTo(tmp, key); + tmp.writeUInt32(2 << 3 | ProtobufFactory.wireType(valueEncoder.getType(), enumtostring)); + valueEncoder.convertTo(tmp, value); + int length = tmp.count(); + ((ProtobufWriter) out).writeUInt32(length); + ((ProtobufWriter) out).writeTo(tmp.toArray()); + } +} diff --git a/src/main/java/org/redkale/convert/proto/ProtobufObjectDecoder.java b/src/main/java/org/redkale/convert/proto/ProtobufObjectDecoder.java index 88c2c591f..9d477cc59 100644 --- a/src/main/java/org/redkale/convert/proto/ProtobufObjectDecoder.java +++ b/src/main/java/org/redkale/convert/proto/ProtobufObjectDecoder.java @@ -1,81 +1,81 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package org.redkale.convert.proto; - -import java.lang.reflect.Type; -import org.redkale.convert.*; -import org.redkale.util.Attribute; -import org.redkale.util.Utility; - -/** - * @author zhangjx - * @param T - */ -public class ProtobufObjectDecoder extends ObjectDecoder { - - protected ProtobufObjectDecoder(Type type) { - super(type); - } - - @Override - protected void initForEachDeMember(ConvertFactory factory, DeMember member) { - if (member.getIndex() < 1) { - throw new ConvertException(Utility.orElse(member.getField(), member.getMethod()) + " not found @" - + ConvertColumn.class.getSimpleName() + ".index"); - } - Attribute attr = member.getAttribute(); - setTag( - member, - ProtobufFactory.getTag( - attr.field(), - attr.genericType(), - member.getPosition(), - ((ProtobufFactory) factory).enumtostring)); - } - - @Override - protected ProtobufReader objectReader(ProtobufReader in) { - if (in.position() > in.initoffset) return new ProtobufReader(in.readByteArray()); - return in; - } - - @Override - protected boolean hasNext(ProtobufReader in, boolean first) { - return in.hasNext(); - } - - @Override - protected Object readDeMemberValue(ProtobufReader in, DeMember member, boolean first) { - Decodeable decoder = member.getDecoder(); - if (decoder instanceof ProtobufArrayDecoder) { - return ((ProtobufArrayDecoder) decoder).convertFrom(in, member); - } else if (decoder instanceof ProtobufCollectionDecoder) { - return ((ProtobufCollectionDecoder) decoder).convertFrom(in, member); - } else if (decoder instanceof ProtobufStreamDecoder) { - return ((ProtobufStreamDecoder) decoder).convertFrom(in, member); - } else if (decoder instanceof ProtobufMapDecoder) { - return ((ProtobufMapDecoder) decoder).convertFrom(in, member); - } else { - return member.read(in); - } - } - - @Override - protected void readDeMemberValue(ProtobufReader in, DeMember member, T result, boolean first) { - Decodeable decoder = member.getDecoder(); - if (decoder instanceof ProtobufArrayDecoder) { - member.getAttribute().set(result, ((ProtobufArrayDecoder) decoder).convertFrom(in, member)); - } else if (decoder instanceof ProtobufCollectionDecoder) { - member.getAttribute().set(result, ((ProtobufCollectionDecoder) decoder).convertFrom(in, member)); - } else if (decoder instanceof ProtobufStreamDecoder) { - member.getAttribute().set(result, ((ProtobufStreamDecoder) decoder).convertFrom(in, member)); - } else if (decoder instanceof ProtobufMapDecoder) { - member.getAttribute().set(result, ((ProtobufMapDecoder) decoder).convertFrom(in, member)); - } else { - member.read(in, result); - } - } -} +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.proto; + +import java.lang.reflect.Type; +import org.redkale.convert.*; +import org.redkale.util.Attribute; +import org.redkale.util.Utility; + +/** + * @author zhangjx + * @param T + */ +public class ProtobufObjectDecoder extends ObjectDecoder { + + protected ProtobufObjectDecoder(Type type) { + super(type); + } + + @Override + protected void initForEachDeMember(ConvertFactory factory, DeMember member) { + if (member.getIndex() < 1) { + throw new ConvertException(Utility.orElse(member.getField(), member.getMethod()) + " not found @" + + ConvertColumn.class.getSimpleName() + ".index"); + } + Attribute attr = member.getAttribute(); + setTag( + member, + ProtobufFactory.getTag( + attr.field(), + attr.genericType(), + member.getPosition(), + ((ProtobufFactory) factory).enumtostring)); + } + + @Override + protected ProtobufReader objectReader(ProtobufReader in) { + if (in.position() > in.initoffset) return new ProtobufReader(in.readByteArray()); + return in; + } + + @Override + protected boolean hasNext(ProtobufReader in, boolean first) { + return in.hasNext(); + } + + @Override + protected Object readDeMemberValue(ProtobufReader in, DeMember member, boolean first) { + Decodeable decoder = member.getDecoder(); + if (decoder instanceof ProtobufArrayDecoder) { + return ((ProtobufArrayDecoder) decoder).convertFrom(in, member); + } else if (decoder instanceof ProtobufCollectionDecoder) { + return ((ProtobufCollectionDecoder) decoder).convertFrom(in, member); + } else if (decoder instanceof ProtobufStreamDecoder) { + return ((ProtobufStreamDecoder) decoder).convertFrom(in, member); + } else if (decoder instanceof ProtobufMapDecoder) { + return ((ProtobufMapDecoder) decoder).convertFrom(in, member); + } else { + return member.read(in); + } + } + + @Override + protected void readDeMemberValue(ProtobufReader in, DeMember member, T result, boolean first) { + Decodeable decoder = member.getDecoder(); + if (decoder instanceof ProtobufArrayDecoder) { + member.getAttribute().set(result, ((ProtobufArrayDecoder) decoder).convertFrom(in, member)); + } else if (decoder instanceof ProtobufCollectionDecoder) { + member.getAttribute().set(result, ((ProtobufCollectionDecoder) decoder).convertFrom(in, member)); + } else if (decoder instanceof ProtobufStreamDecoder) { + member.getAttribute().set(result, ((ProtobufStreamDecoder) decoder).convertFrom(in, member)); + } else if (decoder instanceof ProtobufMapDecoder) { + member.getAttribute().set(result, ((ProtobufMapDecoder) decoder).convertFrom(in, member)); + } else { + member.read(in, result); + } + } +} diff --git a/src/main/java/org/redkale/convert/proto/ProtobufObjectEncoder.java b/src/main/java/org/redkale/convert/proto/ProtobufObjectEncoder.java index 7e7f4d79d..6d484066d 100644 --- a/src/main/java/org/redkale/convert/proto/ProtobufObjectEncoder.java +++ b/src/main/java/org/redkale/convert/proto/ProtobufObjectEncoder.java @@ -1,43 +1,43 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package org.redkale.convert.proto; - -import java.lang.reflect.Type; -import org.redkale.convert.*; -import org.redkale.util.Attribute; -import org.redkale.util.Utility; - -/** @author zhangjx */ -public class ProtobufObjectEncoder extends ObjectEncoder { - - protected ProtobufObjectEncoder(Type type) { - super(type); - } - - @Override - protected void initForEachEnMember(ConvertFactory factory, EnMember member) { - if (member.getIndex() < 1) { - throw new ConvertException(Utility.orElse(member.getField(), member.getMethod()) + " not found @" - + ConvertColumn.class.getSimpleName() + ".index"); - } - Attribute attr = member.getAttribute(); - setTag( - member, - ProtobufFactory.getTag( - attr.field(), - attr.genericType(), - member.getPosition(), - ((ProtobufFactory) factory).enumtostring)); - } - - @Override - protected ProtobufWriter objectWriter(ProtobufWriter out, T value) { - if (out.count() > out.initOffset) { - return new ProtobufWriter(out, out.getFeatures()).configFieldFunc(out); - } - return out; - } -} +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.proto; + +import java.lang.reflect.Type; +import org.redkale.convert.*; +import org.redkale.util.Attribute; +import org.redkale.util.Utility; + +/** @author zhangjx */ +public class ProtobufObjectEncoder extends ObjectEncoder { + + protected ProtobufObjectEncoder(Type type) { + super(type); + } + + @Override + protected void initForEachEnMember(ConvertFactory factory, EnMember member) { + if (member.getIndex() < 1) { + throw new ConvertException(Utility.orElse(member.getField(), member.getMethod()) + " not found @" + + ConvertColumn.class.getSimpleName() + ".index"); + } + Attribute attr = member.getAttribute(); + setTag( + member, + ProtobufFactory.getTag( + attr.field(), + attr.genericType(), + member.getPosition(), + ((ProtobufFactory) factory).enumtostring)); + } + + @Override + protected ProtobufWriter objectWriter(ProtobufWriter out, T value) { + if (out.count() > out.initOffset) { + return new ProtobufWriter(out, out.getFeatures()).configFieldFunc(out); + } + return out; + } +} diff --git a/src/main/java/org/redkale/convert/proto/ProtobufReader.java b/src/main/java/org/redkale/convert/proto/ProtobufReader.java index 58f1d0e64..84509c622 100644 --- a/src/main/java/org/redkale/convert/proto/ProtobufReader.java +++ b/src/main/java/org/redkale/convert/proto/ProtobufReader.java @@ -1,449 +1,449 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package org.redkale.convert.proto; - -import java.lang.reflect.Type; -import java.nio.charset.StandardCharsets; -import java.util.*; -import java.util.concurrent.atomic.*; -import org.redkale.convert.*; -import org.redkale.util.ObjectPool; - -/** @author zhangjx */ -public class ProtobufReader extends Reader { - - protected int position = -1; - - protected int initoffset; - - private byte[] content; - - protected int cachetag = Integer.MIN_VALUE; - - protected boolean enumtostring; - - public static ObjectPool createPool(int max) { - return ObjectPool.createSafePool(max, (Object... params) -> new ProtobufReader(), null, (t) -> t.recycle()); - } - - public ProtobufReader() {} - - public ProtobufReader(byte[] bytes) { - setBytes(bytes, 0, bytes.length); - } - - public ProtobufReader(byte[] bytes, int start, int len) { - setBytes(bytes, start, len); - } - - public ProtobufReader enumtostring(boolean enumtostring) { - this.enumtostring = enumtostring; - return this; - } - - @Override - public void prepare(byte[] bytes) { - setBytes(bytes); - } - - public final void setBytes(byte[] bytes) { - if (bytes == null) { - this.position = 0; - this.initoffset = 0; - } else { - setBytes(bytes, 0, bytes.length); - } - } - - public final void setBytes(byte[] bytes, int start, int len) { - if (bytes == null) { - this.position = 0; - this.initoffset = 0; - } else { - this.content = bytes; - this.position = start - 1; - this.initoffset = this.position; - } - } - - protected boolean recycle() { - this.position = -1; - this.initoffset = -1; - this.content = null; - return true; - } - - public ProtobufReader clear() { - this.recycle(); - return this; - } - - public byte[] remainBytes() { - if (this.position >= this.content.length) { - return new byte[0]; - } - return Arrays.copyOfRange(this.content, this.position + 1, this.content.length); - } - - /** 跳过属性的值 */ - @Override - @SuppressWarnings("unchecked") - public final void skipValue() { - int tag = readTag(); - if (tag == 0) { - return; - } - switch (tag & 0x7) { - case 0: - readRawVarint32(); - break; - case 1: - readRawLittleEndian64(); - break; - case 2: - readByteArray(); - break; - case 5: - readRawLittleEndian32(); - break; - } - } - - @Override - public final String readObjectB(final Class clazz) { - return (this.position + 1) < this.content.length ? "" : null; - } - - @Override - public final void readObjectE(final Class clazz) { - // do nothing - } - - @Override - public final int readMapB(DeMember member, byte[] typevals, Decodeable keyDecoder, Decodeable valueDecoder) { - return Reader.SIGN_NOLENGTH; - } - - @Override - public final void readMapE() { - // do nothing - } - - /** - * 判断下一个非空白字符是否为[ - * - * @param member DeMember - * @param typevals byte[] - * @param componentDecoder Decodeable - * @return SIGN_NOLENGTH 或 SIGN_NULL - */ - @Override - public final int readArrayB(DeMember member, byte[] typevals, Decodeable componentDecoder) { - if (member == null || componentDecoder == null) { - return Reader.SIGN_NOLENBUTBYTES; - } - Type type = componentDecoder.getType(); - if (!(type instanceof Class)) { - return Reader.SIGN_NOLENBUTBYTES; - } - Class clazz = (Class) type; - if (clazz.isPrimitive() - || clazz == Boolean.class - || clazz == Byte.class - || clazz == Short.class - || clazz == Character.class - || clazz == Integer.class - || clazz == Float.class - || clazz == Long.class - || clazz == Double.class - || clazz == AtomicInteger.class - || clazz == AtomicLong.class) { - return Reader.SIGN_NOLENBUTBYTES; - } - return Reader.SIGN_NOLENGTH; - } - - @Override - public final void readArrayE() { - // do nothing - } - - /** 判断下一个非空白字节是否: */ - @Override - public final void readBlank() { - // do nothing - } - - @Override - public final int position() { - return this.position; - } - - @Override - public final int readMemberContentLength(DeMember member, Decodeable decoder) { - if (member == null && decoder == null) { - return -1; // 为byte[] - } - if (member != null) { - if (member.getDecoder() instanceof ProtobufArrayDecoder) { - ProtobufArrayDecoder pdecoder = (ProtobufArrayDecoder) member.getDecoder(); - if (pdecoder.simple) { - return readRawVarint32(); - } - } else if (member.getDecoder() instanceof ProtobufCollectionDecoder) { - ProtobufCollectionDecoder pdecoder = (ProtobufCollectionDecoder) member.getDecoder(); - if (pdecoder.simple) { - return readRawVarint32(); - } - } else if (member.getDecoder() instanceof ProtobufStreamDecoder) { - ProtobufStreamDecoder pdecoder = (ProtobufStreamDecoder) member.getDecoder(); - if (pdecoder.simple) { - return readRawVarint32(); - } - } - return -1; - } - return readRawVarint32(); // readUInt32 - } - - @Override - public final DeMember readFieldName( - final DeMember[] members, Map memberFieldMap, Map memberTagMap) { - int tag = readTag(); - for (DeMember member : members) { - if (member.getTag() == tag) { - return member; - } - } - backTag(tag); - return null; - } - - // ------------------------------------------------------------ - @Override - public final boolean readBoolean() { - return readRawVarint64() != 0; - } - - @Override - public final byte readByte() { - return (byte) readInt(); - } - - @Override - public final char readChar() { - return (char) readInt(); - } - - @Override - public final short readShort() { - return (short) readInt(); - } - - @Override - public final int readInt() { // readSInt32 - int n = readRawVarint32(); - return (n >>> 1) ^ -(n & 1); - } - - @Override - public final long readLong() { // readSInt64 - long n = readRawVarint64(); - return (n >>> 1) ^ -(n & 1); - } - - @Override - public final float readFloat() { - return Float.intBitsToFloat(readRawLittleEndian32()); - } - - @Override - public final double readDouble() { - return Double.longBitsToDouble(readRawLittleEndian64()); - } - - @Override - public final String readClassName() { - return ""; - } - - @Override - public final String readSmallString() { - return readString(); - } - - @Override - public final String readString() { - return new String(readByteArray(), StandardCharsets.UTF_8); - } - - protected final int readTag() { - if (cachetag != Integer.MIN_VALUE) { - int tag = cachetag; - cachetag = Integer.MIN_VALUE; - return tag; - } - return readRawVarint32(); - } - - protected final void backTag(int tag) { - this.cachetag = tag; - } - - protected byte currentByte() { - return this.content[this.position]; - } - - /** - * 判断对象是否存在下一个属性或者数组是否存在下一个元素 - * - * @param startPosition 起始位置 - * @param contentLength 内容大小, 不确定的传-1 - * @return 是否存在 - */ - @Override - public boolean hasNext(int startPosition, int contentLength) { - // ("-------------: " + startPosition + ", " + contentLength + ", " + this.position); - if (startPosition >= 0 && contentLength >= 0) { - return (this.position) < (startPosition + contentLength); - } - return (this.position + 1) < this.content.length; - } - - @Override - public byte[] readByteArray() { - final int size = readRawVarint32(); - byte[] bs = new byte[size]; - System.arraycopy(content, position + 1, bs, 0, size); - position += size; - return bs; - } - - protected int readRawVarint32() { // readUInt32 - fastpath: - { - int tempPos = this.position; - if ((tempPos + 1) == content.length) { - break fastpath; - } - - int x; - if ((x = content[++tempPos]) >= 0) { - this.position = tempPos; - return x; - } else if (content.length - (tempPos + 1) < 9) { - break fastpath; - } else if ((x ^= (content[++tempPos] << 7)) < 0) { - x ^= (~0 << 7); - } else if ((x ^= (content[++tempPos] << 14)) >= 0) { - x ^= (~0 << 7) ^ (~0 << 14); - } else if ((x ^= (content[++tempPos] << 21)) < 0) { - x ^= (~0 << 7) ^ (~0 << 14) ^ (~0 << 21); - } else { - int y = content[++tempPos]; - x ^= y << 28; - x ^= (~0 << 7) ^ (~0 << 14) ^ (~0 << 21) ^ (~0 << 28); - if (y < 0 - && content[++tempPos] < 0 - && content[++tempPos] < 0 - && content[++tempPos] < 0 - && content[++tempPos] < 0 - && content[++tempPos] < 0) { - break fastpath; // Will throw malformedVarint() - } - } - this.position = tempPos; - return x; - } - return (int) readRawVarint64SlowPath(); - } - - protected long readRawVarint64() { - fastpath: - { - int tempPos = this.position; - if ((tempPos + 1) == content.length) { - break fastpath; - } - - long x; - int y; - if ((y = content[++tempPos]) >= 0) { - this.position = tempPos; - return y; - } else if (content.length - (tempPos + 1) < 9) { - break fastpath; - } else if ((y ^= (content[++tempPos] << 7)) < 0) { - x = y ^ (~0 << 7); - } else if ((y ^= (content[++tempPos] << 14)) >= 0) { - x = y ^ ((~0 << 7) ^ (~0 << 14)); - } else if ((y ^= (content[++tempPos] << 21)) < 0) { - x = y ^ ((~0 << 7) ^ (~0 << 14) ^ (~0 << 21)); - } else if ((x = y ^ ((long) content[++tempPos] << 28)) >= 0L) { - x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28); - } else if ((x ^= ((long) content[++tempPos] << 35)) < 0L) { - x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35); - } else if ((x ^= ((long) content[++tempPos] << 42)) >= 0L) { - x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35) ^ (~0L << 42); - } else if ((x ^= ((long) content[++tempPos] << 49)) < 0L) { - x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35) ^ (~0L << 42) ^ (~0L << 49); - } else { - x ^= ((long) content[++tempPos] << 56); - x ^= (~0L << 7) - ^ (~0L << 14) - ^ (~0L << 21) - ^ (~0L << 28) - ^ (~0L << 35) - ^ (~0L << 42) - ^ (~0L << 49) - ^ (~0L << 56); - if (x < 0L) { - if (content[++tempPos] < 0L) { - break fastpath; // Will throw malformedVarint() - } - } - } - this.position = tempPos; - return x; - } - return readRawVarint64SlowPath(); - } - - protected long readRawVarint64SlowPath() { - long result = 0; - for (int shift = 0; shift < 64; shift += 7) { - final byte b = content[++this.position]; - result |= (long) (b & 0x7F) << shift; - if ((b & 0x80) == 0) { - return result; - } - } - throw new ConvertException("readRawVarint64SlowPath error"); - } - - protected int readRawLittleEndian32() { - return ((content[++this.position] & 0xff) - | ((content[++this.position] & 0xff) << 8) - | ((content[++this.position] & 0xff) << 16) - | ((content[++this.position] & 0xff) << 24)); - } - - protected long readRawLittleEndian64() { - return ((content[++this.position] & 0xffL) - | ((content[++this.position] & 0xffL) << 8) - | ((content[++this.position] & 0xffL) << 16) - | ((content[++this.position] & 0xffL) << 24) - | ((content[++this.position] & 0xffL) << 32) - | ((content[++this.position] & 0xffL) << 40) - | ((content[++this.position] & 0xffL) << 48) - | ((content[++this.position] & 0xffL) << 56)); - } - - @Override - public ValueType readType() { - throw new UnsupportedOperationException("Not supported yet."); - } -} +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.proto; + +import java.lang.reflect.Type; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.concurrent.atomic.*; +import org.redkale.convert.*; +import org.redkale.util.ObjectPool; + +/** @author zhangjx */ +public class ProtobufReader extends Reader { + + protected int position = -1; + + protected int initoffset; + + private byte[] content; + + protected int cachetag = Integer.MIN_VALUE; + + protected boolean enumtostring; + + public static ObjectPool createPool(int max) { + return ObjectPool.createSafePool(max, (Object... params) -> new ProtobufReader(), null, (t) -> t.recycle()); + } + + public ProtobufReader() {} + + public ProtobufReader(byte[] bytes) { + setBytes(bytes, 0, bytes.length); + } + + public ProtobufReader(byte[] bytes, int start, int len) { + setBytes(bytes, start, len); + } + + public ProtobufReader enumtostring(boolean enumtostring) { + this.enumtostring = enumtostring; + return this; + } + + @Override + public void prepare(byte[] bytes) { + setBytes(bytes); + } + + public final void setBytes(byte[] bytes) { + if (bytes == null) { + this.position = 0; + this.initoffset = 0; + } else { + setBytes(bytes, 0, bytes.length); + } + } + + public final void setBytes(byte[] bytes, int start, int len) { + if (bytes == null) { + this.position = 0; + this.initoffset = 0; + } else { + this.content = bytes; + this.position = start - 1; + this.initoffset = this.position; + } + } + + protected boolean recycle() { + this.position = -1; + this.initoffset = -1; + this.content = null; + return true; + } + + public ProtobufReader clear() { + this.recycle(); + return this; + } + + public byte[] remainBytes() { + if (this.position >= this.content.length) { + return new byte[0]; + } + return Arrays.copyOfRange(this.content, this.position + 1, this.content.length); + } + + /** 跳过属性的值 */ + @Override + @SuppressWarnings("unchecked") + public final void skipValue() { + int tag = readTag(); + if (tag == 0) { + return; + } + switch (tag & 0x7) { + case 0: + readRawVarint32(); + break; + case 1: + readRawLittleEndian64(); + break; + case 2: + readByteArray(); + break; + case 5: + readRawLittleEndian32(); + break; + } + } + + @Override + public final String readObjectB(final Class clazz) { + return (this.position + 1) < this.content.length ? "" : null; + } + + @Override + public final void readObjectE(final Class clazz) { + // do nothing + } + + @Override + public final int readMapB(DeMember member, byte[] typevals, Decodeable keyDecoder, Decodeable valueDecoder) { + return Reader.SIGN_NOLENGTH; + } + + @Override + public final void readMapE() { + // do nothing + } + + /** + * 判断下一个非空白字符是否为[ + * + * @param member DeMember + * @param typevals byte[] + * @param componentDecoder Decodeable + * @return SIGN_NOLENGTH 或 SIGN_NULL + */ + @Override + public final int readArrayB(DeMember member, byte[] typevals, Decodeable componentDecoder) { + if (member == null || componentDecoder == null) { + return Reader.SIGN_NOLENBUTBYTES; + } + Type type = componentDecoder.getType(); + if (!(type instanceof Class)) { + return Reader.SIGN_NOLENBUTBYTES; + } + Class clazz = (Class) type; + if (clazz.isPrimitive() + || clazz == Boolean.class + || clazz == Byte.class + || clazz == Short.class + || clazz == Character.class + || clazz == Integer.class + || clazz == Float.class + || clazz == Long.class + || clazz == Double.class + || clazz == AtomicInteger.class + || clazz == AtomicLong.class) { + return Reader.SIGN_NOLENBUTBYTES; + } + return Reader.SIGN_NOLENGTH; + } + + @Override + public final void readArrayE() { + // do nothing + } + + /** 判断下一个非空白字节是否: */ + @Override + public final void readBlank() { + // do nothing + } + + @Override + public final int position() { + return this.position; + } + + @Override + public final int readMemberContentLength(DeMember member, Decodeable decoder) { + if (member == null && decoder == null) { + return -1; // 为byte[] + } + if (member != null) { + if (member.getDecoder() instanceof ProtobufArrayDecoder) { + ProtobufArrayDecoder pdecoder = (ProtobufArrayDecoder) member.getDecoder(); + if (pdecoder.simple) { + return readRawVarint32(); + } + } else if (member.getDecoder() instanceof ProtobufCollectionDecoder) { + ProtobufCollectionDecoder pdecoder = (ProtobufCollectionDecoder) member.getDecoder(); + if (pdecoder.simple) { + return readRawVarint32(); + } + } else if (member.getDecoder() instanceof ProtobufStreamDecoder) { + ProtobufStreamDecoder pdecoder = (ProtobufStreamDecoder) member.getDecoder(); + if (pdecoder.simple) { + return readRawVarint32(); + } + } + return -1; + } + return readRawVarint32(); // readUInt32 + } + + @Override + public final DeMember readFieldName( + final DeMember[] members, Map memberFieldMap, Map memberTagMap) { + int tag = readTag(); + for (DeMember member : members) { + if (member.getTag() == tag) { + return member; + } + } + backTag(tag); + return null; + } + + // ------------------------------------------------------------ + @Override + public final boolean readBoolean() { + return readRawVarint64() != 0; + } + + @Override + public final byte readByte() { + return (byte) readInt(); + } + + @Override + public final char readChar() { + return (char) readInt(); + } + + @Override + public final short readShort() { + return (short) readInt(); + } + + @Override + public final int readInt() { // readSInt32 + int n = readRawVarint32(); + return (n >>> 1) ^ -(n & 1); + } + + @Override + public final long readLong() { // readSInt64 + long n = readRawVarint64(); + return (n >>> 1) ^ -(n & 1); + } + + @Override + public final float readFloat() { + return Float.intBitsToFloat(readRawLittleEndian32()); + } + + @Override + public final double readDouble() { + return Double.longBitsToDouble(readRawLittleEndian64()); + } + + @Override + public final String readClassName() { + return ""; + } + + @Override + public final String readSmallString() { + return readString(); + } + + @Override + public final String readString() { + return new String(readByteArray(), StandardCharsets.UTF_8); + } + + protected final int readTag() { + if (cachetag != Integer.MIN_VALUE) { + int tag = cachetag; + cachetag = Integer.MIN_VALUE; + return tag; + } + return readRawVarint32(); + } + + protected final void backTag(int tag) { + this.cachetag = tag; + } + + protected byte currentByte() { + return this.content[this.position]; + } + + /** + * 判断对象是否存在下一个属性或者数组是否存在下一个元素 + * + * @param startPosition 起始位置 + * @param contentLength 内容大小, 不确定的传-1 + * @return 是否存在 + */ + @Override + public boolean hasNext(int startPosition, int contentLength) { + // ("-------------: " + startPosition + ", " + contentLength + ", " + this.position); + if (startPosition >= 0 && contentLength >= 0) { + return (this.position) < (startPosition + contentLength); + } + return (this.position + 1) < this.content.length; + } + + @Override + public byte[] readByteArray() { + final int size = readRawVarint32(); + byte[] bs = new byte[size]; + System.arraycopy(content, position + 1, bs, 0, size); + position += size; + return bs; + } + + protected int readRawVarint32() { // readUInt32 + fastpath: + { + int tempPos = this.position; + if ((tempPos + 1) == content.length) { + break fastpath; + } + + int x; + if ((x = content[++tempPos]) >= 0) { + this.position = tempPos; + return x; + } else if (content.length - (tempPos + 1) < 9) { + break fastpath; + } else if ((x ^= (content[++tempPos] << 7)) < 0) { + x ^= (~0 << 7); + } else if ((x ^= (content[++tempPos] << 14)) >= 0) { + x ^= (~0 << 7) ^ (~0 << 14); + } else if ((x ^= (content[++tempPos] << 21)) < 0) { + x ^= (~0 << 7) ^ (~0 << 14) ^ (~0 << 21); + } else { + int y = content[++tempPos]; + x ^= y << 28; + x ^= (~0 << 7) ^ (~0 << 14) ^ (~0 << 21) ^ (~0 << 28); + if (y < 0 + && content[++tempPos] < 0 + && content[++tempPos] < 0 + && content[++tempPos] < 0 + && content[++tempPos] < 0 + && content[++tempPos] < 0) { + break fastpath; // Will throw malformedVarint() + } + } + this.position = tempPos; + return x; + } + return (int) readRawVarint64SlowPath(); + } + + protected long readRawVarint64() { + fastpath: + { + int tempPos = this.position; + if ((tempPos + 1) == content.length) { + break fastpath; + } + + long x; + int y; + if ((y = content[++tempPos]) >= 0) { + this.position = tempPos; + return y; + } else if (content.length - (tempPos + 1) < 9) { + break fastpath; + } else if ((y ^= (content[++tempPos] << 7)) < 0) { + x = y ^ (~0 << 7); + } else if ((y ^= (content[++tempPos] << 14)) >= 0) { + x = y ^ ((~0 << 7) ^ (~0 << 14)); + } else if ((y ^= (content[++tempPos] << 21)) < 0) { + x = y ^ ((~0 << 7) ^ (~0 << 14) ^ (~0 << 21)); + } else if ((x = y ^ ((long) content[++tempPos] << 28)) >= 0L) { + x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28); + } else if ((x ^= ((long) content[++tempPos] << 35)) < 0L) { + x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35); + } else if ((x ^= ((long) content[++tempPos] << 42)) >= 0L) { + x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35) ^ (~0L << 42); + } else if ((x ^= ((long) content[++tempPos] << 49)) < 0L) { + x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35) ^ (~0L << 42) ^ (~0L << 49); + } else { + x ^= ((long) content[++tempPos] << 56); + x ^= (~0L << 7) + ^ (~0L << 14) + ^ (~0L << 21) + ^ (~0L << 28) + ^ (~0L << 35) + ^ (~0L << 42) + ^ (~0L << 49) + ^ (~0L << 56); + if (x < 0L) { + if (content[++tempPos] < 0L) { + break fastpath; // Will throw malformedVarint() + } + } + } + this.position = tempPos; + return x; + } + return readRawVarint64SlowPath(); + } + + protected long readRawVarint64SlowPath() { + long result = 0; + for (int shift = 0; shift < 64; shift += 7) { + final byte b = content[++this.position]; + result |= (long) (b & 0x7F) << shift; + if ((b & 0x80) == 0) { + return result; + } + } + throw new ConvertException("readRawVarint64SlowPath error"); + } + + protected int readRawLittleEndian32() { + return ((content[++this.position] & 0xff) + | ((content[++this.position] & 0xff) << 8) + | ((content[++this.position] & 0xff) << 16) + | ((content[++this.position] & 0xff) << 24)); + } + + protected long readRawLittleEndian64() { + return ((content[++this.position] & 0xffL) + | ((content[++this.position] & 0xffL) << 8) + | ((content[++this.position] & 0xffL) << 16) + | ((content[++this.position] & 0xffL) << 24) + | ((content[++this.position] & 0xffL) << 32) + | ((content[++this.position] & 0xffL) << 40) + | ((content[++this.position] & 0xffL) << 48) + | ((content[++this.position] & 0xffL) << 56)); + } + + @Override + public ValueType readType() { + throw new UnsupportedOperationException("Not supported yet."); + } +} diff --git a/src/main/java/org/redkale/convert/proto/ProtobufStreamDecoder.java b/src/main/java/org/redkale/convert/proto/ProtobufStreamDecoder.java index ade0a1032..98023111e 100644 --- a/src/main/java/org/redkale/convert/proto/ProtobufStreamDecoder.java +++ b/src/main/java/org/redkale/convert/proto/ProtobufStreamDecoder.java @@ -1,45 +1,45 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package org.redkale.convert.proto; - -import java.lang.reflect.Type; -import java.util.concurrent.atomic.*; -import org.redkale.convert.*; - -/** - * @author zhangjx - * @param 泛型 - */ -public class ProtobufStreamDecoder extends StreamDecoder { - - protected final boolean simple; - - private final boolean string; - - private final boolean enumtostring; - - public ProtobufStreamDecoder(ConvertFactory factory, Type type) { - super(factory, type); - this.enumtostring = ((ProtobufFactory) factory).enumtostring; - Type comtype = this.getComponentType(); - this.string = String.class == comtype; - this.simple = Boolean.class == comtype - || Short.class == comtype - || Character.class == comtype - || Integer.class == comtype - || Float.class == comtype - || Long.class == comtype - || Double.class == comtype - || AtomicInteger.class == comtype - || AtomicLong.class == comtype; - } - - @Override - protected Reader getItemReader(Reader in, DeMember member, boolean first) { - if (simple) return in; - return ProtobufFactory.getItemReader(string, simple, in, member, enumtostring, first); - } -} +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.proto; + +import java.lang.reflect.Type; +import java.util.concurrent.atomic.*; +import org.redkale.convert.*; + +/** + * @author zhangjx + * @param 泛型 + */ +public class ProtobufStreamDecoder extends StreamDecoder { + + protected final boolean simple; + + private final boolean string; + + private final boolean enumtostring; + + public ProtobufStreamDecoder(ConvertFactory factory, Type type) { + super(factory, type); + this.enumtostring = ((ProtobufFactory) factory).enumtostring; + Type comtype = this.getComponentType(); + this.string = String.class == comtype; + this.simple = Boolean.class == comtype + || Short.class == comtype + || Character.class == comtype + || Integer.class == comtype + || Float.class == comtype + || Long.class == comtype + || Double.class == comtype + || AtomicInteger.class == comtype + || AtomicLong.class == comtype; + } + + @Override + protected Reader getItemReader(Reader in, DeMember member, boolean first) { + if (simple) return in; + return ProtobufFactory.getItemReader(string, simple, in, member, enumtostring, first); + } +} diff --git a/src/main/java/org/redkale/convert/proto/ProtobufStreamEncoder.java b/src/main/java/org/redkale/convert/proto/ProtobufStreamEncoder.java index 815638fea..37f5be337 100644 --- a/src/main/java/org/redkale/convert/proto/ProtobufStreamEncoder.java +++ b/src/main/java/org/redkale/convert/proto/ProtobufStreamEncoder.java @@ -1,55 +1,55 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package org.redkale.convert.proto; - -import java.lang.reflect.Type; -import java.util.concurrent.atomic.*; -import org.redkale.convert.*; - -/** - * @author zhangjx - * @param T - */ -public class ProtobufStreamEncoder extends StreamEncoder { - - protected final boolean simple; - - public ProtobufStreamEncoder(ConvertFactory factory, Type type) { - super(factory, type); - Type comtype = this.getComponentType(); - this.simple = Boolean.class == comtype - || Short.class == comtype - || Character.class == comtype - || Integer.class == comtype - || Float.class == comtype - || Long.class == comtype - || Double.class == comtype - || AtomicInteger.class == comtype - || AtomicLong.class == comtype; - } - - @Override - protected void writeMemberValue(Writer out, EnMember member, Object item, boolean first) { - if (simple) { - if (item == null) { - ((ProtobufWriter) out).writeUInt32(0); - } else { - componentEncoder.convertTo(out, item); - } - return; - } - if (member != null) out.writeFieldName(member); - if (item instanceof CharSequence) { - componentEncoder.convertTo(out, item); - } else { - ProtobufWriter tmp = new ProtobufWriter().configFieldFunc(out); - componentEncoder.convertTo(tmp, item); - int length = tmp.count(); - ((ProtobufWriter) out).writeUInt32(length); - ((ProtobufWriter) out).writeTo(tmp.toArray()); - } - } -} +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.proto; + +import java.lang.reflect.Type; +import java.util.concurrent.atomic.*; +import org.redkale.convert.*; + +/** + * @author zhangjx + * @param T + */ +public class ProtobufStreamEncoder extends StreamEncoder { + + protected final boolean simple; + + public ProtobufStreamEncoder(ConvertFactory factory, Type type) { + super(factory, type); + Type comtype = this.getComponentType(); + this.simple = Boolean.class == comtype + || Short.class == comtype + || Character.class == comtype + || Integer.class == comtype + || Float.class == comtype + || Long.class == comtype + || Double.class == comtype + || AtomicInteger.class == comtype + || AtomicLong.class == comtype; + } + + @Override + protected void writeMemberValue(Writer out, EnMember member, Object item, boolean first) { + if (simple) { + if (item == null) { + ((ProtobufWriter) out).writeUInt32(0); + } else { + componentEncoder.convertTo(out, item); + } + return; + } + if (member != null) out.writeFieldName(member); + if (item instanceof CharSequence) { + componentEncoder.convertTo(out, item); + } else { + ProtobufWriter tmp = new ProtobufWriter().configFieldFunc(out); + componentEncoder.convertTo(tmp, item); + int length = tmp.count(); + ((ProtobufWriter) out).writeUInt32(length); + ((ProtobufWriter) out).writeTo(tmp.toArray()); + } + } +} diff --git a/src/main/java/org/redkale/convert/proto/ProtobufStreamReader.java b/src/main/java/org/redkale/convert/proto/ProtobufStreamReader.java index 37f3a8a9e..001fb8166 100644 --- a/src/main/java/org/redkale/convert/proto/ProtobufStreamReader.java +++ b/src/main/java/org/redkale/convert/proto/ProtobufStreamReader.java @@ -1,50 +1,50 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package org.redkale.convert.proto; - -import java.io.*; -import org.redkale.convert.*; - -/** - * 详情见: https://redkale.org - * - * @author zhangjx - */ -class ProtobufStreamReader extends ProtobufByteBufferReader { - - private InputStream in; - - private byte currByte; - - protected ProtobufStreamReader(InputStream in) { - super(); - this.in = in; - } - - @Override - protected boolean recycle() { - super.recycle(); // this.position 初始化值为-1 - this.in = null; - this.currByte = 0; - return false; - } - - @Override - public byte nextByte() { - try { - byte b = (currByte = (byte) in.read()); - this.position++; - return b; - } catch (IOException e) { - throw new ConvertException(e); - } - } - - @Override - protected byte currentByte() { - return currByte; - } -} +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.proto; + +import java.io.*; +import org.redkale.convert.*; + +/** + * 详情见: https://redkale.org + * + * @author zhangjx + */ +class ProtobufStreamReader extends ProtobufByteBufferReader { + + private InputStream in; + + private byte currByte; + + protected ProtobufStreamReader(InputStream in) { + super(); + this.in = in; + } + + @Override + protected boolean recycle() { + super.recycle(); // this.position 初始化值为-1 + this.in = null; + this.currByte = 0; + return false; + } + + @Override + public byte nextByte() { + try { + byte b = (currByte = (byte) in.read()); + this.position++; + return b; + } catch (IOException e) { + throw new ConvertException(e); + } + } + + @Override + protected byte currentByte() { + return currByte; + } +} diff --git a/src/main/java/org/redkale/convert/proto/ProtobufStreamWriter.java b/src/main/java/org/redkale/convert/proto/ProtobufStreamWriter.java index 38392c33b..00e15758c 100644 --- a/src/main/java/org/redkale/convert/proto/ProtobufStreamWriter.java +++ b/src/main/java/org/redkale/convert/proto/ProtobufStreamWriter.java @@ -1,49 +1,49 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package org.redkale.convert.proto; - -import java.io.*; -import org.redkale.convert.ConvertException; - -/** - * 详情见: https://redkale.org - * - * @author zhangjx - */ -class ProtobufStreamWriter extends ProtobufByteBufferWriter { - - private OutputStream out; - - protected ProtobufStreamWriter(int features, boolean enumtostring, OutputStream out) { - super(features, enumtostring, null); - this.out = out; - } - - @Override - protected boolean recycle() { - super.recycle(); - this.out = null; - return false; - } - - @Override - public void writeTo(final byte[] chs, final int start, final int len) { - try { - out.write(chs, start, len); - } catch (IOException e) { - throw new ConvertException(e); - } - } - - @Override - public void writeTo(final byte ch) { - try { - out.write((byte) ch); - } catch (IOException e) { - throw new ConvertException(e); - } - } -} +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.proto; + +import java.io.*; +import org.redkale.convert.ConvertException; + +/** + * 详情见: https://redkale.org + * + * @author zhangjx + */ +class ProtobufStreamWriter extends ProtobufByteBufferWriter { + + private OutputStream out; + + protected ProtobufStreamWriter(int features, boolean enumtostring, OutputStream out) { + super(features, enumtostring, null); + this.out = out; + } + + @Override + protected boolean recycle() { + super.recycle(); + this.out = null; + return false; + } + + @Override + public void writeTo(final byte[] chs, final int start, final int len) { + try { + out.write(chs, start, len); + } catch (IOException e) { + throw new ConvertException(e); + } + } + + @Override + public void writeTo(final byte ch) { + try { + out.write((byte) ch); + } catch (IOException e) { + throw new ConvertException(e); + } + } +} diff --git a/src/main/java/org/redkale/convert/proto/ProtobufWriter.java b/src/main/java/org/redkale/convert/proto/ProtobufWriter.java index 15e6a0b4d..1203da693 100644 --- a/src/main/java/org/redkale/convert/proto/ProtobufWriter.java +++ b/src/main/java/org/redkale/convert/proto/ProtobufWriter.java @@ -1,645 +1,645 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package org.redkale.convert.proto; - -import java.lang.reflect.Type; -import java.nio.ByteBuffer; -import java.util.*; -import java.util.concurrent.atomic.*; -import java.util.function.Consumer; -import java.util.stream.Stream; -import org.redkale.convert.*; -import org.redkale.util.*; - -/** @author zhangjx */ -public class ProtobufWriter extends Writer implements ByteTuple { - - private static final int DEFAULT_SIZE = Integer.getInteger( - "redkale.convert.protobuf.writer.buffer.defsize", - Integer.getInteger("redkale.convert.writer.buffer.defsize", 1024)); - - private byte[] content; - - protected int count; - - protected int initOffset; - - protected boolean enumtostring; - - protected ProtobufWriter parent; - - public static ObjectPool createPool(int max) { - return ObjectPool.createSafePool(max, (Object... params) -> new ProtobufWriter(), null, (t) -> t.recycle()); - } - - protected ProtobufWriter(ProtobufWriter parent, int features) { - this(); - this.parent = parent; - this.features = features; - if (parent != null) { - this.enumtostring = parent.enumtostring; - } - } - - protected ProtobufWriter(byte[] bs) { - this.content = bs; - } - - public ProtobufWriter withFeatures(int features) { - super.withFeatures(features); - return this; - } - - protected ProtobufWriter configFieldFunc(Writer writer) { - if (writer == null) { - return this; - } - ProtobufWriter out = (ProtobufWriter) writer; - this.mapFieldFunc = out.mapFieldFunc; - this.objFieldFunc = out.objFieldFunc; - this.objExtFunc = out.objExtFunc; - this.features = out.features; - this.enumtostring = out.enumtostring; - return this; - } - - public ProtobufWriter() { - this(DEFAULT_SIZE); - } - - public ProtobufWriter(int size) { - this.content = new byte[size > 128 ? size : 128]; - } - - public ProtobufWriter(ByteArray array) { - this.content = array.content(); - this.count = array.length(); - } - - @Override - protected boolean recycle() { - super.recycle(); - this.count = 0; - this.initOffset = 0; - if (this.content.length > DEFAULT_SIZE) { - this.content = new byte[DEFAULT_SIZE]; - } - return true; - } - - @Override - public byte[] content() { - return content; - } - - @Override - public int offset() { - return initOffset; - } - - @Override - public int length() { - return count; - } - - /** - * 将本对象的内容引用复制给array - * - * @param array ByteArray - */ - public void directTo(ByteArray array) { - array.directFrom(content, count); - } - - public ByteBuffer[] toBuffers() { - return new ByteBuffer[] {ByteBuffer.wrap(content, 0, count)}; - } - - /** - * 直接获取全部数据, 实际数据需要根据count长度来截取 - * - * @return byte[] - */ - public byte[] directBytes() { - return content; - } - - public void completed(ConvertBytesHandler handler, Consumer callback) { - handler.completed(content, 0, count, callback, this); - } - - public byte[] toArray() { - if (count == content.length) { - return content; - } - byte[] newdata = new byte[count]; - System.arraycopy(content, 0, newdata, 0, count); - return newdata; - } - - public ProtobufWriter enumtostring(boolean enumtostring) { - this.enumtostring = enumtostring; - return this; - } - - protected int expand(int len) { - int newcount = count + len; - if (newcount > content.length) { - byte[] newdata = new byte[Math.max(content.length * 3 / 2, newcount)]; - System.arraycopy(content, 0, newdata, 0, count); - this.content = newdata; - } - return 0; - } - - public void writeTo(final byte ch) { - expand(1); - content[count++] = ch; - } - - public final void writeTo(final byte... chs) { - writeTo(chs, 0, chs.length); - } - - public void writeTo(final byte[] chs, final int start, final int len) { - expand(len); - System.arraycopy(chs, start, content, count, len); - count += len; - } - - public ProtobufWriter clear() { - this.count = 0; - this.initOffset = 0; - return this; - } - - @Override - public String toString() { - return this.getClass().getSimpleName() + "[count=" + this.count + "]"; - } - - // ------------------------------------------------------------------------ - public final int count() { - return this.count; - } - - @Override - public final void writeBoolean(boolean value) { - writeTo(value ? (byte) 1 : (byte) 0); - } - - @Override - public void writeNull() { - // do nothing - } - - @Override - public boolean needWriteClassName() { - return false; - } - - @Override - public void writeClassName(String clazz) { - // do nothing - } - - @Override - public int writeObjectB(Object obj) { - super.writeObjectB(obj); - return -1; - } - - @Override - public void writeObjectE(Object obj) { - if (parent != null) { - parent.writeUInt32(count()); - parent.writeTo(toArray()); - } - } - - @Override - public int writeArrayB(int size, Encodeable encoder, Encodeable componentEncoder, Object obj) { - if (obj == null) { - writeNull(); - return 0; - } else if (size < 1) { - // writeUInt32(0); - return 0; - } else if (obj instanceof byte[]) { - int length = ((byte[]) obj).length; - writeUInt32(length); - writeTo((byte[]) obj); - return length; - } else { - final Class type = obj.getClass(); - ProtobufWriter tmp = new ProtobufWriter().configFieldFunc(this); - if (type == boolean[].class) { - for (boolean item : (boolean[]) obj) { - tmp.writeBoolean(item); - } - } else if (type == Boolean[].class) { - for (Boolean item : (Boolean[]) obj) { - tmp.writeBoolean(item != null && item); - } - } else if (type == short[].class) { - for (short item : (short[]) obj) { - tmp.writeShort(item); - } - } else if (type == Short[].class) { - for (Short item : (Short[]) obj) { - tmp.writeShort(item == null ? 0 : item); - } - } else if (type == char[].class) { - for (char item : (char[]) obj) { - tmp.writeChar(item); - } - } else if (type == Character[].class) { - for (Character item : (Character[]) obj) { - tmp.writeChar(item == null ? 0 : item); - } - } else if (type == int[].class) { - for (int item : (int[]) obj) { - tmp.writeInt(item); - } - } else if (type == Integer[].class) { - for (Integer item : (Integer[]) obj) { - tmp.writeInt(item == null ? 0 : item); - } - } else if (type == float[].class) { - for (float item : (float[]) obj) { - tmp.writeFloat(item); - } - } else if (type == Float[].class) { - for (Float item : (Float[]) obj) { - tmp.writeFloat(item == null ? 0F : item); - } - } else if (type == long[].class) { - for (long item : (long[]) obj) { - tmp.writeLong(item); - } - } else if (type == Long[].class) { - for (Long item : (Long[]) obj) { - tmp.writeLong(item == null ? 0L : item); - } - } else if (type == double[].class) { - for (double item : (double[]) obj) { - tmp.writeDouble(item); - } - } else if (type == Double[].class) { - for (Double item : (Double[]) obj) { - tmp.writeDouble(item == null ? 0D : item); - } - } else if (type == AtomicInteger[].class) { - for (AtomicInteger item : (AtomicInteger[]) obj) { - tmp.writeInt(item == null ? 0 : item.get()); - } - } else if (type == AtomicLong[].class) { - for (AtomicLong item : (AtomicLong[]) obj) { - tmp.writeLong(item == null ? 0L : item.get()); - } - } else if (encoder instanceof ProtobufCollectionDecoder) { - ProtobufCollectionDecoder listEncoder = (ProtobufCollectionDecoder) encoder; - Type componentType = listEncoder.getComponentType(); - if (listEncoder.simple) { - if (componentType == Boolean.class) { - for (Boolean item : (Collection) obj) { - tmp.writeBoolean(item); - } - } else if (componentType == Short.class) { - for (Short item : (Collection) obj) { - tmp.writeShort(item); - } - } else if (componentType == Integer.class) { - for (Integer item : (Collection) obj) { - tmp.writeInt(item); - } - } else if (componentType == Float.class) { - for (Float item : (Collection) obj) { - tmp.writeFloat(item); - } - } else if (componentType == Long.class) { - for (Long item : (Collection) obj) { - tmp.writeLong(item); - } - } else if (componentType == Double.class) { - for (Double item : (Collection) obj) { - tmp.writeDouble(item); - } - } else if (componentType == Long.class) { - for (Long item : (Collection) obj) { - tmp.writeLong(item); - } - } else if (componentType == AtomicInteger.class) { - for (AtomicInteger item : (Collection) obj) { - tmp.writeInt(item == null ? 0 : item.get()); - } - } else if (componentType == AtomicLong.class) { - for (AtomicLong item : (Collection) obj) { - tmp.writeLong(item == null ? 0L : item.get()); - } - } - } else { - return -1; - } - } else if (encoder instanceof ProtobufStreamDecoder) { - ProtobufStreamDecoder streamEncoder = (ProtobufStreamDecoder) encoder; - Type componentType = streamEncoder.getComponentType(); - if (streamEncoder.simple) { - if (componentType == Boolean.class) { - ((Stream) obj).forEach(item -> tmp.writeBoolean(item)); - } else if (componentType == Short.class) { - ((Stream) obj).forEach(item -> tmp.writeShort(item)); - } else if (componentType == Integer.class) { - ((Stream) obj).forEach(item -> tmp.writeInt(item)); - } else if (componentType == Float.class) { - ((Stream) obj).forEach(item -> tmp.writeFloat(item)); - } else if (componentType == Long.class) { - ((Stream) obj).forEach(item -> tmp.writeLong(item)); - } else if (componentType == Double.class) { - ((Stream) obj).forEach(item -> tmp.writeDouble(item)); - } else if (componentType == AtomicInteger.class) { - ((Stream) obj).forEach(item -> tmp.writeInt(item == null ? 0 : item.get())); - } else if (componentType == AtomicLong.class) { - ((Stream) obj).forEach(item -> tmp.writeLong(item == null ? 0L : item.get())); - } - } else { - return -1; - } - } else { - return -1; - } - int length = tmp.count(); - writeUInt32(length); - writeTo(tmp.toArray()); - return length; - } - } - - @Override - public void writeArrayMark() { - // do nothing - } - - @Override - public void writeArrayE() { - // do nothing - } - - @Override - public int writeMapB( - int size, Encodeable keyEncoder, Encodeable valueEncoder, Object obj) { - return -1; - } - - @Override - public void writeMapMark() { - // do nothing - } - - @Override - public void writeMapE() { - // do nothing - } - - @Override - public void writeFieldName(EnMember member, String fieldName, Type fieldType, int fieldPos) { - int tag = ProtobufFactory.getTag(fieldName, fieldType, fieldPos, enumtostring); - writeUInt32(tag); - } - - @Override - public void writeObjectField(final EnMember member, Object obj) { - Object value; - if (objFieldFunc == null) { - value = member.getAttribute().get(obj); - } else { - value = objFieldFunc.apply(member.getAttribute(), obj); - } - if (value == null) { - this.writeFieldName(member); - writeNull(); - return; - } - if (tiny()) { - if (member.isStringType()) { - if (((CharSequence) value).length() == 0) { - return; - } - } else if (member.isBoolType()) { - if (!((Boolean) value)) { - return; - } - } - } - Type mtype = member.getAttribute().type(); - if (mtype == boolean[].class && ((boolean[]) value).length < 1) { - return; - } - if (mtype == byte[].class && ((byte[]) value).length < 1) { - return; - } - if (mtype == short[].class && ((short[]) value).length < 1) { - return; - } - if (mtype == char[].class && ((char[]) value).length < 1) { - return; - } - if (mtype == int[].class && ((int[]) value).length < 1) { - return; - } - if (mtype == float[].class && ((float[]) value).length < 1) { - return; - } - if (mtype == long[].class && ((long[]) value).length < 1) { - return; - } - if (mtype == double[].class && ((double[]) value).length < 1) { - return; - } - - Encodeable encoder = member.getEncoder(); - if (encoder == null) { - return; - } - if (encoder instanceof MapEncoder) { - if (!((Map) value).isEmpty()) { - ((MapEncoder) encoder).convertTo(this, member, (Map) value); - } - } else if (encoder instanceof ProtobufArrayEncoder) { - ProtobufArrayEncoder arrayEncoder = (ProtobufArrayEncoder) encoder; - if (arrayEncoder.simple) { - if (((Object[]) value).length < 1) { - this.writeFieldName(member); - ProtobufWriter tmp = new ProtobufWriter().configFieldFunc(this); - arrayEncoder.convertTo(tmp, member, (Object[]) value); - // int length = tmp.count(); - // this.writeUInt32(length); - this.writeTo(tmp.toArray()); - } - } else { - arrayEncoder.convertTo(this, member, (Object[]) value); - } - } else if (encoder instanceof ProtobufCollectionEncoder) { - ProtobufCollectionEncoder collectionEncoder = (ProtobufCollectionEncoder) encoder; - if (collectionEncoder.simple) { - if (!((Collection) value).isEmpty()) { - this.writeFieldName(member); - ProtobufWriter tmp = new ProtobufWriter().configFieldFunc(this); - collectionEncoder.convertTo(tmp, member, (Collection) value); - int length = tmp.count(); - this.writeUInt32(length); - this.writeTo(tmp.toArray()); - } - } else { - collectionEncoder.convertTo(this, member, (Collection) value); - } - } else if (encoder instanceof ProtobufStreamEncoder) { - ProtobufStreamEncoder streamEncoder = (ProtobufStreamEncoder) encoder; - if (streamEncoder.simple) { - this.writeFieldName(member); - ProtobufWriter tmp = new ProtobufWriter().configFieldFunc(this); - streamEncoder.convertTo(tmp, member, (Stream) value); - int length = tmp.count(); - this.writeUInt32(length); - this.writeTo(tmp.toArray()); - } else { - streamEncoder.convertTo(this, member, (Stream) value); - } - } else { - this.writeFieldName(member); - encoder.convertTo(this, value); - } - this.comma = true; - } - - @Override - public void writeByte(byte value) { - writeInt(value); - } - - @Override - public final void writeByteArray(byte[] values) { - if (values == null) { - writeNull(); - return; - } - if (writeArrayB(values.length, null, null, values) < 0) { - boolean flag = false; - for (byte v : values) { - if (flag) { - writeArrayMark(); - } - writeByte(v); - flag = true; - } - } - writeArrayE(); - } - - @Override - public void writeChar(char value) { - writeInt(value); - } - - @Override - public void writeShort(short value) { - writeInt(value); - } - - @Override - public void writeInt(int value) { // writeSInt32 - writeUInt32((value << 1) ^ (value >> 31)); - } - - @Override - public void writeLong(long value) { // writeSInt64 - writeUInt64((value << 1) ^ (value >> 63)); - } - - @Override - public void writeFloat(float value) { - writeFixed32(Float.floatToRawIntBits(value)); - } - - @Override - public void writeDouble(double value) { - writeFixed64(Double.doubleToRawLongBits(value)); - } - - @Override - public void writeSmallString(String value) { - writeString(value); - } - - @Override - public void writeString(String value) { - byte[] bs = Utility.isLatin1(value) ? Utility.latin1ByteArray(value) : Utility.encodeUTF8(value); - writeUInt32(bs.length); - writeTo(bs); - } - - @Override - public void writeWrapper(StringWrapper value) { - if (value != null) { - writeString(value.getValue()); - } - } - - public static byte[] uint32(int value) { - byte[] bs = new byte[8]; - int pos = 0; - while (true) { - if ((value & ~0x7F) == 0) { - bs[pos++] = ((byte) value); - return pos == bs.length ? bs : Arrays.copyOf(bs, pos); - } else { - bs[pos++] = ((byte) ((value & 0x7F) | 0x80)); - value >>>= 7; - } - } - } - - protected void writeUInt32(int value) { - while (true) { - if ((value & ~0x7F) == 0) { - writeTo((byte) value); - return; - } else { - writeTo((byte) ((value & 0x7F) | 0x80)); - value >>>= 7; - } - } - } - - protected void writeUInt64(long value) { - while (true) { - if ((value & ~0x7FL) == 0) { - writeTo((byte) value); - return; - } else { - writeTo((byte) (((int) value & 0x7F) | 0x80)); - value >>>= 7; - } - } - } - - protected void writeFixed32(int value) { - writeTo((byte) (value & 0xFF), (byte) ((value >> 8) & 0xFF), (byte) ((value >> 16) & 0xFF), (byte) - ((value >> 24) & 0xFF)); - } - - protected void writeFixed64(long value) { - writeTo( - (byte) ((int) (value) & 0xFF), - (byte) ((int) (value >> 8) & 0xFF), - (byte) ((int) (value >> 16) & 0xFF), - (byte) ((int) (value >> 24) & 0xFF), - (byte) ((int) (value >> 32) & 0xFF), - (byte) ((int) (value >> 40) & 0xFF), - (byte) ((int) (value >> 48) & 0xFF), - (byte) ((int) (value >> 56) & 0xFF)); - } -} +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.proto; + +import java.lang.reflect.Type; +import java.nio.ByteBuffer; +import java.util.*; +import java.util.concurrent.atomic.*; +import java.util.function.Consumer; +import java.util.stream.Stream; +import org.redkale.convert.*; +import org.redkale.util.*; + +/** @author zhangjx */ +public class ProtobufWriter extends Writer implements ByteTuple { + + private static final int DEFAULT_SIZE = Integer.getInteger( + "redkale.convert.protobuf.writer.buffer.defsize", + Integer.getInteger("redkale.convert.writer.buffer.defsize", 1024)); + + private byte[] content; + + protected int count; + + protected int initOffset; + + protected boolean enumtostring; + + protected ProtobufWriter parent; + + public static ObjectPool createPool(int max) { + return ObjectPool.createSafePool(max, (Object... params) -> new ProtobufWriter(), null, (t) -> t.recycle()); + } + + protected ProtobufWriter(ProtobufWriter parent, int features) { + this(); + this.parent = parent; + this.features = features; + if (parent != null) { + this.enumtostring = parent.enumtostring; + } + } + + protected ProtobufWriter(byte[] bs) { + this.content = bs; + } + + public ProtobufWriter withFeatures(int features) { + super.withFeatures(features); + return this; + } + + protected ProtobufWriter configFieldFunc(Writer writer) { + if (writer == null) { + return this; + } + ProtobufWriter out = (ProtobufWriter) writer; + this.mapFieldFunc = out.mapFieldFunc; + this.objFieldFunc = out.objFieldFunc; + this.objExtFunc = out.objExtFunc; + this.features = out.features; + this.enumtostring = out.enumtostring; + return this; + } + + public ProtobufWriter() { + this(DEFAULT_SIZE); + } + + public ProtobufWriter(int size) { + this.content = new byte[size > 128 ? size : 128]; + } + + public ProtobufWriter(ByteArray array) { + this.content = array.content(); + this.count = array.length(); + } + + @Override + protected boolean recycle() { + super.recycle(); + this.count = 0; + this.initOffset = 0; + if (this.content.length > DEFAULT_SIZE) { + this.content = new byte[DEFAULT_SIZE]; + } + return true; + } + + @Override + public byte[] content() { + return content; + } + + @Override + public int offset() { + return initOffset; + } + + @Override + public int length() { + return count; + } + + /** + * 将本对象的内容引用复制给array + * + * @param array ByteArray + */ + public void directTo(ByteArray array) { + array.directFrom(content, count); + } + + public ByteBuffer[] toBuffers() { + return new ByteBuffer[] {ByteBuffer.wrap(content, 0, count)}; + } + + /** + * 直接获取全部数据, 实际数据需要根据count长度来截取 + * + * @return byte[] + */ + public byte[] directBytes() { + return content; + } + + public void completed(ConvertBytesHandler handler, Consumer callback) { + handler.completed(content, 0, count, callback, this); + } + + public byte[] toArray() { + if (count == content.length) { + return content; + } + byte[] newdata = new byte[count]; + System.arraycopy(content, 0, newdata, 0, count); + return newdata; + } + + public ProtobufWriter enumtostring(boolean enumtostring) { + this.enumtostring = enumtostring; + return this; + } + + protected int expand(int len) { + int newcount = count + len; + if (newcount > content.length) { + byte[] newdata = new byte[Math.max(content.length * 3 / 2, newcount)]; + System.arraycopy(content, 0, newdata, 0, count); + this.content = newdata; + } + return 0; + } + + public void writeTo(final byte ch) { + expand(1); + content[count++] = ch; + } + + public final void writeTo(final byte... chs) { + writeTo(chs, 0, chs.length); + } + + public void writeTo(final byte[] chs, final int start, final int len) { + expand(len); + System.arraycopy(chs, start, content, count, len); + count += len; + } + + public ProtobufWriter clear() { + this.count = 0; + this.initOffset = 0; + return this; + } + + @Override + public String toString() { + return this.getClass().getSimpleName() + "[count=" + this.count + "]"; + } + + // ------------------------------------------------------------------------ + public final int count() { + return this.count; + } + + @Override + public final void writeBoolean(boolean value) { + writeTo(value ? (byte) 1 : (byte) 0); + } + + @Override + public void writeNull() { + // do nothing + } + + @Override + public boolean needWriteClassName() { + return false; + } + + @Override + public void writeClassName(String clazz) { + // do nothing + } + + @Override + public int writeObjectB(Object obj) { + super.writeObjectB(obj); + return -1; + } + + @Override + public void writeObjectE(Object obj) { + if (parent != null) { + parent.writeUInt32(count()); + parent.writeTo(toArray()); + } + } + + @Override + public int writeArrayB(int size, Encodeable encoder, Encodeable componentEncoder, Object obj) { + if (obj == null) { + writeNull(); + return 0; + } else if (size < 1) { + // writeUInt32(0); + return 0; + } else if (obj instanceof byte[]) { + int length = ((byte[]) obj).length; + writeUInt32(length); + writeTo((byte[]) obj); + return length; + } else { + final Class type = obj.getClass(); + ProtobufWriter tmp = new ProtobufWriter().configFieldFunc(this); + if (type == boolean[].class) { + for (boolean item : (boolean[]) obj) { + tmp.writeBoolean(item); + } + } else if (type == Boolean[].class) { + for (Boolean item : (Boolean[]) obj) { + tmp.writeBoolean(item != null && item); + } + } else if (type == short[].class) { + for (short item : (short[]) obj) { + tmp.writeShort(item); + } + } else if (type == Short[].class) { + for (Short item : (Short[]) obj) { + tmp.writeShort(item == null ? 0 : item); + } + } else if (type == char[].class) { + for (char item : (char[]) obj) { + tmp.writeChar(item); + } + } else if (type == Character[].class) { + for (Character item : (Character[]) obj) { + tmp.writeChar(item == null ? 0 : item); + } + } else if (type == int[].class) { + for (int item : (int[]) obj) { + tmp.writeInt(item); + } + } else if (type == Integer[].class) { + for (Integer item : (Integer[]) obj) { + tmp.writeInt(item == null ? 0 : item); + } + } else if (type == float[].class) { + for (float item : (float[]) obj) { + tmp.writeFloat(item); + } + } else if (type == Float[].class) { + for (Float item : (Float[]) obj) { + tmp.writeFloat(item == null ? 0F : item); + } + } else if (type == long[].class) { + for (long item : (long[]) obj) { + tmp.writeLong(item); + } + } else if (type == Long[].class) { + for (Long item : (Long[]) obj) { + tmp.writeLong(item == null ? 0L : item); + } + } else if (type == double[].class) { + for (double item : (double[]) obj) { + tmp.writeDouble(item); + } + } else if (type == Double[].class) { + for (Double item : (Double[]) obj) { + tmp.writeDouble(item == null ? 0D : item); + } + } else if (type == AtomicInteger[].class) { + for (AtomicInteger item : (AtomicInteger[]) obj) { + tmp.writeInt(item == null ? 0 : item.get()); + } + } else if (type == AtomicLong[].class) { + for (AtomicLong item : (AtomicLong[]) obj) { + tmp.writeLong(item == null ? 0L : item.get()); + } + } else if (encoder instanceof ProtobufCollectionDecoder) { + ProtobufCollectionDecoder listEncoder = (ProtobufCollectionDecoder) encoder; + Type componentType = listEncoder.getComponentType(); + if (listEncoder.simple) { + if (componentType == Boolean.class) { + for (Boolean item : (Collection) obj) { + tmp.writeBoolean(item); + } + } else if (componentType == Short.class) { + for (Short item : (Collection) obj) { + tmp.writeShort(item); + } + } else if (componentType == Integer.class) { + for (Integer item : (Collection) obj) { + tmp.writeInt(item); + } + } else if (componentType == Float.class) { + for (Float item : (Collection) obj) { + tmp.writeFloat(item); + } + } else if (componentType == Long.class) { + for (Long item : (Collection) obj) { + tmp.writeLong(item); + } + } else if (componentType == Double.class) { + for (Double item : (Collection) obj) { + tmp.writeDouble(item); + } + } else if (componentType == Long.class) { + for (Long item : (Collection) obj) { + tmp.writeLong(item); + } + } else if (componentType == AtomicInteger.class) { + for (AtomicInteger item : (Collection) obj) { + tmp.writeInt(item == null ? 0 : item.get()); + } + } else if (componentType == AtomicLong.class) { + for (AtomicLong item : (Collection) obj) { + tmp.writeLong(item == null ? 0L : item.get()); + } + } + } else { + return -1; + } + } else if (encoder instanceof ProtobufStreamDecoder) { + ProtobufStreamDecoder streamEncoder = (ProtobufStreamDecoder) encoder; + Type componentType = streamEncoder.getComponentType(); + if (streamEncoder.simple) { + if (componentType == Boolean.class) { + ((Stream) obj).forEach(item -> tmp.writeBoolean(item)); + } else if (componentType == Short.class) { + ((Stream) obj).forEach(item -> tmp.writeShort(item)); + } else if (componentType == Integer.class) { + ((Stream) obj).forEach(item -> tmp.writeInt(item)); + } else if (componentType == Float.class) { + ((Stream) obj).forEach(item -> tmp.writeFloat(item)); + } else if (componentType == Long.class) { + ((Stream) obj).forEach(item -> tmp.writeLong(item)); + } else if (componentType == Double.class) { + ((Stream) obj).forEach(item -> tmp.writeDouble(item)); + } else if (componentType == AtomicInteger.class) { + ((Stream) obj).forEach(item -> tmp.writeInt(item == null ? 0 : item.get())); + } else if (componentType == AtomicLong.class) { + ((Stream) obj).forEach(item -> tmp.writeLong(item == null ? 0L : item.get())); + } + } else { + return -1; + } + } else { + return -1; + } + int length = tmp.count(); + writeUInt32(length); + writeTo(tmp.toArray()); + return length; + } + } + + @Override + public void writeArrayMark() { + // do nothing + } + + @Override + public void writeArrayE() { + // do nothing + } + + @Override + public int writeMapB( + int size, Encodeable keyEncoder, Encodeable valueEncoder, Object obj) { + return -1; + } + + @Override + public void writeMapMark() { + // do nothing + } + + @Override + public void writeMapE() { + // do nothing + } + + @Override + public void writeFieldName(EnMember member, String fieldName, Type fieldType, int fieldPos) { + int tag = ProtobufFactory.getTag(fieldName, fieldType, fieldPos, enumtostring); + writeUInt32(tag); + } + + @Override + public void writeObjectField(final EnMember member, Object obj) { + Object value; + if (objFieldFunc == null) { + value = member.getAttribute().get(obj); + } else { + value = objFieldFunc.apply(member.getAttribute(), obj); + } + if (value == null) { + this.writeFieldName(member); + writeNull(); + return; + } + if (tiny()) { + if (member.isStringType()) { + if (((CharSequence) value).length() == 0) { + return; + } + } else if (member.isBoolType()) { + if (!((Boolean) value)) { + return; + } + } + } + Type mtype = member.getAttribute().type(); + if (mtype == boolean[].class && ((boolean[]) value).length < 1) { + return; + } + if (mtype == byte[].class && ((byte[]) value).length < 1) { + return; + } + if (mtype == short[].class && ((short[]) value).length < 1) { + return; + } + if (mtype == char[].class && ((char[]) value).length < 1) { + return; + } + if (mtype == int[].class && ((int[]) value).length < 1) { + return; + } + if (mtype == float[].class && ((float[]) value).length < 1) { + return; + } + if (mtype == long[].class && ((long[]) value).length < 1) { + return; + } + if (mtype == double[].class && ((double[]) value).length < 1) { + return; + } + + Encodeable encoder = member.getEncoder(); + if (encoder == null) { + return; + } + if (encoder instanceof MapEncoder) { + if (!((Map) value).isEmpty()) { + ((MapEncoder) encoder).convertTo(this, member, (Map) value); + } + } else if (encoder instanceof ProtobufArrayEncoder) { + ProtobufArrayEncoder arrayEncoder = (ProtobufArrayEncoder) encoder; + if (arrayEncoder.simple) { + if (((Object[]) value).length < 1) { + this.writeFieldName(member); + ProtobufWriter tmp = new ProtobufWriter().configFieldFunc(this); + arrayEncoder.convertTo(tmp, member, (Object[]) value); + // int length = tmp.count(); + // this.writeUInt32(length); + this.writeTo(tmp.toArray()); + } + } else { + arrayEncoder.convertTo(this, member, (Object[]) value); + } + } else if (encoder instanceof ProtobufCollectionEncoder) { + ProtobufCollectionEncoder collectionEncoder = (ProtobufCollectionEncoder) encoder; + if (collectionEncoder.simple) { + if (!((Collection) value).isEmpty()) { + this.writeFieldName(member); + ProtobufWriter tmp = new ProtobufWriter().configFieldFunc(this); + collectionEncoder.convertTo(tmp, member, (Collection) value); + int length = tmp.count(); + this.writeUInt32(length); + this.writeTo(tmp.toArray()); + } + } else { + collectionEncoder.convertTo(this, member, (Collection) value); + } + } else if (encoder instanceof ProtobufStreamEncoder) { + ProtobufStreamEncoder streamEncoder = (ProtobufStreamEncoder) encoder; + if (streamEncoder.simple) { + this.writeFieldName(member); + ProtobufWriter tmp = new ProtobufWriter().configFieldFunc(this); + streamEncoder.convertTo(tmp, member, (Stream) value); + int length = tmp.count(); + this.writeUInt32(length); + this.writeTo(tmp.toArray()); + } else { + streamEncoder.convertTo(this, member, (Stream) value); + } + } else { + this.writeFieldName(member); + encoder.convertTo(this, value); + } + this.comma = true; + } + + @Override + public void writeByte(byte value) { + writeInt(value); + } + + @Override + public final void writeByteArray(byte[] values) { + if (values == null) { + writeNull(); + return; + } + if (writeArrayB(values.length, null, null, values) < 0) { + boolean flag = false; + for (byte v : values) { + if (flag) { + writeArrayMark(); + } + writeByte(v); + flag = true; + } + } + writeArrayE(); + } + + @Override + public void writeChar(char value) { + writeInt(value); + } + + @Override + public void writeShort(short value) { + writeInt(value); + } + + @Override + public void writeInt(int value) { // writeSInt32 + writeUInt32((value << 1) ^ (value >> 31)); + } + + @Override + public void writeLong(long value) { // writeSInt64 + writeUInt64((value << 1) ^ (value >> 63)); + } + + @Override + public void writeFloat(float value) { + writeFixed32(Float.floatToRawIntBits(value)); + } + + @Override + public void writeDouble(double value) { + writeFixed64(Double.doubleToRawLongBits(value)); + } + + @Override + public void writeSmallString(String value) { + writeString(value); + } + + @Override + public void writeString(String value) { + byte[] bs = Utility.isLatin1(value) ? Utility.latin1ByteArray(value) : Utility.encodeUTF8(value); + writeUInt32(bs.length); + writeTo(bs); + } + + @Override + public void writeWrapper(StringWrapper value) { + if (value != null) { + writeString(value.getValue()); + } + } + + public static byte[] uint32(int value) { + byte[] bs = new byte[8]; + int pos = 0; + while (true) { + if ((value & ~0x7F) == 0) { + bs[pos++] = ((byte) value); + return pos == bs.length ? bs : Arrays.copyOf(bs, pos); + } else { + bs[pos++] = ((byte) ((value & 0x7F) | 0x80)); + value >>>= 7; + } + } + } + + protected void writeUInt32(int value) { + while (true) { + if ((value & ~0x7F) == 0) { + writeTo((byte) value); + return; + } else { + writeTo((byte) ((value & 0x7F) | 0x80)); + value >>>= 7; + } + } + } + + protected void writeUInt64(long value) { + while (true) { + if ((value & ~0x7FL) == 0) { + writeTo((byte) value); + return; + } else { + writeTo((byte) (((int) value & 0x7F) | 0x80)); + value >>>= 7; + } + } + } + + protected void writeFixed32(int value) { + writeTo((byte) (value & 0xFF), (byte) ((value >> 8) & 0xFF), (byte) ((value >> 16) & 0xFF), (byte) + ((value >> 24) & 0xFF)); + } + + protected void writeFixed64(long value) { + writeTo( + (byte) ((int) (value) & 0xFF), + (byte) ((int) (value >> 8) & 0xFF), + (byte) ((int) (value >> 16) & 0xFF), + (byte) ((int) (value >> 24) & 0xFF), + (byte) ((int) (value >> 32) & 0xFF), + (byte) ((int) (value >> 40) & 0xFF), + (byte) ((int) (value >> 48) & 0xFF), + (byte) ((int) (value >> 56) & 0xFF)); + } +} diff --git a/src/main/java/org/redkale/inject/ResourceAnnotationLoader.java b/src/main/java/org/redkale/inject/ResourceAnnotationLoader.java index 522d3f48a..4065747ba 100644 --- a/src/main/java/org/redkale/inject/ResourceAnnotationLoader.java +++ b/src/main/java/org/redkale/inject/ResourceAnnotationLoader.java @@ -1,29 +1,29 @@ -/* - * - */ -package org.redkale.inject; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Field; - -/** - * 自定义注入加载器 - * - *

详情见: https://redkale.org - * - * @since 2.8.0 - * @author zhangjx - * @param Annotation - */ -public interface ResourceAnnotationLoader { - - public void load( - ResourceFactory factory, - String srcResourceName, - Object srcObj, - T annotation, - Field field, - Object attachment); - - public Class annotationType(); -} +/* + * + */ +package org.redkale.inject; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; + +/** + * 自定义注入加载器 + * + *

详情见: https://redkale.org + * + * @since 2.8.0 + * @author zhangjx + * @param Annotation + */ +public interface ResourceAnnotationLoader { + + public void load( + ResourceFactory factory, + String srcResourceName, + Object srcObj, + T annotation, + Field field, + Object attachment); + + public Class annotationType(); +} diff --git a/src/main/java/org/redkale/lock/LockManager.java b/src/main/java/org/redkale/lock/LockManager.java index c72ab8b55..24db6055f 100644 --- a/src/main/java/org/redkale/lock/LockManager.java +++ b/src/main/java/org/redkale/lock/LockManager.java @@ -1,16 +1,16 @@ -/* - * - */ -package org.redkale.lock; - -/** - * //TODO 待实现 - * - *

锁管理器 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public interface LockManager {} +/* + * + */ +package org.redkale.lock; + +/** + * //TODO 待实现 + * + *

锁管理器 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public interface LockManager {} diff --git a/src/main/java/org/redkale/lock/Locked.java b/src/main/java/org/redkale/lock/Locked.java index 3d68717af..b6ddf0b91 100644 --- a/src/main/java/org/redkale/lock/Locked.java +++ b/src/main/java/org/redkale/lock/Locked.java @@ -1,36 +1,36 @@ -/* - * - */ -package org.redkale.lock; - -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; -import org.redkale.service.LoadMode; - -/** - * //TODO 待实现 - * - *

标记在Service的锁接口, 方法有以下限制:
- * 2、方法必须是protected/public 3、方法不能是final/static - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -@Documented -@Target(METHOD) -@Retention(RUNTIME) -public @interface Locked { - - /** - * Service加载模式 - * - * @return 模式 - */ - LoadMode mode() default LoadMode.ANY; -} +/* + * + */ +package org.redkale.lock; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; +import org.redkale.service.LoadMode; + +/** + * //TODO 待实现 + * + *

标记在Service的锁接口, 方法有以下限制:
+ * 2、方法必须是protected/public 3、方法不能是final/static + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +@Documented +@Target(METHOD) +@Retention(RUNTIME) +public @interface Locked { + + /** + * Service加载模式 + * + * @return 模式 + */ + LoadMode mode() default LoadMode.ANY; +} diff --git a/src/main/java/org/redkale/lock/spi/DynForLock.java b/src/main/java/org/redkale/lock/spi/DynForLock.java index d2b883269..bc0c519af 100644 --- a/src/main/java/org/redkale/lock/spi/DynForLock.java +++ b/src/main/java/org/redkale/lock/spi/DynForLock.java @@ -1,28 +1,28 @@ -/* - * - */ -package org.redkale.lock.spi; - -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; -import org.redkale.service.LoadMode; - -/** - * {@link org.redkale.lock.Locked}注解的动态扩展版,会多一个字段信息 用于识别方法是否已经动态处理过 - * - * @author zhangjx - * @since 2.8.0 - */ -@Documented -@Target({METHOD}) -@Retention(RUNTIME) -public @interface DynForLock { - - String dynField(); - - LoadMode mode() default LoadMode.ANY; -} +/* + * + */ +package org.redkale.lock.spi; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; +import org.redkale.service.LoadMode; + +/** + * {@link org.redkale.lock.Locked}注解的动态扩展版,会多一个字段信息 用于识别方法是否已经动态处理过 + * + * @author zhangjx + * @since 2.8.0 + */ +@Documented +@Target({METHOD}) +@Retention(RUNTIME) +public @interface DynForLock { + + String dynField(); + + LoadMode mode() default LoadMode.ANY; +} diff --git a/src/main/java/org/redkale/lock/spi/LockAsmMethodBoost.java b/src/main/java/org/redkale/lock/spi/LockAsmMethodBoost.java index 5067fbb34..fa078d475 100644 --- a/src/main/java/org/redkale/lock/spi/LockAsmMethodBoost.java +++ b/src/main/java/org/redkale/lock/spi/LockAsmMethodBoost.java @@ -1,99 +1,99 @@ -/* - * - */ -package org.redkale.lock.spi; - -import static org.redkale.asm.Opcodes.*; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.List; -import org.redkale.asm.AnnotationVisitor; -import org.redkale.asm.AsmMethodBean; -import org.redkale.asm.AsmMethodBoost; -import org.redkale.asm.Asms; -import org.redkale.asm.ClassWriter; -import org.redkale.asm.Label; -import org.redkale.asm.MethodVisitor; -import org.redkale.asm.Type; -import org.redkale.inject.ResourceFactory; -import org.redkale.lock.Locked; -import org.redkale.service.LoadMode; -import org.redkale.util.RedkaleException; - -/** @author zhangjx */ -public class LockAsmMethodBoost extends AsmMethodBoost { - - private static final List> FILTER_ANN = List.of(Locked.class, DynForLock.class); - - public LockAsmMethodBoost(boolean remote, Class serviceType) { - super(remote, serviceType); - } - - @Override - public List> filterMethodAnnotations(Method method) { - return FILTER_ANN; - } - - @Override - public String doMethod( - ClassLoader classLoader, - ClassWriter cw, - String newDynName, - String fieldPrefix, - List filterAnns, - Method method, - final String newMethodName) { - Locked locked = method.getAnnotation(Locked.class); - if (locked == null) { - return newMethodName; - } - if (!LoadMode.matches(remote, locked.mode())) { - return newMethodName; - } - if (method.getAnnotation(DynForLock.class) != null) { - return newMethodName; - } - if (Modifier.isFinal(method.getModifiers()) || Modifier.isStatic(method.getModifiers())) { - throw new RedkaleException( - "@" + Locked.class.getSimpleName() + " can not on final or static method, but on " + method); - } - if (!Modifier.isProtected(method.getModifiers()) && !Modifier.isPublic(method.getModifiers())) { - throw new RedkaleException( - "@" + Locked.class.getSimpleName() + " must on protected or public method, but on " + method); - } - - final String rsMethodName = method.getName() + "_afterLock"; - final String dynFieldName = fieldPrefix + "_" + method.getName() + "LockAction" + fieldIndex.incrementAndGet(); - { // 定义一个新方法调用 this.rsMethodName - final AsmMethodBean methodBean = getMethodBean(method); - final String lockDynDesc = Type.getDescriptor(DynForLock.class); - final MethodVisitor mv = createMethodVisitor(cw, method, newMethodName, methodBean); - // mv.setDebug(true); - Label l0 = new Label(); - mv.visitLabel(l0); - AnnotationVisitor av = mv.visitAnnotation(lockDynDesc, true); - av.visit("dynField", dynFieldName); - Asms.visitAnnotation(av, locked); - visitRawAnnotation(method, newMethodName, mv, Locked.class, filterAnns); - mv.visitVarInsn(ALOAD, 0); - List insns = visitVarInsnParamTypes(mv, method, 0); - mv.visitMethodInsn(INVOKESPECIAL, newDynName, rsMethodName, Type.getMethodDescriptor(method), false); - visitInsnReturn(mv, method, l0, insns, methodBean); - mv.visitMaxs(20, 20); - mv.visitEnd(); - } - return rsMethodName; - } - - @Override - public void doAfterMethods(ClassLoader classLoader, ClassWriter cw, String newDynName, String fieldPrefix) { - // do nothing - } - - @Override - public void doInstance(ResourceFactory resourceFactory, Object service) { - // do nothing - } -} +/* + * + */ +package org.redkale.lock.spi; + +import static org.redkale.asm.Opcodes.*; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.List; +import org.redkale.asm.AnnotationVisitor; +import org.redkale.asm.AsmMethodBean; +import org.redkale.asm.AsmMethodBoost; +import org.redkale.asm.Asms; +import org.redkale.asm.ClassWriter; +import org.redkale.asm.Label; +import org.redkale.asm.MethodVisitor; +import org.redkale.asm.Type; +import org.redkale.inject.ResourceFactory; +import org.redkale.lock.Locked; +import org.redkale.service.LoadMode; +import org.redkale.util.RedkaleException; + +/** @author zhangjx */ +public class LockAsmMethodBoost extends AsmMethodBoost { + + private static final List> FILTER_ANN = List.of(Locked.class, DynForLock.class); + + public LockAsmMethodBoost(boolean remote, Class serviceType) { + super(remote, serviceType); + } + + @Override + public List> filterMethodAnnotations(Method method) { + return FILTER_ANN; + } + + @Override + public String doMethod( + ClassLoader classLoader, + ClassWriter cw, + String newDynName, + String fieldPrefix, + List filterAnns, + Method method, + final String newMethodName) { + Locked locked = method.getAnnotation(Locked.class); + if (locked == null) { + return newMethodName; + } + if (!LoadMode.matches(remote, locked.mode())) { + return newMethodName; + } + if (method.getAnnotation(DynForLock.class) != null) { + return newMethodName; + } + if (Modifier.isFinal(method.getModifiers()) || Modifier.isStatic(method.getModifiers())) { + throw new RedkaleException( + "@" + Locked.class.getSimpleName() + " can not on final or static method, but on " + method); + } + if (!Modifier.isProtected(method.getModifiers()) && !Modifier.isPublic(method.getModifiers())) { + throw new RedkaleException( + "@" + Locked.class.getSimpleName() + " must on protected or public method, but on " + method); + } + + final String rsMethodName = method.getName() + "_afterLock"; + final String dynFieldName = fieldPrefix + "_" + method.getName() + "LockAction" + fieldIndex.incrementAndGet(); + { // 定义一个新方法调用 this.rsMethodName + final AsmMethodBean methodBean = getMethodBean(method); + final String lockDynDesc = Type.getDescriptor(DynForLock.class); + final MethodVisitor mv = createMethodVisitor(cw, method, newMethodName, methodBean); + // mv.setDebug(true); + Label l0 = new Label(); + mv.visitLabel(l0); + AnnotationVisitor av = mv.visitAnnotation(lockDynDesc, true); + av.visit("dynField", dynFieldName); + Asms.visitAnnotation(av, locked); + visitRawAnnotation(method, newMethodName, mv, Locked.class, filterAnns); + mv.visitVarInsn(ALOAD, 0); + List insns = visitVarInsnParamTypes(mv, method, 0); + mv.visitMethodInsn(INVOKESPECIAL, newDynName, rsMethodName, Type.getMethodDescriptor(method), false); + visitInsnReturn(mv, method, l0, insns, methodBean); + mv.visitMaxs(20, 20); + mv.visitEnd(); + } + return rsMethodName; + } + + @Override + public void doAfterMethods(ClassLoader classLoader, ClassWriter cw, String newDynName, String fieldPrefix) { + // do nothing + } + + @Override + public void doInstance(ResourceFactory resourceFactory, Object service) { + // do nothing + } +} diff --git a/src/main/java/org/redkale/lock/spi/LockManagerProvider.java b/src/main/java/org/redkale/lock/spi/LockManagerProvider.java index 6a40c2f29..185add3da 100644 --- a/src/main/java/org/redkale/lock/spi/LockManagerProvider.java +++ b/src/main/java/org/redkale/lock/spi/LockManagerProvider.java @@ -1,18 +1,18 @@ -/* - -*/ - -package org.redkale.lock.spi; - -import org.redkale.lock.LockManager; -import org.redkale.util.InstanceProvider; - -/** - * 自定义的LockManager加载器, 如果标记@Priority加载器的优先级需要大于1000, 1000以下预留给官方加载器 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public interface LockManagerProvider extends InstanceProvider {} +/* + +*/ + +package org.redkale.lock.spi; + +import org.redkale.lock.LockManager; +import org.redkale.util.InstanceProvider; + +/** + * 自定义的LockManager加载器, 如果标记@Priority加载器的优先级需要大于1000, 1000以下预留给官方加载器 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public interface LockManagerProvider extends InstanceProvider {} diff --git a/src/main/java/org/redkale/lock/spi/LockManagerService.java b/src/main/java/org/redkale/lock/spi/LockManagerService.java index eda20dcc2..47a30f9db 100644 --- a/src/main/java/org/redkale/lock/spi/LockManagerService.java +++ b/src/main/java/org/redkale/lock/spi/LockManagerService.java @@ -1,54 +1,54 @@ -/* - * - */ -package org.redkale.lock.spi; - -import org.redkale.annotation.AutoLoad; -import org.redkale.annotation.Component; -import org.redkale.annotation.Nullable; -import org.redkale.annotation.Resource; -import org.redkale.annotation.ResourceType; -import org.redkale.boot.Application; -import org.redkale.lock.LockManager; -import org.redkale.service.Local; -import org.redkale.service.Service; -import org.redkale.source.CacheSource; -import org.redkale.util.AnyValue; - -/** @author zhangjx */ -@Local -@Component -@AutoLoad(false) -@ResourceType(LockManager.class) -public class LockManagerService implements LockManager, Service { - - // 是否开启锁 - protected boolean enabled = true; - - // 配置 - protected AnyValue config; - - @Resource(required = false) - protected Application application; - - // 远程缓存Source - protected CacheSource remoteSource; - - protected LockManagerService(@Nullable CacheSource remoteSource) { - this.remoteSource = remoteSource; - } - - // 一般用于独立组件 - public static LockManagerService create(@Nullable CacheSource remoteSource) { - return new LockManagerService(remoteSource); - } - - public boolean enabled() { - return this.enabled; - } - - public LockManagerService enabled(boolean val) { - this.enabled = val; - return this; - } -} +/* + * + */ +package org.redkale.lock.spi; + +import org.redkale.annotation.AutoLoad; +import org.redkale.annotation.Component; +import org.redkale.annotation.Nullable; +import org.redkale.annotation.Resource; +import org.redkale.annotation.ResourceType; +import org.redkale.boot.Application; +import org.redkale.lock.LockManager; +import org.redkale.service.Local; +import org.redkale.service.Service; +import org.redkale.source.CacheSource; +import org.redkale.util.AnyValue; + +/** @author zhangjx */ +@Local +@Component +@AutoLoad(false) +@ResourceType(LockManager.class) +public class LockManagerService implements LockManager, Service { + + // 是否开启锁 + protected boolean enabled = true; + + // 配置 + protected AnyValue config; + + @Resource(required = false) + protected Application application; + + // 远程缓存Source + protected CacheSource remoteSource; + + protected LockManagerService(@Nullable CacheSource remoteSource) { + this.remoteSource = remoteSource; + } + + // 一般用于独立组件 + public static LockManagerService create(@Nullable CacheSource remoteSource) { + return new LockManagerService(remoteSource); + } + + public boolean enabled() { + return this.enabled; + } + + public LockManagerService enabled(boolean val) { + this.enabled = val; + return this; + } +} diff --git a/src/main/java/org/redkale/lock/spi/LockModuleEngine.java b/src/main/java/org/redkale/lock/spi/LockModuleEngine.java index a7abba40e..7881d10d6 100644 --- a/src/main/java/org/redkale/lock/spi/LockModuleEngine.java +++ b/src/main/java/org/redkale/lock/spi/LockModuleEngine.java @@ -1,100 +1,100 @@ -/* - * - */ -package org.redkale.lock.spi; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.ServiceLoader; -import org.redkale.asm.AsmMethodBoost; -import org.redkale.boot.Application; -import org.redkale.boot.ModuleEngine; -import org.redkale.lock.LockManager; -import org.redkale.service.Service; -import org.redkale.util.AnyValue; -import org.redkale.util.InstanceProvider; -import org.redkale.util.RedkaleClassLoader; - -/** @author zhangjx */ -public class LockModuleEngine extends ModuleEngine { - - // 全局锁管理器 - private LockManager lockManager; - - private AnyValue config; - - public LockModuleEngine(Application application) { - super(application); - } - - /** - * 判断模块的配置项合并策略, 返回null表示模块不识别此配置项 - * - * @param path 配置项路径 - * @param key 配置项名称 - * @param val1 配置项原值 - * @param val2 配置项新值 - * @return MergeEnum - */ - @Override - public AnyValue.MergeEnum mergeAppConfigStrategy(String path, String key, AnyValue val1, AnyValue val2) { - if ("".equals(path) && "lock".equals(key)) { - return AnyValue.MergeEnum.REPLACE; - } - return null; - } - - /** - * 动态扩展类的方法 - * - * @param remote 是否远程模式 - * @param serviceClass 类 - * @return 方法动态扩展器 - */ - public AsmMethodBoost createAsmMethodBoost(boolean remote, Class serviceClass) { - return new LockAsmMethodBoost(remote, serviceClass); - } - - /** 结束Application.init方法前被调用 */ - @Override - public void onAppPostInit() { - // 设置锁管理器 - this.config = application.getAppConfig().getAnyValue("lock"); - this.lockManager = createManager(this.config); - if (!application.isCompileMode()) { - this.resourceFactory.inject(this.lockManager); - if (this.lockManager instanceof Service) { - ((Service) this.lockManager).init(this.config); - } - } - this.resourceFactory.register("", LockManager.class, this.lockManager); - } - - /** 进入Application.shutdown方法被调用 */ - @Override - public void onAppPreShutdown() { - if (!application.isCompileMode() && this.lockManager instanceof Service) { - ((Service) this.lockManager).destroy(this.config); - } - } - - private LockManager createManager(AnyValue conf) { - Iterator it = ServiceLoader.load(LockManagerProvider.class, application.getClassLoader()) - .iterator(); - RedkaleClassLoader.putServiceLoader(LockManagerProvider.class); - List providers = new ArrayList<>(); - while (it.hasNext()) { - LockManagerProvider provider = it.next(); - if (provider != null && provider.acceptsConf(conf)) { - RedkaleClassLoader.putReflectionPublicConstructors( - provider.getClass(), provider.getClass().getName()); - providers.add(provider); - } - } - for (LockManagerProvider provider : InstanceProvider.sort(providers)) { - return provider.createInstance(); - } - return LockManagerService.create(null).enabled(false); - } -} +/* + * + */ +package org.redkale.lock.spi; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.ServiceLoader; +import org.redkale.asm.AsmMethodBoost; +import org.redkale.boot.Application; +import org.redkale.boot.ModuleEngine; +import org.redkale.lock.LockManager; +import org.redkale.service.Service; +import org.redkale.util.AnyValue; +import org.redkale.util.InstanceProvider; +import org.redkale.util.RedkaleClassLoader; + +/** @author zhangjx */ +public class LockModuleEngine extends ModuleEngine { + + // 全局锁管理器 + private LockManager lockManager; + + private AnyValue config; + + public LockModuleEngine(Application application) { + super(application); + } + + /** + * 判断模块的配置项合并策略, 返回null表示模块不识别此配置项 + * + * @param path 配置项路径 + * @param key 配置项名称 + * @param val1 配置项原值 + * @param val2 配置项新值 + * @return MergeEnum + */ + @Override + public AnyValue.MergeEnum mergeAppConfigStrategy(String path, String key, AnyValue val1, AnyValue val2) { + if ("".equals(path) && "lock".equals(key)) { + return AnyValue.MergeEnum.REPLACE; + } + return null; + } + + /** + * 动态扩展类的方法 + * + * @param remote 是否远程模式 + * @param serviceClass 类 + * @return 方法动态扩展器 + */ + public AsmMethodBoost createAsmMethodBoost(boolean remote, Class serviceClass) { + return new LockAsmMethodBoost(remote, serviceClass); + } + + /** 结束Application.init方法前被调用 */ + @Override + public void onAppPostInit() { + // 设置锁管理器 + this.config = application.getAppConfig().getAnyValue("lock"); + this.lockManager = createManager(this.config); + if (!application.isCompileMode()) { + this.resourceFactory.inject(this.lockManager); + if (this.lockManager instanceof Service) { + ((Service) this.lockManager).init(this.config); + } + } + this.resourceFactory.register("", LockManager.class, this.lockManager); + } + + /** 进入Application.shutdown方法被调用 */ + @Override + public void onAppPreShutdown() { + if (!application.isCompileMode() && this.lockManager instanceof Service) { + ((Service) this.lockManager).destroy(this.config); + } + } + + private LockManager createManager(AnyValue conf) { + Iterator it = ServiceLoader.load(LockManagerProvider.class, application.getClassLoader()) + .iterator(); + RedkaleClassLoader.putServiceLoader(LockManagerProvider.class); + List providers = new ArrayList<>(); + while (it.hasNext()) { + LockManagerProvider provider = it.next(); + if (provider != null && provider.acceptsConf(conf)) { + RedkaleClassLoader.putReflectionPublicConstructors( + provider.getClass(), provider.getClass().getName()); + providers.add(provider); + } + } + for (LockManagerProvider provider : InstanceProvider.sort(providers)) { + return provider.createInstance(); + } + return LockManagerService.create(null).enabled(false); + } +} diff --git a/src/main/java/org/redkale/mq/MessageConext.java b/src/main/java/org/redkale/mq/MessageConext.java index f3f8c9890..7cd08aa4b 100644 --- a/src/main/java/org/redkale/mq/MessageConext.java +++ b/src/main/java/org/redkale/mq/MessageConext.java @@ -1,61 +1,61 @@ -/* - * - */ -package org.redkale.mq; - -import java.util.Objects; -import org.redkale.convert.ConvertColumn; -import org.redkale.convert.json.JsonConvert; - -/** - * MessageConsumer回调的上下文 - * - *

详情见: https://redkale.org - * - * @see org.redkale.mq.MessageConsumer - * @author zhangjx - * @since 2.8.0 - */ -public class MessageConext { - - @ConvertColumn(index = 1) - protected String topic; - - @ConvertColumn(index = 2) - protected Integer partition; - - public MessageConext(String topic, Integer partition) { - this.topic = topic; - this.partition = partition; - } - - public String getTopic() { - return topic; - } - - public Integer getPartition() { - return partition; - } - - @Override - public int hashCode() { - return Objects.hash(this.topic, this.partition); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null || getClass() != obj.getClass()) { - return false; - } - final MessageConext other = (MessageConext) obj; - return Objects.equals(this.topic, other.topic) && Objects.equals(this.partition, other.partition); - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } -} +/* + * + */ +package org.redkale.mq; + +import java.util.Objects; +import org.redkale.convert.ConvertColumn; +import org.redkale.convert.json.JsonConvert; + +/** + * MessageConsumer回调的上下文 + * + *

详情见: https://redkale.org + * + * @see org.redkale.mq.MessageConsumer + * @author zhangjx + * @since 2.8.0 + */ +public class MessageConext { + + @ConvertColumn(index = 1) + protected String topic; + + @ConvertColumn(index = 2) + protected Integer partition; + + public MessageConext(String topic, Integer partition) { + this.topic = topic; + this.partition = partition; + } + + public String getTopic() { + return topic; + } + + public Integer getPartition() { + return partition; + } + + @Override + public int hashCode() { + return Objects.hash(this.topic, this.partition); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + final MessageConext other = (MessageConext) obj; + return Objects.equals(this.topic, other.topic) && Objects.equals(this.partition, other.partition); + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } +} diff --git a/src/main/java/org/redkale/mq/MessageConsumer.java b/src/main/java/org/redkale/mq/MessageConsumer.java index 2e17815da..2f948d9a7 100644 --- a/src/main/java/org/redkale/mq/MessageConsumer.java +++ b/src/main/java/org/redkale/mq/MessageConsumer.java @@ -1,32 +1,32 @@ -/* - * - */ -package org.redkale.mq; - -import org.redkale.annotation.ClassDepends; -import org.redkale.annotation.Component; -import org.redkale.service.Local; -import org.redkale.util.AnyValue; - -/** - * MQ消费器, 实现类必须标记{@link org.redkale.mq.ResourceConsumer} - * - *

详情见: https://redkale.org - * - * @see org.redkale.mq.MessageConext - * @see org.redkale.mq.ResourceConsumer - * @author zhangjx - * @param T - * @since 2.8.0 - */ -@Local -@Component -@ClassDepends -public interface MessageConsumer { - - default void init(AnyValue config) {} - - public void onMessage(MessageConext context, T message); - - default void destroy(AnyValue config) {} -} +/* + * + */ +package org.redkale.mq; + +import org.redkale.annotation.ClassDepends; +import org.redkale.annotation.Component; +import org.redkale.service.Local; +import org.redkale.util.AnyValue; + +/** + * MQ消费器, 实现类必须标记{@link org.redkale.mq.ResourceConsumer} + * + *

详情见: https://redkale.org + * + * @see org.redkale.mq.MessageConext + * @see org.redkale.mq.ResourceConsumer + * @author zhangjx + * @param T + * @since 2.8.0 + */ +@Local +@Component +@ClassDepends +public interface MessageConsumer { + + default void init(AnyValue config) {} + + public void onMessage(MessageConext context, T message); + + default void destroy(AnyValue config) {} +} diff --git a/src/main/java/org/redkale/mq/MessageManager.java b/src/main/java/org/redkale/mq/MessageManager.java index bbc978029..5ab82fa3c 100644 --- a/src/main/java/org/redkale/mq/MessageManager.java +++ b/src/main/java/org/redkale/mq/MessageManager.java @@ -1,27 +1,27 @@ -/* - * - */ -package org.redkale.mq; - -import java.util.List; -import org.redkale.inject.Resourcable; - -/** - * MQ消息管理器 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public interface MessageManager extends Resourcable { - - // - public boolean createTopic(String... topics); - - // 删除topic,如果不存在则跳过 - public boolean deleteTopic(String... topics); - - // 查询所有topic - public abstract List queryTopic(); -} +/* + * + */ +package org.redkale.mq; + +import java.util.List; +import org.redkale.inject.Resourcable; + +/** + * MQ消息管理器 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public interface MessageManager extends Resourcable { + + // + public boolean createTopic(String... topics); + + // 删除topic,如果不存在则跳过 + public boolean deleteTopic(String... topics); + + // 查询所有topic + public abstract List queryTopic(); +} diff --git a/src/main/java/org/redkale/mq/MessageProducer.java b/src/main/java/org/redkale/mq/MessageProducer.java index 08eb22a9d..e741ab666 100644 --- a/src/main/java/org/redkale/mq/MessageProducer.java +++ b/src/main/java/org/redkale/mq/MessageProducer.java @@ -1,42 +1,42 @@ -/* - * - */ -package org.redkale.mq; - -import java.lang.reflect.Type; -import java.util.concurrent.CompletableFuture; -import org.redkale.convert.Convert; - -/** - * MQ消息发送器 {@link org.redkale.mq.ResourceProducer} - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public interface MessageProducer { - - public CompletableFuture sendMessage( - String topic, Integer partition, Convert convert, Type type, Object value); - - default CompletableFuture sendMessage(String topic, Integer partition, Convert convert, Object value) { - return sendMessage(topic, partition, convert, (Type) null, value); - } - - default CompletableFuture sendMessage(String topic, Integer partition, Object value) { - return sendMessage(topic, partition, (Convert) null, (Type) null, value); - } - - default CompletableFuture sendMessage(String topic, Convert convert, Type type, Object value) { - return sendMessage(topic, (Integer) null, convert, type, value); - } - - default CompletableFuture sendMessage(String topic, Convert convert, Object value) { - return sendMessage(topic, (Integer) null, convert, value); - } - - default CompletableFuture sendMessage(String topic, Object value) { - return sendMessage(topic, (Integer) null, value); - } -} +/* + * + */ +package org.redkale.mq; + +import java.lang.reflect.Type; +import java.util.concurrent.CompletableFuture; +import org.redkale.convert.Convert; + +/** + * MQ消息发送器 {@link org.redkale.mq.ResourceProducer} + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public interface MessageProducer { + + public CompletableFuture sendMessage( + String topic, Integer partition, Convert convert, Type type, Object value); + + default CompletableFuture sendMessage(String topic, Integer partition, Convert convert, Object value) { + return sendMessage(topic, partition, convert, (Type) null, value); + } + + default CompletableFuture sendMessage(String topic, Integer partition, Object value) { + return sendMessage(topic, partition, (Convert) null, (Type) null, value); + } + + default CompletableFuture sendMessage(String topic, Convert convert, Type type, Object value) { + return sendMessage(topic, (Integer) null, convert, type, value); + } + + default CompletableFuture sendMessage(String topic, Convert convert, Object value) { + return sendMessage(topic, (Integer) null, convert, value); + } + + default CompletableFuture sendMessage(String topic, Object value) { + return sendMessage(topic, (Integer) null, value); + } +} diff --git a/src/main/java/org/redkale/mq/Messaged.java b/src/main/java/org/redkale/mq/Messaged.java index 807fd1d74..f212a9a0f 100644 --- a/src/main/java/org/redkale/mq/Messaged.java +++ b/src/main/java/org/redkale/mq/Messaged.java @@ -1,43 +1,43 @@ -/* - * - */ -package org.redkale.mq; - -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; -import org.redkale.convert.ConvertType; -import org.redkale.service.LoadMode; - -/** - * MQ资源注解, 只能标记在Service类方法上 1、方法必须是protected/public 2、方法不能是final/static - * - *

详情见: https://redkale.org - * - * @see org.redkale.mq.ResourceConsumer - * @author zhangjx - * @since 2.8.0 - */ -@Documented -@Target({METHOD}) -@Retention(RUNTIME) -public @interface Messaged { - - String mq() default ""; - - String group() default ""; - - String[] topics(); - - ConvertType convertType() default ConvertType.JSON; - - /** - * Service加载模式 - * - * @return 模式 - */ - LoadMode mode() default LoadMode.LOCAL; -} +/* + * + */ +package org.redkale.mq; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; +import org.redkale.convert.ConvertType; +import org.redkale.service.LoadMode; + +/** + * MQ资源注解, 只能标记在Service类方法上 1、方法必须是protected/public 2、方法不能是final/static + * + *

详情见: https://redkale.org + * + * @see org.redkale.mq.ResourceConsumer + * @author zhangjx + * @since 2.8.0 + */ +@Documented +@Target({METHOD}) +@Retention(RUNTIME) +public @interface Messaged { + + String mq() default ""; + + String group() default ""; + + String[] topics(); + + ConvertType convertType() default ConvertType.JSON; + + /** + * Service加载模式 + * + * @return 模式 + */ + LoadMode mode() default LoadMode.LOCAL; +} diff --git a/src/main/java/org/redkale/mq/ResourceConsumer.java b/src/main/java/org/redkale/mq/ResourceConsumer.java index e2f9c4dbe..bcc3bc56f 100644 --- a/src/main/java/org/redkale/mq/ResourceConsumer.java +++ b/src/main/java/org/redkale/mq/ResourceConsumer.java @@ -1,34 +1,34 @@ -/* - * - */ -package org.redkale.mq; - -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.*; -import org.redkale.annotation.ClassDepends; -import org.redkale.convert.ConvertType; - -/** - * MQ资源注解, 只能标记在{@link org.redkale.mq.MessageConsumer}子类上 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -@ClassDepends -@Documented -@Target({TYPE}) -@Retention(RUNTIME) -public @interface ResourceConsumer { - - String mq() default ""; - - String group() default ""; - - String[] topics(); - - ConvertType convertType() default ConvertType.JSON; -} +/* + * + */ +package org.redkale.mq; + +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.*; +import org.redkale.annotation.ClassDepends; +import org.redkale.convert.ConvertType; + +/** + * MQ资源注解, 只能标记在{@link org.redkale.mq.MessageConsumer}子类上 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +@ClassDepends +@Documented +@Target({TYPE}) +@Retention(RUNTIME) +public @interface ResourceConsumer { + + String mq() default ""; + + String group() default ""; + + String[] topics(); + + ConvertType convertType() default ConvertType.JSON; +} diff --git a/src/main/java/org/redkale/mq/ResourceProducer.java b/src/main/java/org/redkale/mq/ResourceProducer.java index da86c817d..df419b32c 100644 --- a/src/main/java/org/redkale/mq/ResourceProducer.java +++ b/src/main/java/org/redkale/mq/ResourceProducer.java @@ -1,31 +1,31 @@ -/* - * - */ -package org.redkale.mq; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.*; -import org.redkale.convert.ConvertType; - -/** - * MQ资源注解, 只能标记在{@link org.redkale.mq.MessageProducer}类型字段上 - * - *

详情见: https://redkale.org - * - * @see org.redkale.mq.MessageProducer - * @author zhangjx - * @since 2.8.0 - */ -@Documented -@Target({FIELD}) -@Retention(RUNTIME) -public @interface ResourceProducer { - - String mq() default ""; - - boolean required() default true; - - ConvertType convertType() default ConvertType.JSON; -} +/* + * + */ +package org.redkale.mq; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.*; +import org.redkale.convert.ConvertType; + +/** + * MQ资源注解, 只能标记在{@link org.redkale.mq.MessageProducer}类型字段上 + * + *

详情见: https://redkale.org + * + * @see org.redkale.mq.MessageProducer + * @author zhangjx + * @since 2.8.0 + */ +@Documented +@Target({FIELD}) +@Retention(RUNTIME) +public @interface ResourceProducer { + + String mq() default ""; + + boolean required() default true; + + ConvertType convertType() default ConvertType.JSON; +} diff --git a/src/main/java/org/redkale/mq/spi/DynForMessage.java b/src/main/java/org/redkale/mq/spi/DynForMessage.java index a62ade99d..61334f387 100644 --- a/src/main/java/org/redkale/mq/spi/DynForMessage.java +++ b/src/main/java/org/redkale/mq/spi/DynForMessage.java @@ -1,38 +1,38 @@ -/* - * - */ -package org.redkale.mq.spi; - -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.Documented; -import java.lang.annotation.Inherited; -import java.lang.annotation.Repeatable; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; -import org.redkale.mq.MessageConsumer; - -/** - * 只标准在类上面,因动态方法不作变动,只增加内部类 - * - * @author zhangjx - */ -@Inherited -@Documented -@Target({TYPE}) -@Retention(RUNTIME) -@Repeatable(DynForMessage.DynForMessages.class) -public @interface DynForMessage { - - Class value(); - - @Inherited - @Documented - @Target({TYPE}) - @Retention(RUNTIME) - @interface DynForMessages { - - DynForMessage[] value(); - } -} +/* + * + */ +package org.redkale.mq.spi; + +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Inherited; +import java.lang.annotation.Repeatable; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; +import org.redkale.mq.MessageConsumer; + +/** + * 只标准在类上面,因动态方法不作变动,只增加内部类 + * + * @author zhangjx + */ +@Inherited +@Documented +@Target({TYPE}) +@Retention(RUNTIME) +@Repeatable(DynForMessage.DynForMessages.class) +public @interface DynForMessage { + + Class value(); + + @Inherited + @Documented + @Target({TYPE}) + @Retention(RUNTIME) + @interface DynForMessages { + + DynForMessage[] value(); + } +} diff --git a/src/main/java/org/redkale/mq/spi/HttpRpcMessageClient.java b/src/main/java/org/redkale/mq/spi/HttpRpcMessageClient.java index 501bccb46..a9c7a41fa 100644 --- a/src/main/java/org/redkale/mq/spi/HttpRpcMessageClient.java +++ b/src/main/java/org/redkale/mq/spi/HttpRpcMessageClient.java @@ -1,50 +1,50 @@ -/* - * - */ -package org.redkale.mq.spi; - -import static org.redkale.mq.spi.MessageRecord.CTYPE_HTTP_REQUEST; - -import java.io.Serializable; -import java.util.concurrent.CompletableFuture; -import org.redkale.cluster.HttpRpcClient; -import org.redkale.net.http.HttpResult; -import org.redkale.net.http.WebRequest; - -/** @author zhangjx */ -final class HttpRpcMessageClient extends HttpRpcClient { - - private final MessageCoder requestCoder = WebRequestCoder.getInstance(); - - private final String nodeid; - - private final MessageClient messageClient; - - public HttpRpcMessageClient(MessageClient messageClient, final String nodeid) { - this.messageClient = messageClient; - this.nodeid = nodeid; - } - - @Override - public CompletableFuture> sendMessage( - String topic, Serializable userid, String groupid, WebRequest request) { - MessageRecord message = messageClient.createMessageRecord( - CTYPE_HTTP_REQUEST, topic, null, request.getTraceid(), requestCoder.encode(request)); - message.userid(userid).groupid(groupid); - return messageClient.sendMessage(message).thenApply(r -> r.decodeContent(HttpResultCoder.getInstance())); - } - - @Override - public CompletableFuture produceMessage( - String topic, Serializable userid, String groupid, WebRequest request) { - MessageRecord message = messageClient.createMessageRecord( - CTYPE_HTTP_REQUEST, topic, null, request.getTraceid(), requestCoder.encode(request)); - message.userid(userid).groupid(groupid); - return messageClient.produceMessage(message); - } - - @Override - protected String getNodeid() { - return nodeid; - } -} +/* + * + */ +package org.redkale.mq.spi; + +import static org.redkale.mq.spi.MessageRecord.CTYPE_HTTP_REQUEST; + +import java.io.Serializable; +import java.util.concurrent.CompletableFuture; +import org.redkale.cluster.HttpRpcClient; +import org.redkale.net.http.HttpResult; +import org.redkale.net.http.WebRequest; + +/** @author zhangjx */ +final class HttpRpcMessageClient extends HttpRpcClient { + + private final MessageCoder requestCoder = WebRequestCoder.getInstance(); + + private final String nodeid; + + private final MessageClient messageClient; + + public HttpRpcMessageClient(MessageClient messageClient, final String nodeid) { + this.messageClient = messageClient; + this.nodeid = nodeid; + } + + @Override + public CompletableFuture> sendMessage( + String topic, Serializable userid, String groupid, WebRequest request) { + MessageRecord message = messageClient.createMessageRecord( + CTYPE_HTTP_REQUEST, topic, null, request.getTraceid(), requestCoder.encode(request)); + message.userid(userid).groupid(groupid); + return messageClient.sendMessage(message).thenApply(r -> r.decodeContent(HttpResultCoder.getInstance())); + } + + @Override + public CompletableFuture produceMessage( + String topic, Serializable userid, String groupid, WebRequest request) { + MessageRecord message = messageClient.createMessageRecord( + CTYPE_HTTP_REQUEST, topic, null, request.getTraceid(), requestCoder.encode(request)); + message.userid(userid).groupid(groupid); + return messageClient.produceMessage(message); + } + + @Override + protected String getNodeid() { + return nodeid; + } +} diff --git a/src/main/java/org/redkale/mq/spi/MessageAsmMethodBoost.java b/src/main/java/org/redkale/mq/spi/MessageAsmMethodBoost.java index bdbaf7eb7..c314063b4 100644 --- a/src/main/java/org/redkale/mq/spi/MessageAsmMethodBoost.java +++ b/src/main/java/org/redkale/mq/spi/MessageAsmMethodBoost.java @@ -1,345 +1,345 @@ -/* - * - */ -package org.redkale.mq.spi; - -import static org.redkale.asm.ClassWriter.COMPUTE_FRAMES; -import static org.redkale.asm.Opcodes.ACC_BRIDGE; -import static org.redkale.asm.Opcodes.ACC_PRIVATE; -import static org.redkale.asm.Opcodes.ACC_PUBLIC; -import static org.redkale.asm.Opcodes.ACC_STATIC; -import static org.redkale.asm.Opcodes.ACC_SUPER; -import static org.redkale.asm.Opcodes.ACC_SYNTHETIC; -import static org.redkale.asm.Opcodes.ALOAD; -import static org.redkale.asm.Opcodes.ASTORE; -import static org.redkale.asm.Opcodes.ATHROW; -import static org.redkale.asm.Opcodes.CHECKCAST; -import static org.redkale.asm.Opcodes.DUP; -import static org.redkale.asm.Opcodes.GETFIELD; -import static org.redkale.asm.Opcodes.GOTO; -import static org.redkale.asm.Opcodes.INVOKESPECIAL; -import static org.redkale.asm.Opcodes.INVOKEVIRTUAL; -import static org.redkale.asm.Opcodes.NEW; -import static org.redkale.asm.Opcodes.POP; -import static org.redkale.asm.Opcodes.PUTFIELD; -import static org.redkale.asm.Opcodes.RETURN; -import static org.redkale.asm.Opcodes.V11; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.lang.reflect.Type; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; -import org.redkale.asm.AnnotationVisitor; -import org.redkale.asm.AsmMethodBean; -import org.redkale.asm.AsmMethodBoost; -import org.redkale.asm.Asms; -import org.redkale.asm.ClassWriter; -import org.redkale.asm.FieldVisitor; -import org.redkale.asm.Label; -import org.redkale.asm.MethodVisitor; -import org.redkale.asm.Opcodes; -import org.redkale.convert.ConvertFactory; -import org.redkale.inject.ResourceFactory; -import org.redkale.mq.MessageConext; -import org.redkale.mq.MessageConsumer; -import org.redkale.mq.Messaged; -import org.redkale.mq.ResourceConsumer; -import org.redkale.service.LoadMode; -import org.redkale.util.RedkaleClassLoader; -import org.redkale.util.RedkaleException; -import org.redkale.util.TypeToken; -import org.redkale.util.Utility; - -/** @author zhangjx */ -public class MessageAsmMethodBoost extends AsmMethodBoost { - - private static final List> FILTER_ANN = List.of(Messaged.class); - - private final AtomicInteger index = new AtomicInteger(); - - private final MessageModuleEngine messageEngine; - - private Map methodBeans; - - private RedkaleClassLoader.DynBytesClassLoader newLoader; - - private List> consumers; - - public MessageAsmMethodBoost(boolean remote, Class serviceType, MessageModuleEngine messageEngine) { - super(remote, serviceType); - this.messageEngine = messageEngine; - } - - @Override - public List> filterMethodAnnotations(Method method) { - return FILTER_ANN; - } - - @Override - public String doMethod( - ClassLoader classLoader, - ClassWriter cw, - String newDynName, - String fieldPrefix, - List filterAnns, - Method method, - String newMethodName) { - if (serviceType.getAnnotation(DynForMessage.class) != null) { - return newMethodName; - } - Messaged messaged = method.getAnnotation(Messaged.class); - if (messaged == null) { - return newMethodName; - } - if (!LoadMode.matches(remote, messaged.mode())) { - return newMethodName; - } - if (Modifier.isFinal(method.getModifiers()) || Modifier.isStatic(method.getModifiers())) { - throw new RedkaleException( - "@" + Messaged.class.getSimpleName() + " cannot on final or static method, but on " + method); - } - if (!Modifier.isProtected(method.getModifiers()) && !Modifier.isPublic(method.getModifiers())) { - throw new RedkaleException( - "@" + Messaged.class.getSimpleName() + " must on protected or public method, but on " + method); - } - int paramCount = method.getParameterCount(); - if (paramCount != 1 && paramCount != 2) { - throw new RedkaleException( - "@" + Messaged.class.getSimpleName() + " must on one or two parameter method, but on " + method); - } - int paramKind = 1; // 1:单个MessageType; 2: MessageConext & MessageType; 3: MessageType & MessageConext; - Type messageType; - Type[] paramTypes = method.getGenericParameterTypes(); - if (paramCount == 1) { - messageType = paramTypes[0]; - paramKind = 1; - } else { - if (paramTypes[0] == MessageConext.class) { - messageType = paramTypes[1]; - paramKind = 2; - } else if (paramTypes[1] == MessageConext.class) { - messageType = paramTypes[0]; - paramKind = 3; - } else { - throw new RedkaleException( - "@" + Messaged.class.getSimpleName() + " on two-parameter method must contains " - + MessageConext.class.getSimpleName() + " parameter type, but on " + method); - } - } - ConvertFactory factory = - ConvertFactory.findConvert(messaged.convertType()).getFactory(); - factory.loadDecoder(messageType); - if (newLoader == null) { - newLoader = new RedkaleClassLoader.DynBytesClassLoader( - classLoader == null ? Thread.currentThread().getContextClassLoader() : classLoader); - } - createInnerConsumer( - cw, method, paramKind, TypeToken.typeToClass(messageType), messaged, newDynName, newMethodName); - return newMethodName; - } - - // paramKind: 1:单个MessageType; 2: MessageConext & MessageType; 3: MessageType & MessageConext; - private void createInnerConsumer( - ClassWriter parentCW, - Method method, - int paramKind, - Class msgType, - Messaged messaged, - String newDynName, - String newMethodName) { - final String newDynDesc = "L" + newDynName + ";"; - final String innerClassName = "Dyn" + MessageConsumer.class.getSimpleName() + index.incrementAndGet(); - final String innerFullName = newDynName + "$" + innerClassName; - final String msgTypeDesc = org.redkale.asm.Type.getDescriptor(TypeToken.primitiveToWrapper(msgType)); - final String messageConsumerName = MessageConsumer.class.getName().replace('.', '/'); - final String messageConsumerDesc = org.redkale.asm.Type.getDescriptor(MessageConsumer.class); - final String messageConextDesc = org.redkale.asm.Type.getDescriptor(MessageConext.class); - final boolean throwFlag = - Utility.contains(method.getExceptionTypes(), e -> !RuntimeException.class.isAssignableFrom(e)); - - if (methodBeans == null) { - methodBeans = AsmMethodBoost.getMethodBeans(serviceType); - } - AsmMethodBean methodBean = AsmMethodBean.get(methodBeans, method); - String genericMsgTypeDesc = msgTypeDesc; - if (!msgType.isPrimitive()) { - String methodSignature = methodBean.getSignature().replace(messageConextDesc, ""); - genericMsgTypeDesc = methodSignature.substring(1, methodSignature.lastIndexOf(')')); // 获取()中的值 - } - - parentCW.visitInnerClass(innerFullName, newDynName, innerClassName, ACC_PUBLIC + ACC_STATIC); - - MethodVisitor mv; - ClassWriter cw = new ClassWriter(COMPUTE_FRAMES); - // - cw.visit( - V11, - ACC_PUBLIC + ACC_SUPER, - innerFullName, - "Ljava/lang/Object;" + messageConsumerDesc.replace(";", "<" + genericMsgTypeDesc + ">;"), - "java/lang/Object", - new String[] {messageConsumerName}); - { - AnnotationVisitor av = cw.visitAnnotation(org.redkale.asm.Type.getDescriptor(ResourceConsumer.class), true); - Asms.visitAnnotation(av, messaged); - av.visitEnd(); - } - cw.visitInnerClass(innerFullName, newDynName, innerClassName, ACC_PUBLIC + ACC_STATIC); - { - FieldVisitor fv = cw.visitField(ACC_PRIVATE, "service", newDynDesc, null, null); - fv.visitEnd(); - } - { - mv = cw.visitMethod(ACC_PUBLIC, "", "(" + newDynDesc + ")V", null, null); - mv.visitCode(); - Label l0 = new Label(); - mv.visitLabel(l0); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); - Label l1 = new Label(); - mv.visitLabel(l1); - mv.visitVarInsn(ALOAD, 0); - mv.visitVarInsn(ALOAD, 1); - mv.visitFieldInsn(PUTFIELD, innerFullName, "service", newDynDesc); - Label l2 = new Label(); - mv.visitLabel(l2); - mv.visitInsn(RETURN); - Label l3 = new Label(); - mv.visitLabel(l3); - mv.visitLocalVariable("this", "L" + innerFullName + ";", null, l0, l3, 0); - mv.visitLocalVariable("service", newDynDesc, null, l0, l3, 1); - mv.visitMaxs(2, 2); - mv.visitEnd(); - } - { - String methodName = newMethodName == null ? method.getName() : newMethodName; - mv = cw.visitMethod( - ACC_PUBLIC, - "onMessage", - "(" + messageConextDesc + msgTypeDesc + ")V", - msgTypeDesc.equals(genericMsgTypeDesc) - ? null - : ("(" + messageConextDesc + genericMsgTypeDesc + ")V"), - null); - Label l0 = new Label(); - Label l1 = new Label(); - Label l2 = new Label(); - if (throwFlag) { - mv.visitTryCatchBlock(l0, l1, l2, "java/lang/Throwable"); - mv.visitLabel(l0); - } - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, innerFullName, "service", newDynDesc); - if (paramKind == 1) { // 1: 单个MessageType; - mv.visitVarInsn(ALOAD, 2); - Asms.visitPrimitiveVirtual(mv, msgType); - } else if (paramKind == 2) { // 2: MessageConext & MessageType; - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(ALOAD, 2); - Asms.visitPrimitiveVirtual(mv, msgType); - } else { // 3: MessageType & MessageConext; - mv.visitVarInsn(ALOAD, 2); - Asms.visitPrimitiveVirtual(mv, msgType); - mv.visitVarInsn(ALOAD, 1); - } - mv.visitMethodInsn( - INVOKEVIRTUAL, newDynName, methodName, org.redkale.asm.Type.getMethodDescriptor(method), false); - if (method.getReturnType() != void.class) { - mv.visitInsn(POP); - } - mv.visitLabel(l1); - Label l3 = null, l4 = null; - if (throwFlag) { - l3 = new Label(); - mv.visitJumpInsn(GOTO, l3); - mv.visitLabel(l2); - mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {"java/lang/Throwable"}); - mv.visitVarInsn(ASTORE, 3); - l4 = new Label(); - mv.visitLabel(l4); - mv.visitTypeInsn(NEW, "java/lang/RuntimeException"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 3); - mv.visitMethodInsn( - INVOKESPECIAL, "java/lang/RuntimeException", "", "(Ljava/lang/Throwable;)V", false); - mv.visitInsn(ATHROW); - mv.visitLabel(l3); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - } - mv.visitInsn(RETURN); - Label l5 = new Label(); - mv.visitLabel(l5); - mv.visitLocalVariable("this", "L" + innerFullName + ";", null, l0, l5, 0); - mv.visitLocalVariable("context", messageConextDesc, null, l0, l5, 1); - mv.visitLocalVariable( - "message", - msgTypeDesc, - msgTypeDesc.equals(genericMsgTypeDesc) ? null : genericMsgTypeDesc, - l0, - l5, - 2); - if (throwFlag) { - mv.visitLocalVariable("e", "Ljava/lang/Throwable;", null, l4, l3, 3); - } - mv.visitMaxs(4, 4); - mv.visitEnd(); - } - { - mv = cw.visitMethod( - ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC, - "onMessage", - "(" + messageConextDesc + "Ljava/lang/Object;)V", - null, - null); - mv.visitCode(); - Label l0 = new Label(); - mv.visitLabel(l0); - mv.visitVarInsn(ALOAD, 0); - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(ALOAD, 2); - mv.visitTypeInsn(CHECKCAST, "java/lang/String"); - mv.visitMethodInsn( - INVOKEVIRTUAL, innerFullName, "onMessage", "(" + messageConextDesc + msgTypeDesc + ")V", false); - mv.visitInsn(RETURN); - mv.visitMaxs(3, 3); - mv.visitEnd(); - } - cw.visitEnd(); - - byte[] bytes = cw.toByteArray(); - Class cz = newLoader.loadClass((innerFullName).replace('/', '.'), bytes); - if (consumers == null) { - consumers = new ArrayList<>(); - } - consumers.add(cz); - RedkaleClassLoader.putDynClass((innerFullName).replace('/', '.'), bytes, cz); - } - - @Override - public void doInstance(ResourceFactory resourceFactory, Object service) { - DynForMessage[] dyns = service.getClass().getAnnotationsByType(DynForMessage.class); - if (dyns.length < 1) { - return; - } - try { - if (Utility.isNotEmpty(consumers)) { - for (Class clazz : consumers) { - MessageConsumer consumer = (MessageConsumer) clazz.getConstructors()[0].newInstance(service); - messageEngine.addMessageConsumer(consumer); - } - } else { - for (DynForMessage item : dyns) { - Class clazz = item.value(); - MessageConsumer consumer = (MessageConsumer) clazz.getConstructors()[0].newInstance(service); - messageEngine.addMessageConsumer(consumer); - } - } - } catch (Exception e) { - throw new RedkaleException(e); - } - } -} +/* + * + */ +package org.redkale.mq.spi; + +import static org.redkale.asm.ClassWriter.COMPUTE_FRAMES; +import static org.redkale.asm.Opcodes.ACC_BRIDGE; +import static org.redkale.asm.Opcodes.ACC_PRIVATE; +import static org.redkale.asm.Opcodes.ACC_PUBLIC; +import static org.redkale.asm.Opcodes.ACC_STATIC; +import static org.redkale.asm.Opcodes.ACC_SUPER; +import static org.redkale.asm.Opcodes.ACC_SYNTHETIC; +import static org.redkale.asm.Opcodes.ALOAD; +import static org.redkale.asm.Opcodes.ASTORE; +import static org.redkale.asm.Opcodes.ATHROW; +import static org.redkale.asm.Opcodes.CHECKCAST; +import static org.redkale.asm.Opcodes.DUP; +import static org.redkale.asm.Opcodes.GETFIELD; +import static org.redkale.asm.Opcodes.GOTO; +import static org.redkale.asm.Opcodes.INVOKESPECIAL; +import static org.redkale.asm.Opcodes.INVOKEVIRTUAL; +import static org.redkale.asm.Opcodes.NEW; +import static org.redkale.asm.Opcodes.POP; +import static org.redkale.asm.Opcodes.PUTFIELD; +import static org.redkale.asm.Opcodes.RETURN; +import static org.redkale.asm.Opcodes.V11; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; +import org.redkale.asm.AnnotationVisitor; +import org.redkale.asm.AsmMethodBean; +import org.redkale.asm.AsmMethodBoost; +import org.redkale.asm.Asms; +import org.redkale.asm.ClassWriter; +import org.redkale.asm.FieldVisitor; +import org.redkale.asm.Label; +import org.redkale.asm.MethodVisitor; +import org.redkale.asm.Opcodes; +import org.redkale.convert.ConvertFactory; +import org.redkale.inject.ResourceFactory; +import org.redkale.mq.MessageConext; +import org.redkale.mq.MessageConsumer; +import org.redkale.mq.Messaged; +import org.redkale.mq.ResourceConsumer; +import org.redkale.service.LoadMode; +import org.redkale.util.RedkaleClassLoader; +import org.redkale.util.RedkaleException; +import org.redkale.util.TypeToken; +import org.redkale.util.Utility; + +/** @author zhangjx */ +public class MessageAsmMethodBoost extends AsmMethodBoost { + + private static final List> FILTER_ANN = List.of(Messaged.class); + + private final AtomicInteger index = new AtomicInteger(); + + private final MessageModuleEngine messageEngine; + + private Map methodBeans; + + private RedkaleClassLoader.DynBytesClassLoader newLoader; + + private List> consumers; + + public MessageAsmMethodBoost(boolean remote, Class serviceType, MessageModuleEngine messageEngine) { + super(remote, serviceType); + this.messageEngine = messageEngine; + } + + @Override + public List> filterMethodAnnotations(Method method) { + return FILTER_ANN; + } + + @Override + public String doMethod( + ClassLoader classLoader, + ClassWriter cw, + String newDynName, + String fieldPrefix, + List filterAnns, + Method method, + String newMethodName) { + if (serviceType.getAnnotation(DynForMessage.class) != null) { + return newMethodName; + } + Messaged messaged = method.getAnnotation(Messaged.class); + if (messaged == null) { + return newMethodName; + } + if (!LoadMode.matches(remote, messaged.mode())) { + return newMethodName; + } + if (Modifier.isFinal(method.getModifiers()) || Modifier.isStatic(method.getModifiers())) { + throw new RedkaleException( + "@" + Messaged.class.getSimpleName() + " cannot on final or static method, but on " + method); + } + if (!Modifier.isProtected(method.getModifiers()) && !Modifier.isPublic(method.getModifiers())) { + throw new RedkaleException( + "@" + Messaged.class.getSimpleName() + " must on protected or public method, but on " + method); + } + int paramCount = method.getParameterCount(); + if (paramCount != 1 && paramCount != 2) { + throw new RedkaleException( + "@" + Messaged.class.getSimpleName() + " must on one or two parameter method, but on " + method); + } + int paramKind = 1; // 1:单个MessageType; 2: MessageConext & MessageType; 3: MessageType & MessageConext; + Type messageType; + Type[] paramTypes = method.getGenericParameterTypes(); + if (paramCount == 1) { + messageType = paramTypes[0]; + paramKind = 1; + } else { + if (paramTypes[0] == MessageConext.class) { + messageType = paramTypes[1]; + paramKind = 2; + } else if (paramTypes[1] == MessageConext.class) { + messageType = paramTypes[0]; + paramKind = 3; + } else { + throw new RedkaleException( + "@" + Messaged.class.getSimpleName() + " on two-parameter method must contains " + + MessageConext.class.getSimpleName() + " parameter type, but on " + method); + } + } + ConvertFactory factory = + ConvertFactory.findConvert(messaged.convertType()).getFactory(); + factory.loadDecoder(messageType); + if (newLoader == null) { + newLoader = new RedkaleClassLoader.DynBytesClassLoader( + classLoader == null ? Thread.currentThread().getContextClassLoader() : classLoader); + } + createInnerConsumer( + cw, method, paramKind, TypeToken.typeToClass(messageType), messaged, newDynName, newMethodName); + return newMethodName; + } + + // paramKind: 1:单个MessageType; 2: MessageConext & MessageType; 3: MessageType & MessageConext; + private void createInnerConsumer( + ClassWriter parentCW, + Method method, + int paramKind, + Class msgType, + Messaged messaged, + String newDynName, + String newMethodName) { + final String newDynDesc = "L" + newDynName + ";"; + final String innerClassName = "Dyn" + MessageConsumer.class.getSimpleName() + index.incrementAndGet(); + final String innerFullName = newDynName + "$" + innerClassName; + final String msgTypeDesc = org.redkale.asm.Type.getDescriptor(TypeToken.primitiveToWrapper(msgType)); + final String messageConsumerName = MessageConsumer.class.getName().replace('.', '/'); + final String messageConsumerDesc = org.redkale.asm.Type.getDescriptor(MessageConsumer.class); + final String messageConextDesc = org.redkale.asm.Type.getDescriptor(MessageConext.class); + final boolean throwFlag = + Utility.contains(method.getExceptionTypes(), e -> !RuntimeException.class.isAssignableFrom(e)); + + if (methodBeans == null) { + methodBeans = AsmMethodBoost.getMethodBeans(serviceType); + } + AsmMethodBean methodBean = AsmMethodBean.get(methodBeans, method); + String genericMsgTypeDesc = msgTypeDesc; + if (!msgType.isPrimitive()) { + String methodSignature = methodBean.getSignature().replace(messageConextDesc, ""); + genericMsgTypeDesc = methodSignature.substring(1, methodSignature.lastIndexOf(')')); // 获取()中的值 + } + + parentCW.visitInnerClass(innerFullName, newDynName, innerClassName, ACC_PUBLIC + ACC_STATIC); + + MethodVisitor mv; + ClassWriter cw = new ClassWriter(COMPUTE_FRAMES); + // + cw.visit( + V11, + ACC_PUBLIC + ACC_SUPER, + innerFullName, + "Ljava/lang/Object;" + messageConsumerDesc.replace(";", "<" + genericMsgTypeDesc + ">;"), + "java/lang/Object", + new String[] {messageConsumerName}); + { + AnnotationVisitor av = cw.visitAnnotation(org.redkale.asm.Type.getDescriptor(ResourceConsumer.class), true); + Asms.visitAnnotation(av, messaged); + av.visitEnd(); + } + cw.visitInnerClass(innerFullName, newDynName, innerClassName, ACC_PUBLIC + ACC_STATIC); + { + FieldVisitor fv = cw.visitField(ACC_PRIVATE, "service", newDynDesc, null, null); + fv.visitEnd(); + } + { + mv = cw.visitMethod(ACC_PUBLIC, "", "(" + newDynDesc + ")V", null, null); + mv.visitCode(); + Label l0 = new Label(); + mv.visitLabel(l0); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); + Label l1 = new Label(); + mv.visitLabel(l1); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 1); + mv.visitFieldInsn(PUTFIELD, innerFullName, "service", newDynDesc); + Label l2 = new Label(); + mv.visitLabel(l2); + mv.visitInsn(RETURN); + Label l3 = new Label(); + mv.visitLabel(l3); + mv.visitLocalVariable("this", "L" + innerFullName + ";", null, l0, l3, 0); + mv.visitLocalVariable("service", newDynDesc, null, l0, l3, 1); + mv.visitMaxs(2, 2); + mv.visitEnd(); + } + { + String methodName = newMethodName == null ? method.getName() : newMethodName; + mv = cw.visitMethod( + ACC_PUBLIC, + "onMessage", + "(" + messageConextDesc + msgTypeDesc + ")V", + msgTypeDesc.equals(genericMsgTypeDesc) + ? null + : ("(" + messageConextDesc + genericMsgTypeDesc + ")V"), + null); + Label l0 = new Label(); + Label l1 = new Label(); + Label l2 = new Label(); + if (throwFlag) { + mv.visitTryCatchBlock(l0, l1, l2, "java/lang/Throwable"); + mv.visitLabel(l0); + } + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, innerFullName, "service", newDynDesc); + if (paramKind == 1) { // 1: 单个MessageType; + mv.visitVarInsn(ALOAD, 2); + Asms.visitPrimitiveVirtual(mv, msgType); + } else if (paramKind == 2) { // 2: MessageConext & MessageType; + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 2); + Asms.visitPrimitiveVirtual(mv, msgType); + } else { // 3: MessageType & MessageConext; + mv.visitVarInsn(ALOAD, 2); + Asms.visitPrimitiveVirtual(mv, msgType); + mv.visitVarInsn(ALOAD, 1); + } + mv.visitMethodInsn( + INVOKEVIRTUAL, newDynName, methodName, org.redkale.asm.Type.getMethodDescriptor(method), false); + if (method.getReturnType() != void.class) { + mv.visitInsn(POP); + } + mv.visitLabel(l1); + Label l3 = null, l4 = null; + if (throwFlag) { + l3 = new Label(); + mv.visitJumpInsn(GOTO, l3); + mv.visitLabel(l2); + mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {"java/lang/Throwable"}); + mv.visitVarInsn(ASTORE, 3); + l4 = new Label(); + mv.visitLabel(l4); + mv.visitTypeInsn(NEW, "java/lang/RuntimeException"); + mv.visitInsn(DUP); + mv.visitVarInsn(ALOAD, 3); + mv.visitMethodInsn( + INVOKESPECIAL, "java/lang/RuntimeException", "", "(Ljava/lang/Throwable;)V", false); + mv.visitInsn(ATHROW); + mv.visitLabel(l3); + mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); + } + mv.visitInsn(RETURN); + Label l5 = new Label(); + mv.visitLabel(l5); + mv.visitLocalVariable("this", "L" + innerFullName + ";", null, l0, l5, 0); + mv.visitLocalVariable("context", messageConextDesc, null, l0, l5, 1); + mv.visitLocalVariable( + "message", + msgTypeDesc, + msgTypeDesc.equals(genericMsgTypeDesc) ? null : genericMsgTypeDesc, + l0, + l5, + 2); + if (throwFlag) { + mv.visitLocalVariable("e", "Ljava/lang/Throwable;", null, l4, l3, 3); + } + mv.visitMaxs(4, 4); + mv.visitEnd(); + } + { + mv = cw.visitMethod( + ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC, + "onMessage", + "(" + messageConextDesc + "Ljava/lang/Object;)V", + null, + null); + mv.visitCode(); + Label l0 = new Label(); + mv.visitLabel(l0); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 2); + mv.visitTypeInsn(CHECKCAST, "java/lang/String"); + mv.visitMethodInsn( + INVOKEVIRTUAL, innerFullName, "onMessage", "(" + messageConextDesc + msgTypeDesc + ")V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(3, 3); + mv.visitEnd(); + } + cw.visitEnd(); + + byte[] bytes = cw.toByteArray(); + Class cz = newLoader.loadClass((innerFullName).replace('/', '.'), bytes); + if (consumers == null) { + consumers = new ArrayList<>(); + } + consumers.add(cz); + RedkaleClassLoader.putDynClass((innerFullName).replace('/', '.'), bytes, cz); + } + + @Override + public void doInstance(ResourceFactory resourceFactory, Object service) { + DynForMessage[] dyns = service.getClass().getAnnotationsByType(DynForMessage.class); + if (dyns.length < 1) { + return; + } + try { + if (Utility.isNotEmpty(consumers)) { + for (Class clazz : consumers) { + MessageConsumer consumer = (MessageConsumer) clazz.getConstructors()[0].newInstance(service); + messageEngine.addMessageConsumer(consumer); + } + } else { + for (DynForMessage item : dyns) { + Class clazz = item.value(); + MessageConsumer consumer = (MessageConsumer) clazz.getConstructors()[0].newInstance(service); + messageEngine.addMessageConsumer(consumer); + } + } + } catch (Exception e) { + throw new RedkaleException(e); + } + } +} diff --git a/src/main/java/org/redkale/mq/spi/MessageModuleEngine.java b/src/main/java/org/redkale/mq/spi/MessageModuleEngine.java index 0265a2e4f..1546779d6 100644 --- a/src/main/java/org/redkale/mq/spi/MessageModuleEngine.java +++ b/src/main/java/org/redkale/mq/spi/MessageModuleEngine.java @@ -1,513 +1,513 @@ -/* - * - */ -package org.redkale.mq.spi; - -import java.lang.reflect.Field; -import java.lang.reflect.Type; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Properties; -import java.util.ServiceLoader; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.logging.Level; -import org.redkale.asm.AsmMethodBoost; -import org.redkale.boot.Application; -import org.redkale.boot.ClassFilter; -import org.redkale.boot.ModuleEngine; -import org.redkale.boot.NodeServer; -import org.redkale.convert.json.JsonConvert; -import org.redkale.inject.ResourceAnnotationLoader; -import org.redkale.inject.ResourceEvent; -import org.redkale.inject.ResourceFactory; -import org.redkale.inject.ResourceTypeLoader; -import org.redkale.mq.MessageConsumer; -import org.redkale.mq.MessageManager; -import org.redkale.mq.MessageProducer; -import org.redkale.mq.ResourceConsumer; -import org.redkale.mq.ResourceProducer; -import org.redkale.net.http.RestException; -import org.redkale.util.AnyValue; -import org.redkale.util.AnyValueWriter; -import org.redkale.util.RedkaleClassLoader; -import org.redkale.util.RedkaleException; -import org.redkale.util.Utility; - -/** @author zhangjx */ -public class MessageModuleEngine extends ModuleEngine { - - // MQ管理配置资源 - // @since 2.8.0 - private final Properties messageProperties = new Properties(); - - // - private final Map> agentConsumers = new ConcurrentHashMap<>(); - - // MQ管理接口 - // @since 2.1.0 - private MessageAgent[] messageAgents; - - public MessageModuleEngine(Application application) { - super(application); - } - - /** - * 动态扩展类的方法 - * - * @param remote 是否远程模式 - * @param serviceClass 类 - * @return 方法动态扩展器 - */ - @Override - public AsmMethodBoost createAsmMethodBoost(boolean remote, Class serviceClass) { - return new MessageAsmMethodBoost(remote, serviceClass, this); - } - - void addMessageConsumer(MessageConsumer consumer) { - String agentName = environment.getPropertyValue( - consumer.getClass().getAnnotation(ResourceConsumer.class).mq()); - agentConsumers - .computeIfAbsent(agentName, v -> new CopyOnWriteArrayList<>()) - .add(consumer); - } - - /** - * 判断模块的配置项合并策略, 返回null表示模块不识别此配置项 - * - * @param path 配置项路径 - * @param key 配置项名称 - * @param val1 配置项原值 - * @param val2 配置项新值 - * @return MergeEnum - */ - @Override - public AnyValue.MergeEnum mergeAppConfigStrategy(String path, String key, AnyValue val1, AnyValue val2) { - if ("".equals(path) && "mq".equals(key)) { - if (Objects.equals(val1.getValue("name"), val2.getValue("name"))) { - return AnyValue.MergeEnum.REPLACE; - } else { - return AnyValue.MergeEnum.DEFAULT; - } - } - return null; - } - - /** 配置项加载后被调用 */ - @Override - public void onEnvironmentLoaded(Properties allProps) { - if (this.messageAgents == null) { - return; - } - allProps.forEach((key, val) -> { - if (key.toString().startsWith("redkale.mq.") || key.toString().startsWith("redkale.mq[")) { - if (key.toString().endsWith(".name")) { - logger.log(Level.WARNING, "skip illegal key " + key + " in mq config, key cannot endsWith '.name'"); - } else { - this.messageProperties.put(key, val); - } - } - }); - } - - /** 结束Application.init方法前被调用 */ - @Override - public void onAppPostInit() { - MessageAgent[] mqs = null; - AnyValue[] mqConfs = application.getAppConfig().getAnyValues("mq"); - if (mqConfs != null && mqConfs.length > 0) { - mqs = new MessageAgent[mqConfs.length]; - Set mqnames = new HashSet<>(); - for (int i = 0; i < mqConfs.length; i++) { - AnyValue mqConf = mqConfs[i]; - String names = environment.getPropertyValue(mqConf.getValue("name")); // 含,或者;表示多个别名使用同一mq对象 - if (names != null && !names.isEmpty()) { - for (String n : names.replace(',', ';').split(";")) { - if (n.trim().isEmpty()) { - continue; - } - if (mqnames.contains(n.trim())) { - throw new RedkaleException("mq.name(" + n.trim() + ") is repeat"); - } - mqnames.add(n.trim()); - } - } else if (names != null && names.isEmpty()) { - String n = ""; - if (mqnames.contains(n.trim())) { - throw new RedkaleException("mq.name(" + n.trim() + ") is repeat"); - } - mqnames.add(n); - } - try { - String classVal = environment.getPropertyValue( - mqConf.getValue("type", mqConf.getValue("value"))); // 兼容value字段 - if (classVal == null - || classVal.isEmpty() - || classVal.indexOf('.') < 0) { // 不包含.表示非类名,比如值: kafka, pulsar - Iterator it = ServiceLoader.load( - MessageAgentProvider.class, application.getClassLoader()) - .iterator(); - RedkaleClassLoader.putServiceLoader(MessageAgentProvider.class); - while (it.hasNext()) { - MessageAgentProvider provider = it.next(); - if (provider != null) { - RedkaleClassLoader.putReflectionPublicConstructors( - provider.getClass(), provider.getClass().getName()); // loader class - } - if (provider != null && provider.acceptsConf(mqConf)) { - mqs[i] = provider.createInstance(); - mqs[i].setConfig(mqConf); - break; - } - } - if (mqs[i] == null) { - logger.log( - Level.SEVERE, - "load application mq resource, but not found name='value' value error: " + mqConf); - } - } else { - Class type = application.getClassLoader().loadClass(classVal); - if (!MessageAgent.class.isAssignableFrom(type)) { - logger.log( - Level.SEVERE, - "load application mq resource, but not found " + MessageAgent.class.getSimpleName() - + " implements class error: " + mqConf); - } else { - RedkaleClassLoader.putReflectionDeclaredConstructors(type, type.getName()); - mqs[i] = - (MessageAgent) type.getDeclaredConstructor().newInstance(); - mqs[i].setConfig(mqConf); - } - } - // 此时不能执行mq.init,因内置的对象可能依赖config.properties配置项 - } catch (Exception e) { - logger.log(Level.SEVERE, "load application mq resource error: " + mqs[i], e); - } - } - } - this.messageAgents = mqs; - // ------------------------------------ 注册 ResourceProducer MessageProducer ------------------------------------ - resourceFactory.register(new ResourceAnnotationLoader() { - @Override - public void load( - ResourceFactory rf, - String srcResourceName, - Object srcObj, - ResourceProducer annotation, - Field field, - Object attachment) { - if (field.getType() != MessageProducer.class) { - throw new RestException("@" + ResourceProducer.class.getSimpleName() + " must on " - + MessageProducer.class.getName() + " type field, but on " + field); - } - MessageAgent agent = resourceFactory.find(annotation.mq(), MessageAgent.class); - if (!annotation.required() && agent == null) { - return; - } - if (agent == null) { - throw new RedkaleException("Not found " + MessageAgent.class.getSimpleName() + "(name = " - + annotation.mq() + ") on " + field); - } - try { - MessageProducer producer = agent.loadMessageProducer(annotation); - field.set(srcObj, producer); - } catch (RuntimeException ex) { - throw ex; - } catch (Exception e) { - throw new RedkaleException(field + "inject error", e); - } - } - - @Override - public Class annotationType() { - return ResourceProducer.class; - } - }); - - if (this.messageAgents == null) { - return; - } - if (logger.isLoggable(Level.FINER)) { - logger.log(Level.FINER, "MessageAgent initing"); - } - long s = System.currentTimeMillis(); - for (MessageAgent agent : this.messageAgents) { - String agentName = agent.getConfig().getValue("name", ""); - if (!application.isCompileMode()) { - this.resourceFactory.inject(agent); - agent.init(agent.getConfig()); - agentName = agent.getName(); - } else { - agent.name = agentName; - agent.application = application; - } - this.resourceFactory.register(agentName, MessageManager.class, agent); - this.resourceFactory.register(agentName, MessageAgent.class, agent); - } - logger.info("MessageAgent init in " + (System.currentTimeMillis() - s) + " ms"); - } - - /** - * 配置项变更时被调用 - * - * @param namespace 命名空间 - * @param events 变更项 - */ - @Override - public void onEnvironmentChanged(String namespace, List events) { - Set messageRemovedKeys = new HashSet<>(); - Properties messageChangedProps = new Properties(); - - for (ResourceEvent event : events) { - if (event.name().startsWith("redkale.mq.") || event.name().startsWith("redkale.mq[")) { - if (event.name().endsWith(".name")) { - logger.log( - Level.WARNING, - "skip illegal key " + event.name() + " in mq config " + (namespace == null ? "" : namespace) - + ", key cannot endsWith '.name'"); - } else { - if (!Objects.equals(event.newValue(), this.messageProperties.getProperty(event.name()))) { - if (event.newValue() == null) { - if (this.messageProperties.containsKey(event.name())) { - messageRemovedKeys.add(event.name()); - } - } else { - messageChangedProps.put(event.name(), event.newValue()); - } - } - } - } - } - // MQ配置项的变更 - if (!messageChangedProps.isEmpty() || !messageRemovedKeys.isEmpty()) { - Set messageNames = new LinkedHashSet<>(); - List keys = new ArrayList<>(); - keys.addAll(messageRemovedKeys); - keys.addAll((Set) messageChangedProps.keySet()); - for (final String key : keys) { - if (key.startsWith("redkale.mq[")) { - messageNames.add(key.substring("redkale.mq[".length(), key.indexOf(']'))); - } else if (key.startsWith("redkale.mq.")) { - messageNames.add(key.substring("redkale.mq.".length(), key.indexOf('.', "redkale.mq.".length()))); - } - } - // 更新MQ - for (String mqName : messageNames) { - MessageAgent agent = Utility.find(messageAgents, s -> Objects.equals(s.resourceName(), mqName)); - if (agent == null) { - continue; // 多余的数据源 - } - final AnyValueWriter old = (AnyValueWriter) findMQConfig(mqName); - Properties newProps = new Properties(); - this.messageProperties.forEach((k, v) -> { - final String key = k.toString(); - String prefix = "redkale.mq[" + mqName + "]."; - int pos = key.indexOf(prefix); - if (pos < 0) { - prefix = "redkale.mq." + mqName + "."; - pos = key.indexOf(prefix); - } - if (pos < 0) { - return; // 不是同一name数据源配置项 - } - newProps.put(k, v); - }); - List changeEvents = new ArrayList<>(); - messageChangedProps.forEach((k, v) -> { - final String key = k.toString(); - String prefix = "redkale.mq[" + mqName + "]."; - int pos = key.indexOf(prefix); - if (pos < 0) { - prefix = "redkale.mq." + mqName + "."; - pos = key.indexOf(prefix); - } - if (pos < 0) { - return; // 不是同一name数据源配置项 - } - newProps.put(k, v); - changeEvents.add(ResourceEvent.create( - key.substring(prefix.length()), v, this.messageProperties.getProperty(key))); - }); - messageRemovedKeys.forEach(k -> { - final String key = k; - String prefix = "redkale.mq[" + mqName + "]."; - int pos = key.indexOf(prefix); - if (pos < 0) { - prefix = "redkale.mq." + mqName + "."; - pos = key.indexOf(prefix); - } - if (pos < 0) { - return; - } - newProps.remove(k); // 不是同一name数据源配置项 - changeEvents.add(ResourceEvent.create( - key.substring(prefix.length()), null, this.messageProperties.getProperty(key))); - }); - if (!changeEvents.isEmpty()) { - AnyValueWriter back = old.copy(); - try { - old.replace(AnyValue.loadFromProperties(newProps) - .getAnyValue("redkale") - .getAnyValue("mq") - .getAnyValue(mqName)); - agent.onResourceChange(changeEvents.toArray(new ResourceEvent[changeEvents.size()])); - } catch (RuntimeException e) { - old.replace(back); // 还原配置 - throw e; - } - } - } - messageRemovedKeys.forEach(this.messageProperties::remove); - this.messageProperties.putAll(messageChangedProps); - } - } - - /** 服务全部启动后被调用 */ - @Override - public void onServersPostStart() { - if (this.messageAgents == null) { - return; - } - // startMessageAgent - if (logger.isLoggable(Level.FINE)) { - logger.log(Level.FINE, MessageAgent.class.getSimpleName() + " starting"); - } - long s = System.currentTimeMillis(); - Set names = new HashSet<>(); - ResourceFactory serResourceFactory = this.resourceFactory.createChild(); - List factorys = new ArrayList<>(); - for (NodeServer ns : application.getNodeServers()) { - factorys.add(ns.getResourceFactory()); - } - serResourceFactory.register(new ResourceTypeLoader() { - @Override - public Object load( - ResourceFactory rf, - String srcResourceName, - Object srcObj, - String resourceName, - Field field, - Object attachment) { - for (ResourceFactory f : factorys) { - Object val = f.find(resourceName, field.getGenericType()); - if (val != null) { - return val; - } - } - return null; - } - - @Override - public Type resourceType() { - return Object.class; - } - - @Override - public boolean autoNone() { - return false; - } - }); - for (MessageAgent agent : this.messageAgents) { - names.add(agent.getName()); - List consumers = - agentConsumers.getOrDefault(agent.getName(), new CopyOnWriteArrayList<>()); - AnyValue consumerConf = agent.getConfig().getAnyValue("consumer"); - if (consumerConf != null) { // 加载 MessageConsumer - ClassFilter filter = new ClassFilter( - application.getServerClassLoader(), ResourceConsumer.class, MessageConsumer.class, null, null); - if (consumerConf.getBoolValue("autoload", true)) { - String includes = consumerConf.getValue("includes", ""); - String excludes = consumerConf.getValue("excludes", ""); - filter.setIncludePatterns(includes.split(";")); - filter.setExcludePatterns(excludes.split(";")); - } else { - filter.setRefused(true); - } - - try { - application.loadServerClassFilters(filter); - List> entrys = - new ArrayList(filter.getFilterEntrys()); - for (ClassFilter.FilterEntry en : entrys) { - Class clazz = en.getType(); - ResourceConsumer res = clazz.getAnnotation(ResourceConsumer.class); - if (!Objects.equals(agent.getName(), environment.getPropertyValue(res.mq()))) { - continue; - } - RedkaleClassLoader.putReflectionDeclaredConstructors(clazz, clazz.getName()); - final MessageConsumer consumer = - clazz.getDeclaredConstructor().newInstance(); - serResourceFactory.inject(consumer); - consumers.add(consumer); - } - } catch (Exception e) { - throw new RedkaleException(e); - } - for (MessageConsumer consumer : consumers) { - consumer.init(consumerConf); - } - } - agent.start(consumers); - } - logger.info("MessageAgent(names=" + JsonConvert.root().convertTo(names) + ") started in " - + (System.currentTimeMillis() - s) + " ms"); - } - - /** 服务全部停掉前被调用 */ - @Override - public void onServersPreStop() { - if (application.isCompileMode() && this.messageAgents != null) { - Set names = new HashSet<>(); - if (logger.isLoggable(Level.FINER)) { - logger.log(Level.FINER, "MessageAgent stopping"); - } - long s = System.currentTimeMillis(); - for (MessageAgent agent : this.messageAgents) { - names.add(agent.getName()); - if (!application.isCompileMode()) { - agent.stop(); - } - } - logger.info("MessageAgent(names=" + JsonConvert.root().convertTo(names) + ") stop in " - + (System.currentTimeMillis() - s) + " ms"); - } - } - - /** 服务全部停掉后被调用 */ - @Override - public void onServersPostStop() { - if (this.messageAgents != null) { - Set names = new HashSet<>(); - if (logger.isLoggable(Level.FINER)) { - logger.log(Level.FINER, "MessageAgent destroying"); - } - long s = System.currentTimeMillis(); - for (MessageAgent agent : this.messageAgents) { - names.add(agent.getName()); - if (!application.isCompileMode()) { - agent.destroy(agent.getConfig()); - } - } - logger.info("MessageAgent(names=" + JsonConvert.root().convertTo(names) + ") destroy in " - + (System.currentTimeMillis() - s) + " ms"); - } - } - - private AnyValue findMQConfig(String mqName) { - AnyValue mqsNode = application.getAppConfig().getAnyValue("mq"); - if (mqsNode != null) { - AnyValue confNode = mqsNode.getAnyValue(mqName); - if (confNode != null) { // 必须要设置name属性 - ((AnyValueWriter) confNode).setValue("name", mqName); - } - return confNode; - } - return null; - } -} +/* + * + */ +package org.redkale.mq.spi; + +import java.lang.reflect.Field; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Properties; +import java.util.ServiceLoader; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.logging.Level; +import org.redkale.asm.AsmMethodBoost; +import org.redkale.boot.Application; +import org.redkale.boot.ClassFilter; +import org.redkale.boot.ModuleEngine; +import org.redkale.boot.NodeServer; +import org.redkale.convert.json.JsonConvert; +import org.redkale.inject.ResourceAnnotationLoader; +import org.redkale.inject.ResourceEvent; +import org.redkale.inject.ResourceFactory; +import org.redkale.inject.ResourceTypeLoader; +import org.redkale.mq.MessageConsumer; +import org.redkale.mq.MessageManager; +import org.redkale.mq.MessageProducer; +import org.redkale.mq.ResourceConsumer; +import org.redkale.mq.ResourceProducer; +import org.redkale.net.http.RestException; +import org.redkale.util.AnyValue; +import org.redkale.util.AnyValueWriter; +import org.redkale.util.RedkaleClassLoader; +import org.redkale.util.RedkaleException; +import org.redkale.util.Utility; + +/** @author zhangjx */ +public class MessageModuleEngine extends ModuleEngine { + + // MQ管理配置资源 + // @since 2.8.0 + private final Properties messageProperties = new Properties(); + + // + private final Map> agentConsumers = new ConcurrentHashMap<>(); + + // MQ管理接口 + // @since 2.1.0 + private MessageAgent[] messageAgents; + + public MessageModuleEngine(Application application) { + super(application); + } + + /** + * 动态扩展类的方法 + * + * @param remote 是否远程模式 + * @param serviceClass 类 + * @return 方法动态扩展器 + */ + @Override + public AsmMethodBoost createAsmMethodBoost(boolean remote, Class serviceClass) { + return new MessageAsmMethodBoost(remote, serviceClass, this); + } + + void addMessageConsumer(MessageConsumer consumer) { + String agentName = environment.getPropertyValue( + consumer.getClass().getAnnotation(ResourceConsumer.class).mq()); + agentConsumers + .computeIfAbsent(agentName, v -> new CopyOnWriteArrayList<>()) + .add(consumer); + } + + /** + * 判断模块的配置项合并策略, 返回null表示模块不识别此配置项 + * + * @param path 配置项路径 + * @param key 配置项名称 + * @param val1 配置项原值 + * @param val2 配置项新值 + * @return MergeEnum + */ + @Override + public AnyValue.MergeEnum mergeAppConfigStrategy(String path, String key, AnyValue val1, AnyValue val2) { + if ("".equals(path) && "mq".equals(key)) { + if (Objects.equals(val1.getValue("name"), val2.getValue("name"))) { + return AnyValue.MergeEnum.REPLACE; + } else { + return AnyValue.MergeEnum.DEFAULT; + } + } + return null; + } + + /** 配置项加载后被调用 */ + @Override + public void onEnvironmentLoaded(Properties allProps) { + if (this.messageAgents == null) { + return; + } + allProps.forEach((key, val) -> { + if (key.toString().startsWith("redkale.mq.") || key.toString().startsWith("redkale.mq[")) { + if (key.toString().endsWith(".name")) { + logger.log(Level.WARNING, "skip illegal key " + key + " in mq config, key cannot endsWith '.name'"); + } else { + this.messageProperties.put(key, val); + } + } + }); + } + + /** 结束Application.init方法前被调用 */ + @Override + public void onAppPostInit() { + MessageAgent[] mqs = null; + AnyValue[] mqConfs = application.getAppConfig().getAnyValues("mq"); + if (mqConfs != null && mqConfs.length > 0) { + mqs = new MessageAgent[mqConfs.length]; + Set mqnames = new HashSet<>(); + for (int i = 0; i < mqConfs.length; i++) { + AnyValue mqConf = mqConfs[i]; + String names = environment.getPropertyValue(mqConf.getValue("name")); // 含,或者;表示多个别名使用同一mq对象 + if (names != null && !names.isEmpty()) { + for (String n : names.replace(',', ';').split(";")) { + if (n.trim().isEmpty()) { + continue; + } + if (mqnames.contains(n.trim())) { + throw new RedkaleException("mq.name(" + n.trim() + ") is repeat"); + } + mqnames.add(n.trim()); + } + } else if (names != null && names.isEmpty()) { + String n = ""; + if (mqnames.contains(n.trim())) { + throw new RedkaleException("mq.name(" + n.trim() + ") is repeat"); + } + mqnames.add(n); + } + try { + String classVal = environment.getPropertyValue( + mqConf.getValue("type", mqConf.getValue("value"))); // 兼容value字段 + if (classVal == null + || classVal.isEmpty() + || classVal.indexOf('.') < 0) { // 不包含.表示非类名,比如值: kafka, pulsar + Iterator it = ServiceLoader.load( + MessageAgentProvider.class, application.getClassLoader()) + .iterator(); + RedkaleClassLoader.putServiceLoader(MessageAgentProvider.class); + while (it.hasNext()) { + MessageAgentProvider provider = it.next(); + if (provider != null) { + RedkaleClassLoader.putReflectionPublicConstructors( + provider.getClass(), provider.getClass().getName()); // loader class + } + if (provider != null && provider.acceptsConf(mqConf)) { + mqs[i] = provider.createInstance(); + mqs[i].setConfig(mqConf); + break; + } + } + if (mqs[i] == null) { + logger.log( + Level.SEVERE, + "load application mq resource, but not found name='value' value error: " + mqConf); + } + } else { + Class type = application.getClassLoader().loadClass(classVal); + if (!MessageAgent.class.isAssignableFrom(type)) { + logger.log( + Level.SEVERE, + "load application mq resource, but not found " + MessageAgent.class.getSimpleName() + + " implements class error: " + mqConf); + } else { + RedkaleClassLoader.putReflectionDeclaredConstructors(type, type.getName()); + mqs[i] = + (MessageAgent) type.getDeclaredConstructor().newInstance(); + mqs[i].setConfig(mqConf); + } + } + // 此时不能执行mq.init,因内置的对象可能依赖config.properties配置项 + } catch (Exception e) { + logger.log(Level.SEVERE, "load application mq resource error: " + mqs[i], e); + } + } + } + this.messageAgents = mqs; + // ------------------------------------ 注册 ResourceProducer MessageProducer ------------------------------------ + resourceFactory.register(new ResourceAnnotationLoader() { + @Override + public void load( + ResourceFactory rf, + String srcResourceName, + Object srcObj, + ResourceProducer annotation, + Field field, + Object attachment) { + if (field.getType() != MessageProducer.class) { + throw new RestException("@" + ResourceProducer.class.getSimpleName() + " must on " + + MessageProducer.class.getName() + " type field, but on " + field); + } + MessageAgent agent = resourceFactory.find(annotation.mq(), MessageAgent.class); + if (!annotation.required() && agent == null) { + return; + } + if (agent == null) { + throw new RedkaleException("Not found " + MessageAgent.class.getSimpleName() + "(name = " + + annotation.mq() + ") on " + field); + } + try { + MessageProducer producer = agent.loadMessageProducer(annotation); + field.set(srcObj, producer); + } catch (RuntimeException ex) { + throw ex; + } catch (Exception e) { + throw new RedkaleException(field + "inject error", e); + } + } + + @Override + public Class annotationType() { + return ResourceProducer.class; + } + }); + + if (this.messageAgents == null) { + return; + } + if (logger.isLoggable(Level.FINER)) { + logger.log(Level.FINER, "MessageAgent initing"); + } + long s = System.currentTimeMillis(); + for (MessageAgent agent : this.messageAgents) { + String agentName = agent.getConfig().getValue("name", ""); + if (!application.isCompileMode()) { + this.resourceFactory.inject(agent); + agent.init(agent.getConfig()); + agentName = agent.getName(); + } else { + agent.name = agentName; + agent.application = application; + } + this.resourceFactory.register(agentName, MessageManager.class, agent); + this.resourceFactory.register(agentName, MessageAgent.class, agent); + } + logger.info("MessageAgent init in " + (System.currentTimeMillis() - s) + " ms"); + } + + /** + * 配置项变更时被调用 + * + * @param namespace 命名空间 + * @param events 变更项 + */ + @Override + public void onEnvironmentChanged(String namespace, List events) { + Set messageRemovedKeys = new HashSet<>(); + Properties messageChangedProps = new Properties(); + + for (ResourceEvent event : events) { + if (event.name().startsWith("redkale.mq.") || event.name().startsWith("redkale.mq[")) { + if (event.name().endsWith(".name")) { + logger.log( + Level.WARNING, + "skip illegal key " + event.name() + " in mq config " + (namespace == null ? "" : namespace) + + ", key cannot endsWith '.name'"); + } else { + if (!Objects.equals(event.newValue(), this.messageProperties.getProperty(event.name()))) { + if (event.newValue() == null) { + if (this.messageProperties.containsKey(event.name())) { + messageRemovedKeys.add(event.name()); + } + } else { + messageChangedProps.put(event.name(), event.newValue()); + } + } + } + } + } + // MQ配置项的变更 + if (!messageChangedProps.isEmpty() || !messageRemovedKeys.isEmpty()) { + Set messageNames = new LinkedHashSet<>(); + List keys = new ArrayList<>(); + keys.addAll(messageRemovedKeys); + keys.addAll((Set) messageChangedProps.keySet()); + for (final String key : keys) { + if (key.startsWith("redkale.mq[")) { + messageNames.add(key.substring("redkale.mq[".length(), key.indexOf(']'))); + } else if (key.startsWith("redkale.mq.")) { + messageNames.add(key.substring("redkale.mq.".length(), key.indexOf('.', "redkale.mq.".length()))); + } + } + // 更新MQ + for (String mqName : messageNames) { + MessageAgent agent = Utility.find(messageAgents, s -> Objects.equals(s.resourceName(), mqName)); + if (agent == null) { + continue; // 多余的数据源 + } + final AnyValueWriter old = (AnyValueWriter) findMQConfig(mqName); + Properties newProps = new Properties(); + this.messageProperties.forEach((k, v) -> { + final String key = k.toString(); + String prefix = "redkale.mq[" + mqName + "]."; + int pos = key.indexOf(prefix); + if (pos < 0) { + prefix = "redkale.mq." + mqName + "."; + pos = key.indexOf(prefix); + } + if (pos < 0) { + return; // 不是同一name数据源配置项 + } + newProps.put(k, v); + }); + List changeEvents = new ArrayList<>(); + messageChangedProps.forEach((k, v) -> { + final String key = k.toString(); + String prefix = "redkale.mq[" + mqName + "]."; + int pos = key.indexOf(prefix); + if (pos < 0) { + prefix = "redkale.mq." + mqName + "."; + pos = key.indexOf(prefix); + } + if (pos < 0) { + return; // 不是同一name数据源配置项 + } + newProps.put(k, v); + changeEvents.add(ResourceEvent.create( + key.substring(prefix.length()), v, this.messageProperties.getProperty(key))); + }); + messageRemovedKeys.forEach(k -> { + final String key = k; + String prefix = "redkale.mq[" + mqName + "]."; + int pos = key.indexOf(prefix); + if (pos < 0) { + prefix = "redkale.mq." + mqName + "."; + pos = key.indexOf(prefix); + } + if (pos < 0) { + return; + } + newProps.remove(k); // 不是同一name数据源配置项 + changeEvents.add(ResourceEvent.create( + key.substring(prefix.length()), null, this.messageProperties.getProperty(key))); + }); + if (!changeEvents.isEmpty()) { + AnyValueWriter back = old.copy(); + try { + old.replace(AnyValue.loadFromProperties(newProps) + .getAnyValue("redkale") + .getAnyValue("mq") + .getAnyValue(mqName)); + agent.onResourceChange(changeEvents.toArray(new ResourceEvent[changeEvents.size()])); + } catch (RuntimeException e) { + old.replace(back); // 还原配置 + throw e; + } + } + } + messageRemovedKeys.forEach(this.messageProperties::remove); + this.messageProperties.putAll(messageChangedProps); + } + } + + /** 服务全部启动后被调用 */ + @Override + public void onServersPostStart() { + if (this.messageAgents == null) { + return; + } + // startMessageAgent + if (logger.isLoggable(Level.FINE)) { + logger.log(Level.FINE, MessageAgent.class.getSimpleName() + " starting"); + } + long s = System.currentTimeMillis(); + Set names = new HashSet<>(); + ResourceFactory serResourceFactory = this.resourceFactory.createChild(); + List factorys = new ArrayList<>(); + for (NodeServer ns : application.getNodeServers()) { + factorys.add(ns.getResourceFactory()); + } + serResourceFactory.register(new ResourceTypeLoader() { + @Override + public Object load( + ResourceFactory rf, + String srcResourceName, + Object srcObj, + String resourceName, + Field field, + Object attachment) { + for (ResourceFactory f : factorys) { + Object val = f.find(resourceName, field.getGenericType()); + if (val != null) { + return val; + } + } + return null; + } + + @Override + public Type resourceType() { + return Object.class; + } + + @Override + public boolean autoNone() { + return false; + } + }); + for (MessageAgent agent : this.messageAgents) { + names.add(agent.getName()); + List consumers = + agentConsumers.getOrDefault(agent.getName(), new CopyOnWriteArrayList<>()); + AnyValue consumerConf = agent.getConfig().getAnyValue("consumer"); + if (consumerConf != null) { // 加载 MessageConsumer + ClassFilter filter = new ClassFilter( + application.getServerClassLoader(), ResourceConsumer.class, MessageConsumer.class, null, null); + if (consumerConf.getBoolValue("autoload", true)) { + String includes = consumerConf.getValue("includes", ""); + String excludes = consumerConf.getValue("excludes", ""); + filter.setIncludePatterns(includes.split(";")); + filter.setExcludePatterns(excludes.split(";")); + } else { + filter.setRefused(true); + } + + try { + application.loadServerClassFilters(filter); + List> entrys = + new ArrayList(filter.getFilterEntrys()); + for (ClassFilter.FilterEntry en : entrys) { + Class clazz = en.getType(); + ResourceConsumer res = clazz.getAnnotation(ResourceConsumer.class); + if (!Objects.equals(agent.getName(), environment.getPropertyValue(res.mq()))) { + continue; + } + RedkaleClassLoader.putReflectionDeclaredConstructors(clazz, clazz.getName()); + final MessageConsumer consumer = + clazz.getDeclaredConstructor().newInstance(); + serResourceFactory.inject(consumer); + consumers.add(consumer); + } + } catch (Exception e) { + throw new RedkaleException(e); + } + for (MessageConsumer consumer : consumers) { + consumer.init(consumerConf); + } + } + agent.start(consumers); + } + logger.info("MessageAgent(names=" + JsonConvert.root().convertTo(names) + ") started in " + + (System.currentTimeMillis() - s) + " ms"); + } + + /** 服务全部停掉前被调用 */ + @Override + public void onServersPreStop() { + if (application.isCompileMode() && this.messageAgents != null) { + Set names = new HashSet<>(); + if (logger.isLoggable(Level.FINER)) { + logger.log(Level.FINER, "MessageAgent stopping"); + } + long s = System.currentTimeMillis(); + for (MessageAgent agent : this.messageAgents) { + names.add(agent.getName()); + if (!application.isCompileMode()) { + agent.stop(); + } + } + logger.info("MessageAgent(names=" + JsonConvert.root().convertTo(names) + ") stop in " + + (System.currentTimeMillis() - s) + " ms"); + } + } + + /** 服务全部停掉后被调用 */ + @Override + public void onServersPostStop() { + if (this.messageAgents != null) { + Set names = new HashSet<>(); + if (logger.isLoggable(Level.FINER)) { + logger.log(Level.FINER, "MessageAgent destroying"); + } + long s = System.currentTimeMillis(); + for (MessageAgent agent : this.messageAgents) { + names.add(agent.getName()); + if (!application.isCompileMode()) { + agent.destroy(agent.getConfig()); + } + } + logger.info("MessageAgent(names=" + JsonConvert.root().convertTo(names) + ") destroy in " + + (System.currentTimeMillis() - s) + " ms"); + } + } + + private AnyValue findMQConfig(String mqName) { + AnyValue mqsNode = application.getAppConfig().getAnyValue("mq"); + if (mqsNode != null) { + AnyValue confNode = mqsNode.getAnyValue(mqName); + if (confNode != null) { // 必须要设置name属性 + ((AnyValueWriter) confNode).setValue("name", mqName); + } + return confNode; + } + return null; + } +} diff --git a/src/main/java/org/redkale/mq/spi/MessageProcessor.java b/src/main/java/org/redkale/mq/spi/MessageProcessor.java index 91560769d..13000b392 100644 --- a/src/main/java/org/redkale/mq/spi/MessageProcessor.java +++ b/src/main/java/org/redkale/mq/spi/MessageProcessor.java @@ -1,10 +1,10 @@ -/* - * - */ -package org.redkale.mq.spi; - -/** @author zhangjx */ -public interface MessageProcessor { - - public void process(final MessageRecord msg, long time); -} +/* + * + */ +package org.redkale.mq.spi; + +/** @author zhangjx */ +public interface MessageProcessor { + + public void process(final MessageRecord msg, long time); +} diff --git a/src/main/java/org/redkale/mq/spi/MessageRespProcessor.java b/src/main/java/org/redkale/mq/spi/MessageRespProcessor.java index e17750e0f..321034365 100644 --- a/src/main/java/org/redkale/mq/spi/MessageRespProcessor.java +++ b/src/main/java/org/redkale/mq/spi/MessageRespProcessor.java @@ -1,72 +1,72 @@ -/* - * - */ -package org.redkale.mq.spi; - -import java.util.logging.Level; -import java.util.logging.Logger; -import org.redkale.util.Traces; - -/** - * 响应结果 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public class MessageRespProcessor implements MessageProcessor { - - private final MessageClient messageClient; - - public MessageRespProcessor(MessageClient messageClient) { - this.messageClient = messageClient; - } - - @Override - public void process(final MessageRecord msg, long time) { - String traceid = msg.getTraceid(); - long now = System.currentTimeMillis(); - Logger logger = messageClient.logger; - final boolean finest = logger.isLoggable(Level.FINEST); - MessageRespFuture resp = messageClient.respQueue.remove(msg.getSeqid()); - if (resp == null) { - logger.log( - Level.WARNING, - getClass().getSimpleName() + " process " + msg + " error, not found MessageRespFuture"); - return; - } - if (resp.scheduledFuture != null) { - resp.scheduledFuture.cancel(true); - } - final long deplay = now - msg.createTime; - if (finest) { - logger.log( - Level.FINEST, - getClass().getSimpleName() + ".MessageRespFuture.receive (mq.delay = " + deplay + "ms, mq.seqid = " - + msg.getSeqid() + ")"); - } - messageClient.getMessageAgent().execute(() -> { - Traces.currentTraceid(traceid); - resp.future.complete(msg); - long comems = System.currentTimeMillis() - now; - if ((deplay > 1000 || comems > 1000) && logger.isLoggable(Level.FINE)) { - logger.log( - Level.FINE, - getClass().getSimpleName() + ".MessageRespFuture.complete (mq.delay-slower = " + deplay - + "ms, mq.complete-slower = " + comems + "ms) mqresp.msg: " + msg); - } else if ((deplay > 50 || comems > 50) && logger.isLoggable(Level.FINER)) { - logger.log( - Level.FINER, - getClass().getSimpleName() + ".MessageRespFuture.complete (mq.delay-slowly = " + deplay - + "ms, mq.complete-slowly = " + comems + "ms) mqresp.msg: " + msg); - } else if (finest) { - logger.log( - Level.FINEST, - getClass().getSimpleName() + ".MessageRespFuture.complete (mq.delay-normal = " + deplay - + "ms, mq.complete-normal = " + comems + "ms) mqresp.msg: " + msg); - } - Traces.removeTraceid(); - }); - } -} +/* + * + */ +package org.redkale.mq.spi; + +import java.util.logging.Level; +import java.util.logging.Logger; +import org.redkale.util.Traces; + +/** + * 响应结果 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public class MessageRespProcessor implements MessageProcessor { + + private final MessageClient messageClient; + + public MessageRespProcessor(MessageClient messageClient) { + this.messageClient = messageClient; + } + + @Override + public void process(final MessageRecord msg, long time) { + String traceid = msg.getTraceid(); + long now = System.currentTimeMillis(); + Logger logger = messageClient.logger; + final boolean finest = logger.isLoggable(Level.FINEST); + MessageRespFuture resp = messageClient.respQueue.remove(msg.getSeqid()); + if (resp == null) { + logger.log( + Level.WARNING, + getClass().getSimpleName() + " process " + msg + " error, not found MessageRespFuture"); + return; + } + if (resp.scheduledFuture != null) { + resp.scheduledFuture.cancel(true); + } + final long deplay = now - msg.createTime; + if (finest) { + logger.log( + Level.FINEST, + getClass().getSimpleName() + ".MessageRespFuture.receive (mq.delay = " + deplay + "ms, mq.seqid = " + + msg.getSeqid() + ")"); + } + messageClient.getMessageAgent().execute(() -> { + Traces.currentTraceid(traceid); + resp.future.complete(msg); + long comems = System.currentTimeMillis() - now; + if ((deplay > 1000 || comems > 1000) && logger.isLoggable(Level.FINE)) { + logger.log( + Level.FINE, + getClass().getSimpleName() + ".MessageRespFuture.complete (mq.delay-slower = " + deplay + + "ms, mq.complete-slower = " + comems + "ms) mqresp.msg: " + msg); + } else if ((deplay > 50 || comems > 50) && logger.isLoggable(Level.FINER)) { + logger.log( + Level.FINER, + getClass().getSimpleName() + ".MessageRespFuture.complete (mq.delay-slowly = " + deplay + + "ms, mq.complete-slowly = " + comems + "ms) mqresp.msg: " + msg); + } else if (finest) { + logger.log( + Level.FINEST, + getClass().getSimpleName() + ".MessageRespFuture.complete (mq.delay-normal = " + deplay + + "ms, mq.complete-normal = " + comems + "ms) mqresp.msg: " + msg); + } + Traces.removeTraceid(); + }); + } +} diff --git a/src/main/java/org/redkale/net/AsyncNioConnection.java b/src/main/java/org/redkale/net/AsyncNioConnection.java index eb9826491..19e914967 100644 --- a/src/main/java/org/redkale/net/AsyncNioConnection.java +++ b/src/main/java/org/redkale/net/AsyncNioConnection.java @@ -1,698 +1,698 @@ -/* - * 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.io.*; -import java.net.SocketAddress; -import java.nio.ByteBuffer; -import java.nio.channels.*; -import java.util.*; -import java.util.concurrent.*; -import java.util.function.Consumer; -import javax.net.ssl.SSLContext; -import org.redkale.util.ByteBufferWriter; - -/** - * 详情见: https://redkale.org - * - * @author zhangjx - * @since 2.3.0 - */ -abstract class AsyncNioConnection extends AsyncConnection { - - protected SocketAddress remoteAddress; - - // protected final AtomicLong fastWriteCount = new AtomicLong(); - protected final Queue fastWriteQueue = new ConcurrentLinkedQueue<>(); - - // -------------------------------- 连操作 -------------------------------------- - protected Object connectAttachment; - - protected CompletionHandler connectCompletionHandler; - - protected SelectionKey connectKey; - - // -------------------------------- 读操作 -------------------------------------- - protected final AsyncNioCompletionHandler readTimeoutCompletionHandler = - new AsyncNioCompletionHandler<>(true, this); - - protected int readTimeoutSeconds; - - protected ByteBuffer readByteBuffer; - - protected CompletionHandler readCompletionHandler; - - protected SelectionKey readKey; - - // -------------------------------- 写操作 -------------------------------------- - protected final AsyncNioCompletionHandler writeTimeoutCompletionHandler = - new AsyncNioCompletionHandler<>(false, this); - - protected int writeTimeoutSeconds; - - protected byte[] writeByteTuple1Array; - - protected int writeByteTuple1Offset; - - protected int writeByteTuple1Length; - - protected byte[] writeByteTuple2Array; - - protected int writeByteTuple2Offset; - - protected int writeByteTuple2Length; - - // 写操作, 二选一,要么writeByteBuffer有值,要么writeByteBuffers、writeBuffersOffset、writeBuffersLength有值 - protected ByteBuffer writeByteBuffer; - - protected ByteBuffer[] writeByteBuffers; - - protected int writeBuffersOffset; - - protected int writeBuffersLength; - - protected int writeTotal; - - protected Object writeAttachment; - - protected CompletionHandler writeCompletionHandler; - - protected SelectionKey writeKey; - - // protected CompletionHandler writeFastHandler; - public AsyncNioConnection( - boolean clientMode, - AsyncIOGroup ioGroup, - AsyncIOThread ioReadThread, - AsyncIOThread ioWriteThread, - final int bufferCapacity, - SSLBuilder sslBuilder, - SSLContext sslContext) { - super(clientMode, ioGroup, ioReadThread, ioWriteThread, bufferCapacity, sslBuilder, sslContext); - } - - @Override - public SocketAddress getRemoteAddress() { - return remoteAddress; - } - - @Override - public void setReadTimeoutSeconds(int readTimeoutSeconds) { - this.readTimeoutSeconds = readTimeoutSeconds; - } - - @Override - public void setWriteTimeoutSeconds(int writeTimeoutSeconds) { - this.writeTimeoutSeconds = writeTimeoutSeconds; - } - - @Override - public int getReadTimeoutSeconds() { - return this.readTimeoutSeconds; - } - - @Override - public int getWriteTimeoutSeconds() { - return this.writeTimeoutSeconds; - } - - // @Override - // public AsyncConnection fastHandler(CompletionHandler handler) { - // Objects.requireNonNull(handler); - // this.writeFastHandler = (CompletionHandler) handler; - // return this; - // } - @Override - protected void startHandshake(final Consumer callback) { - ioReadThread.register(t -> super.startHandshake(callback)); - } - - @Override - protected void startRead(CompletionHandler handler) { - read(handler); - } - - @Override - protected final void readRegisterImpl(CompletionHandler handler) { - Objects.requireNonNull(handler); - if (!this.isConnected()) { - handler.failed(new NotYetConnectedException(), null); - return; - } - if (handler != readCompletionHandler && handler != readTimeoutCompletionHandler.handler) { - if (this.readPending) { - handler.failed(new ReadPendingException(), null); - return; - } - this.readPending = true; - if (this.readTimeoutSeconds > 0) { - AsyncNioCompletionHandler newHandler = this.readTimeoutCompletionHandler; - newHandler.handler( - handler, this.readByteBuffer); // new AsyncNioCompletionHandler(handler, this.readByteBuffer); - this.readCompletionHandler = newHandler; - newHandler.timeoutFuture = - ioGroup.scheduleTimeout(newHandler, this.readTimeoutSeconds, TimeUnit.SECONDS); - } else { - this.readCompletionHandler = handler; - } - } else { - this.readPending = true; - } - try { - if (readKey == null) { - ioReadThread.register(selector -> { - try { - if (readKey == null) { - readKey = keyFor(selector); - } - if (readKey == null) { - readKey = implRegister(selector, SelectionKey.OP_READ); - readKey.attach(this); - } else { - readKey.interestOps(readKey.interestOps() | SelectionKey.OP_READ); - } - } catch (ClosedChannelException e) { - handleRead(0, e); - } - }); - } else { - ioReadThread.interestOpsOr(readKey, SelectionKey.OP_READ); - } - } catch (Exception e) { - handleRead(0, e); - } - } - - @Override - public void readImpl(CompletionHandler handler) { - Objects.requireNonNull(handler); - if (!this.isConnected()) { - handler.failed(new NotYetConnectedException(), null); - return; - } - if (this.readPending) { - handler.failed(new ReadPendingException(), null); - return; - } - this.readPending = true; - if (this.readTimeoutSeconds > 0) { - AsyncNioCompletionHandler newHandler = this.readTimeoutCompletionHandler; - newHandler.handler( - handler, this.readByteBuffer); // new AsyncNioCompletionHandler(handler, this.readByteBuffer); - this.readCompletionHandler = newHandler; - newHandler.timeoutFuture = ioGroup.scheduleTimeout(newHandler, this.readTimeoutSeconds, TimeUnit.SECONDS); - } else { - this.readCompletionHandler = handler; - } - doRead(this.ioReadThread.inCurrThread()); - } - - @Override - public void write( - byte[] headerContent, - int headerOffset, - int headerLength, - byte[] bodyContent, - int bodyOffset, - int bodyLength, - CompletionHandler handler) { - - if (sslEngine != null) { - super.write(headerContent, headerOffset, headerLength, bodyContent, bodyOffset, bodyLength, handler); - return; - } - Objects.requireNonNull(headerContent); - Objects.requireNonNull(handler); - if (!this.isConnected()) { - handler.failed(new NotYetConnectedException(), null); - return; - } - if (this.writePending) { - handler.failed(new WritePendingException(), null); - return; - } - this.writePending = true; - this.writeByteTuple1Array = headerContent; - this.writeByteTuple1Offset = headerOffset; - this.writeByteTuple1Length = headerLength; - this.writeByteTuple2Array = bodyContent; - this.writeByteTuple2Offset = bodyOffset; - this.writeByteTuple2Length = bodyLength; - this.writeAttachment = null; - if (this.writeTimeoutSeconds > 0) { - AsyncNioCompletionHandler newHandler = this.writeTimeoutCompletionHandler; - newHandler.handler(handler, null); // new AsyncNioCompletionHandler(handler, null); - this.writeCompletionHandler = newHandler; - newHandler.timeoutFuture = ioGroup.scheduleTimeout(newHandler, this.writeTimeoutSeconds, TimeUnit.SECONDS); - } else { - AsyncNioCompletionHandler newHandler = this.writeTimeoutCompletionHandler; - newHandler.handler(handler, null); // new AsyncNioCompletionHandler(handler, null); - this.writeCompletionHandler = newHandler; - } - doWrite(); // 如果不是true,则bodyCallback的执行可能会切换线程 - } - - @Override - public void writeImpl(ByteBuffer src, A attachment, CompletionHandler handler) { - Objects.requireNonNull(src); - Objects.requireNonNull(handler); - if (!this.isConnected()) { - handler.failed(new NotYetConnectedException(), attachment); - return; - } - if (this.writePending) { - handler.failed(new WritePendingException(), attachment); - return; - } - this.writePending = true; - this.writeByteBuffer = src; - this.writeAttachment = attachment; - if (this.writeTimeoutSeconds > 0) { - AsyncNioCompletionHandler newHandler = this.writeTimeoutCompletionHandler; - newHandler.handler(handler, attachment); // new AsyncNioCompletionHandler(handler, attachment); - this.writeCompletionHandler = newHandler; - newHandler.timeoutFuture = ioGroup.scheduleTimeout(newHandler, this.writeTimeoutSeconds, TimeUnit.SECONDS); - } else { - this.writeCompletionHandler = (CompletionHandler) handler; - } - doWrite(); - } - - @Override - public void writeImpl( - ByteBuffer[] srcs, int offset, int length, A attachment, CompletionHandler handler) { - Objects.requireNonNull(srcs); - Objects.requireNonNull(handler); - if (!this.isConnected()) { - handler.failed(new NotYetConnectedException(), attachment); - return; - } - if (this.writePending) { - handler.failed(new WritePendingException(), attachment); - return; - } - this.writePending = true; - this.writeByteBuffers = srcs; - this.writeBuffersOffset = offset; - this.writeBuffersLength = length; - this.writeAttachment = attachment; - if (this.writeTimeoutSeconds > 0) { - AsyncNioCompletionHandler newHandler = this.writeTimeoutCompletionHandler; - newHandler.handler(handler, attachment); // new AsyncNioCompletionHandler(handler, attachment); - this.writeCompletionHandler = newHandler; - newHandler.timeoutFuture = ioGroup.scheduleTimeout(newHandler, this.writeTimeoutSeconds, TimeUnit.SECONDS); - } else { - this.writeCompletionHandler = (CompletionHandler) handler; - } - doWrite(); - } - - // @Override - // public void fastWrite(byte[] data) { - // CompletionHandler handler = this.writeFastHandler; - // Objects.requireNonNull(data); - // Objects.requireNonNull(handler, "fastHandler is null"); - // if (!this.isConnected()) { - // handler.failed(new NotYetConnectedException(), null); - // return; - // } - // this.writePending = true; - // this.fastWriteQueue.offer(data); - // this.fastWriteCount.incrementAndGet(); - // this.writeCompletionHandler = (CompletionHandler) handler; - // this.writeAttachment = null; - // try { - // if (writeKey == null) { - // ioWriteThread.register(selector -> { - // try { - // if (writeKey == null) { - // writeKey = keyFor(selector); - // } - // if (writeKey == null) { - // writeKey = implRegister(selector, SelectionKey.OP_WRITE); - // writeKey.attach(this); - // } else { - // writeKey.interestOps(writeKey.interestOps() | SelectionKey.OP_WRITE); - // } - // } catch (ClosedChannelException e) { - // handleWrite(0, e); - // } - // }); - // } else { - // ioWriteThread.interestOpsOr(writeKey, SelectionKey.OP_WRITE); - // } - // } catch (Exception e) { - // handleWrite(0, e); - // } - // } - public void doRead(boolean direct) { - try { - this.readTime = System.currentTimeMillis(); - int readCount = 0; - if (direct) { - if (this.readByteBuffer == null) { - this.readByteBuffer = sslEngine == null ? pollReadBuffer() : pollReadSSLBuffer(); - if (this.readTimeoutSeconds > 0) { - this.readTimeoutCompletionHandler.attachment(this.readByteBuffer); - } - } - readCount = implRead(readByteBuffer); - } - - if (readCount != 0) { - handleRead(readCount, null); - } else if (readKey == null) { - ioReadThread.register(selector -> { - try { - if (readKey == null) { - readKey = keyFor(selector); - } - if (readKey == null) { - readKey = implRegister(selector, SelectionKey.OP_READ); - readKey.attach(this); - } else { - readKey.interestOps(readKey.interestOps() | SelectionKey.OP_READ); - } - } catch (ClosedChannelException e) { - handleRead(0, e); - } - }); - } else { - ioReadThread.interestOpsOr(readKey, SelectionKey.OP_READ); - } - } catch (Exception e) { - handleRead(0, e); - } - } - - public void doWrite() { - try { - this.writeTime = System.currentTimeMillis(); - int totalCount = 0; - boolean hasRemain = true; - boolean writeCompleted = true; - boolean error = false; - // if (writeByteBuffer == null && writeByteBuffers == null && writeByteTuple1Array == null && - // fastWriteCount.get() > 0) { - // final ByteBuffer buffer = pollWriteBuffer(); - // ByteBufferWriter writer = null; - // byte[] item; - // while ((item = fastWriteQueue.poll()) != null) { - // fastWriteCount.decrementAndGet(); - // if (writer != null) { - // writer.put(item); - // } else if (buffer.remaining() >= item.length) { - // buffer.put(item); - // } else { - // writer = ByteBufferWriter.create(getWriteBufferSupplier(), buffer); - // writer.put(item); - // } - // } - // this.writeBuffersOffset = 0; - // if (writer == null) { - // this.writeByteBuffer = buffer.flip(); - // this.writeBuffersLength = 0; - // } else { - // this.writeByteBuffers = writer.toBuffers(); - // this.writeBuffersLength = this.writeByteBuffers.length; - // } - // this.writeByteTuple1Array = null; - // this.writeByteTuple1Offset = 0; - // this.writeByteTuple1Length = 0; - // this.writeByteTuple2Array = null; - // this.writeByteTuple2Offset = 0; - // this.writeByteTuple2Length = 0; - // } - - int batchOffset = writeBuffersOffset; - int batchLength = writeBuffersLength; - while (hasRemain) { // 必须要将buffer写完为止 - if (writeByteTuple1Array != null) { - final ByteBuffer buffer = pollWriteBuffer(); - if (buffer.remaining() >= writeByteTuple1Length + writeByteTuple2Length) { - buffer.put(writeByteTuple1Array, writeByteTuple1Offset, writeByteTuple1Length); - if (writeByteTuple2Length > 0) { - buffer.put(writeByteTuple2Array, writeByteTuple2Offset, writeByteTuple2Length); - } - this.writeByteBuffer = buffer.flip(); - this.writeByteTuple1Array = null; - this.writeByteTuple1Offset = 0; - this.writeByteTuple1Length = 0; - this.writeByteTuple2Array = null; - this.writeByteTuple2Offset = 0; - this.writeByteTuple2Length = 0; - } else { - ByteBufferWriter writer = ByteBufferWriter.create(getWriteBufferSupplier(), buffer); - writer.put(writeByteTuple1Array, writeByteTuple1Offset, writeByteTuple1Length); - if (writeByteTuple2Length > 0) { - writer.put(writeByteTuple2Array, writeByteTuple2Offset, writeByteTuple2Length); - } - final ByteBuffer[] buffers = writer.toBuffers(); - this.writeByteBuffers = buffers; - this.writeBuffersOffset = 0; - this.writeBuffersLength = buffers.length; - batchOffset = writeBuffersOffset; - batchLength = writeBuffersLength; - this.writeByteTuple1Array = null; - this.writeByteTuple1Offset = 0; - this.writeByteTuple1Length = 0; - this.writeByteTuple2Array = null; - this.writeByteTuple2Offset = 0; - this.writeByteTuple2Length = 0; - } - if (this.writeCompletionHandler == this.writeTimeoutCompletionHandler) { - if (writeByteBuffer == null) { - this.writeTimeoutCompletionHandler.buffers(writeByteBuffers); - } else { - this.writeTimeoutCompletionHandler.buffer(writeByteBuffer); - } - } - } - int writeCount; - if (writeByteBuffer != null) { - writeCount = implWrite(writeByteBuffer); - hasRemain = writeByteBuffer.hasRemaining(); - } else { - writeCount = implWrite(writeByteBuffers, batchOffset, batchLength); - boolean remain = false; - for (int i = 0; i < batchLength; i++) { - if (writeByteBuffers[batchOffset + i].hasRemaining()) { - remain = true; - batchOffset += i; - batchLength -= i; - break; - } - } - hasRemain = remain; - } - - if (writeCount == 0) { - if (hasRemain) { - // writeCompleted = false; - // writeTotal = totalCount; - continue; // 要全部输出完才返回 - } - break; - } else if (writeCount < 0) { - error = true; - totalCount = writeCount; - break; - } else { - totalCount += writeCount; - } - if (!hasRemain) { - break; - } - } - - if (error) { - handleWrite(totalCount, new ClosedChannelException()); - } else if (writeCompleted && (totalCount != 0 || !hasRemain)) { - handleWrite(this.writeTotal + totalCount, null); - // if (fastWriteCount.get() > 0) { - // doWrite(); - // } - } else if (writeKey == null) { - ioWriteThread.register(selector -> { - try { - if (writeKey == null) { - writeKey = keyFor(selector); - } - if (writeKey == null) { - writeKey = implRegister(selector, SelectionKey.OP_WRITE); - writeKey.attach(this); - } else { - writeKey.interestOps(writeKey.interestOps() | SelectionKey.OP_WRITE); - } - } catch (ClosedChannelException e) { - handleWrite(0, e); - } - }); - } else { - ioWriteThread.interestOpsOr(writeKey, SelectionKey.OP_WRITE); - } - } catch (IOException e) { - handleWrite(0, e); - } - } - - protected void handleConnect(Throwable t) { - if (connectKey != null) { - connectKey.cancel(); - connectKey = null; - } - CompletionHandler handler = this.connectCompletionHandler; - Object attach = this.connectAttachment; - - this.connectCompletionHandler = null; - this.connectAttachment = null; - this.connectPending = false; // 必须放最后 - - if (handler != null) { - if (t == null) { - handler.completed(null, attach); - } else { - handler.failed(t, attach); - } - } - } - - protected void handleRead(final int totalCount, Throwable t) { - CompletionHandler handler = this.readCompletionHandler; - ByteBuffer attach = this.readByteBuffer; - // 清空读参数 - this.readCompletionHandler = null; - this.readByteBuffer = null; - this.readPending = false; // 必须放最后 - - if (handler == null) { - if (t == null) { - protocolCodec.completed(totalCount, attach); - } else { - protocolCodec.failed(t, attach); - } - } else { - if (t == null) { - handler.completed(totalCount, attach); - } else { - handler.failed(t, attach); - } - } - } - - protected void handleWrite(final int totalCount, Throwable t) { - CompletionHandler handler = this.writeCompletionHandler; - Object attach = this.writeAttachment; - // 清空写参数 - this.writeCompletionHandler = null; - this.writeAttachment = null; - this.writeByteBuffer = null; - this.writeByteBuffers = null; - this.writeBuffersOffset = 0; - this.writeBuffersLength = 0; - this.writeTotal = 0; - this.writePending = false; // 必须放最后 - - if (t == null) { - handler.completed(totalCount, attach); - } else { - handler.failed(t, attach); - } - } - - @Deprecated(since = "2.5.0") - protected abstract ReadableByteChannel readableByteChannel(); - - @Deprecated(since = "2.5.0") - protected abstract WritableByteChannel writableByteChannel(); - - protected InputStream newInputStream() { - final ReadableByteChannel reader = readableByteChannel(); - return new InputStream() { - - ByteBuffer bb; - - @Override - public int read() throws IOException { - if (bb == null || !bb.hasRemaining()) { - int r = readBuffer(); - if (r < 1) { - return -1; - } - } - return bb.get() & 0xff; - } - - @Override - public int read(byte b[], int off, int len) throws IOException { - if (b == null) { - throw new NullPointerException(); - } else if (off < 0 || len < 0 || len > b.length - off) { - throw new IndexOutOfBoundsException(); - } else if (len == 0) { - return 0; - } - if (bb == null || !bb.hasRemaining()) { - int r = readBuffer(); - if (r < 1) { - return -1; - } - } - int size = Math.min(b.length, Math.min(len, bb.remaining())); - bb.get(b, off, size); - return size; - } - - @Override - public void close() throws IOException { - if (bb != null) { - offerReadBuffer(bb); - bb = null; - } - reader.close(); - } - - @Override - public int available() throws IOException { - if (bb == null || !bb.hasRemaining()) { - return 0; - } - return bb.remaining(); - } - - private int readBuffer() throws IOException { - if (bb == null) { - bb = pollReadBuffer(); - } else { - bb.clear(); - } - try { - int size = reader.read(bb); - bb.flip(); - return size; - } catch (IOException ioe) { - throw ioe; - } catch (Exception e) { - throw new IOException(e); - } - } - }; - } - - protected abstract SelectionKey keyFor(Selector sel); - - protected abstract SelectionKey implRegister(Selector sel, int ops) throws ClosedChannelException; - - protected abstract int implRead(ByteBuffer dst) throws IOException; - - protected abstract int implWrite(ByteBuffer src) throws IOException; - - protected abstract int implWrite(ByteBuffer[] srcs, int offset, int length) throws IOException; - - public abstract boolean isConnected(); - - public abstract void doConnect(); -} +/* + * 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.io.*; +import java.net.SocketAddress; +import java.nio.ByteBuffer; +import java.nio.channels.*; +import java.util.*; +import java.util.concurrent.*; +import java.util.function.Consumer; +import javax.net.ssl.SSLContext; +import org.redkale.util.ByteBufferWriter; + +/** + * 详情见: https://redkale.org + * + * @author zhangjx + * @since 2.3.0 + */ +abstract class AsyncNioConnection extends AsyncConnection { + + protected SocketAddress remoteAddress; + + // protected final AtomicLong fastWriteCount = new AtomicLong(); + protected final Queue fastWriteQueue = new ConcurrentLinkedQueue<>(); + + // -------------------------------- 连操作 -------------------------------------- + protected Object connectAttachment; + + protected CompletionHandler connectCompletionHandler; + + protected SelectionKey connectKey; + + // -------------------------------- 读操作 -------------------------------------- + protected final AsyncNioCompletionHandler readTimeoutCompletionHandler = + new AsyncNioCompletionHandler<>(true, this); + + protected int readTimeoutSeconds; + + protected ByteBuffer readByteBuffer; + + protected CompletionHandler readCompletionHandler; + + protected SelectionKey readKey; + + // -------------------------------- 写操作 -------------------------------------- + protected final AsyncNioCompletionHandler writeTimeoutCompletionHandler = + new AsyncNioCompletionHandler<>(false, this); + + protected int writeTimeoutSeconds; + + protected byte[] writeByteTuple1Array; + + protected int writeByteTuple1Offset; + + protected int writeByteTuple1Length; + + protected byte[] writeByteTuple2Array; + + protected int writeByteTuple2Offset; + + protected int writeByteTuple2Length; + + // 写操作, 二选一,要么writeByteBuffer有值,要么writeByteBuffers、writeBuffersOffset、writeBuffersLength有值 + protected ByteBuffer writeByteBuffer; + + protected ByteBuffer[] writeByteBuffers; + + protected int writeBuffersOffset; + + protected int writeBuffersLength; + + protected int writeTotal; + + protected Object writeAttachment; + + protected CompletionHandler writeCompletionHandler; + + protected SelectionKey writeKey; + + // protected CompletionHandler writeFastHandler; + public AsyncNioConnection( + boolean clientMode, + AsyncIOGroup ioGroup, + AsyncIOThread ioReadThread, + AsyncIOThread ioWriteThread, + final int bufferCapacity, + SSLBuilder sslBuilder, + SSLContext sslContext) { + super(clientMode, ioGroup, ioReadThread, ioWriteThread, bufferCapacity, sslBuilder, sslContext); + } + + @Override + public SocketAddress getRemoteAddress() { + return remoteAddress; + } + + @Override + public void setReadTimeoutSeconds(int readTimeoutSeconds) { + this.readTimeoutSeconds = readTimeoutSeconds; + } + + @Override + public void setWriteTimeoutSeconds(int writeTimeoutSeconds) { + this.writeTimeoutSeconds = writeTimeoutSeconds; + } + + @Override + public int getReadTimeoutSeconds() { + return this.readTimeoutSeconds; + } + + @Override + public int getWriteTimeoutSeconds() { + return this.writeTimeoutSeconds; + } + + // @Override + // public AsyncConnection fastHandler(CompletionHandler handler) { + // Objects.requireNonNull(handler); + // this.writeFastHandler = (CompletionHandler) handler; + // return this; + // } + @Override + protected void startHandshake(final Consumer callback) { + ioReadThread.register(t -> super.startHandshake(callback)); + } + + @Override + protected void startRead(CompletionHandler handler) { + read(handler); + } + + @Override + protected final void readRegisterImpl(CompletionHandler handler) { + Objects.requireNonNull(handler); + if (!this.isConnected()) { + handler.failed(new NotYetConnectedException(), null); + return; + } + if (handler != readCompletionHandler && handler != readTimeoutCompletionHandler.handler) { + if (this.readPending) { + handler.failed(new ReadPendingException(), null); + return; + } + this.readPending = true; + if (this.readTimeoutSeconds > 0) { + AsyncNioCompletionHandler newHandler = this.readTimeoutCompletionHandler; + newHandler.handler( + handler, this.readByteBuffer); // new AsyncNioCompletionHandler(handler, this.readByteBuffer); + this.readCompletionHandler = newHandler; + newHandler.timeoutFuture = + ioGroup.scheduleTimeout(newHandler, this.readTimeoutSeconds, TimeUnit.SECONDS); + } else { + this.readCompletionHandler = handler; + } + } else { + this.readPending = true; + } + try { + if (readKey == null) { + ioReadThread.register(selector -> { + try { + if (readKey == null) { + readKey = keyFor(selector); + } + if (readKey == null) { + readKey = implRegister(selector, SelectionKey.OP_READ); + readKey.attach(this); + } else { + readKey.interestOps(readKey.interestOps() | SelectionKey.OP_READ); + } + } catch (ClosedChannelException e) { + handleRead(0, e); + } + }); + } else { + ioReadThread.interestOpsOr(readKey, SelectionKey.OP_READ); + } + } catch (Exception e) { + handleRead(0, e); + } + } + + @Override + public void readImpl(CompletionHandler handler) { + Objects.requireNonNull(handler); + if (!this.isConnected()) { + handler.failed(new NotYetConnectedException(), null); + return; + } + if (this.readPending) { + handler.failed(new ReadPendingException(), null); + return; + } + this.readPending = true; + if (this.readTimeoutSeconds > 0) { + AsyncNioCompletionHandler newHandler = this.readTimeoutCompletionHandler; + newHandler.handler( + handler, this.readByteBuffer); // new AsyncNioCompletionHandler(handler, this.readByteBuffer); + this.readCompletionHandler = newHandler; + newHandler.timeoutFuture = ioGroup.scheduleTimeout(newHandler, this.readTimeoutSeconds, TimeUnit.SECONDS); + } else { + this.readCompletionHandler = handler; + } + doRead(this.ioReadThread.inCurrThread()); + } + + @Override + public void write( + byte[] headerContent, + int headerOffset, + int headerLength, + byte[] bodyContent, + int bodyOffset, + int bodyLength, + CompletionHandler handler) { + + if (sslEngine != null) { + super.write(headerContent, headerOffset, headerLength, bodyContent, bodyOffset, bodyLength, handler); + return; + } + Objects.requireNonNull(headerContent); + Objects.requireNonNull(handler); + if (!this.isConnected()) { + handler.failed(new NotYetConnectedException(), null); + return; + } + if (this.writePending) { + handler.failed(new WritePendingException(), null); + return; + } + this.writePending = true; + this.writeByteTuple1Array = headerContent; + this.writeByteTuple1Offset = headerOffset; + this.writeByteTuple1Length = headerLength; + this.writeByteTuple2Array = bodyContent; + this.writeByteTuple2Offset = bodyOffset; + this.writeByteTuple2Length = bodyLength; + this.writeAttachment = null; + if (this.writeTimeoutSeconds > 0) { + AsyncNioCompletionHandler newHandler = this.writeTimeoutCompletionHandler; + newHandler.handler(handler, null); // new AsyncNioCompletionHandler(handler, null); + this.writeCompletionHandler = newHandler; + newHandler.timeoutFuture = ioGroup.scheduleTimeout(newHandler, this.writeTimeoutSeconds, TimeUnit.SECONDS); + } else { + AsyncNioCompletionHandler newHandler = this.writeTimeoutCompletionHandler; + newHandler.handler(handler, null); // new AsyncNioCompletionHandler(handler, null); + this.writeCompletionHandler = newHandler; + } + doWrite(); // 如果不是true,则bodyCallback的执行可能会切换线程 + } + + @Override + public void writeImpl(ByteBuffer src, A attachment, CompletionHandler handler) { + Objects.requireNonNull(src); + Objects.requireNonNull(handler); + if (!this.isConnected()) { + handler.failed(new NotYetConnectedException(), attachment); + return; + } + if (this.writePending) { + handler.failed(new WritePendingException(), attachment); + return; + } + this.writePending = true; + this.writeByteBuffer = src; + this.writeAttachment = attachment; + if (this.writeTimeoutSeconds > 0) { + AsyncNioCompletionHandler newHandler = this.writeTimeoutCompletionHandler; + newHandler.handler(handler, attachment); // new AsyncNioCompletionHandler(handler, attachment); + this.writeCompletionHandler = newHandler; + newHandler.timeoutFuture = ioGroup.scheduleTimeout(newHandler, this.writeTimeoutSeconds, TimeUnit.SECONDS); + } else { + this.writeCompletionHandler = (CompletionHandler) handler; + } + doWrite(); + } + + @Override + public void writeImpl( + ByteBuffer[] srcs, int offset, int length, A attachment, CompletionHandler handler) { + Objects.requireNonNull(srcs); + Objects.requireNonNull(handler); + if (!this.isConnected()) { + handler.failed(new NotYetConnectedException(), attachment); + return; + } + if (this.writePending) { + handler.failed(new WritePendingException(), attachment); + return; + } + this.writePending = true; + this.writeByteBuffers = srcs; + this.writeBuffersOffset = offset; + this.writeBuffersLength = length; + this.writeAttachment = attachment; + if (this.writeTimeoutSeconds > 0) { + AsyncNioCompletionHandler newHandler = this.writeTimeoutCompletionHandler; + newHandler.handler(handler, attachment); // new AsyncNioCompletionHandler(handler, attachment); + this.writeCompletionHandler = newHandler; + newHandler.timeoutFuture = ioGroup.scheduleTimeout(newHandler, this.writeTimeoutSeconds, TimeUnit.SECONDS); + } else { + this.writeCompletionHandler = (CompletionHandler) handler; + } + doWrite(); + } + + // @Override + // public void fastWrite(byte[] data) { + // CompletionHandler handler = this.writeFastHandler; + // Objects.requireNonNull(data); + // Objects.requireNonNull(handler, "fastHandler is null"); + // if (!this.isConnected()) { + // handler.failed(new NotYetConnectedException(), null); + // return; + // } + // this.writePending = true; + // this.fastWriteQueue.offer(data); + // this.fastWriteCount.incrementAndGet(); + // this.writeCompletionHandler = (CompletionHandler) handler; + // this.writeAttachment = null; + // try { + // if (writeKey == null) { + // ioWriteThread.register(selector -> { + // try { + // if (writeKey == null) { + // writeKey = keyFor(selector); + // } + // if (writeKey == null) { + // writeKey = implRegister(selector, SelectionKey.OP_WRITE); + // writeKey.attach(this); + // } else { + // writeKey.interestOps(writeKey.interestOps() | SelectionKey.OP_WRITE); + // } + // } catch (ClosedChannelException e) { + // handleWrite(0, e); + // } + // }); + // } else { + // ioWriteThread.interestOpsOr(writeKey, SelectionKey.OP_WRITE); + // } + // } catch (Exception e) { + // handleWrite(0, e); + // } + // } + public void doRead(boolean direct) { + try { + this.readTime = System.currentTimeMillis(); + int readCount = 0; + if (direct) { + if (this.readByteBuffer == null) { + this.readByteBuffer = sslEngine == null ? pollReadBuffer() : pollReadSSLBuffer(); + if (this.readTimeoutSeconds > 0) { + this.readTimeoutCompletionHandler.attachment(this.readByteBuffer); + } + } + readCount = implRead(readByteBuffer); + } + + if (readCount != 0) { + handleRead(readCount, null); + } else if (readKey == null) { + ioReadThread.register(selector -> { + try { + if (readKey == null) { + readKey = keyFor(selector); + } + if (readKey == null) { + readKey = implRegister(selector, SelectionKey.OP_READ); + readKey.attach(this); + } else { + readKey.interestOps(readKey.interestOps() | SelectionKey.OP_READ); + } + } catch (ClosedChannelException e) { + handleRead(0, e); + } + }); + } else { + ioReadThread.interestOpsOr(readKey, SelectionKey.OP_READ); + } + } catch (Exception e) { + handleRead(0, e); + } + } + + public void doWrite() { + try { + this.writeTime = System.currentTimeMillis(); + int totalCount = 0; + boolean hasRemain = true; + boolean writeCompleted = true; + boolean error = false; + // if (writeByteBuffer == null && writeByteBuffers == null && writeByteTuple1Array == null && + // fastWriteCount.get() > 0) { + // final ByteBuffer buffer = pollWriteBuffer(); + // ByteBufferWriter writer = null; + // byte[] item; + // while ((item = fastWriteQueue.poll()) != null) { + // fastWriteCount.decrementAndGet(); + // if (writer != null) { + // writer.put(item); + // } else if (buffer.remaining() >= item.length) { + // buffer.put(item); + // } else { + // writer = ByteBufferWriter.create(getWriteBufferSupplier(), buffer); + // writer.put(item); + // } + // } + // this.writeBuffersOffset = 0; + // if (writer == null) { + // this.writeByteBuffer = buffer.flip(); + // this.writeBuffersLength = 0; + // } else { + // this.writeByteBuffers = writer.toBuffers(); + // this.writeBuffersLength = this.writeByteBuffers.length; + // } + // this.writeByteTuple1Array = null; + // this.writeByteTuple1Offset = 0; + // this.writeByteTuple1Length = 0; + // this.writeByteTuple2Array = null; + // this.writeByteTuple2Offset = 0; + // this.writeByteTuple2Length = 0; + // } + + int batchOffset = writeBuffersOffset; + int batchLength = writeBuffersLength; + while (hasRemain) { // 必须要将buffer写完为止 + if (writeByteTuple1Array != null) { + final ByteBuffer buffer = pollWriteBuffer(); + if (buffer.remaining() >= writeByteTuple1Length + writeByteTuple2Length) { + buffer.put(writeByteTuple1Array, writeByteTuple1Offset, writeByteTuple1Length); + if (writeByteTuple2Length > 0) { + buffer.put(writeByteTuple2Array, writeByteTuple2Offset, writeByteTuple2Length); + } + this.writeByteBuffer = buffer.flip(); + this.writeByteTuple1Array = null; + this.writeByteTuple1Offset = 0; + this.writeByteTuple1Length = 0; + this.writeByteTuple2Array = null; + this.writeByteTuple2Offset = 0; + this.writeByteTuple2Length = 0; + } else { + ByteBufferWriter writer = ByteBufferWriter.create(getWriteBufferSupplier(), buffer); + writer.put(writeByteTuple1Array, writeByteTuple1Offset, writeByteTuple1Length); + if (writeByteTuple2Length > 0) { + writer.put(writeByteTuple2Array, writeByteTuple2Offset, writeByteTuple2Length); + } + final ByteBuffer[] buffers = writer.toBuffers(); + this.writeByteBuffers = buffers; + this.writeBuffersOffset = 0; + this.writeBuffersLength = buffers.length; + batchOffset = writeBuffersOffset; + batchLength = writeBuffersLength; + this.writeByteTuple1Array = null; + this.writeByteTuple1Offset = 0; + this.writeByteTuple1Length = 0; + this.writeByteTuple2Array = null; + this.writeByteTuple2Offset = 0; + this.writeByteTuple2Length = 0; + } + if (this.writeCompletionHandler == this.writeTimeoutCompletionHandler) { + if (writeByteBuffer == null) { + this.writeTimeoutCompletionHandler.buffers(writeByteBuffers); + } else { + this.writeTimeoutCompletionHandler.buffer(writeByteBuffer); + } + } + } + int writeCount; + if (writeByteBuffer != null) { + writeCount = implWrite(writeByteBuffer); + hasRemain = writeByteBuffer.hasRemaining(); + } else { + writeCount = implWrite(writeByteBuffers, batchOffset, batchLength); + boolean remain = false; + for (int i = 0; i < batchLength; i++) { + if (writeByteBuffers[batchOffset + i].hasRemaining()) { + remain = true; + batchOffset += i; + batchLength -= i; + break; + } + } + hasRemain = remain; + } + + if (writeCount == 0) { + if (hasRemain) { + // writeCompleted = false; + // writeTotal = totalCount; + continue; // 要全部输出完才返回 + } + break; + } else if (writeCount < 0) { + error = true; + totalCount = writeCount; + break; + } else { + totalCount += writeCount; + } + if (!hasRemain) { + break; + } + } + + if (error) { + handleWrite(totalCount, new ClosedChannelException()); + } else if (writeCompleted && (totalCount != 0 || !hasRemain)) { + handleWrite(this.writeTotal + totalCount, null); + // if (fastWriteCount.get() > 0) { + // doWrite(); + // } + } else if (writeKey == null) { + ioWriteThread.register(selector -> { + try { + if (writeKey == null) { + writeKey = keyFor(selector); + } + if (writeKey == null) { + writeKey = implRegister(selector, SelectionKey.OP_WRITE); + writeKey.attach(this); + } else { + writeKey.interestOps(writeKey.interestOps() | SelectionKey.OP_WRITE); + } + } catch (ClosedChannelException e) { + handleWrite(0, e); + } + }); + } else { + ioWriteThread.interestOpsOr(writeKey, SelectionKey.OP_WRITE); + } + } catch (IOException e) { + handleWrite(0, e); + } + } + + protected void handleConnect(Throwable t) { + if (connectKey != null) { + connectKey.cancel(); + connectKey = null; + } + CompletionHandler handler = this.connectCompletionHandler; + Object attach = this.connectAttachment; + + this.connectCompletionHandler = null; + this.connectAttachment = null; + this.connectPending = false; // 必须放最后 + + if (handler != null) { + if (t == null) { + handler.completed(null, attach); + } else { + handler.failed(t, attach); + } + } + } + + protected void handleRead(final int totalCount, Throwable t) { + CompletionHandler handler = this.readCompletionHandler; + ByteBuffer attach = this.readByteBuffer; + // 清空读参数 + this.readCompletionHandler = null; + this.readByteBuffer = null; + this.readPending = false; // 必须放最后 + + if (handler == null) { + if (t == null) { + protocolCodec.completed(totalCount, attach); + } else { + protocolCodec.failed(t, attach); + } + } else { + if (t == null) { + handler.completed(totalCount, attach); + } else { + handler.failed(t, attach); + } + } + } + + protected void handleWrite(final int totalCount, Throwable t) { + CompletionHandler handler = this.writeCompletionHandler; + Object attach = this.writeAttachment; + // 清空写参数 + this.writeCompletionHandler = null; + this.writeAttachment = null; + this.writeByteBuffer = null; + this.writeByteBuffers = null; + this.writeBuffersOffset = 0; + this.writeBuffersLength = 0; + this.writeTotal = 0; + this.writePending = false; // 必须放最后 + + if (t == null) { + handler.completed(totalCount, attach); + } else { + handler.failed(t, attach); + } + } + + @Deprecated(since = "2.5.0") + protected abstract ReadableByteChannel readableByteChannel(); + + @Deprecated(since = "2.5.0") + protected abstract WritableByteChannel writableByteChannel(); + + protected InputStream newInputStream() { + final ReadableByteChannel reader = readableByteChannel(); + return new InputStream() { + + ByteBuffer bb; + + @Override + public int read() throws IOException { + if (bb == null || !bb.hasRemaining()) { + int r = readBuffer(); + if (r < 1) { + return -1; + } + } + return bb.get() & 0xff; + } + + @Override + public int read(byte b[], int off, int len) throws IOException { + if (b == null) { + throw new NullPointerException(); + } else if (off < 0 || len < 0 || len > b.length - off) { + throw new IndexOutOfBoundsException(); + } else if (len == 0) { + return 0; + } + if (bb == null || !bb.hasRemaining()) { + int r = readBuffer(); + if (r < 1) { + return -1; + } + } + int size = Math.min(b.length, Math.min(len, bb.remaining())); + bb.get(b, off, size); + return size; + } + + @Override + public void close() throws IOException { + if (bb != null) { + offerReadBuffer(bb); + bb = null; + } + reader.close(); + } + + @Override + public int available() throws IOException { + if (bb == null || !bb.hasRemaining()) { + return 0; + } + return bb.remaining(); + } + + private int readBuffer() throws IOException { + if (bb == null) { + bb = pollReadBuffer(); + } else { + bb.clear(); + } + try { + int size = reader.read(bb); + bb.flip(); + return size; + } catch (IOException ioe) { + throw ioe; + } catch (Exception e) { + throw new IOException(e); + } + } + }; + } + + protected abstract SelectionKey keyFor(Selector sel); + + protected abstract SelectionKey implRegister(Selector sel, int ops) throws ClosedChannelException; + + protected abstract int implRead(ByteBuffer dst) throws IOException; + + protected abstract int implWrite(ByteBuffer src) throws IOException; + + protected abstract int implWrite(ByteBuffer[] srcs, int offset, int length) throws IOException; + + public abstract boolean isConnected(); + + public abstract void doConnect(); +} diff --git a/src/main/java/org/redkale/net/ProtocolCodec.java b/src/main/java/org/redkale/net/ProtocolCodec.java index 8e3f1f9ef..8183d6a1a 100644 --- a/src/main/java/org/redkale/net/ProtocolCodec.java +++ b/src/main/java/org/redkale/net/ProtocolCodec.java @@ -1,249 +1,249 @@ -/* - * 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.net.SocketException; -import java.nio.ByteBuffer; -import java.nio.channels.CompletionHandler; -import java.util.function.*; -import java.util.logging.Level; - -/** - * 一个AsyncConnection绑定一个ProtocolCodec实例, 只会在读IOThread中运行 - * - * @author zhangjx - */ -class ProtocolCodec implements CompletionHandler { - - private final Context context; - - private final Supplier responseSupplier; - - private final Consumer responseConsumer; - - private final ReadCompletionHandler readHandler = new ReadCompletionHandler(); - - private AsyncConnection channel; - - private Response resp; - - public ProtocolCodec( - Context context, - Supplier responseSupplier, - Consumer responseConsumer, - AsyncConnection channel) { - this.context = context; - this.channel = channel; - this.responseSupplier = responseSupplier; - this.responseConsumer = responseConsumer; - } - - public void prepare() { - // do nothing - } - - protected boolean recycle() { - this.channel = null; - this.resp = null; - return true; - } - - public ProtocolCodec response(Response resp) { - this.resp = resp; - return this; - } - - private Response createResponse() { - Response response = resp; - if (response == null) { - response = responseSupplier.get(); - } else { - response.prepare(); - } - response.responseSupplier = responseSupplier; - response.responseConsumer = responseConsumer; - return response; - } - - @Override - public void completed(Integer count, ByteBuffer buffer) { - if (count < 1) { - channel.offerReadBuffer(buffer); - channel.dispose(); // response.init(channel); 在调用之前异常 - return; - } - // { //测试 - // buffer.flip(); - // byte[] bs = new byte[buffer.remaining()]; - // buffer.get(bs); - // System.println(new String(bs)); - // } - buffer.flip(); - final Response response = createResponse(); - try { - decode(buffer, response, 0, null); - } catch (Throwable t) { // 此处不可 context.offerBuffer(buffer); 以免dispatcher.dispatch内部异常导致重复 offerBuffer - context.logger.log(Level.WARNING, "dispatch servlet abort, force to close channel ", t); - response.codecError(t); - } - } - - @Override - public void failed(Throwable exc, ByteBuffer buffer) { - channel.offerReadBuffer(buffer); - channel.dispose(); // response.init(channel); 在调用之前异常 - if (exc != null - && context.logger.isLoggable(Level.FINEST) - && !(exc instanceof SocketException && "Connection reset".equals(exc.getMessage()))) { - context.logger.log(Level.FINEST, "Servlet Handler read channel erroneous, force to close channel ", exc); - } - } - - public void start(final ByteBuffer data) { - if (data != null) { // pipeline模式或UDP连接创建AsyncConnection时已经获取到ByteBuffer数据了 - final Response response = createResponse(); - try { - decode(data, response, 0, null); - } catch (Throwable t) { - context.logger.log(Level.WARNING, "dispatch servlet abort, force to close channel ", t); - response.codecError(t); - } - return; - } - try { - channel.readRegisterInIOThread(this); - } catch (Exception te) { - channel.dispose(); // response.init(channel); 在调用之前异常 - if (context.logger.isLoggable(Level.FINEST)) { - context.logger.log(Level.FINEST, "Servlet start read channel erroneous, force to close channel ", te); - } - } - } - - public void run(final ByteBuffer data) { - if (data != null) { // pipeline模式或UDP连接创建AsyncConnection时已经获取到ByteBuffer数据了 - final Response response = createResponse(); - try { - decode(data, response, 0, null); - } catch (Throwable t) { - context.logger.log(Level.WARNING, "dispatch servlet abort, force to close channel ", t); - response.codecError(t); - } - return; - } - try { - channel.read(this); - } catch (Exception te) { - channel.dispose(); // response.init(channel); 在调用之前异常 - if (context.logger.isLoggable(Level.FINEST)) { - context.logger.log(Level.FINEST, "Servlet run read channel erroneous, force to close channel ", te); - } - } - } - - protected void decode( - final ByteBuffer buffer, final Response response, final int pipelineIndex, final Request lastReq) { - response.init(channel); - final Request request = response.request; - final int rs = request.readHeader(buffer, lastReq); - if (rs < 0) { // 表示数据格式不正确 - final DispatcherServlet dispatcher = context.dispatcher; - dispatcher.incrExecuteCounter(); - channel.offerReadBuffer(buffer); - if (rs != Integer.MIN_VALUE) { - dispatcher.incrIllegalRequestCounter(); - } - response.codecError(null); - if (context.logger.isLoggable(Level.FINEST)) { - context.logger.log(Level.FINEST, "request.readHeader erroneous (" + rs + "), force to close channel "); - } - } else if (rs == 0) { - context.dispatcher.incrExecuteCounter(); - int pindex = pipelineIndex; - boolean pipeline = false; - boolean seted = false; - boolean completed = request.completed; - Request hreq = lastReq; - if (buffer.hasRemaining()) { - pipeline = true; - if (pindex == 0) { - pindex++; - } - if (request.getRequestid() == null) { // 存在requestid则无视pipeline模式 - request.pipeline(pindex, pindex + 1); - } - if (hreq == null) { - hreq = request.copyHeader(); - } - } else { - if (request.getRequestid() == null) { // 存在requestid则无视pipeline模式 - request.pipeline(pindex, pindex); - } - channel.setReadBuffer(buffer.clear()); - seted = true; - } - context.executeDispatch(request, response); - if (pipeline) { - final Response pipelineResponse = createResponse(); - try { - decode(buffer, pipelineResponse, pindex + 1, hreq); - } catch (Throwable t) { // 此处不可 offerBuffer(buffer); 以免dispatcher.dispatch内部异常导致重复 offerBuffer - context.logger.log(Level.WARNING, "dispatch pipeline servlet abort, force to close channel ", t); - pipelineResponse.codecError(t); - } - } else if (completed) { - if (!seted) { - channel.setReadBuffer(buffer.clear()); - } - channel.readRegister(this); - } - } else { - channel.setReadBuffer(buffer); - channel.read(readHandler.prepare(request, response, pipelineIndex, lastReq)); - } - } - - private class ReadCompletionHandler implements CompletionHandler { - - private Request request; - - private Response response; - - private int pipelineIndex; - - private Request lastReq; - - public ReadCompletionHandler prepare(Request request, Response response, int pipelineIndex, Request lastReq) { - this.request = request; - this.response = response; - this.pipelineIndex = pipelineIndex; - this.lastReq = lastReq; - return this; - } - - @Override - public void completed(Integer count, ByteBuffer attachment) { - if (count < 1) { - channel.offerReadBuffer(attachment); - channel.dispose(); - return; - } - attachment.flip(); - decode(attachment, response, pipelineIndex, lastReq); - } - - @Override - public void failed(Throwable exc, ByteBuffer attachment) { - context.dispatcher.incrIllegalRequestCounter(); - channel.offerReadBuffer(attachment); - response.codecError(exc); - if (exc != null) { - request.context.logger.log( - Level.FINER, "Servlet continue read channel erroneous, force to close channel ", exc); - } - } - } -} +/* + * 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.net.SocketException; +import java.nio.ByteBuffer; +import java.nio.channels.CompletionHandler; +import java.util.function.*; +import java.util.logging.Level; + +/** + * 一个AsyncConnection绑定一个ProtocolCodec实例, 只会在读IOThread中运行 + * + * @author zhangjx + */ +class ProtocolCodec implements CompletionHandler { + + private final Context context; + + private final Supplier responseSupplier; + + private final Consumer responseConsumer; + + private final ReadCompletionHandler readHandler = new ReadCompletionHandler(); + + private AsyncConnection channel; + + private Response resp; + + public ProtocolCodec( + Context context, + Supplier responseSupplier, + Consumer responseConsumer, + AsyncConnection channel) { + this.context = context; + this.channel = channel; + this.responseSupplier = responseSupplier; + this.responseConsumer = responseConsumer; + } + + public void prepare() { + // do nothing + } + + protected boolean recycle() { + this.channel = null; + this.resp = null; + return true; + } + + public ProtocolCodec response(Response resp) { + this.resp = resp; + return this; + } + + private Response createResponse() { + Response response = resp; + if (response == null) { + response = responseSupplier.get(); + } else { + response.prepare(); + } + response.responseSupplier = responseSupplier; + response.responseConsumer = responseConsumer; + return response; + } + + @Override + public void completed(Integer count, ByteBuffer buffer) { + if (count < 1) { + channel.offerReadBuffer(buffer); + channel.dispose(); // response.init(channel); 在调用之前异常 + return; + } + // { //测试 + // buffer.flip(); + // byte[] bs = new byte[buffer.remaining()]; + // buffer.get(bs); + // System.println(new String(bs)); + // } + buffer.flip(); + final Response response = createResponse(); + try { + decode(buffer, response, 0, null); + } catch (Throwable t) { // 此处不可 context.offerBuffer(buffer); 以免dispatcher.dispatch内部异常导致重复 offerBuffer + context.logger.log(Level.WARNING, "dispatch servlet abort, force to close channel ", t); + response.codecError(t); + } + } + + @Override + public void failed(Throwable exc, ByteBuffer buffer) { + channel.offerReadBuffer(buffer); + channel.dispose(); // response.init(channel); 在调用之前异常 + if (exc != null + && context.logger.isLoggable(Level.FINEST) + && !(exc instanceof SocketException && "Connection reset".equals(exc.getMessage()))) { + context.logger.log(Level.FINEST, "Servlet Handler read channel erroneous, force to close channel ", exc); + } + } + + public void start(final ByteBuffer data) { + if (data != null) { // pipeline模式或UDP连接创建AsyncConnection时已经获取到ByteBuffer数据了 + final Response response = createResponse(); + try { + decode(data, response, 0, null); + } catch (Throwable t) { + context.logger.log(Level.WARNING, "dispatch servlet abort, force to close channel ", t); + response.codecError(t); + } + return; + } + try { + channel.readRegisterInIOThread(this); + } catch (Exception te) { + channel.dispose(); // response.init(channel); 在调用之前异常 + if (context.logger.isLoggable(Level.FINEST)) { + context.logger.log(Level.FINEST, "Servlet start read channel erroneous, force to close channel ", te); + } + } + } + + public void run(final ByteBuffer data) { + if (data != null) { // pipeline模式或UDP连接创建AsyncConnection时已经获取到ByteBuffer数据了 + final Response response = createResponse(); + try { + decode(data, response, 0, null); + } catch (Throwable t) { + context.logger.log(Level.WARNING, "dispatch servlet abort, force to close channel ", t); + response.codecError(t); + } + return; + } + try { + channel.read(this); + } catch (Exception te) { + channel.dispose(); // response.init(channel); 在调用之前异常 + if (context.logger.isLoggable(Level.FINEST)) { + context.logger.log(Level.FINEST, "Servlet run read channel erroneous, force to close channel ", te); + } + } + } + + protected void decode( + final ByteBuffer buffer, final Response response, final int pipelineIndex, final Request lastReq) { + response.init(channel); + final Request request = response.request; + final int rs = request.readHeader(buffer, lastReq); + if (rs < 0) { // 表示数据格式不正确 + final DispatcherServlet dispatcher = context.dispatcher; + dispatcher.incrExecuteCounter(); + channel.offerReadBuffer(buffer); + if (rs != Integer.MIN_VALUE) { + dispatcher.incrIllegalRequestCounter(); + } + response.codecError(null); + if (context.logger.isLoggable(Level.FINEST)) { + context.logger.log(Level.FINEST, "request.readHeader erroneous (" + rs + "), force to close channel "); + } + } else if (rs == 0) { + context.dispatcher.incrExecuteCounter(); + int pindex = pipelineIndex; + boolean pipeline = false; + boolean seted = false; + boolean completed = request.completed; + Request hreq = lastReq; + if (buffer.hasRemaining()) { + pipeline = true; + if (pindex == 0) { + pindex++; + } + if (request.getRequestid() == null) { // 存在requestid则无视pipeline模式 + request.pipeline(pindex, pindex + 1); + } + if (hreq == null) { + hreq = request.copyHeader(); + } + } else { + if (request.getRequestid() == null) { // 存在requestid则无视pipeline模式 + request.pipeline(pindex, pindex); + } + channel.setReadBuffer(buffer.clear()); + seted = true; + } + context.executeDispatch(request, response); + if (pipeline) { + final Response pipelineResponse = createResponse(); + try { + decode(buffer, pipelineResponse, pindex + 1, hreq); + } catch (Throwable t) { // 此处不可 offerBuffer(buffer); 以免dispatcher.dispatch内部异常导致重复 offerBuffer + context.logger.log(Level.WARNING, "dispatch pipeline servlet abort, force to close channel ", t); + pipelineResponse.codecError(t); + } + } else if (completed) { + if (!seted) { + channel.setReadBuffer(buffer.clear()); + } + channel.readRegister(this); + } + } else { + channel.setReadBuffer(buffer); + channel.read(readHandler.prepare(request, response, pipelineIndex, lastReq)); + } + } + + private class ReadCompletionHandler implements CompletionHandler { + + private Request request; + + private Response response; + + private int pipelineIndex; + + private Request lastReq; + + public ReadCompletionHandler prepare(Request request, Response response, int pipelineIndex, Request lastReq) { + this.request = request; + this.response = response; + this.pipelineIndex = pipelineIndex; + this.lastReq = lastReq; + return this; + } + + @Override + public void completed(Integer count, ByteBuffer attachment) { + if (count < 1) { + channel.offerReadBuffer(attachment); + channel.dispose(); + return; + } + attachment.flip(); + decode(attachment, response, pipelineIndex, lastReq); + } + + @Override + public void failed(Throwable exc, ByteBuffer attachment) { + context.dispatcher.incrIllegalRequestCounter(); + channel.offerReadBuffer(attachment); + response.codecError(exc); + if (exc != null) { + request.context.logger.log( + Level.FINER, "Servlet continue read channel erroneous, force to close channel ", exc); + } + } + } +} diff --git a/src/main/java/org/redkale/net/client/ClientCodec.java b/src/main/java/org/redkale/net/client/ClientCodec.java index 01b23e8ab..cf62eef0c 100644 --- a/src/main/java/org/redkale/net/client/ClientCodec.java +++ b/src/main/java/org/redkale/net/client/ClientCodec.java @@ -1,214 +1,214 @@ -/* - * 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.client; - -import java.io.Serializable; -import java.nio.ByteBuffer; -import java.nio.channels.*; -import java.util.*; -import java.util.logging.Level; -import org.redkale.convert.json.JsonConvert; -import org.redkale.net.*; -import org.redkale.util.*; - -/** - * 每个ClientConnection绑定一个独立的ClientCodec实例, 只会同一读线程ReadIOThread里运行 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.3.0 - * @param ClientRequest - * @param

响应对象 - */ -public abstract class ClientCodec - implements CompletionHandler { - - private final List> respResults = new ArrayList<>(); - - private final ByteArray readArray = new ByteArray(); - - private final ObjectPool> respPool = ObjectPool.createUnsafePool( - 256, t -> new ClientResponse(), ClientResponse::prepare, ClientResponse::recycle); - - protected final ClientConnection connection; - - protected ClientMessageListener messageListener; - - protected ClientCodec(ClientConnection connection) { - Objects.requireNonNull(connection); - this.connection = connection; - } - - // buffer之后会clear - public abstract void decodeMessages(ByteBuffer buffer, ByteArray array); - - public ClientCodec withMessageListener(ClientMessageListener listener) { - this.messageListener = listener; - return this; - } - - @Override - public final void completed(Integer count, ByteBuffer attachment) { - AsyncConnection channel = connection.channel; - if (count < 1) { - channel.setReadBuffer(attachment); - connection.dispose(new NonReadableChannelException()); - return; - } - try { - attachment.flip(); - decodeResponse(attachment); - } catch (Throwable e) { - channel.setReadBuffer(attachment); - connection.dispose(e); - } - } - - private void decodeResponse(ByteBuffer buffer) { - AsyncConnection channel = connection.channel; - connection.currRespIterator = null; - decodeMessages(buffer, readArray); - if (!respResults.isEmpty()) { // 存在解析结果 - connection.currRespIterator = null; - readArray.clear(); - boolean keepAlive = true; - for (ClientResponse cr : respResults) { - connection.doneResponseCounter.increment(); - if (cr.isError()) { - connection.dispose(cr.cause); - return; - } else if (messageListener != null) { - messageListener.onMessage(connection, cr); - respPool.accept(cr); - } else { - ClientFuture respFuture = connection.pollRespFuture(cr.getRequestid()); - if (respFuture != null) { - if (respFuture.request != cr.request) { - connection.dispose(new RedkaleException("request pipeline error")); - return; - } - responseComplete(false, respFuture, cr.message, cr.cause); - if (cr.message != null && !cr.message.isKeepAlive()) { - keepAlive = false; - } - } - respPool.accept(cr); - } - } - respResults.clear(); - if (!keepAlive) { - connection.dispose(null); - } - if (buffer.hasRemaining()) { // 还有响应数据包 - decodeResponse(buffer); - } else if (keepAlive) { // 队列都已处理完了 - buffer.clear(); - channel.setReadBuffer(buffer); - channel.readRegister(this); - } - } else { // 数据不全, 继续读 - connection.currRespIterator = null; - buffer.clear(); - channel.setReadBuffer(buffer); - channel.read(this); - } - } - - void responseComplete(boolean halfCompleted, ClientFuture respFuture, P message, Throwable exc) { - final R request = respFuture.request; - Traces.currentTraceid(request.getTraceid()); - AsyncIOThread readThread = connection.channel.getReadIOThread(); - final WorkThread workThread = request.workThread == null ? readThread : request.workThread; - try { - if (!halfCompleted && !request.isCompleted()) { - if (exc == null) { - connection.sendHalfWriteInReadThread(request, exc); - // request没有发送完,respFuture需要再次接收 - return; - } else { - connection.sendHalfWriteInReadThread(request, exc); - // 异常了需要清掉半包 - } - } - connection.respWaitingCounter.decrement(); - if (connection.isAuthenticated()) { - connection.client.incrRespDoneCounter(); - } - respFuture.cancelTimeout(); - // if (connection.client.debug) { - // connection.client.logger.log(Level.FINEST, Utility.nowMillis() + ": " + - // Thread.currentThread().getName() + ": " + connection - // + ", 回调处理(" + (request != null ? (System.currentTimeMillis() - - // request.getCreateTime()) : -1) + "ms), req=" + request + ", message=" + message, exc); - // } - connection.preComplete(message, (R) request, exc); - - if (exc == null) { - final Object rs = request.respTransfer == null ? message : request.respTransfer.apply(message); - // workThread不区分IO线程,respFuture.complete中使用CompletableFuture.join会一直阻塞 - workThread.runWork(() -> { - Traces.currentTraceid(request.traceid); - respFuture.complete(rs); - Traces.removeTraceid(); - }); - } else { // 异常 - workThread.runWork(() -> { - Traces.currentTraceid(request.traceid); - respFuture.completeExceptionally(exc); - Traces.removeTraceid(); - }); - } - } catch (Throwable t) { - workThread.runWork(() -> { - Traces.currentTraceid(request.traceid); - respFuture.completeExceptionally(t); - Traces.removeTraceid(); - }); - connection.client.logger.log(Level.INFO, "Complete result error, request: " + respFuture.request, t); - } - } - - @Override - public final void failed(Throwable t, ByteBuffer attachment) { - connection.dispose(t); - } - - public ClientMessageListener getMessageListener() { - return messageListener; - } - - protected R nextRequest() { - return connection.findRequest(null); - } - - protected R findRequest(Serializable requestid) { - return connection.findRequest(requestid); - } - - protected ClientResponse getLastMessage() { - List> results = this.respResults; - int size = results.size(); - return size == 0 ? null : results.get(size - 1); - } - - public void addMessage(R request, P result) { - this.respResults.add(respPool.get().success(request, result)); - } - - public void addMessage(R request, Throwable exc) { - this.respResults.add(respPool.get().fail(request, exc)); - } - - public void occurError(R request, Throwable exc) { - this.respResults.add(new ClientResponse.ClientErrorResponse<>(request, exc)); - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } -} +/* + * 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.client; + +import java.io.Serializable; +import java.nio.ByteBuffer; +import java.nio.channels.*; +import java.util.*; +import java.util.logging.Level; +import org.redkale.convert.json.JsonConvert; +import org.redkale.net.*; +import org.redkale.util.*; + +/** + * 每个ClientConnection绑定一个独立的ClientCodec实例, 只会同一读线程ReadIOThread里运行 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.3.0 + * @param ClientRequest + * @param

响应对象 + */ +public abstract class ClientCodec + implements CompletionHandler { + + private final List> respResults = new ArrayList<>(); + + private final ByteArray readArray = new ByteArray(); + + private final ObjectPool> respPool = ObjectPool.createUnsafePool( + 256, t -> new ClientResponse(), ClientResponse::prepare, ClientResponse::recycle); + + protected final ClientConnection connection; + + protected ClientMessageListener messageListener; + + protected ClientCodec(ClientConnection connection) { + Objects.requireNonNull(connection); + this.connection = connection; + } + + // buffer之后会clear + public abstract void decodeMessages(ByteBuffer buffer, ByteArray array); + + public ClientCodec withMessageListener(ClientMessageListener listener) { + this.messageListener = listener; + return this; + } + + @Override + public final void completed(Integer count, ByteBuffer attachment) { + AsyncConnection channel = connection.channel; + if (count < 1) { + channel.setReadBuffer(attachment); + connection.dispose(new NonReadableChannelException()); + return; + } + try { + attachment.flip(); + decodeResponse(attachment); + } catch (Throwable e) { + channel.setReadBuffer(attachment); + connection.dispose(e); + } + } + + private void decodeResponse(ByteBuffer buffer) { + AsyncConnection channel = connection.channel; + connection.currRespIterator = null; + decodeMessages(buffer, readArray); + if (!respResults.isEmpty()) { // 存在解析结果 + connection.currRespIterator = null; + readArray.clear(); + boolean keepAlive = true; + for (ClientResponse cr : respResults) { + connection.doneResponseCounter.increment(); + if (cr.isError()) { + connection.dispose(cr.cause); + return; + } else if (messageListener != null) { + messageListener.onMessage(connection, cr); + respPool.accept(cr); + } else { + ClientFuture respFuture = connection.pollRespFuture(cr.getRequestid()); + if (respFuture != null) { + if (respFuture.request != cr.request) { + connection.dispose(new RedkaleException("request pipeline error")); + return; + } + responseComplete(false, respFuture, cr.message, cr.cause); + if (cr.message != null && !cr.message.isKeepAlive()) { + keepAlive = false; + } + } + respPool.accept(cr); + } + } + respResults.clear(); + if (!keepAlive) { + connection.dispose(null); + } + if (buffer.hasRemaining()) { // 还有响应数据包 + decodeResponse(buffer); + } else if (keepAlive) { // 队列都已处理完了 + buffer.clear(); + channel.setReadBuffer(buffer); + channel.readRegister(this); + } + } else { // 数据不全, 继续读 + connection.currRespIterator = null; + buffer.clear(); + channel.setReadBuffer(buffer); + channel.read(this); + } + } + + void responseComplete(boolean halfCompleted, ClientFuture respFuture, P message, Throwable exc) { + final R request = respFuture.request; + Traces.currentTraceid(request.getTraceid()); + AsyncIOThread readThread = connection.channel.getReadIOThread(); + final WorkThread workThread = request.workThread == null ? readThread : request.workThread; + try { + if (!halfCompleted && !request.isCompleted()) { + if (exc == null) { + connection.sendHalfWriteInReadThread(request, exc); + // request没有发送完,respFuture需要再次接收 + return; + } else { + connection.sendHalfWriteInReadThread(request, exc); + // 异常了需要清掉半包 + } + } + connection.respWaitingCounter.decrement(); + if (connection.isAuthenticated()) { + connection.client.incrRespDoneCounter(); + } + respFuture.cancelTimeout(); + // if (connection.client.debug) { + // connection.client.logger.log(Level.FINEST, Utility.nowMillis() + ": " + + // Thread.currentThread().getName() + ": " + connection + // + ", 回调处理(" + (request != null ? (System.currentTimeMillis() - + // request.getCreateTime()) : -1) + "ms), req=" + request + ", message=" + message, exc); + // } + connection.preComplete(message, (R) request, exc); + + if (exc == null) { + final Object rs = request.respTransfer == null ? message : request.respTransfer.apply(message); + // workThread不区分IO线程,respFuture.complete中使用CompletableFuture.join会一直阻塞 + workThread.runWork(() -> { + Traces.currentTraceid(request.traceid); + respFuture.complete(rs); + Traces.removeTraceid(); + }); + } else { // 异常 + workThread.runWork(() -> { + Traces.currentTraceid(request.traceid); + respFuture.completeExceptionally(exc); + Traces.removeTraceid(); + }); + } + } catch (Throwable t) { + workThread.runWork(() -> { + Traces.currentTraceid(request.traceid); + respFuture.completeExceptionally(t); + Traces.removeTraceid(); + }); + connection.client.logger.log(Level.INFO, "Complete result error, request: " + respFuture.request, t); + } + } + + @Override + public final void failed(Throwable t, ByteBuffer attachment) { + connection.dispose(t); + } + + public ClientMessageListener getMessageListener() { + return messageListener; + } + + protected R nextRequest() { + return connection.findRequest(null); + } + + protected R findRequest(Serializable requestid) { + return connection.findRequest(requestid); + } + + protected ClientResponse getLastMessage() { + List> results = this.respResults; + int size = results.size(); + return size == 0 ? null : results.get(size - 1); + } + + public void addMessage(R request, P result) { + this.respResults.add(respPool.get().success(request, result)); + } + + public void addMessage(R request, Throwable exc) { + this.respResults.add(respPool.get().fail(request, exc)); + } + + public void occurError(R request, Throwable exc) { + this.respResults.add(new ClientResponse.ClientErrorResponse<>(request, exc)); + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } +} diff --git a/src/main/java/org/redkale/net/client/ClientConnection.java b/src/main/java/org/redkale/net/client/ClientConnection.java index 7d7504aba..e5fb10087 100644 --- a/src/main/java/org/redkale/net/client/ClientConnection.java +++ b/src/main/java/org/redkale/net/client/ClientConnection.java @@ -1,473 +1,473 @@ -/* - * 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.client; - -import java.io.Serializable; -import java.net.SocketAddress; -import java.nio.ByteBuffer; -import java.nio.channels.*; -import java.util.*; -import java.util.concurrent.*; -import java.util.concurrent.atomic.*; -import java.util.concurrent.locks.ReentrantLock; -import java.util.function.*; -import org.redkale.annotation.*; -import org.redkale.net.*; -import org.redkale.util.*; - -/** - * 注意: 要确保AsyncConnection的读写过程都必须在channel.ioThread中运行 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.3.0 - * @param 请求对象 - * @param

响应对象 - */ -public abstract class ClientConnection - implements Consumer { - - protected final Client client; - - @Nonnull - protected LongAdder respWaitingCounter; - - protected final LongAdder doneRequestCounter = new LongAdder(); - - protected final LongAdder doneResponseCounter = new LongAdder(); - - protected final AtomicBoolean writePending = new AtomicBoolean(); - - protected final ReentrantLock writeLock = new ReentrantLock(); - - protected final ByteArray writeArray = new ByteArray(); - - protected final ThreadLocal arrayThreadLocal = Utility.withInitialThreadLocal(ByteArray::new); - - protected final ByteBuffer writeBuffer; - - protected final CompletionHandler writeHandler = - new CompletionHandler() { - - @Override - public void completed(Integer result, ClientConnection attachment) { - // do nothing - } - - @Override - public void failed(Throwable exc, ClientConnection attachment) { - writePending.set(false); - attachment.dispose(exc); - } - }; - - final AtomicBoolean pauseWriting = new AtomicBoolean(); - - final ConcurrentLinkedQueue pauseRequests = new ConcurrentLinkedQueue<>(); - - // pauseWriting=true,此字段才会有值; pauseWriting=false,此字段值为null - ClientFuture currHalfWriteFuture; - - @Nonnull - private Client.AddressConnEntry connEntry; - - protected final AsyncConnection channel; - - private final ClientCodec codec; - - // respFutureQueue、respFutureMap二选一, SPSC队列模式 - private final ConcurrentLinkedDeque> respFutureQueue = new ConcurrentLinkedDeque<>(); - - // respFutureQueue、respFutureMap二选一, key: requestid, SPSC模式 - private final ConcurrentHashMap> respFutureMap = new ConcurrentHashMap<>(); - - Iterator> currRespIterator; // 必须在调用decodeMessages之前重置为null - - private int maxPipelines; // 最大并行处理数 - - private boolean authenticated; - - @SuppressWarnings({"LeakingThisInConstructor", "OverridableMethodCallInConstructor"}) - public ClientConnection(Client, R, P> client, AsyncConnection channel) { - this.client = client; - this.codec = createCodec(); - this.channel = channel.beforeCloseListener(this); // .fastHandler(writeHandler); - this.writeBuffer = channel.pollWriteBuffer(); - } - - ClientConnection setConnEntry(Client.AddressConnEntry entry) { - this.connEntry = entry; - this.respWaitingCounter = entry.connRespWaiting; - return this; - } - - protected abstract ClientCodec createCodec(); - - protected final CompletableFuture

writeChannel(R request) { - return writeChannel(request, null); - } - - protected final CompletableFuture> writeChannel(R[] requests) { - return writeChannel(requests, null); - } - - // respTransfer只会在ClientCodec的读线程里调用 - protected final CompletableFuture writeChannel(R request, Function respTransfer) { - // if (client.debug) { - // client.logger.log(Level.FINEST, Utility.nowMillis() + ": " + Thread.currentThread().getName() + ": - // " - // + this + ", 发送请求: " + request); - // } - request.respTransfer = respTransfer; - ClientFuture respFuture = createClientFuture(request); - int rts = this.channel.getReadTimeoutSeconds(); - if (rts > 0 && !request.isCloseType()) { - respFuture.setTimeout(client.timeoutScheduler.schedule(respFuture, rts, TimeUnit.SECONDS)); - } - respWaitingCounter.increment(); // 放在writeChannelInWriteThread计数会延迟,导致不准确 - writeLock.lock(); - try { - offerRespFuture(respFuture); - if (pauseWriting.get()) { - pauseRequests.add(respFuture); - } else { - sendRequestInLocking(request, respFuture); - } - } finally { - writeLock.unlock(); - } - return respFuture; - } - - private void sendRequestInLocking(R request, ClientFuture respFuture) { - // 发送请求数据包 - writeArray.clear(); - request.writeTo(this, writeArray); - if (request.isCompleted()) { - doneRequestCounter.increment(); - } else { // 还剩半包没发送完 - pauseWriting.set(true); - currHalfWriteFuture = respFuture; - } - if (writeArray.length() > 0) { - if (writeBuffer.capacity() >= writeArray.length()) { - writeBuffer.clear(); - writeBuffer.put(writeArray.content(), 0, writeArray.length()); - writeBuffer.flip(); - channel.write(writeBuffer, this, writeHandler); - } else { - channel.write(writeArray, this, writeHandler); - } - } - } - - // respTransfer只会在ClientCodec的读线程里调用 - protected final CompletableFuture> writeChannel(R[] requests, Function respTransfer) { - // if (client.debug) { - // client.logger.log(Level.FINEST, Utility.nowMillis() + ": " + Thread.currentThread().getName() + ": - // " - // + this + ", 发送请求: " + Arrays.toString(requests) + ", readTimeoutSeconds: " + - // this.channel.getReadTimeoutSeconds()); - // } - ClientFuture[] respFutures = new ClientFuture[requests.length]; - int rts = this.channel.getReadTimeoutSeconds(); - for (int i = 0; i < respFutures.length; i++) { - R request = requests[i]; - request.respTransfer = respTransfer; - ClientFuture respFuture = createClientFuture(requests[i]); - respFutures[i] = respFuture; - if (rts > 0 && !request.isCloseType()) { - respFuture.setTimeout(client.timeoutScheduler.schedule(respFuture, rts, TimeUnit.SECONDS)); - } - } - respWaitingCounter.add(respFutures.length); // 放在writeChannelInWriteThread计数会延迟,导致不准确 - - writeLock.lock(); - try { - if (pauseWriting.get()) { - for (ClientFuture respFuture : respFutures) { - offerRespFuture(respFuture); - pauseRequests.add(respFuture); - } - } else { - for (ClientFuture respFuture : respFutures) { - offerRespFuture(respFuture); - } - sendRequestInLocking(respFutures); - } - } finally { - writeLock.unlock(); - } - return Utility.allOfFutures(respFutures); - } - - private void sendRequestInLocking(ClientFuture[] respFutures) { - // 发送请求数据包 - writeArray.clear(); - for (ClientFuture respFuture : respFutures) { - if (pauseWriting.get()) { - pauseRequests.add(respFuture); - } else { - ClientRequest request = respFuture.request; - request.writeTo(this, writeArray); - if (request.isCompleted()) { - doneRequestCounter.increment(); - } else { // 还剩半包没发送完 - pauseWriting.set(true); - currHalfWriteFuture = respFuture; - } - } - } - if (writeArray.length() > 0) { - if (writeBuffer.capacity() >= writeArray.length()) { - writeBuffer.clear(); - writeBuffer.put(writeArray.content(), 0, writeArray.length()); - writeBuffer.flip(); - channel.write(writeBuffer, this, writeHandler); - } else { - channel.write(writeArray, this, writeHandler); - } - } - } - - // private void sendFastRequestInLocking(R request, ClientFuture respFuture) { - // ByteArray array = arrayThreadLocal.get(); - // array.clear(); - // request.writeTo(this, array); - // if (request.isCompleted()) { - // doneRequestCounter.increment(); - // } else { //还剩半包没发送完 - // pauseWriting.set(true); - // currHalfWriteFuture = respFuture; - // } - // channel.fastWrite(array.getBytes()); - // } - // - // private void sendFastRequestInLocking(ClientFuture[] respFutures) { - // ByteArray array = arrayThreadLocal.get(); - // array.clear(); - // for (ClientFuture respFuture : respFutures) { - // if (pauseWriting.get()) { - // pauseRequests.add(respFuture); - // } else { - // ClientRequest request = respFuture.request; - // request.writeTo(this, array); - // if (request.isCompleted()) { - // doneRequestCounter.increment(); - // } else { //还剩半包没发送完 - // pauseWriting.set(true); - // currHalfWriteFuture = respFuture; - // } - // } - // } - // channel.fastWrite(array.getBytes()); - // } - // 发送半包和积压的请求数据包 - void sendHalfWriteInReadThread(R request, Throwable halfRequestExc) { - writeLock.lock(); - try { - pauseWriting.set(false); - ClientFuture respFuture = this.currHalfWriteFuture; - if (respFuture != null) { - this.currHalfWriteFuture = null; - if (halfRequestExc == null) { - offerFirstRespFuture(respFuture); - sendRequestInLocking(request, respFuture); - } else { - codec.responseComplete(true, respFuture, null, halfRequestExc); - } - } - while (!pauseWriting.get() && (respFuture = pauseRequests.poll()) != null) { - sendRequestInLocking((R) respFuture.getRequest(), respFuture); - } - } finally { - writeLock.unlock(); - } - } - - CompletableFuture

writeVirtualRequest(R request) { - if (!request.isVirtualType()) { - return CompletableFuture.failedFuture( - new RuntimeException("ClientVirtualRequest must be virtualType = true")); - } - ClientFuture respFuture = createClientFuture(request); - writeLock.lock(); - try { - offerRespFuture(respFuture); - } finally { - writeLock.unlock(); - } - channel.readRegister(getCodec()); // 不能在创建连接时注册读事件 - return respFuture; - } - - protected void preComplete(P resp, R req, Throwable exc) {} - - protected ClientFuture createClientFuture(R request) { - return new ClientFuture(this, request); - } - - @Override // AsyncConnection.beforeCloseListener - public void accept(AsyncConnection t) { - respWaitingCounter.reset(); - if (connEntry != null) { // index=-1 - connEntry.connection = null; - connEntry.connOpenState.set(false); - } - ClientMessageListener listener = getCodec().getMessageListener(); - if (listener != null) { - listener.onClose(this); - } - } - - public void dispose(Throwable exc) { - channel.offerWriteBuffer(writeBuffer); - channel.dispose(); - Throwable e = exc == null ? new ClosedChannelException() : exc; - CompletableFuture f; - respWaitingCounter.reset(); - WorkThread thread = channel.getReadIOThread(); - if (!respFutureQueue.isEmpty()) { - while ((f = respFutureQueue.poll()) != null) { - CompletableFuture future = f; - thread.runWork(() -> future.completeExceptionally(e)); - } - } - if (!respFutureMap.isEmpty()) { - respFutureMap.forEach((key, future) -> { - respFutureMap.remove(key); - thread.runWork(() -> future.completeExceptionally(e)); - }); - } - } - - // 只会在WriteIOThread中调用, 必须在writeLock内执行 - void offerFirstRespFuture(ClientFuture respFuture) { - Serializable requestid = respFuture.request.getRequestid(); - if (requestid == null) { - respFutureQueue.offerFirst(respFuture); - } else { - respFutureMap.put(requestid, respFuture); - } - } - - // 必须在writeLock内执行 - void offerRespFuture(ClientFuture respFuture) { - Serializable requestid = respFuture.request.getRequestid(); - if (requestid == null) { - respFutureQueue.offer(respFuture); - } else { - respFutureMap.put(requestid, respFuture); - } - } - - // 只会被Timeout在ReadIOThread中调用 - void removeRespFuture(Serializable requestid, ClientFuture respFuture) { - if (requestid == null) { - respFutureQueue.remove(respFuture); - } else { - respFutureMap.remove(requestid); - } - } - - // 只会被ClientCodec在ReadIOThread中调用 - R findRequest(Serializable requestid) { - if (requestid == null) { - if (currRespIterator == null) { - currRespIterator = respFutureQueue.iterator(); - } - ClientFuture future = currRespIterator.hasNext() ? currRespIterator.next() : null; - return future == null ? null : future.request; - } else { - ClientFuture future = respFutureMap.get(requestid); - return future == null ? null : future.request; - } - } - - // 只会被ClientCodec在ReadIOThread中调用 - protected ClientFuture pollRespFuture(Serializable requestid) { - if (requestid == null) { - return respFutureQueue.poll(); - } else { - return respFutureMap.remove(requestid); - } - } - - public boolean isAuthenticated() { - return authenticated; - } - - public AsyncConnection getChannel() { - return channel; - } - - public SocketAddress getRemoteAddress() { - return channel.getRemoteAddress(); - } - - public long getDoneRequestCounter() { - return doneRequestCounter.longValue(); - } - - public long getDoneResponseCounter() { - return doneResponseCounter.longValue(); - } - - public > C getCodec() { - return (C) codec; - } - - public int getMaxPipelines() { - return maxPipelines; - } - - protected ClientConnection setAuthenticated(boolean authenticated) { - this.authenticated = authenticated; - return this; - } - - protected ClientConnection setMaxPipelines(int maxPipelines) { - this.maxPipelines = maxPipelines; - return this; - } - - protected ClientConnection resetMaxPipelines() { - this.maxPipelines = client.maxPipelines; - return this; - } - - public int runningCount() { - return respWaitingCounter.intValue(); - } - - public long getLastWriteTime() { - return channel.getLastWriteTime(); - } - - public long getLastReadTime() { - return channel.getLastReadTime(); - } - - public boolean isOpen() { - return channel.isOpen(); - } - - @Override - public String toString() { - String s = super.toString(); - int pos = s.lastIndexOf('@'); - if (pos < 1) { - return s; - } - int cha = pos + 10 - s.length(); - if (cha < 1) { - return s; - } - for (int i = 0; i < cha; i++) s += ' '; - return s; - } -} +/* + * 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.client; + +import java.io.Serializable; +import java.net.SocketAddress; +import java.nio.ByteBuffer; +import java.nio.channels.*; +import java.util.*; +import java.util.concurrent.*; +import java.util.concurrent.atomic.*; +import java.util.concurrent.locks.ReentrantLock; +import java.util.function.*; +import org.redkale.annotation.*; +import org.redkale.net.*; +import org.redkale.util.*; + +/** + * 注意: 要确保AsyncConnection的读写过程都必须在channel.ioThread中运行 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.3.0 + * @param 请求对象 + * @param

响应对象 + */ +public abstract class ClientConnection + implements Consumer { + + protected final Client client; + + @Nonnull + protected LongAdder respWaitingCounter; + + protected final LongAdder doneRequestCounter = new LongAdder(); + + protected final LongAdder doneResponseCounter = new LongAdder(); + + protected final AtomicBoolean writePending = new AtomicBoolean(); + + protected final ReentrantLock writeLock = new ReentrantLock(); + + protected final ByteArray writeArray = new ByteArray(); + + protected final ThreadLocal arrayThreadLocal = Utility.withInitialThreadLocal(ByteArray::new); + + protected final ByteBuffer writeBuffer; + + protected final CompletionHandler writeHandler = + new CompletionHandler() { + + @Override + public void completed(Integer result, ClientConnection attachment) { + // do nothing + } + + @Override + public void failed(Throwable exc, ClientConnection attachment) { + writePending.set(false); + attachment.dispose(exc); + } + }; + + final AtomicBoolean pauseWriting = new AtomicBoolean(); + + final ConcurrentLinkedQueue pauseRequests = new ConcurrentLinkedQueue<>(); + + // pauseWriting=true,此字段才会有值; pauseWriting=false,此字段值为null + ClientFuture currHalfWriteFuture; + + @Nonnull + private Client.AddressConnEntry connEntry; + + protected final AsyncConnection channel; + + private final ClientCodec codec; + + // respFutureQueue、respFutureMap二选一, SPSC队列模式 + private final ConcurrentLinkedDeque> respFutureQueue = new ConcurrentLinkedDeque<>(); + + // respFutureQueue、respFutureMap二选一, key: requestid, SPSC模式 + private final ConcurrentHashMap> respFutureMap = new ConcurrentHashMap<>(); + + Iterator> currRespIterator; // 必须在调用decodeMessages之前重置为null + + private int maxPipelines; // 最大并行处理数 + + private boolean authenticated; + + @SuppressWarnings({"LeakingThisInConstructor", "OverridableMethodCallInConstructor"}) + public ClientConnection(Client, R, P> client, AsyncConnection channel) { + this.client = client; + this.codec = createCodec(); + this.channel = channel.beforeCloseListener(this); // .fastHandler(writeHandler); + this.writeBuffer = channel.pollWriteBuffer(); + } + + ClientConnection setConnEntry(Client.AddressConnEntry entry) { + this.connEntry = entry; + this.respWaitingCounter = entry.connRespWaiting; + return this; + } + + protected abstract ClientCodec createCodec(); + + protected final CompletableFuture

writeChannel(R request) { + return writeChannel(request, null); + } + + protected final CompletableFuture> writeChannel(R[] requests) { + return writeChannel(requests, null); + } + + // respTransfer只会在ClientCodec的读线程里调用 + protected final CompletableFuture writeChannel(R request, Function respTransfer) { + // if (client.debug) { + // client.logger.log(Level.FINEST, Utility.nowMillis() + ": " + Thread.currentThread().getName() + ": + // " + // + this + ", 发送请求: " + request); + // } + request.respTransfer = respTransfer; + ClientFuture respFuture = createClientFuture(request); + int rts = this.channel.getReadTimeoutSeconds(); + if (rts > 0 && !request.isCloseType()) { + respFuture.setTimeout(client.timeoutScheduler.schedule(respFuture, rts, TimeUnit.SECONDS)); + } + respWaitingCounter.increment(); // 放在writeChannelInWriteThread计数会延迟,导致不准确 + writeLock.lock(); + try { + offerRespFuture(respFuture); + if (pauseWriting.get()) { + pauseRequests.add(respFuture); + } else { + sendRequestInLocking(request, respFuture); + } + } finally { + writeLock.unlock(); + } + return respFuture; + } + + private void sendRequestInLocking(R request, ClientFuture respFuture) { + // 发送请求数据包 + writeArray.clear(); + request.writeTo(this, writeArray); + if (request.isCompleted()) { + doneRequestCounter.increment(); + } else { // 还剩半包没发送完 + pauseWriting.set(true); + currHalfWriteFuture = respFuture; + } + if (writeArray.length() > 0) { + if (writeBuffer.capacity() >= writeArray.length()) { + writeBuffer.clear(); + writeBuffer.put(writeArray.content(), 0, writeArray.length()); + writeBuffer.flip(); + channel.write(writeBuffer, this, writeHandler); + } else { + channel.write(writeArray, this, writeHandler); + } + } + } + + // respTransfer只会在ClientCodec的读线程里调用 + protected final CompletableFuture> writeChannel(R[] requests, Function respTransfer) { + // if (client.debug) { + // client.logger.log(Level.FINEST, Utility.nowMillis() + ": " + Thread.currentThread().getName() + ": + // " + // + this + ", 发送请求: " + Arrays.toString(requests) + ", readTimeoutSeconds: " + + // this.channel.getReadTimeoutSeconds()); + // } + ClientFuture[] respFutures = new ClientFuture[requests.length]; + int rts = this.channel.getReadTimeoutSeconds(); + for (int i = 0; i < respFutures.length; i++) { + R request = requests[i]; + request.respTransfer = respTransfer; + ClientFuture respFuture = createClientFuture(requests[i]); + respFutures[i] = respFuture; + if (rts > 0 && !request.isCloseType()) { + respFuture.setTimeout(client.timeoutScheduler.schedule(respFuture, rts, TimeUnit.SECONDS)); + } + } + respWaitingCounter.add(respFutures.length); // 放在writeChannelInWriteThread计数会延迟,导致不准确 + + writeLock.lock(); + try { + if (pauseWriting.get()) { + for (ClientFuture respFuture : respFutures) { + offerRespFuture(respFuture); + pauseRequests.add(respFuture); + } + } else { + for (ClientFuture respFuture : respFutures) { + offerRespFuture(respFuture); + } + sendRequestInLocking(respFutures); + } + } finally { + writeLock.unlock(); + } + return Utility.allOfFutures(respFutures); + } + + private void sendRequestInLocking(ClientFuture[] respFutures) { + // 发送请求数据包 + writeArray.clear(); + for (ClientFuture respFuture : respFutures) { + if (pauseWriting.get()) { + pauseRequests.add(respFuture); + } else { + ClientRequest request = respFuture.request; + request.writeTo(this, writeArray); + if (request.isCompleted()) { + doneRequestCounter.increment(); + } else { // 还剩半包没发送完 + pauseWriting.set(true); + currHalfWriteFuture = respFuture; + } + } + } + if (writeArray.length() > 0) { + if (writeBuffer.capacity() >= writeArray.length()) { + writeBuffer.clear(); + writeBuffer.put(writeArray.content(), 0, writeArray.length()); + writeBuffer.flip(); + channel.write(writeBuffer, this, writeHandler); + } else { + channel.write(writeArray, this, writeHandler); + } + } + } + + // private void sendFastRequestInLocking(R request, ClientFuture respFuture) { + // ByteArray array = arrayThreadLocal.get(); + // array.clear(); + // request.writeTo(this, array); + // if (request.isCompleted()) { + // doneRequestCounter.increment(); + // } else { //还剩半包没发送完 + // pauseWriting.set(true); + // currHalfWriteFuture = respFuture; + // } + // channel.fastWrite(array.getBytes()); + // } + // + // private void sendFastRequestInLocking(ClientFuture[] respFutures) { + // ByteArray array = arrayThreadLocal.get(); + // array.clear(); + // for (ClientFuture respFuture : respFutures) { + // if (pauseWriting.get()) { + // pauseRequests.add(respFuture); + // } else { + // ClientRequest request = respFuture.request; + // request.writeTo(this, array); + // if (request.isCompleted()) { + // doneRequestCounter.increment(); + // } else { //还剩半包没发送完 + // pauseWriting.set(true); + // currHalfWriteFuture = respFuture; + // } + // } + // } + // channel.fastWrite(array.getBytes()); + // } + // 发送半包和积压的请求数据包 + void sendHalfWriteInReadThread(R request, Throwable halfRequestExc) { + writeLock.lock(); + try { + pauseWriting.set(false); + ClientFuture respFuture = this.currHalfWriteFuture; + if (respFuture != null) { + this.currHalfWriteFuture = null; + if (halfRequestExc == null) { + offerFirstRespFuture(respFuture); + sendRequestInLocking(request, respFuture); + } else { + codec.responseComplete(true, respFuture, null, halfRequestExc); + } + } + while (!pauseWriting.get() && (respFuture = pauseRequests.poll()) != null) { + sendRequestInLocking((R) respFuture.getRequest(), respFuture); + } + } finally { + writeLock.unlock(); + } + } + + CompletableFuture

writeVirtualRequest(R request) { + if (!request.isVirtualType()) { + return CompletableFuture.failedFuture( + new RuntimeException("ClientVirtualRequest must be virtualType = true")); + } + ClientFuture respFuture = createClientFuture(request); + writeLock.lock(); + try { + offerRespFuture(respFuture); + } finally { + writeLock.unlock(); + } + channel.readRegister(getCodec()); // 不能在创建连接时注册读事件 + return respFuture; + } + + protected void preComplete(P resp, R req, Throwable exc) {} + + protected ClientFuture createClientFuture(R request) { + return new ClientFuture(this, request); + } + + @Override // AsyncConnection.beforeCloseListener + public void accept(AsyncConnection t) { + respWaitingCounter.reset(); + if (connEntry != null) { // index=-1 + connEntry.connection = null; + connEntry.connOpenState.set(false); + } + ClientMessageListener listener = getCodec().getMessageListener(); + if (listener != null) { + listener.onClose(this); + } + } + + public void dispose(Throwable exc) { + channel.offerWriteBuffer(writeBuffer); + channel.dispose(); + Throwable e = exc == null ? new ClosedChannelException() : exc; + CompletableFuture f; + respWaitingCounter.reset(); + WorkThread thread = channel.getReadIOThread(); + if (!respFutureQueue.isEmpty()) { + while ((f = respFutureQueue.poll()) != null) { + CompletableFuture future = f; + thread.runWork(() -> future.completeExceptionally(e)); + } + } + if (!respFutureMap.isEmpty()) { + respFutureMap.forEach((key, future) -> { + respFutureMap.remove(key); + thread.runWork(() -> future.completeExceptionally(e)); + }); + } + } + + // 只会在WriteIOThread中调用, 必须在writeLock内执行 + void offerFirstRespFuture(ClientFuture respFuture) { + Serializable requestid = respFuture.request.getRequestid(); + if (requestid == null) { + respFutureQueue.offerFirst(respFuture); + } else { + respFutureMap.put(requestid, respFuture); + } + } + + // 必须在writeLock内执行 + void offerRespFuture(ClientFuture respFuture) { + Serializable requestid = respFuture.request.getRequestid(); + if (requestid == null) { + respFutureQueue.offer(respFuture); + } else { + respFutureMap.put(requestid, respFuture); + } + } + + // 只会被Timeout在ReadIOThread中调用 + void removeRespFuture(Serializable requestid, ClientFuture respFuture) { + if (requestid == null) { + respFutureQueue.remove(respFuture); + } else { + respFutureMap.remove(requestid); + } + } + + // 只会被ClientCodec在ReadIOThread中调用 + R findRequest(Serializable requestid) { + if (requestid == null) { + if (currRespIterator == null) { + currRespIterator = respFutureQueue.iterator(); + } + ClientFuture future = currRespIterator.hasNext() ? currRespIterator.next() : null; + return future == null ? null : future.request; + } else { + ClientFuture future = respFutureMap.get(requestid); + return future == null ? null : future.request; + } + } + + // 只会被ClientCodec在ReadIOThread中调用 + protected ClientFuture pollRespFuture(Serializable requestid) { + if (requestid == null) { + return respFutureQueue.poll(); + } else { + return respFutureMap.remove(requestid); + } + } + + public boolean isAuthenticated() { + return authenticated; + } + + public AsyncConnection getChannel() { + return channel; + } + + public SocketAddress getRemoteAddress() { + return channel.getRemoteAddress(); + } + + public long getDoneRequestCounter() { + return doneRequestCounter.longValue(); + } + + public long getDoneResponseCounter() { + return doneResponseCounter.longValue(); + } + + public > C getCodec() { + return (C) codec; + } + + public int getMaxPipelines() { + return maxPipelines; + } + + protected ClientConnection setAuthenticated(boolean authenticated) { + this.authenticated = authenticated; + return this; + } + + protected ClientConnection setMaxPipelines(int maxPipelines) { + this.maxPipelines = maxPipelines; + return this; + } + + protected ClientConnection resetMaxPipelines() { + this.maxPipelines = client.maxPipelines; + return this; + } + + public int runningCount() { + return respWaitingCounter.intValue(); + } + + public long getLastWriteTime() { + return channel.getLastWriteTime(); + } + + public long getLastReadTime() { + return channel.getLastReadTime(); + } + + public boolean isOpen() { + return channel.isOpen(); + } + + @Override + public String toString() { + String s = super.toString(); + int pos = s.lastIndexOf('@'); + if (pos < 1) { + return s; + } + int cha = pos + 10 - s.length(); + if (cha < 1) { + return s; + } + for (int i = 0; i < cha; i++) s += ' '; + return s; + } +} diff --git a/src/main/java/org/redkale/net/client/ClientMessageListener.java b/src/main/java/org/redkale/net/client/ClientMessageListener.java index a1e11af12..34c93fb30 100644 --- a/src/main/java/org/redkale/net/client/ClientMessageListener.java +++ b/src/main/java/org/redkale/net/client/ClientMessageListener.java @@ -1,19 +1,19 @@ -/* - * - */ -package org.redkale.net.client; - -/** - * 接收消息事件 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public abstract class ClientMessageListener { - - public abstract void onMessage(ClientConnection conn, ClientResponse resp); - - public void onClose(ClientConnection conn) {} -} +/* + * + */ +package org.redkale.net.client; + +/** + * 接收消息事件 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public abstract class ClientMessageListener { + + public abstract void onMessage(ClientConnection conn, ClientResponse resp); + + public void onClose(ClientConnection conn) {} +} diff --git a/src/main/java/org/redkale/net/client/ClientResponse.java b/src/main/java/org/redkale/net/client/ClientResponse.java index fd4f459c5..56d74ae81 100644 --- a/src/main/java/org/redkale/net/client/ClientResponse.java +++ b/src/main/java/org/redkale/net/client/ClientResponse.java @@ -1,116 +1,116 @@ -/* - * 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.client; - -import java.io.Serializable; -import org.redkale.annotation.Nullable; - -/** - * 详情见: https://redkale.org - * - * @author zhangjx - * @since 2.3.0 - * @param 请求对象 - * @param

message - */ -public class ClientResponse { - - @Nullable - protected R request; // 服务端返回一个不存在的requestid,可能为null - - protected P message; - - protected Throwable cause; - - public ClientResponse() {} - - public ClientResponse(R request, P message) { - this.request = request; - this.message = message; - } - - public ClientResponse(R request, Throwable exc) { - this.request = request; - this.cause = exc; - } - - public Serializable getRequestid() { - return request == null ? null : request.getRequestid(); - } - - public ClientResponse success(R request, P message) { - this.request = request; - this.message = message; - return this; - } - - public ClientResponse fail(R request, Throwable exc) { - this.request = request; - this.cause = exc; - return this; - } - - protected void prepare() { - this.request = null; - this.message = null; - this.cause = null; - } - - protected boolean recycle() { - this.request = null; - this.message = null; - this.cause = null; - return true; - } - - public R getRequest() { - return request; - } - - public void setRequest(R request) { - this.request = request; - } - - public P getMessage() { - return message; - } - - public void setMessage(P message) { - this.message = message; - } - - public Throwable getCause() { - return cause; - } - - public void setCause(Throwable cause) { - this.cause = cause; - } - - @Override - public String toString() { - if (cause != null) { - return "{\"exc\":" + cause + "}"; - } - return "{\"message\":" + message + "}"; - } - - boolean isError() { - return false; - } - - static class ClientErrorResponse extends ClientResponse { - - public ClientErrorResponse(R request, Throwable exc) { - super(request, exc); - } - - @Override - boolean isError() { - return true; - } - } -} +/* + * 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.client; + +import java.io.Serializable; +import org.redkale.annotation.Nullable; + +/** + * 详情见: https://redkale.org + * + * @author zhangjx + * @since 2.3.0 + * @param 请求对象 + * @param

message + */ +public class ClientResponse { + + @Nullable + protected R request; // 服务端返回一个不存在的requestid,可能为null + + protected P message; + + protected Throwable cause; + + public ClientResponse() {} + + public ClientResponse(R request, P message) { + this.request = request; + this.message = message; + } + + public ClientResponse(R request, Throwable exc) { + this.request = request; + this.cause = exc; + } + + public Serializable getRequestid() { + return request == null ? null : request.getRequestid(); + } + + public ClientResponse success(R request, P message) { + this.request = request; + this.message = message; + return this; + } + + public ClientResponse fail(R request, Throwable exc) { + this.request = request; + this.cause = exc; + return this; + } + + protected void prepare() { + this.request = null; + this.message = null; + this.cause = null; + } + + protected boolean recycle() { + this.request = null; + this.message = null; + this.cause = null; + return true; + } + + public R getRequest() { + return request; + } + + public void setRequest(R request) { + this.request = request; + } + + public P getMessage() { + return message; + } + + public void setMessage(P message) { + this.message = message; + } + + public Throwable getCause() { + return cause; + } + + public void setCause(Throwable cause) { + this.cause = cause; + } + + @Override + public String toString() { + if (cause != null) { + return "{\"exc\":" + cause + "}"; + } + return "{\"message\":" + message + "}"; + } + + boolean isError() { + return false; + } + + static class ClientErrorResponse extends ClientResponse { + + public ClientErrorResponse(R request, Throwable exc) { + super(request, exc); + } + + @Override + boolean isError() { + return true; + } + } +} diff --git a/src/main/java/org/redkale/net/client/ClientResult.java b/src/main/java/org/redkale/net/client/ClientResult.java index 41cd9dfa6..11046a881 100644 --- a/src/main/java/org/redkale/net/client/ClientResult.java +++ b/src/main/java/org/redkale/net/client/ClientResult.java @@ -1,15 +1,15 @@ -/* - * - */ -package org.redkale.net.client; - -/** - * 详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public interface ClientResult { - - public boolean isKeepAlive(); -} +/* + * + */ +package org.redkale.net.client; + +/** + * 详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public interface ClientResult { + + public boolean isKeepAlive(); +} diff --git a/src/main/java/org/redkale/net/client/WeightAddress.java b/src/main/java/org/redkale/net/client/WeightAddress.java index 6a403295b..0ede8bc0d 100644 --- a/src/main/java/org/redkale/net/client/WeightAddress.java +++ b/src/main/java/org/redkale/net/client/WeightAddress.java @@ -1,92 +1,92 @@ -/* - * - */ -package org.redkale.net.client; - -import java.net.SocketAddress; -import java.util.List; -import java.util.Objects; -import org.redkale.annotation.ConstructorParameters; -import org.redkale.convert.ConvertColumn; -import org.redkale.convert.json.JsonConvert; - -/** - * 带权重的地址 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public class WeightAddress implements Comparable, java.io.Serializable { - - @ConvertColumn(index = 1) - private final SocketAddress address; - - // 权重值,取值范围[0-100] - @ConvertColumn(index = 2) - private final int weight; - - @ConstructorParameters({"address", "weight"}) - public WeightAddress(SocketAddress address, int weight) { - Objects.requireNonNull(address); - if (weight < 0 || weight > 100) { - throw new IndexOutOfBoundsException("weight must be [0 - 100]"); - } - this.address = address; - this.weight = weight; - } - - public static SocketAddress[] createAddressArray(List ws) { - int min = 0; - int size = 0; // 20,35,45去掉最大公约数,数组长度为:4+7+9=20 - for (WeightAddress w : ws) { - size += w.getWeight(); - if (min == 0 || w.getWeight() < min) { - min = w.getWeight(); - } - } - int divisor = 1; // 最大公约数 - for (int i = 2; i <= min; i++) { - boolean all = true; - for (WeightAddress w : ws) { - if (w.getWeight() % i > 0) { - all = false; - break; - } - } - if (all) { - divisor = i; - } - } - size /= divisor; - SocketAddress[] newAddrs = new SocketAddress[size]; - int index = -1; - for (int i = 0; i < ws.size(); i++) { - WeightAddress w = ws.get(i); - int z = w.getWeight() / divisor; - for (int j = 0; j < z; j++) { - newAddrs[++index] = w.getAddress(); - } - } - return newAddrs; - } - - @Override - public int compareTo(WeightAddress o) { - return this.weight - (o == null ? 0 : o.weight); - } - - public SocketAddress getAddress() { - return address; - } - - public int getWeight() { - return this.weight; - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } -} +/* + * + */ +package org.redkale.net.client; + +import java.net.SocketAddress; +import java.util.List; +import java.util.Objects; +import org.redkale.annotation.ConstructorParameters; +import org.redkale.convert.ConvertColumn; +import org.redkale.convert.json.JsonConvert; + +/** + * 带权重的地址 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public class WeightAddress implements Comparable, java.io.Serializable { + + @ConvertColumn(index = 1) + private final SocketAddress address; + + // 权重值,取值范围[0-100] + @ConvertColumn(index = 2) + private final int weight; + + @ConstructorParameters({"address", "weight"}) + public WeightAddress(SocketAddress address, int weight) { + Objects.requireNonNull(address); + if (weight < 0 || weight > 100) { + throw new IndexOutOfBoundsException("weight must be [0 - 100]"); + } + this.address = address; + this.weight = weight; + } + + public static SocketAddress[] createAddressArray(List ws) { + int min = 0; + int size = 0; // 20,35,45去掉最大公约数,数组长度为:4+7+9=20 + for (WeightAddress w : ws) { + size += w.getWeight(); + if (min == 0 || w.getWeight() < min) { + min = w.getWeight(); + } + } + int divisor = 1; // 最大公约数 + for (int i = 2; i <= min; i++) { + boolean all = true; + for (WeightAddress w : ws) { + if (w.getWeight() % i > 0) { + all = false; + break; + } + } + if (all) { + divisor = i; + } + } + size /= divisor; + SocketAddress[] newAddrs = new SocketAddress[size]; + int index = -1; + for (int i = 0; i < ws.size(); i++) { + WeightAddress w = ws.get(i); + int z = w.getWeight() / divisor; + for (int j = 0; j < z; j++) { + newAddrs[++index] = w.getAddress(); + } + } + return newAddrs; + } + + @Override + public int compareTo(WeightAddress o) { + return this.weight - (o == null ? 0 : o.weight); + } + + public SocketAddress getAddress() { + return address; + } + + public int getWeight() { + return this.weight; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } +} diff --git a/src/main/java/org/redkale/net/http/HttpException.java b/src/main/java/org/redkale/net/http/HttpException.java index 9bba187dc..054e8e2c3 100644 --- a/src/main/java/org/redkale/net/http/HttpException.java +++ b/src/main/java/org/redkale/net/http/HttpException.java @@ -1,33 +1,33 @@ -/* - * - */ -package org.redkale.net.http; - -import org.redkale.util.RedkaleException; - -/** - * Http自定义异常类 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public class HttpException extends RedkaleException { - - public HttpException() { - super(); - } - - public HttpException(String s) { - super(s); - } - - public HttpException(String message, Throwable cause) { - super(message, cause); - } - - public HttpException(Throwable cause) { - super(cause); - } -} +/* + * + */ +package org.redkale.net.http; + +import org.redkale.util.RedkaleException; + +/** + * Http自定义异常类 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public class HttpException extends RedkaleException { + + public HttpException() { + super(); + } + + public HttpException(String s) { + super(s); + } + + public HttpException(String message, Throwable cause) { + super(message, cause); + } + + public HttpException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/org/redkale/net/http/HttpFilter.java b/src/main/java/org/redkale/net/http/HttpFilter.java index bbfc32f3a..636a087b6 100644 --- a/src/main/java/org/redkale/net/http/HttpFilter.java +++ b/src/main/java/org/redkale/net/http/HttpFilter.java @@ -1,78 +1,78 @@ -/* - * 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.http; - -import org.redkale.net.Filter; -import org.redkale.util.AnyValue; - -/** - * HTTP 过滤器
- * - *

详情见: https://redkale.org - * - * @author zhangjx - */ -public abstract class HttpFilter extends Filter { - - // Server执行start后运行此方法 - protected void postStart(HttpContext context, AnyValue config) {} - - protected void setMethod(HttpRequest request, String method) { - request.setMethod(method); - } - - protected void setPath(HttpRequest request, String path) { - request.setRequestPath(path); - } - - protected void setRemoteAddr(HttpRequest request, String remoteAddr) { - request.setRemoteAddr(remoteAddr); - } - - protected void setLocale(HttpRequest request, String locale) { - request.setLocale(locale); - } - - protected T setProperty(HttpRequest request, String name, T value) { - return request.setProperty(name, value); - } - - protected T getProperty(HttpRequest request, String name) { - return request.getProperty(name); - } - - protected void removeProperty(HttpRequest request, String name) { - request.removeProperty(name); - } - - protected void addHeader(HttpRequest request, String name, String value) { - request.addHeader(name, value); - } - - protected void setHeader(HttpRequest request, String name, String value) { - request.setHeader(name, value); - } - - protected void removeHeader(HttpRequest request, String name) { - request.removeHeader(name); - } - - protected void setParameter(HttpRequest request, String name, String value) { - request.setParameter(name, value); - } - - protected void removeParameter(HttpRequest request, String name) { - request.removeParameter(name); - } - - protected void setFilter(HttpResponse response, HttpFilter filter) { - response.setFilter(filter); - } - - protected void thenEvent(HttpResponse response, HttpFilter filter) { - response.thenEvent(filter); - } -} +/* + * 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.http; + +import org.redkale.net.Filter; +import org.redkale.util.AnyValue; + +/** + * HTTP 过滤器
+ * + *

详情见: https://redkale.org + * + * @author zhangjx + */ +public abstract class HttpFilter extends Filter { + + // Server执行start后运行此方法 + protected void postStart(HttpContext context, AnyValue config) {} + + protected void setMethod(HttpRequest request, String method) { + request.setMethod(method); + } + + protected void setPath(HttpRequest request, String path) { + request.setRequestPath(path); + } + + protected void setRemoteAddr(HttpRequest request, String remoteAddr) { + request.setRemoteAddr(remoteAddr); + } + + protected void setLocale(HttpRequest request, String locale) { + request.setLocale(locale); + } + + protected T setProperty(HttpRequest request, String name, T value) { + return request.setProperty(name, value); + } + + protected T getProperty(HttpRequest request, String name) { + return request.getProperty(name); + } + + protected void removeProperty(HttpRequest request, String name) { + request.removeProperty(name); + } + + protected void addHeader(HttpRequest request, String name, String value) { + request.addHeader(name, value); + } + + protected void setHeader(HttpRequest request, String name, String value) { + request.setHeader(name, value); + } + + protected void removeHeader(HttpRequest request, String name) { + request.removeHeader(name); + } + + protected void setParameter(HttpRequest request, String name, String value) { + request.setParameter(name, value); + } + + protected void removeParameter(HttpRequest request, String name) { + request.removeParameter(name); + } + + protected void setFilter(HttpResponse response, HttpFilter filter) { + response.setFilter(filter); + } + + protected void thenEvent(HttpResponse response, HttpFilter filter) { + response.thenEvent(filter); + } +} diff --git a/src/main/java/org/redkale/net/http/HttpHeaders.java b/src/main/java/org/redkale/net/http/HttpHeaders.java index 7c1972665..27f877d7c 100644 --- a/src/main/java/org/redkale/net/http/HttpHeaders.java +++ b/src/main/java/org/redkale/net/http/HttpHeaders.java @@ -1,369 +1,369 @@ -/* - * - */ -package org.redkale.net.http; - -import java.io.Serializable; -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.Collection; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.BiConsumer; -import java.util.function.Predicate; -import org.redkale.convert.TextConvert; -import org.redkale.convert.json.JsonConvert; -import org.redkale.util.RedkaleException; - -/** - * Http Header Object - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public class HttpHeaders implements RestHeaders, Serializable { - - // value值只能是String、List - protected LinkedHashMap map; - - protected HttpHeaders() {} - - public static HttpHeaders create() { - return new HttpHeaders(); - } - - public static HttpHeaders of(String... items) { - HttpHeaders header = new HttpHeaders(); - int len = items.length / 2; - for (int i = 0; i < len; i++) { - header.add(items[i * 2], items[i * 2 + 1]); - } - return header; - } - - /** - * 无需校验参数合法性 - * - * @param map 参数 - * @return HttpHeaders - */ - public static HttpHeaders ofValid(Map map) { - HttpHeaders header = new HttpHeaders(); - if (map != null) { - header.map = map instanceof LinkedHashMap ? (LinkedHashMap) map : new LinkedHashMap(map); - } - return header; - } - - @Override - public String firstValue(String name) { - return firstValue(name, null); - } - - @Override - public String firstValue(String name, String defaultValue) { - if (map == null) { - return defaultValue; - } - Serializable val = get(name); - if (val == null) { - return defaultValue; - } - if (val instanceof Collection) { - for (Object item : (Collection) val) { - return String.valueOf(item); // return fisrt value - } - return defaultValue; - } - return String.valueOf(val); - } - - @Override - public List listValue(String name) { - if (this.map == null) { - return null; - } - Serializable val = get(name); - if (val == null) { - return null; - } - if (val instanceof Collection) { - return new ArrayList<>((Collection) val); - } - List list = new ArrayList<>(); - list.add(val); - return list; - } - - @Override - public void forEach(BiConsumer consumer) { - forEach((Predicate) null, consumer); - } - - @Override - public void forEach(Predicate filter, BiConsumer consumer) { - if (map != null) { - map.forEach((k, v) -> { - if (filter == null || filter.test(k)) { - if (v instanceof Collection) { - for (Object item : (Collection) v) { - consumer.accept(k, item == null ? null : item.toString()); - } - } else { - consumer.accept(k, v == null ? null : v.toString()); - } - } - }); - } - } - - @Override - public String[] names() { - if (this.map == null) { - return new String[0]; - } - Set names = this.map.keySet(); - return names.toArray(new String[names.size()]); - } - - @Override - public boolean contains(String name) { - return this.map != null && name != null && get(name) != null; - } - - public HttpHeaders addAll(HttpHeaders header) { - if (header.map != null) { - if (this.map == null) { - this.map = new LinkedHashMap<>(header.map); - } else { - header.forEach(this::add); - } - } - return this; - } - - public HttpHeaders add(Map values) { - if (values != null) { - values.forEach(this::add); - } - return this; - } - - private Serializable get(String name) { - Serializable val = this.map.get(name); - if (val != null) { - return val; - } - for (Map.Entry en : this.map.entrySet()) { - if (en.getKey().equalsIgnoreCase(name)) { - return en.getValue(); - } - } - return null; - } - - // 服务端接收,无需校验参数合法性 - void addValid(String name, Serializable value) { - if (this.map == null) { - this.map = new LinkedHashMap<>(); - this.map.put(name, value); - } else { - Serializable old = get(name); - if (old == null) { - this.map.put(name, value); - } else if (old instanceof Collection) { - ((Collection) old).add(value); - } else { - ArrayList list = new ArrayList(); - list.add(old); - list.add(value); - this.map.put(name, list); - } - } - } - - public HttpHeaders add(String name, String value) { - check(name, value); - addValid(name, value); - return this; - } - - public HttpHeaders add(String name, List value) { - if (value.isEmpty()) { - return this; - } - for (String val : value) { - check(name, val); - } - addValid(name, new ArrayList(value)); - return this; - } - - public HttpHeaders add(String name, TextConvert convert, Object value) { - return add(name, (convert == null ? JsonConvert.root() : convert).convertTo(value)); - } - - public HttpHeaders add(String name, Object value) { - return add(name, JsonConvert.root().convertTo(value)); - } - - public HttpHeaders add(String name, boolean value) { - return add(name, String.valueOf(value)); - } - - public HttpHeaders add(String name, short value) { - return add(name, String.valueOf(value)); - } - - public HttpHeaders add(String name, int value) { - return add(name, String.valueOf(value)); - } - - public HttpHeaders add(String name, float value) { - return add(name, String.valueOf(value)); - } - - public HttpHeaders add(String name, long value) { - return add(name, String.valueOf(value)); - } - - public HttpHeaders add(String name, double value) { - return add(name, String.valueOf(value)); - } - - public HttpHeaders add(String name, BigInteger value) { - return add(name, String.valueOf(value)); - } - - public HttpHeaders setAll(HttpHeaders header) { - if (header.map != null) { - if (this.map == null) { - this.map = new LinkedHashMap<>(); - } - this.map.putAll(header.map); - } - return this; - } - - public HttpHeaders set(Map values) { - if (values != null) { - values.forEach(this::set); - } - return this; - } - - // 服务端接收,无需校验参数合法性 - void setValid(String name, Serializable value) { - if (this.map == null) { - this.map = new LinkedHashMap<>(); - this.map.put(name, value); - } else { - boolean unfound = true; - for (Map.Entry en : this.map.entrySet()) { - if (en.getKey().equalsIgnoreCase(name)) { - this.map.put(en.getKey(), value); - unfound = false; - break; - } - } - if (unfound) { - this.map.put(name, value); - } - } - } - - public HttpHeaders set(String name, String value) { - check(name, value); - setValid(name, value); - return this; - } - - public HttpHeaders set(String name, List value) { - if (value.isEmpty()) { - return this; - } - for (String val : value) { - check(name, val); - } - setValid(name, new ArrayList(value)); - return this; - } - - public HttpHeaders set(String name, TextConvert convert, Object value) { - return set(name, (convert == null ? JsonConvert.root() : convert).convertTo(value)); - } - - public HttpHeaders set(String name, Object value) { - return set(name, JsonConvert.root().convertTo(value)); - } - - public HttpHeaders set(String name, boolean value) { - return set(name, String.valueOf(value)); - } - - public HttpHeaders set(String name, short value) { - return set(name, String.valueOf(value)); - } - - public HttpHeaders set(String name, int value) { - return set(name, String.valueOf(value)); - } - - public HttpHeaders set(String name, float value) { - return set(name, String.valueOf(value)); - } - - public HttpHeaders set(String name, long value) { - return set(name, String.valueOf(value)); - } - - public HttpHeaders set(String name, double value) { - return set(name, String.valueOf(value)); - } - - public HttpHeaders set(String name, BigInteger value) { - return set(name, String.valueOf(value)); - } - - public HttpHeaders remove(String name) { - if (this.map != null) { - this.map.remove(name); - } - return this; - } - - @Override - public Map map() { - return this.map; - } - - public boolean isEmpty() { - return this.map == null || this.map.isEmpty(); - } - - public HttpHeaders clear() { - if (this.map != null) { - this.map.clear(); - } - return this; - } - - protected String check(String name, String value) { - if (name.indexOf('\r') >= 0 || name.indexOf('\n') >= 0) { - throw new RedkaleException("http-header name(name = " + name + ") is illegal"); - } - if (value.indexOf('\r') >= 0 || value.indexOf('\n') >= 0) { - throw new RedkaleException("http-header value(name = " + name + ", value = " + value + ") is illegal"); - } - return value; - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this.map); - } -} +/* + * + */ +package org.redkale.net.http; + +import java.io.Serializable; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.BiConsumer; +import java.util.function.Predicate; +import org.redkale.convert.TextConvert; +import org.redkale.convert.json.JsonConvert; +import org.redkale.util.RedkaleException; + +/** + * Http Header Object + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public class HttpHeaders implements RestHeaders, Serializable { + + // value值只能是String、List + protected LinkedHashMap map; + + protected HttpHeaders() {} + + public static HttpHeaders create() { + return new HttpHeaders(); + } + + public static HttpHeaders of(String... items) { + HttpHeaders header = new HttpHeaders(); + int len = items.length / 2; + for (int i = 0; i < len; i++) { + header.add(items[i * 2], items[i * 2 + 1]); + } + return header; + } + + /** + * 无需校验参数合法性 + * + * @param map 参数 + * @return HttpHeaders + */ + public static HttpHeaders ofValid(Map map) { + HttpHeaders header = new HttpHeaders(); + if (map != null) { + header.map = map instanceof LinkedHashMap ? (LinkedHashMap) map : new LinkedHashMap(map); + } + return header; + } + + @Override + public String firstValue(String name) { + return firstValue(name, null); + } + + @Override + public String firstValue(String name, String defaultValue) { + if (map == null) { + return defaultValue; + } + Serializable val = get(name); + if (val == null) { + return defaultValue; + } + if (val instanceof Collection) { + for (Object item : (Collection) val) { + return String.valueOf(item); // return fisrt value + } + return defaultValue; + } + return String.valueOf(val); + } + + @Override + public List listValue(String name) { + if (this.map == null) { + return null; + } + Serializable val = get(name); + if (val == null) { + return null; + } + if (val instanceof Collection) { + return new ArrayList<>((Collection) val); + } + List list = new ArrayList<>(); + list.add(val); + return list; + } + + @Override + public void forEach(BiConsumer consumer) { + forEach((Predicate) null, consumer); + } + + @Override + public void forEach(Predicate filter, BiConsumer consumer) { + if (map != null) { + map.forEach((k, v) -> { + if (filter == null || filter.test(k)) { + if (v instanceof Collection) { + for (Object item : (Collection) v) { + consumer.accept(k, item == null ? null : item.toString()); + } + } else { + consumer.accept(k, v == null ? null : v.toString()); + } + } + }); + } + } + + @Override + public String[] names() { + if (this.map == null) { + return new String[0]; + } + Set names = this.map.keySet(); + return names.toArray(new String[names.size()]); + } + + @Override + public boolean contains(String name) { + return this.map != null && name != null && get(name) != null; + } + + public HttpHeaders addAll(HttpHeaders header) { + if (header.map != null) { + if (this.map == null) { + this.map = new LinkedHashMap<>(header.map); + } else { + header.forEach(this::add); + } + } + return this; + } + + public HttpHeaders add(Map values) { + if (values != null) { + values.forEach(this::add); + } + return this; + } + + private Serializable get(String name) { + Serializable val = this.map.get(name); + if (val != null) { + return val; + } + for (Map.Entry en : this.map.entrySet()) { + if (en.getKey().equalsIgnoreCase(name)) { + return en.getValue(); + } + } + return null; + } + + // 服务端接收,无需校验参数合法性 + void addValid(String name, Serializable value) { + if (this.map == null) { + this.map = new LinkedHashMap<>(); + this.map.put(name, value); + } else { + Serializable old = get(name); + if (old == null) { + this.map.put(name, value); + } else if (old instanceof Collection) { + ((Collection) old).add(value); + } else { + ArrayList list = new ArrayList(); + list.add(old); + list.add(value); + this.map.put(name, list); + } + } + } + + public HttpHeaders add(String name, String value) { + check(name, value); + addValid(name, value); + return this; + } + + public HttpHeaders add(String name, List value) { + if (value.isEmpty()) { + return this; + } + for (String val : value) { + check(name, val); + } + addValid(name, new ArrayList(value)); + return this; + } + + public HttpHeaders add(String name, TextConvert convert, Object value) { + return add(name, (convert == null ? JsonConvert.root() : convert).convertTo(value)); + } + + public HttpHeaders add(String name, Object value) { + return add(name, JsonConvert.root().convertTo(value)); + } + + public HttpHeaders add(String name, boolean value) { + return add(name, String.valueOf(value)); + } + + public HttpHeaders add(String name, short value) { + return add(name, String.valueOf(value)); + } + + public HttpHeaders add(String name, int value) { + return add(name, String.valueOf(value)); + } + + public HttpHeaders add(String name, float value) { + return add(name, String.valueOf(value)); + } + + public HttpHeaders add(String name, long value) { + return add(name, String.valueOf(value)); + } + + public HttpHeaders add(String name, double value) { + return add(name, String.valueOf(value)); + } + + public HttpHeaders add(String name, BigInteger value) { + return add(name, String.valueOf(value)); + } + + public HttpHeaders setAll(HttpHeaders header) { + if (header.map != null) { + if (this.map == null) { + this.map = new LinkedHashMap<>(); + } + this.map.putAll(header.map); + } + return this; + } + + public HttpHeaders set(Map values) { + if (values != null) { + values.forEach(this::set); + } + return this; + } + + // 服务端接收,无需校验参数合法性 + void setValid(String name, Serializable value) { + if (this.map == null) { + this.map = new LinkedHashMap<>(); + this.map.put(name, value); + } else { + boolean unfound = true; + for (Map.Entry en : this.map.entrySet()) { + if (en.getKey().equalsIgnoreCase(name)) { + this.map.put(en.getKey(), value); + unfound = false; + break; + } + } + if (unfound) { + this.map.put(name, value); + } + } + } + + public HttpHeaders set(String name, String value) { + check(name, value); + setValid(name, value); + return this; + } + + public HttpHeaders set(String name, List value) { + if (value.isEmpty()) { + return this; + } + for (String val : value) { + check(name, val); + } + setValid(name, new ArrayList(value)); + return this; + } + + public HttpHeaders set(String name, TextConvert convert, Object value) { + return set(name, (convert == null ? JsonConvert.root() : convert).convertTo(value)); + } + + public HttpHeaders set(String name, Object value) { + return set(name, JsonConvert.root().convertTo(value)); + } + + public HttpHeaders set(String name, boolean value) { + return set(name, String.valueOf(value)); + } + + public HttpHeaders set(String name, short value) { + return set(name, String.valueOf(value)); + } + + public HttpHeaders set(String name, int value) { + return set(name, String.valueOf(value)); + } + + public HttpHeaders set(String name, float value) { + return set(name, String.valueOf(value)); + } + + public HttpHeaders set(String name, long value) { + return set(name, String.valueOf(value)); + } + + public HttpHeaders set(String name, double value) { + return set(name, String.valueOf(value)); + } + + public HttpHeaders set(String name, BigInteger value) { + return set(name, String.valueOf(value)); + } + + public HttpHeaders remove(String name) { + if (this.map != null) { + this.map.remove(name); + } + return this; + } + + @Override + public Map map() { + return this.map; + } + + public boolean isEmpty() { + return this.map == null || this.map.isEmpty(); + } + + public HttpHeaders clear() { + if (this.map != null) { + this.map.clear(); + } + return this; + } + + protected String check(String name, String value) { + if (name.indexOf('\r') >= 0 || name.indexOf('\n') >= 0) { + throw new RedkaleException("http-header name(name = " + name + ") is illegal"); + } + if (value.indexOf('\r') >= 0 || value.indexOf('\n') >= 0) { + throw new RedkaleException("http-header value(name = " + name + ", value = " + value + ") is illegal"); + } + return value; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this.map); + } +} diff --git a/src/main/java/org/redkale/net/http/HttpParameters.java b/src/main/java/org/redkale/net/http/HttpParameters.java index 39dd146f9..5e98ffee2 100644 --- a/src/main/java/org/redkale/net/http/HttpParameters.java +++ b/src/main/java/org/redkale/net/http/HttpParameters.java @@ -1,189 +1,189 @@ -/* - * - */ -package org.redkale.net.http; - -import java.io.Serializable; -import java.math.BigInteger; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Set; -import java.util.function.BiConsumer; -import org.redkale.convert.TextConvert; -import org.redkale.convert.json.JsonConvert; -import org.redkale.util.RedkaleException; - -/** @author zhangjx */ -public class HttpParameters implements RestParams, Serializable { - - protected HashMap map; - - protected HttpParameters() {} - - public static HttpParameters create() { - return new HttpParameters(); - } - - public static HttpParameters of(String... items) { - HttpParameters params = new HttpParameters(); - int len = items.length / 2; - for (int i = 0; i < len; i++) { - params.put(items[i * 2], items[i * 2 + 1]); - } - return params; - } - - /** - * 无需校验参数合法性 - * - * @param map 参数 - * @return HttpParameters - */ - public static HttpParameters ofValid(Map map) { - HttpParameters params = new HttpParameters(); - if (map != null) { - params.map = map instanceof HashMap ? (HashMap) map : new HashMap(map); - } - return params; - } - - @Override - public String get(String name) { - return get(name, null); - } - - @Override - public String get(String name, String defaultValue) { - if (map == null) { - return defaultValue; - } - return map.getOrDefault(name, defaultValue); - } - - @Override - public void forEach(BiConsumer consumer) { - if (map != null) { - map.forEach(consumer); - } - } - - @Override - public String[] names() { - if (this.map == null) { - return new String[0]; - } - Set names = this.map.keySet(); - return names.toArray(new String[names.size()]); - } - - @Override - public boolean contains(String name) { - return this.map != null && this.map.containsKey(name); - } - - public HttpParameters putAll(HttpParameters params) { - if (params.map != null) { - if (this.map == null) { - this.map = new LinkedHashMap<>(); - } - this.map.putAll(params.map); - } - return this; - } - - public HttpParameters put(Map values) { - if (values != null) { - values.forEach(this::put); - } - return this; - } - - // 服务端接收,无需校验参数合法性 - void setValid(String name, String value) { - if (this.map == null) { - this.map = new LinkedHashMap<>(); - } - this.map.put(name, value); - } - - public HttpParameters put(String name, String value) { - check(name, value); - if (this.map == null) { - this.map = new LinkedHashMap<>(); - } - this.map.put(name, value); - return this; - } - - public HttpParameters put(String name, TextConvert convert, Object value) { - return put(name, (convert == null ? JsonConvert.root() : convert).convertTo(value)); - } - - public HttpParameters put(String name, Object value) { - return put(name, JsonConvert.root().convertTo(value)); - } - - public HttpParameters put(String name, boolean value) { - return put(name, String.valueOf(value)); - } - - public HttpParameters put(String name, short value) { - return put(name, String.valueOf(value)); - } - - public HttpParameters put(String name, int value) { - return put(name, String.valueOf(value)); - } - - public HttpParameters put(String name, float value) { - return put(name, String.valueOf(value)); - } - - public HttpParameters put(String name, long value) { - return put(name, String.valueOf(value)); - } - - public HttpParameters put(String name, double value) { - return put(name, String.valueOf(value)); - } - - public HttpParameters put(String name, BigInteger value) { - return put(name, String.valueOf(value)); - } - - public HttpParameters remove(String name) { - if (this.map != null) { - this.map.remove(name); - } - return this; - } - - @Override - public Map map() { - return this.map; - } - - public boolean isEmpty() { - return this.map == null || this.map.isEmpty(); - } - - public HttpParameters clear() { - if (this.map != null) { - this.map.clear(); - } - return this; - } - - protected String check(String name, String value) { - if (name.indexOf(' ') >= 0 || name.indexOf('\r') >= 0 || name.indexOf('\n') >= 0) { - throw new RedkaleException("http-param name(name = " + name + ") is illegal"); - } - return value; - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this.map); - } -} +/* + * + */ +package org.redkale.net.http; + +import java.io.Serializable; +import java.math.BigInteger; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; +import java.util.function.BiConsumer; +import org.redkale.convert.TextConvert; +import org.redkale.convert.json.JsonConvert; +import org.redkale.util.RedkaleException; + +/** @author zhangjx */ +public class HttpParameters implements RestParams, Serializable { + + protected HashMap map; + + protected HttpParameters() {} + + public static HttpParameters create() { + return new HttpParameters(); + } + + public static HttpParameters of(String... items) { + HttpParameters params = new HttpParameters(); + int len = items.length / 2; + for (int i = 0; i < len; i++) { + params.put(items[i * 2], items[i * 2 + 1]); + } + return params; + } + + /** + * 无需校验参数合法性 + * + * @param map 参数 + * @return HttpParameters + */ + public static HttpParameters ofValid(Map map) { + HttpParameters params = new HttpParameters(); + if (map != null) { + params.map = map instanceof HashMap ? (HashMap) map : new HashMap(map); + } + return params; + } + + @Override + public String get(String name) { + return get(name, null); + } + + @Override + public String get(String name, String defaultValue) { + if (map == null) { + return defaultValue; + } + return map.getOrDefault(name, defaultValue); + } + + @Override + public void forEach(BiConsumer consumer) { + if (map != null) { + map.forEach(consumer); + } + } + + @Override + public String[] names() { + if (this.map == null) { + return new String[0]; + } + Set names = this.map.keySet(); + return names.toArray(new String[names.size()]); + } + + @Override + public boolean contains(String name) { + return this.map != null && this.map.containsKey(name); + } + + public HttpParameters putAll(HttpParameters params) { + if (params.map != null) { + if (this.map == null) { + this.map = new LinkedHashMap<>(); + } + this.map.putAll(params.map); + } + return this; + } + + public HttpParameters put(Map values) { + if (values != null) { + values.forEach(this::put); + } + return this; + } + + // 服务端接收,无需校验参数合法性 + void setValid(String name, String value) { + if (this.map == null) { + this.map = new LinkedHashMap<>(); + } + this.map.put(name, value); + } + + public HttpParameters put(String name, String value) { + check(name, value); + if (this.map == null) { + this.map = new LinkedHashMap<>(); + } + this.map.put(name, value); + return this; + } + + public HttpParameters put(String name, TextConvert convert, Object value) { + return put(name, (convert == null ? JsonConvert.root() : convert).convertTo(value)); + } + + public HttpParameters put(String name, Object value) { + return put(name, JsonConvert.root().convertTo(value)); + } + + public HttpParameters put(String name, boolean value) { + return put(name, String.valueOf(value)); + } + + public HttpParameters put(String name, short value) { + return put(name, String.valueOf(value)); + } + + public HttpParameters put(String name, int value) { + return put(name, String.valueOf(value)); + } + + public HttpParameters put(String name, float value) { + return put(name, String.valueOf(value)); + } + + public HttpParameters put(String name, long value) { + return put(name, String.valueOf(value)); + } + + public HttpParameters put(String name, double value) { + return put(name, String.valueOf(value)); + } + + public HttpParameters put(String name, BigInteger value) { + return put(name, String.valueOf(value)); + } + + public HttpParameters remove(String name) { + if (this.map != null) { + this.map.remove(name); + } + return this; + } + + @Override + public Map map() { + return this.map; + } + + public boolean isEmpty() { + return this.map == null || this.map.isEmpty(); + } + + public HttpParameters clear() { + if (this.map != null) { + this.map.clear(); + } + return this; + } + + protected String check(String name, String value) { + if (name.indexOf(' ') >= 0 || name.indexOf('\r') >= 0 || name.indexOf('\n') >= 0) { + throw new RedkaleException("http-param name(name = " + name + ") is illegal"); + } + return value; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this.map); + } +} diff --git a/src/main/java/org/redkale/net/http/HttpRequest.java b/src/main/java/org/redkale/net/http/HttpRequest.java index 83b9e1f57..19265030b 100644 --- a/src/main/java/org/redkale/net/http/HttpRequest.java +++ b/src/main/java/org/redkale/net/http/HttpRequest.java @@ -1,2884 +1,2884 @@ -/* - * To change this license headers, 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.http; - -import static org.redkale.util.Utility.isEmpty; -import static org.redkale.util.Utility.isNotEmpty; - -import java.io.*; -import java.lang.annotation.Annotation; -import java.net.*; -import java.nio.ByteBuffer; -import java.nio.charset.*; -import java.util.*; -import java.util.function.Supplier; -import java.util.logging.Level; -import org.redkale.annotation.ClassDepends; -import org.redkale.annotation.Comment; -import org.redkale.convert.*; -import org.redkale.convert.json.JsonConvert; -import org.redkale.net.Request; -import org.redkale.util.*; - -/** - * Http请求包 与javax.servlet.http.HttpServletRequest 基本类似。
- * 同时提供json的解析接口: public Object getJsonParameter(Type type, String name)
- * Redkale提倡带简单的参数的GET请求采用类似REST风格, 因此提供了 getPathParam 系列接口。
- * 例如简单的翻页查询
- * /pipes/user/query/offset:0/limit:20
- * 获取页号: int offset = request.getPathParam("offset:", 0);
- * 获取行数: int limit = request.getPathParam("limit:", 10);
- * - *

详情见: https://redkale.org - * - * @author zhangjx - */ -public class HttpRequest extends Request { - - private static final boolean PIPELINE_SAME_HEADERS = - Boolean.getBoolean("redkale.http.request.pipeline.sameheaders"); - - protected static final Serializable CURRUSERID_NIL = new Serializable() {}; - - protected static final int READ_STATE_ROUTE = 1; - - protected static final int READ_STATE_HEADER = 2; - - protected static final int READ_STATE_BODY = 3; - - protected static final int READ_STATE_END = 4; - - protected static final byte[] EMPTY_BYTES = new byte[0]; - - protected static final String METHOD_GET = "GET"; - - protected static final String METHOD_PUT = "PUT"; - - protected static final String METHOD_POST = "POST"; - - protected static final String METHOD_HEAD = "HEAD"; - - protected static final String METHOD_OPTIONS = "OPTIONS"; - - protected static final String HTTP_1_1 = "HTTP/1.1"; - - protected static final String HTTP_2_0 = "HTTP/2.0"; - - protected static final String HEAD_COOKIE = "Cookie"; - - protected static final String HEAD_CONNECTION = "Connection"; - - protected static final String HEAD_CONTENT_TYPE = "Content-Type"; - - protected static final String HEAD_CONTENT_LENGTH = "Content-Length"; - - protected static final String HEAD_ACCEPT = "Accept"; - - protected static final String HEAD_HOST = "Host"; - - protected static final String HEAD_UPGRADE = "Upgrade"; - - protected static final String HEAD_USER_AGENT = "User-Agent"; - - protected static final String HEAD_EXPECT = "Expect"; - - public static final String SESSIONID_NAME = "JSESSIONID"; - - // ---------- header 相关参数 开始 ---------- - protected int headerLength; - - protected int headerHalfLen; - - protected String contentType; - - protected long contentLength = -1; - - protected String host; - - @Comment("原始的cookie字符串,解析后值赋给HttpCookie[] cookies") - protected String cookie; - - protected HttpCookie[] cookies; - - private boolean maybews = false; // 是否可能是WebSocket - - private boolean expect = false; // 是否Expect:100-continue - - protected boolean rpc; - - protected int readState = READ_STATE_ROUTE; - - // @since 2.1.0 - protected Serializable currentUserid = CURRUSERID_NIL; - - protected Supplier currentUserSupplier; - - protected ConvertType reqConvertType; - - protected Convert reqConvert; - - protected ConvertType respConvertType; - - protected Convert respConvert; - - protected final HttpHeaders headers = HttpHeaders.create(); - - // ---------- header 相关参数 结束 ---------- - @Comment("Method GET/POST/...") - protected String method; - - protected boolean getmethod; - - protected String protocol; - - protected String requestPath; - - protected byte[] queryBytes; - - protected String newSessionid; - - protected final HttpParameters params = HttpParameters.create(); - - protected boolean boundary = false; - - protected int moduleid; - - protected int actionid; - - protected Annotation[] annotations; - - protected String remoteAddr; - - protected String locale; - - private String lastPathString; - - private byte[] lastPathBytes; - - private final ByteArray array; - - private byte[] headerBytes; - - private boolean headerParsed = false; - - private boolean bodyParsed = false; - - private final String remoteAddrHeader; - - private final String localHeader; - - private final String localParameter; - - final HttpRpcAuthenticator rpcAuthenticator; - - HttpServlet.ActionEntry actionEntry; // 仅供HttpServlet传递Entry使用 - - public HttpRequest(HttpContext context) { - this(context, new ByteArray()); - } - - protected HttpRequest(HttpContext context, ByteArray array) { - super(context); - this.array = array; - this.remoteAddrHeader = context.remoteAddrHeader; - this.localHeader = context.localHeader; - this.localParameter = context.localParameter; - this.rpcAuthenticator = context.rpcAuthenticator; - } - - @SuppressWarnings("OverridableMethodCallInConstructor") - protected HttpRequest(HttpContext context, WebRequest req) { - super(context); - this.array = new ByteArray(); - this.remoteAddrHeader = null; - this.localHeader = null; - this.localParameter = null; - this.rpcAuthenticator = null; - if (req != null) { - initWebRequest(req, true); - } - } - - protected HttpRequest initWebRequest(WebRequest req, boolean needPath) { - if (req != null) { - this.rpc = req.rpc; - this.traceid = req.getTraceid(); - if (req.getBody() != null) { - this.array.put(req.getBody()); - } - if (req.getHeaders() != null) { - this.headers.setAll(req.getHeaders()); - } - this.reqConvertType = req.getReqConvertType(); - this.reqConvert = - req.getReqConvertType() == null ? null : ConvertFactory.findConvert(req.getReqConvertType()); - this.respConvertType = req.getRespConvertType(); - this.respConvert = - req.getRespConvertType() == null ? null : ConvertFactory.findConvert(req.getRespConvertType()); - if (req.getParams() != null) { - this.params.putAll(req.getParams()); - } - if (req.getCurrentUserid() != null) { - this.currentUserid = req.getCurrentUserid(); - } - this.contentType = req.getContentType(); - this.remoteAddr = req.getRemoteAddr(); - this.locale = req.getLocale(); - this.requestPath = needPath ? req.requestPath() : req.getPath(); - this.method = req.getMethod(); - if (isNotEmpty(req.getSessionid())) { - this.cookies = new HttpCookie[] {new HttpCookie(SESSIONID_NAME, req.getSessionid())}; - } - } - return this; - } - - public WebRequest createSimpleRequest(String contextPath) { - WebRequest req = new WebRequest(); - req.setBody(array.length() == 0 ? null : array.getBytes()); - if (!getHeaders().isEmpty()) { - req.setHeaders(headers); - if (headers.contains(Rest.REST_HEADER_RPC)) { // 外部request不能包含RPC的header信息 - req.removeHeader(Rest.REST_HEADER_RPC); - } - if (headers.contains(Rest.REST_HEADER_RESNAME)) { // 外部request不能包含RPC的header信息 - req.removeHeader(Rest.REST_HEADER_RESNAME); - } - if (headers.contains(Rest.REST_HEADER_CURRUSERID)) { // 外部request不能包含RPC的header信息 - req.removeHeader(Rest.REST_HEADER_CURRUSERID); - } - } - parseBody(); - req.setParams(params.isEmpty() ? null : params); - req.setRemoteAddr(getRemoteAddr()); - req.setLocale(getLocale()); - req.setContentType(getContentType()); - req.setContextPath(contextPath); - req.setMethod(this.method); - String path0 = this.requestPath; - if (isNotEmpty(contextPath) && path0.startsWith(contextPath)) { - path0 = path0.substring(contextPath.length()); - } - req.setPath(path0); - req.setSessionid(getSessionid(false)); - req.setRpc(this.rpc); - req.setTraceid(this.traceid); - return req; - } - - protected boolean isWebSocket() { - return maybews && getmethod && "Upgrade".equalsIgnoreCase(getHeader("Connection")); - } - - protected boolean isExpect() { - return expect; - } - - protected void setKeepAlive(boolean keepAlive) { - this.keepAlive = keepAlive; - } - - protected ConvertType getRespConvertType() { - return this.respConvertType; - } - - protected Convert getRespConvert() { - return this.respConvert == null ? this.jsonConvert : this.respConvert; - } - - @Override - protected int readHeader(final ByteBuffer buf, final Request last) { - final ByteBuffer buffer = buf; - ByteArray bytes = array; - if (this.readState == READ_STATE_ROUTE) { - int rs = readMethodUriLine(buffer); - if (rs != 0) { - return rs; - } - this.readState = READ_STATE_HEADER; - } - if (this.readState == READ_STATE_HEADER) { - if (last != null && ((HttpRequest) last).headerLength > 0) { - final HttpRequest httplast = (HttpRequest) last; - int bufremain = buffer.remaining(); - int remainHalf = httplast.headerLength - this.headerHalfLen; - if (remainHalf > bufremain) { - bytes.put(buffer); - this.headerHalfLen += bufremain; - buffer.clear(); - return 1; - } - buffer.position(buffer.position() + remainHalf); - this.contentType = httplast.contentType; - this.contentLength = httplast.contentLength; - this.host = httplast.host; - this.cookie = httplast.cookie; - this.cookies = httplast.cookies; - this.keepAlive = httplast.keepAlive; - this.maybews = httplast.maybews; - this.expect = httplast.expect; - this.rpc = httplast.rpc; - this.traceid = httplast.traceid; - this.currentUserid = httplast.currentUserid; - this.reqConvertType = httplast.reqConvertType; - this.reqConvert = httplast.reqConvert; - this.respConvertType = httplast.respConvertType; - this.respConvert = httplast.respConvert; - this.headerLength = httplast.headerLength; - this.headerHalfLen = httplast.headerHalfLen; - this.headerBytes = httplast.headerBytes; - this.headerParsed = httplast.headerParsed; - this.headers.setAll(httplast.headers); - } else if (context.lazyHeaders && getmethod) { // 非GET必须要读header,会有Content-Length - int rs = loadHeaderBytes(buffer); - if (rs != 0) { - buffer.clear(); - return rs; - } - this.headerParsed = false; - } else { - int startpos = buffer.position(); - int rs = readHeaderLines(buffer, bytes); - if (rs != 0) { - this.headerHalfLen = bytes.length(); - buffer.clear(); - return rs; - } - this.headerParsed = true; - this.headerLength = buffer.position() - startpos + this.headerHalfLen; - this.headerHalfLen = this.headerLength; - } - bytes.clear(); - if (this.contentType != null && this.contentType.contains("boundary=")) { - this.boundary = true; - } - if (this.boundary) { - this.keepAlive = false; // 文件上传必须设置keepAlive为false,因为文件过大时用户不一定会skip掉多余的数据 - } - // completed=true时ProtocolCodec会继续读下一个request - this.completed = !this.boundary && !maybews && this.headerParsed; - this.readState = READ_STATE_BODY; - } - if (this.readState == READ_STATE_BODY) { - if (this.contentLength > 0 && (this.contentType == null || !this.boundary)) { - if (this.contentLength > context.getMaxBody()) { - return -1; - } - bytes.put(buffer, Math.min((int) this.contentLength, buffer.remaining())); - int lr = (int) this.contentLength - bytes.length(); - if (lr == 0) { - this.readState = READ_STATE_END; - if (bytes.isEmpty()) { - this.bodyParsed = true; // no body data - } - } else { - buffer.clear(); - } - return lr > 0 ? lr : 0; - } - if (buffer.hasRemaining() && (this.boundary || !this.keepAlive)) { - bytes.put(buffer, buffer.remaining()); // 文件上传、HTTP1.0或Connection:close - } - this.readState = READ_STATE_END; - if (bytes.isEmpty()) { - this.bodyParsed = true; // no body data - } - } - // 暂不考虑是keep-alive且存在body却没有指定Content-Length的情况 - return 0; - } - - private int loadHeaderBytes(final ByteBuffer buf) { - final ByteBuffer buffer = buf; - ByteArray bytes = array; - int remain = buffer.remaining(); - byte b1, b2, b3, b4; - for (; ; ) { - if (remain-- < 4) { // bytes不存放\r\n\r\n这4个字节 - bytes.put(buffer); - buffer.clear(); - if (bytes.length() > 0) { - byte rn1 = 0, rn2 = 0, rn3 = 0; - byte b = bytes.getLastByte(); - if (b == '\r' || b == '\n') { - rn3 = b; - bytes.backCount(); - if (bytes.length() > 0) { - b = bytes.getLastByte(); - if (b == '\r' || b == '\n') { - rn2 = b; - bytes.backCount(); - if (bytes.length() > 0) { - b = bytes.getLastByte(); - if (b == '\r' || b == '\n') { - rn1 = b; - bytes.backCount(); - } - } - } - } - } - if (rn1 != 0) { - buffer.put(rn1); - } - if (rn2 != 0) { - buffer.put(rn2); - } - if (rn3 != 0) { - buffer.put(rn3); - } - } - return 1; - } - b1 = buffer.get(); - bytes.put(b1); - if (b1 == '\r') { - remain--; - b2 = buffer.get(); - bytes.put(b2); - if (b2 == '\n') { - remain--; - b3 = buffer.get(); - bytes.put(b3); - if (b3 == '\r') { - remain--; - b4 = buffer.get(); - bytes.put(b4); - if (b4 == '\n') { - this.headerBytes = Utility.append(this.headerBytes, bytes.content(), 0, bytes.length()); - this.headerLength = this.headerBytes.length; - this.headerHalfLen = this.headerLength; - bytes.clear(); - return 0; - } - } - } - } - } - } - - // 解析 GET /xxx HTTP/1.1 - private int readMethodUriLine(final ByteBuffer buf) { - final ByteBuffer buffer = buf; - Charset charset = this.context.getCharset(); - int remain = buffer.remaining(); - int size; - ByteArray bytes = array; - // 读method - if (this.method == null) { - boolean flag = false; - if (remain >= 5) { - byte b1 = buffer.get(); - byte b2 = buffer.get(); - if (b2 == ' ') { - remain -= 2; - this.method = Character.toString(b1); - this.getmethod = false; - } else { - byte b3 = buffer.get(); - if (b3 == ' ') { - remain -= 3; - this.method = new String(new byte[] {b1, b2}); - this.getmethod = false; - } else { - byte b4 = buffer.get(); - if (b4 == ' ') { - remain -= 4; - if (b1 == 'G' && b2 == 'E' && b3 == 'T') { - this.method = METHOD_GET; - this.getmethod = true; - } else if (b1 == 'P' && b2 == 'U' && b3 == 'T') { - this.method = METHOD_PUT; - this.getmethod = false; - } else { - this.method = new String(new byte[] {b1, b2, b3}); - this.getmethod = false; - } - } else { - byte b5 = buffer.get(); - remain -= 5; - if (b5 == ' ') { - if (b1 == 'P' && b2 == 'O' && b3 == 'S' && b3 == 'T') { - this.method = METHOD_POST; - this.getmethod = false; - } else if (b1 == 'H' && b2 == 'E' && b3 == 'A' && b3 == 'D') { - this.method = METHOD_HEAD; - this.getmethod = false; - } else { - this.method = new String(new byte[] {b1, b2, b3, b4}); - this.getmethod = false; - } - } else { - flag = true; - bytes.put(b1, b2, b3, b4, b5); - } - } - } - } - } - if (flag) { - for (; ; ) { - if (remain-- < 1) { - buffer.clear(); - return 1; - } - byte b = buffer.get(); - if (b == ' ') { - break; - } - bytes.put(b); - } - size = bytes.length(); - byte[] content = bytes.content(); - if (size == 3) { - if (content[0] == 'G' && content[1] == 'E' && content[2] == 'T') { - this.method = METHOD_GET; - this.getmethod = true; - } else if (content[0] == 'P' && content[1] == 'U' && content[2] == 'T') { - this.method = METHOD_PUT; - this.getmethod = false; - } else { - this.method = bytes.toString(true, charset); - this.getmethod = false; - } - } else if (size == 4) { - this.getmethod = false; - if (content[0] == 'P' && content[1] == 'O' && content[2] == 'S' && content[3] == 'T') { - this.method = METHOD_POST; - } else if (content[0] == 'H' && content[1] == 'E' && content[2] == 'A' && content[3] == 'D') { - this.method = METHOD_HEAD; - } else { - this.method = bytes.toString(true, charset); - } - } else if (size == 7) { - this.getmethod = false; - if (content[0] == 'O' - && content[1] == 'P' - && content[2] == 'T' - && content[3] == 'I' - && content[4] == 'O' - && content[5] == 'N' - && content[6] == 'S') { - this.method = METHOD_OPTIONS; - } else { - this.method = bytes.toString(true, charset); - } - } else { - this.method = bytes.toString(true, charset); - this.getmethod = false; - } - bytes.clear(); - } - } - - // 读uri - if (this.requestPath == null) { - int qst = -1; // ?的位置 - boolean decodeable = false; - boolean latin1 = true; - for (; ; ) { - if (remain-- < 1) { - buffer.clear(); - return 1; - } - byte b = buffer.get(); - if (b == ' ') { - break; - } - if (b == '?' && qst < 0) { - qst = bytes.length(); - } else if (!decodeable && (b == '+' || b == '%')) { - decodeable = true; - } else if (latin1 && (b < 0x20 || b >= 0x80)) { - latin1 = false; - } - bytes.put(b); - } - size = bytes.length(); - if (qst > 0) { // 带?参数 - this.requestPath = decodeable - ? toDecodeString(bytes, 0, qst, charset) - : context.loadUriPath(bytes, qst, latin1, charset); // bytes.toString(latin1, 0, qst, charset); - int qlen = size - qst - 1; - this.queryBytes = bytes.getBytes(qst + 1, qlen); - this.lastPathString = null; - this.lastPathBytes = null; - try { - addParameter(bytes, false, qst + 1, qlen); - } catch (Exception e) { - this.context - .getLogger() - .log(Level.WARNING, "HttpRequest.addParameter error: " + bytes.toString(), e); - } - } else { - if (decodeable) { // 需要转义 - this.requestPath = toDecodeString(bytes, 0, bytes.length(), charset); - this.lastPathString = null; - this.lastPathBytes = null; - } else if (context.lazyHeaders) { - byte[] lastURIBytes = lastPathBytes; - if (lastURIBytes != null && lastURIBytes.length == size && bytes.deepEquals(lastURIBytes)) { - this.requestPath = this.lastPathString; - } else { - this.requestPath = - context.loadUriPath(bytes, latin1, charset); // bytes.toString(latin1, charset); - this.lastPathString = this.requestPath; - this.lastPathBytes = bytes.getBytes(); - } - } else { - this.requestPath = context.loadUriPath(bytes, latin1, charset); // bytes.toString(latin1, charset); - this.lastPathString = null; - this.lastPathBytes = null; - } - this.queryBytes = EMPTY_BYTES; - } - bytes.clear(); - } - // 读protocol - for (; ; ) { - if (remain-- < 1) { - this.params.clear(); - buffer.clear(); - return 1; - } - byte b = buffer.get(); - if (b == '\r') { - if (remain-- < 1) { - this.params.clear(); - buffer.clear(); - buffer.put(b); - return 1; - } - if (buffer.get() != '\n') { - return -1; - } - break; - } - bytes.put(b); - } - size = bytes.length(); - byte[] content = bytes.content(); - if (size == 8 && content[0] == 'H' && content[5] == '1' && content[7] == '1') { - this.protocol = HTTP_1_1; - } else if (size == 8 && content[0] == 'H' && content[5] == '2' && content[7] == '0') { - this.protocol = HTTP_2_0; - } else { - this.protocol = bytes.toString(true, charset); - } - bytes.clear(); - return 0; - } - - // 解析Header Connection: keep-alive - private int readHeaderLines(final ByteBuffer buf, ByteArray bytes) { - final ByteBuffer buffer = buf; - Charset charset = this.context.getCharset(); - int remain = buffer.remaining(); - for (; ; ) { - bytes.clear(); - if (remain-- < 2) { - if (remain == 1) { - byte one = buffer.get(); - buffer.clear(); - buffer.put(one); - return 1; - } - buffer.clear(); - return 1; - } - remain--; - byte b1 = buffer.get(); - byte b2 = buffer.get(); - if (b1 == '\r' && b2 == '\n') { - return 0; - } - boolean latin1 = true; - if (latin1 && (b1 < 0x20 || b1 >= 0x80)) { - latin1 = false; - } - if (latin1 && (b2 < 0x20 || b2 >= 0x80)) { - latin1 = false; - } - bytes.put(b1, b2); - for (; ; ) { // name - if (remain-- < 1) { - buffer.clear(); - buffer.put(bytes.content(), 0, bytes.length()); - return 1; - } - byte b = buffer.get(); - if (b == ':') { - break; - } else if (latin1 && (b < 0x20 || b >= 0x80)) { - latin1 = false; - } - bytes.put(b); - } - String name = parseHeaderName(latin1, bytes, charset); - bytes.clear(); - boolean first = true; - int space = 0; - for (; ; ) { // value - if (remain-- < 1) { - buffer.clear(); - buffer.put(name.getBytes()); - buffer.put((byte) ':'); - if (space == 1) { - buffer.put((byte) ' '); - } else if (space > 0) { - for (int i = 0; i < space; i++) buffer.put((byte) ' '); - } - buffer.put(bytes.content(), 0, bytes.length()); - return 1; - } - byte b = buffer.get(); - if (b == '\r') { - if (remain-- < 1) { - buffer.clear(); - buffer.put(name.getBytes()); - buffer.put((byte) ':'); - if (space == 1) { - buffer.put((byte) ' '); - } else if (space > 0) { - for (int i = 0; i < space; i++) buffer.put((byte) ' '); - } - buffer.put(bytes.content(), 0, bytes.length()); - buffer.put((byte) '\r'); - return 1; - } - if (buffer.get() != '\n') { - return -1; - } - break; - } - if (first) { - if (b <= ' ') { - space++; - continue; - } - first = false; - } - bytes.put(b); - } - String value; - int vlen = bytes.length(); - byte[] content = bytes.content(); - switch (name) { - case HEAD_CONTENT_TYPE: // Content-Type - this.contentType = bytes.toString(true, charset); - break; - case HEAD_CONTENT_LENGTH: // Content-Length - this.contentLength = Long.decode(bytes.toString(true, charset)); - break; - case HEAD_HOST: // Host - this.host = bytes.toString(charset); - break; - case HEAD_COOKIE: // Cookie - if (this.cookie == null || this.cookie.isEmpty()) { - this.cookie = bytes.toString(charset); - } else { - this.cookie += ";" + bytes.toString(charset); - } - break; - case HEAD_CONNECTION: // Connection - if (vlen > 0) { - if (vlen == 5 - && content[0] == 'c' - && content[1] == 'l' - && content[2] == 'o' - && content[3] == 's' - && content[4] == 'e') { - value = "close"; - this.setKeepAlive(false); - } else if (vlen == 10 - && content[0] == 'k' - && content[1] == 'e' - && content[2] == 'e' - && content[3] == 'p' - && content[4] == '-' - && content[5] == 'a' - && content[6] == 'l' - && content[7] == 'i' - && content[8] == 'v' - && content[9] == 'e') { - value = "keep-alive"; - this.setKeepAlive(true); - } else { - value = bytes.toString(charset); - this.setKeepAlive(true); - } - } else { - value = ""; - } - headers.setValid(HEAD_CONNECTION, value); - break; - case HEAD_UPGRADE: // Upgrade - this.maybews = vlen == 9 - && content[0] == 'w' - && content[1] == 'e' - && content[2] == 'b' - && content[3] == 's' - && content[4] == 'o' - && content[5] == 'c' - && content[6] == 'k' - && content[7] == 'e' - && content[8] == 't'; - headers.setValid(HEAD_UPGRADE, this.maybews ? "websocket" : bytes.toString(true, charset)); - break; - case HEAD_EXPECT: // Expect - this.expect = vlen == 12 - && content[0] == '1' - && content[1] == '0' - && content[2] == '0' - && content[3] == '-' - && content[4] == 'c' - && content[5] == 'o' - && content[6] == 'n' - && content[7] == 't' - && content[8] == 'i' - && content[9] == 'n' - && content[10] == 'u' - && content[11] == 'e'; - headers.setValid(HEAD_EXPECT, this.expect ? "100-continue" : bytes.toString(true, charset)); - break; - case Rest.REST_HEADER_RPC: // rest-rpc - this.rpc = vlen == 4 - && content[0] == 't' - && content[1] == 'r' - && content[2] == 'u' - && content[3] == 'e'; - headers.setValid( - name, - this.rpc - ? "true" - : (vlen == 5 - && content[0] == 'f' - && content[1] == 'a' - && content[2] == 'l' - && content[3] == 's' - && content[4] == 'e' - ? "false" - : bytes.toString(true, charset))); - break; - case Rest.REST_HEADER_TRACEID: // rest-traceid - value = bytes.toString(true, charset); - this.traceid = value; - headers.setValid(name, value); - break; - case Rest.REST_HEADER_CURRUSERID: // rest-curruserid - value = bytes.toString(true, charset); - this.currentUserid = value; - headers.setValid(name, value); - break; - case Rest.REST_HEADER_REQ_CONVERT: // rest-req-convert-type - value = bytes.toString(true, charset); - reqConvertType = ConvertType.valueOf(value); - reqConvert = ConvertFactory.findConvert(reqConvertType); - headers.setValid(name, value); - break; - case Rest.REST_HEADER_RESP_CONVERT: // rest-resp-convert-type - value = bytes.toString(true, charset); - respConvertType = ConvertType.valueOf(value); - respConvert = ConvertFactory.findConvert(respConvertType); - headers.setValid(name, value); - break; - default: - headers.addValid(name, bytes.toString(charset)); - } - } - } - - private void parseHeader() { - if (headerParsed) { - return; - } - headerParsed = true; - if (headerBytes == null) { - return; - } - if (array.isEmpty()) { - readHeaderLines(ByteBuffer.wrap(headerBytes), array); - array.clear(); - } else { // array存有body数据 - readHeaderLines(ByteBuffer.wrap(headerBytes), new ByteArray()); - } - } - - static String parseHeaderName(boolean latin1, ByteArray bytes, Charset charset) { - final int size = bytes.length(); - final byte[] bs = bytes.content(); - final byte first = bs[0]; - if ((first == 'H' || first == 'h') && size == 4) { // Host - if (bs[1] == 'o' && bs[2] == 's' && bs[3] == 't') { - return HEAD_HOST; - } - } else if ((first == 'A' || first == 'a') && size == 6) { // Accept - if (bs[1] == 'c' && bs[2] == 'c' && bs[3] == 'e' && bs[4] == 'p' && bs[5] == 't') { - return HEAD_ACCEPT; - } - } else if (first == 'C' || first == 'c') { - if (size == 10) { // Connection - if (bs[1] == 'o' - && bs[2] == 'n' - && bs[3] == 'n' - && bs[4] == 'e' - && bs[5] == 'c' - && bs[6] == 't' - && bs[7] == 'i' - && bs[8] == 'o' - && bs[9] == 'n') { - return HEAD_CONNECTION; - } - } else if (size == 12) { // Content-Type - if (bs[1] == 'o' - && bs[2] == 'n' - && bs[3] == 't' - && bs[4] == 'e' - && bs[5] == 'n' - && bs[6] == 't' - && bs[7] == '-' - && (bs[8] == 'T' || bs[8] == 't') - && bs[9] == 'y' - && bs[10] == 'p' - && bs[11] == 'e') { - return HEAD_CONTENT_TYPE; - } - } else if (size == 14) { // Content-Length - if (bs[1] == 'o' - && bs[2] == 'n' - && bs[3] == 't' - && bs[4] == 'e' - && bs[5] == 'n' - && bs[6] == 't' - && bs[7] == '-' - && (bs[8] == 'L' || bs[8] == 'l') - && bs[9] == 'e' - && bs[10] == 'n' - && bs[11] == 'g' - && bs[12] == 't' - && bs[13] == 'h') { - return HEAD_CONTENT_LENGTH; - } - } else if (size == 6) { // Cookie - if (bs[1] == 'o' && bs[2] == 'o' && bs[3] == 'k' && bs[4] == 'i' && bs[5] == 'e') { - return HEAD_COOKIE; - } - } - } else if (first == 'U' || first == 'u') { - if (size == 7) { // Upgrade - if (bs[1] == 'p' && bs[2] == 'g' && bs[3] == 'r' && bs[4] == 'a' && bs[5] == 'd' && bs[6] == 'e') { - return HEAD_UPGRADE; - } - } else if (size == 10) { // User-Agent - if (bs[1] == 's' - && bs[2] == 'e' - && bs[3] == 'r' - && bs[4] == '-' - && (bs[5] == 'A' || bs[5] == 'a') - && bs[6] == 'g' - && bs[7] == 'e' - && bs[8] == 'n' - && bs[9] == 't') { - return HEAD_USER_AGENT; - } - } - } else if ((first == 'E' || first == 'e') && size == 6) { // Expect - if (bs[1] == 'x' && bs[2] == 'p' && bs[3] == 'e' && bs[4] == 'c' && bs[5] == 't') { - return HEAD_EXPECT; - } - } - return bytes.toString(latin1, charset); - } - - @Override - protected HttpRequest copyHeader() { - if (!PIPELINE_SAME_HEADERS || !context.lazyHeaders) { - return null; - } - HttpRequest req = new HttpRequest(context, this.array); - req.headerLength = this.headerLength; - req.headerBytes = this.headerBytes; - req.headerParsed = this.headerParsed; - req.contentType = this.contentType; - req.contentLength = this.contentLength; - req.host = this.host; - req.cookie = this.cookie; - req.cookies = this.cookies; - req.keepAlive = this.keepAlive; - req.maybews = this.maybews; - req.expect = this.expect; - req.rpc = this.rpc; - req.traceid = this.traceid; - req.currentUserid = this.currentUserid; - req.currentUserSupplier = this.currentUserSupplier; - req.reqConvertType = this.reqConvertType; - req.reqConvert = this.reqConvert; - req.respConvert = this.respConvert; - req.respConvertType = this.respConvertType; - req.headers.setAll(this.headers); - return req; - } - - @Override - protected Serializable getRequestid() { - return null; - } - - @Override - protected void prepare() { - this.keepAlive = true; // 默认HTTP/1.1 - } - - @Override - protected void recycle() { - // header - this.headerLength = 0; - this.headerHalfLen = 0; - this.headerBytes = null; - this.headerParsed = false; - this.contentType = null; - this.contentLength = -1; - this.host = null; - this.cookie = null; - this.cookies = null; - this.maybews = false; - this.expect = false; - this.rpc = false; - this.readState = READ_STATE_ROUTE; - this.currentUserid = CURRUSERID_NIL; - this.currentUserSupplier = null; - this.reqConvertType = null; - this.reqConvert = null; - this.respConvert = jsonConvert; - this.respConvertType = null; - this.headers.clear(); - // 其他 - this.newSessionid = null; - this.method = null; - this.getmethod = false; - this.protocol = null; - this.requestPath = null; - this.queryBytes = null; - this.boundary = false; - this.bodyParsed = false; - this.moduleid = 0; - this.actionid = 0; - this.annotations = null; - this.remoteAddr = null; - this.params.clear(); - this.array.clear(); - // 内部 - this.actionEntry = null; - super.recycle(); - } - - protected void skipBodyParse() { - this.bodyParsed = true; - } - - private void parseBody() { - if (this.boundary || bodyParsed) { - return; - } - bodyParsed = true; - if (this.getContentType() != null && this.contentType.toLowerCase().contains("x-www-form-urlencoded")) { - addParameter(array, true, 0, array.length()); - } - } - - private void addParameter(final ByteArray array, final boolean body, final int offset, final int len) { - if (len < 1) { - return; - } - Charset charset = this.context.getCharset(); - int limit = offset + len; - int keypos = array.indexOf(offset, limit, '='); - int valpos = array.indexOf(offset, limit, '&'); - if (keypos <= 0 || (valpos >= 0 && valpos < keypos)) { - if (valpos > 0) { - addParameter(array, body, valpos + 1, limit - valpos - 1); - } - return; - } - String name = toDecodeString(array, offset, keypos - offset, charset); - if (body && !name.isEmpty() && name.charAt(0) == '<') { - return; // 内容可能是xml格式; 如: = 0) { - addParameter(array, body, valpos + 1, limit - valpos - 1); - } - } - - protected HttpRequest setMethod(String method) { - this.method = method; - this.getmethod = METHOD_GET.equalsIgnoreCase(method); - return this; - } - - protected HttpRequest setRequestPath(String path) { - this.requestPath = path; - return this; - } - - protected HttpRequest setRemoteAddr(String remoteAddr) { - this.remoteAddr = remoteAddr; - return this; - } - - protected HttpRequest setLocale(String locale) { - this.locale = locale; - return this; - } - - protected HttpRequest setParameter(String name, String value) { - this.params.put(name, value); - return this; - } - - protected HttpRequest setHeader(String name, String value) { - this.headers.setValid(name, value); - return this; - } - - protected HttpRequest addHeader(String name, String value) { - this.headers.add(name, value); - return this; - } - - protected HttpRequest removeParameter(String name) { - this.params.remove(name); - return this; - } - - protected HttpRequest removeHeader(String name) { - this.headers.remove(name); - return this; - } - - protected static String toDecodeString(ByteArray array, int offset, int len, final Charset charset) { - byte[] content = array.content(); - if (len == 1) { - return Character.toString(content[offset]); - } else if (len == 2 && content[offset] >= 0x20 && content[offset] < 0x80) { - return new String(content, 0, offset, len); - } else if (len == 3 && content[offset + 1] >= 0x20 && content[offset + 1] < 0x80) { - return new String(content, 0, offset, len); - } - int start = offset; - final int end = offset + len; - boolean flag = false; // 是否需要转义 - byte[] bs = content; - for (int i = offset; i < end; i++) { - if (content[i] == '+' || content[i] == '%') { - flag = true; - break; - } - } - if (flag) { - int index = 0; - bs = new byte[len]; - for (int i = offset; i < end; i++) { - switch (content[i]) { - case '+': - bs[index] = ' '; - break; - case '%': - bs[index] = (byte) ((hexBit(content[++i]) * 16 + hexBit(content[++i]))); - break; - default: - bs[index] = content[i]; - break; - } - index++; - } - start = 0; - len = index; - } - return new String(bs, start, len, charset == null ? StandardCharsets.UTF_8 : charset); - } - - private static int hexBit(byte b) { - if ('0' <= b && '9' >= b) { - return b - '0'; - } - if ('a' <= b && 'z' >= b) { - return b - 'a' + 10; - } - if ('A' <= b && 'Z' >= b) { - return b - 'A' + 10; - } - return b; - } - - @Override - protected T setProperty(String name, T value) { - return super.setProperty(name, value); - } - - @Override - @SuppressWarnings("unchecked") - protected T getProperty(String name) { - return super.getProperty(name); - } - - @Override - protected T removeProperty(String name) { - return super.removeProperty(name); - } - - /** - * 设置当前用户ID, 通常在HttpServlet.preExecute方法里设置currentUserid
- * 数据类型只能是int、long、String、JavaBean - * - * @param 泛型 - * @param userid 用户ID - * @return HttpRequest - * @since 2.1.0 - */ - public HttpRequest setCurrentUserid(T userid) { - this.currentUserid = userid; - return this; - } - - /** - * 获取当前用户ID的int值
- * - * @return 用户ID - * @since 2.4.0 - */ - @ClassDepends - @SuppressWarnings("unchecked") - public int currentIntUserid() { - if (currentUserid == CURRUSERID_NIL || currentUserid == null) { - return 0; - } - if (this.currentUserid instanceof Number) { - return ((Number) this.currentUserid).intValue(); - } - String uid = this.currentUserid.toString(); - return uid.isEmpty() ? 0 : Integer.parseInt(uid); - } - - /** - * 获取当前用户ID的long值
- * - * @return 用户ID - * @since 2.7.0 - */ - @ClassDepends - @SuppressWarnings("unchecked") - public long currentLongUserid() { - if (currentUserid == CURRUSERID_NIL || currentUserid == null) { - return 0L; - } - if (this.currentUserid instanceof Number) { - return ((Number) this.currentUserid).longValue(); - } - String uid = this.currentUserid.toString(); - return uid.isEmpty() ? 0L : Long.parseLong(uid); - } - - /** - * 获取当前用户ID的String值
- * - * @return 用户ID - * @since 2.8.0 - */ - @ClassDepends - @SuppressWarnings("unchecked") - public String currentStringUserid() { - if (currentUserid == CURRUSERID_NIL || currentUserid == null) { - return null; - } - return this.currentUserid.toString(); - } - - /** - * 获取当前用户ID
- * - * @param 数据类型只能是int、long、String、JavaBean - * @param type 类型 - * @return 用户ID - * @since 2.1.0 - */ - @ClassDepends - @SuppressWarnings("unchecked") - public T currentUserid(Class type) { - if (currentUserid == CURRUSERID_NIL || currentUserid == null) { - if (type == int.class || type == Integer.class) { - return (T) (Integer) (int) 0; - } - if (type == long.class || type == Long.class) { - return (T) (Long) (long) 0; - } - return null; - } - if (type == int.class || type == Integer.class) { - if (this.currentUserid instanceof Number) { - return (T) (Integer) ((Number) this.currentUserid).intValue(); - } - String uid = this.currentUserid.toString(); - return (T) (Integer) (uid.isEmpty() ? 0 : Integer.parseInt(uid)); - } - if (type == long.class || type == Long.class) { - if (this.currentUserid instanceof Number) { - return (T) (Long) ((Number) this.currentUserid).longValue(); - } - String uid = this.currentUserid.toString(); - return (T) (Long) (uid.isEmpty() ? 0L : Long.parseLong(uid)); - } - if (type == String.class) { - return (T) this.currentUserid.toString(); - } - if (this.currentUserid instanceof CharSequence) { - return JsonConvert.root().convertFrom(type, this.currentUserid.toString()); - } - return (T) this.currentUserid; - } - - /** - * 建议使用 setCurrentUserid, 通过userid从Service或缓存中获取用户信息
- * 设置当前用户信息, 通常在HttpServlet.preExecute方法里设置currentUser
- * 数据类型由@HttpUserType指定 - * - * @param supplier currentUser对象方法 - * @since 2.4.0 - * @return HttpRequest - */ - public HttpRequest setCurrentUserSupplier(Supplier supplier) { - this.currentUserSupplier = supplier; - return this; - } - - /** - * 建议使用 currentUserid, 通过userid从Service或缓存中获取用户信息
- * 获取当前用户信息
- * 数据类型由@HttpUserType指定 - * - * @param @HttpUserType指定的用户信息类型 - * @return 用户信息 - */ - @SuppressWarnings("unchecked") - public T currentUser() { - Supplier supplier = this.currentUserSupplier; - return (T) (supplier == null ? null : supplier.get()); - } - - /** - * 获取模块ID,来自@HttpServlet.moduleid() - * - * @return 模块ID - */ - @ConvertDisabled - public int getModuleid() { - return this.moduleid; - } - - /** - * 获取操作ID,来自@HttpMapping.actionid() - * - * @return 模块ID - */ - @ConvertDisabled - public int getActionid() { - return this.actionid; - } - - /** - * 获取当前操作Method上的注解集合 - * - * @return Annotation[] - */ - @ConvertDisabled - public Annotation[] getAnnotations() { - if (this.annotations == null) { - return new Annotation[0]; - } - Annotation[] newanns = new Annotation[this.annotations.length]; - System.arraycopy(this.annotations, 0, newanns, 0, newanns.length); - return newanns; - } - - /** - * 获取当前操作Method上的注解 - * - * @param 注解泛型 - * @param annotationClass 注解类型 - * @return Annotation - */ - public T getAnnotation(Class annotationClass) { - if (this.annotations == null) { - return null; - } - for (Annotation ann : this.annotations) { - if (ann.getClass() == annotationClass) { - return (T) ann; - } - } - return null; - } - - /** - * 获取当前操作Method上的注解集合 - * - * @param 注解泛型 - * @param annotationClass 注解类型 - * @return Annotation[] - */ - public T[] getAnnotationsByType(Class annotationClass) { - if (this.annotations == null) { - return Creator.newArray(annotationClass, 0); - } - T[] news = Creator.newArray(annotationClass, this.annotations.length); - int index = 0; - for (Annotation ann : this.annotations) { - if (ann.getClass() == annotationClass) { - news[index++] = (T) ann; - } - } - if (index < 1) { - return Creator.newArray(annotationClass, 0); - } - return Arrays.copyOf(news, index); - } - - /** - * 获取客户端地址IP - * - * @return 地址 - */ - @ConvertDisabled - public SocketAddress getRemoteAddress() { - return this.channel == null || !this.channel.isOpen() ? null : this.channel.getRemoteAddress(); - } - - /** - * 获取客户端地址IP, 与getRemoteAddress() 的区别在于:本方法优先取header中指定为RemoteAddress名的值,没有则返回getRemoteAddress()的getHostAddress()。 - *
- * 本方法适用于服务前端有如nginx的代理服务器进行中转,通过 getRemoteAddress()是获取不到客户端的真实IP。 - * - * @return 地址 - */ - public String getRemoteAddr() { - if (this.remoteAddr != null) { - return this.remoteAddr; - } - parseHeader(); - if (remoteAddrHeader != null) { - String val = getHeader(remoteAddrHeader); - if (val != null) { - this.remoteAddr = val; - return val; - } - } - SocketAddress addr = getRemoteAddress(); - if (addr == null) { - return ""; - } - if (addr instanceof InetSocketAddress) { - this.remoteAddr = ((InetSocketAddress) addr).getAddress().getHostAddress(); - return this.remoteAddr; - } - this.remoteAddr = String.valueOf(addr); - return this.remoteAddr; - } - - /** - * 获取国际化Locale,值可以取之于header或parameter - * - * @return 国际化Locale - */ - public String getLocale() { - if (this.locale != null) { - return this.locale; - } - if (localHeader != null) { - String val = getHeader(localHeader); - if (val != null) { - this.locale = val; - return val; - } - } - if (localParameter != null) { - String val = getParameter(localParameter); - if (val != null) { - this.locale = val; - return val; - } - } - return this.locale; - } - - /** - * 获取请求内容指定的编码字符串 - * - * @param charset 编码 - * @return 内容 - */ - public String getBody(final Charset charset) { - return charset == null ? array.toString() : array.toString(charset); - } - - /** - * 获取请求内容的UTF-8编码字符串 - * - * @return 内容 - */ - @ConvertDisabled - public String getBodyUTF8() { - return array.toString(StandardCharsets.UTF_8); - } - - /** - * 获取请求内容的JavaBean对象 - * - * @param 泛型 - * @param type 类型 - * @return 内容 - */ - public T getBodyJson(java.lang.reflect.Type type) { - if (array == null || array.isEmpty()) { - return null; - } - Convert convert = this.reqConvert; - if (convert == null) { - convert = context.getJsonConvert(); - } - if (type == byte[].class) { - return (T) array.getBytes(); - } - return (T) convert.convertFrom(type, array.content()); - } - - /** - * 获取请求内容的JavaBean对象 - * - * @param 泛型 - * @param convert Convert - * @param type 类型 - * @return 内容 - */ - public T getBodyJson(Convert convert, java.lang.reflect.Type type) { - if (array.isEmpty()) { - return null; - } - if (type == byte[].class) { - return (T) array.getBytes(); - } - return (T) convert.convertFrom(type, array.content()); - } - - /** - * 获取请求内容的byte[] - * - * @return 内容 - */ - public byte[] getBody() { - return array.length() == 0 ? null : array.getBytes(); - } - - /** - * 直接获取body对象 - * - * @return body对象 - */ - @ConvertDisabled - protected ByteArray getDirectBody() { - return array; - } - - @Override - public String toString() { - parseBody(); - return this.getClass().getSimpleName() + "{\r\n method: " + this.method + ", \r\n path: " - + this.requestPath - + (this.reqConvertType != null ? (", \r\n reqConvertType: " + this.reqConvertType) : "") - + (this.respConvertType != null ? (", \r\n respConvertType: " + this.respConvertType) : "") - + (this.currentUserid != CURRUSERID_NIL - ? (", \r\n currentUserid: " - + (this.currentUserid == CURRUSERID_NIL ? null : this.currentUserid)) - : "") - + (this.getRemoteAddr() != null ? (", \r\n remoteAddr: " + this.getRemoteAddr()) : "") - + (this.cookie != null ? (", \r\n cookies: " + this.cookie) : "") - + (this.getContentType() != null ? (", \r\n contentType: " + this.contentType) : "") - + (this.protocol != null ? (", \r\n protocol: " + this.protocol) : "") - + (this.getHost() != null ? (", \r\n host: " + this.host) : "") - + (this.getContentLength() >= 0 ? (", \r\n contentLength: " + this.contentLength) : "") - + (this.array.length() > 0 ? (", \r\n bodyLength: " + this.array.length()) : "") - + (this.boundary || this.array.isEmpty() - ? "" - : (", \r\n bodyContent: " - + (this.respConvertType == null || this.respConvertType == ConvertType.JSON - ? this.getBodyUTF8() - : Arrays.toString(getBody())))) - + ", \r\n params: " + toMapString(this.params.map, 4) - + ", \r\n header: " + toMapString(this.headers.map, 4) - + "\r\n}"; // this.headers.toString(4) - } - - private static CharSequence toMapString(Map map, int indent) { - final String space = " ".repeat(indent); - StringBuilder sb = new StringBuilder(); - sb.append("{\r\n"); - if (map != null) { - for (Map.Entry en : map.entrySet()) { - Object val = en.getValue(); - if (val instanceof Collection) { - for (Object item : (Collection) val) { - sb.append(space) - .append(" '") - .append(en.getKey()) - .append("': '") - .append(item) - .append("',\r\n"); - } - } else { - sb.append(space) - .append(" '") - .append(en.getKey()) - .append("': '") - .append(val) - .append("',\r\n"); - } - } - } - sb.append(space).append('}'); - return sb; - } - - /** - * 获取文件上传对象 - * - * @return 文件上传对象 - */ - @ConvertDisabled - public final MultiContext getMultiContext() { - final InputStream in = newInputStream(); - return new MultiContext( - context.getCharset(), - this.getContentType(), - this.params.map(), - new BufferedInputStream(in, Math.max(array.length(), 8192)) { - { - array.copyTo(this.buf); - this.count = array.length(); - } - }, - null); - } - - /** - * 是否上传文件请求 - * - * @return boolean - */ - public final boolean isMultipart() { - return boundary; - } - - /** - * 获取文件上传信息列表 - * - * @return 文件上传对象集合 - * @throws IOException IO异常 - */ - @ConvertDisabled - public final Iterable multiParts() throws IOException { - return getMultiContext().parts(); - } - - /** - * 获取sessionid - * - * @param autoCreate 无sessionid是否自动创建 - * @return sessionid - */ - @ConvertDisabled - public String getSessionid(boolean autoCreate) { - String sessionid = getCookie(SESSIONID_NAME, null); - if (autoCreate && (sessionid == null || sessionid.isEmpty())) { - sessionid = context.createSessionid(); - this.newSessionid = sessionid; - } - return sessionid; - } - - /** - * 更新sessionid - * - * @return 新的sessionid值 - */ - public String changeSessionid() { - this.newSessionid = context.createSessionid(); - return newSessionid; - } - - /** - * 指定值更新sessionid - * - * @param newSessionid 新sessionid值 - * @return 新的sessionid值 - */ - public String changeSessionid(String newSessionid) { - this.newSessionid = newSessionid == null ? context.createSessionid() : newSessionid.trim(); - return newSessionid; - } - - /** 使sessionid失效 */ - public void invalidateSession() { - this.newSessionid = ""; // 为空表示删除sessionid - } - - /** - * 获取所有Cookie对象 - * - * @return cookie对象数组 - */ - public HttpCookie[] getCookies() { - parseHeader(); - if (this.cookies == null) { - this.cookies = parseCookies(this.cookie); - } - return this.cookies.length == 0 ? null : this.cookies; - } - - /** - * 获取Cookie值 - * - * @param name cookie名 - * @return cookie值 - */ - public String getCookie(String name) { - return getCookie(name, null); - } - - /** - * 获取Cookie值, 没有返回默认值 - * - * @param name cookie名 - * @param dfvalue 默认cookie值 - * @return cookie值 - */ - public String getCookie(String name, String dfvalue) { - HttpCookie[] cs = getCookies(); - if (cs == null) { - return dfvalue; - } - for (HttpCookie c : cs) { - if (name.equals(c.getName())) { - return c.getValue(); - } - } - return dfvalue; - } - - private static HttpCookie[] parseCookies(String cookiestr) { - if (cookiestr == null || cookiestr.isEmpty()) { - return new HttpCookie[0]; - } - String str = cookiestr.replaceAll("(^;)|(;$)", "").replaceAll(";+", ";"); - if (str.isEmpty()) { - return new HttpCookie[0]; - } - String[] strs = str.split(";"); - HttpCookie[] cookies = new HttpCookie[strs.length]; - for (int i = 0; i < strs.length; i++) { - String s = strs[i]; - int pos = s.indexOf('='); - String v = (pos < 0 ? "" : s.substring(pos + 1)); - if (v.indexOf('"') == 0 && v.lastIndexOf('"') == v.length() - 1) { - v = v.substring(1, v.length() - 1); - } - cookies[i] = new HttpCookie((pos < 0 ? s : s.substring(0, pos)), v); - } - return cookies; - } - - /** - * 获取协议名 http、https、ws、wss等 - * - * @return protocol - */ - public String getProtocol() { - return protocol; - } - - /** - * 获取请求方法 GET、POST等 - * - * @return method - */ - public String getMethod() { - return method; - } - - /** - * 获取Content-Type的header值 - * - * @return contentType - */ - public String getContentType() { - if (contentType == null) { - parseHeader(); - } - return contentType; - } - - /** - * 获取请求内容的长度, 为-1表示内容长度不确定 - * - * @return 内容长度 - */ - public long getContentLength() { - if (contentLength < 1) { - parseHeader(); - } - return contentLength; - } - - /** - * 获取Host的Header值 - * - * @return Host - */ - public String getHost() { - if (host == null) { - parseHeader(); - } - return host; - } - - /** - * 获取请求的URL - * - * @return 请求的URL - */ - public String getRequestPath() { - return requestPath; - } - - /** - * 获取请求参数的byte[] - * - * @return byte[] - */ - public byte[] getQueryBytes() { - return queryBytes; - } - - /** - * 截取getRequestPath最后的一个/后面的部分 - * - * @return String - */ - @ConvertDisabled - public String getPathLastParam() { - if (requestPath == null) { - return ""; - } - return requestPath.substring(requestPath.lastIndexOf('/') + 1); - } - - /** - * 获取请求URL最后的一个/后面的部分的short值
- * 例如请求URL /pipes/user/query/2
- * 获取type参数: short type = request.getPathLastParam((short)0); //type = 2 - * - * @param defvalue 默认short值 - * @return short值 - */ - public short getPathLastParam(short defvalue) { - String val = getPathLastParam(); - if (val.isEmpty()) { - return defvalue; - } - try { - return Short.parseShort(val); - } catch (NumberFormatException e) { - return defvalue; - } - } - - /** - * 获取请求URL最后的一个/后面的部分的short值
- * 例如请求URL /pipes/user/query/2
- * 获取type参数: short type = request.getPathLastParam(16, (short)0); //type = 2 - * - * @param radix 进制数 - * @param defvalue 默认short值 - * @return short值 - */ - public short getPathLastParam(int radix, short defvalue) { - String val = getPathLastParam(); - if (val.isEmpty()) { - return defvalue; - } - try { - return Short.parseShort(val, radix); - } catch (NumberFormatException e) { - return defvalue; - } - } - - /** - * 获取请求URL最后的一个/后面的部分的int值
- * 例如请求URL /pipes/user/query/2
- * 获取type参数: int type = request.getPathLastParam(0); //type = 2 - * - * @param defvalue 默认int值 - * @return int值 - */ - public int getPathLastParam(int defvalue) { - String val = getPathLastParam(); - try { - return val.isEmpty() ? defvalue : Integer.parseInt(val); - } catch (NumberFormatException e) { - return defvalue; - } - } - - /** - * 获取请求URL最后的一个/后面的部分的int值
- * 例如请求URL /pipes/user/query/2
- * 获取type参数: int type = request.getPathLastParam(16, 0); //type = 2 - * - * @param radix 进制数 - * @param defvalue 默认int值 - * @return int值 - */ - public int getPathLastParam(int radix, int defvalue) { - String val = getPathLastParam(); - try { - return val.isEmpty() ? defvalue : Integer.parseInt(val, radix); - } catch (NumberFormatException e) { - return defvalue; - } - } - - /** - * 获取请求URL最后的一个/后面的部分的float值
- * 例如请求URL /pipes/user/query/2
- * 获取type参数: float type = request.getPathLastParam(0.0f); //type = 2.0f - * - * @param defvalue 默认float值 - * @return float值 - */ - public float getPathLastParam(float defvalue) { - String val = getPathLastParam(); - try { - return val.isEmpty() ? defvalue : Float.parseFloat(val); - } catch (NumberFormatException e) { - return defvalue; - } - } - - /** - * 获取请求URL最后的一个/后面的部分的int值
- * 例如请求URL /pipes/user/query/2
- * 获取type参数: long type = request.getPathLastParam(0L); //type = 2 - * - * @param defvalue 默认long值 - * @return long值 - */ - public long getPathLastParam(long defvalue) { - String val = getPathLastParam(); - try { - return val.isEmpty() ? defvalue : Long.parseLong(val); - } catch (NumberFormatException e) { - return defvalue; - } - } - - /** - * 获取请求URL最后的一个/后面的部分的int值
- * 例如请求URL /pipes/user/query/2
- * 获取type参数: long type = request.getPathLastParam(16, 0L); //type = 2 - * - * @param radix 进制数 - * @param defvalue 默认long值 - * @return long值 - */ - public long getPathLastParam(int radix, long defvalue) { - String val = getPathLastParam(); - try { - return val.isEmpty() ? defvalue : Long.parseLong(val, radix); - } catch (NumberFormatException e) { - return defvalue; - } - } - - /** - * 获取请求URL最后的一个/后面的部分的double值
- * 例如请求URL /pipes/user/query/2
- * 获取type参数: double type = request.getPathLastParam(0.0); //type = 2.0 - * - * @param defvalue 默认double值 - * @return double值 - */ - public double getPathLastParam(double defvalue) { - String val = getPathLastParam(); - try { - return val.isEmpty() ? defvalue : Double.parseDouble(val); - } catch (NumberFormatException e) { - return defvalue; - } - } - - /** - * 从prefix之后截取getPath再对"/"进行分隔 - * - *

- * - * @param prefix 前缀 - * @return String[] - */ - public String[] getPathParams(String prefix) { - if (requestPath == null || prefix == null) { - return new String[0]; - } - return requestPath - .substring(requestPath.indexOf(prefix) + prefix.length() + (prefix.endsWith("/") ? 0 : 1)) - .split("/"); - } - - /** - * 获取请求URL分段中含prefix段的值
- * 例如请求URL /pipes/user/query/name:hello
- * 获取name参数: String name = request.getPathParam("name:", "none"); - * - * @param prefix prefix段前缀 - * @param defvalue 默认值 - * @return prefix截断后的值 - */ - public String getPathParam(String prefix, String defvalue) { - if (requestPath == null || prefix == null || prefix.isEmpty()) { - return defvalue; - } - int pos = requestPath.indexOf(prefix); - if (pos < 0) { - return defvalue; - } - String sub = requestPath.substring(pos + prefix.length()); - pos = sub.indexOf('/'); - return pos < 0 ? sub : sub.substring(0, pos); - } - - /** - * 获取请求URL分段中含prefix段的short值
- * 例如请求URL /pipes/user/query/type:10
- * 获取type参数: short type = request.getPathParam("type:", (short)0); - * - * @param prefix prefix段前缀 - * @param defvalue 默认short值 - * @return short值 - */ - public short getPathParam(String prefix, short defvalue) { - String val = getPathParam(prefix, null); - try { - return val == null ? defvalue : Short.parseShort(val); - } catch (NumberFormatException e) { - return defvalue; - } - } - - /** - * 获取请求URL分段中含prefix段的short值
- * 例如请求URL /pipes/user/query/type:a
- * 获取type参数: short type = request.getPathParam(16, "type:", (short)0); //type = 10 - * - * @param radix 进制数 - * @param prefix prefix段前缀 - * @param defvalue 默认short值 - * @return short值 - */ - public short getPathParam(int radix, String prefix, short defvalue) { - String val = getPathParam(prefix, null); - try { - return val == null ? defvalue : Short.parseShort(val, radix); - } catch (NumberFormatException e) { - return defvalue; - } - } - - /** - * 获取请求URL分段中含prefix段的int值
- * 例如请求URL /pipes/user/query/offset:0/limit:50
- * 获取offset参数: int offset = request.getPathParam("offset:", 0);
- * 获取limit参数: int limit = request.getPathParam("limit:", 20);
- * - * @param prefix prefix段前缀 - * @param defvalue 默认int值 - * @return int值 - */ - public int getPathParam(String prefix, int defvalue) { - String val = getPathParam(prefix, null); - try { - return val == null ? defvalue : Integer.parseInt(val); - } catch (NumberFormatException e) { - return defvalue; - } - } - - /** - * 获取请求URL分段中含prefix段的int值
- * 例如请求URL /pipes/user/query/offset:0/limit:50
- * 获取offset参数: int offset = request.getPathParam("offset:", 0);
- * 获取limit参数: int limit = request.getPathParam(16, "limit:", 20); // limit = 16
- * - * @param radix 进制数 - * @param prefix prefix段前缀 - * @param defvalue 默认int值 - * @return int值 - */ - public int getPathParam(int radix, String prefix, int defvalue) { - String val = getPathParam(prefix, null); - try { - return val == null ? defvalue : Integer.parseInt(val, radix); - } catch (NumberFormatException e) { - return defvalue; - } - } - - /** - * 获取请求URL分段中含prefix段的float值
- * 例如请求URL /pipes/user/query/point:40.0
- * 获取time参数: float point = request.getPathParam("point:", 0.0f); - * - * @param prefix prefix段前缀 - * @param defvalue 默认float值 - * @return float值 - */ - public float getPathParam(String prefix, float defvalue) { - String val = getPathParam(prefix, null); - try { - return val == null ? defvalue : Float.parseFloat(val); - } catch (NumberFormatException e) { - return defvalue; - } - } - - /** - * 获取请求URL分段中含prefix段的long值
- * 例如请求URL /pipes/user/query/time:1453104341363/id:40
- * 获取time参数: long time = request.getPathParam("time:", 0L); - * - * @param prefix prefix段前缀 - * @param defvalue 默认long值 - * @return long值 - */ - public long getPathParam(String prefix, long defvalue) { - String val = getPathParam(prefix, null); - try { - return val == null ? defvalue : Long.parseLong(val); - } catch (NumberFormatException e) { - return defvalue; - } - } - - /** - * 获取请求URL分段中含prefix段的long值
- * 例如请求URL /pipes/user/query/time:1453104341363/id:40
- * 获取time参数: long time = request.getPathParam(16, "time:", 0L); - * - * @param radix 进制数 - * @param prefix prefix段前缀 - * @param defvalue 默认long值 - * @return long值 - */ - public long getPathParam(int radix, String prefix, long defvalue) { - String val = getPathParam(prefix, null); - try { - return val == null ? defvalue : Long.parseLong(val, radix); - } catch (NumberFormatException e) { - return defvalue; - } - } - - /** - * 获取请求URL分段中含prefix段的double值
- * 例如请求URL /pipes/user/query/point:40.0
- * 获取time参数: double point = request.getPathParam("point:", 0.0); - * - * @param prefix prefix段前缀 - * @param defvalue 默认double值 - * @return double值 - */ - public double getPathParam(String prefix, double defvalue) { - String val = getPathParam(prefix, null); - try { - return val == null ? defvalue : Double.parseDouble(val); - } catch (NumberFormatException e) { - return defvalue; - } - } - - // ------------------------------------------------------------------------------ - /** - * 获取请求Header总对象 - * - * @return AnyValue - */ - @ClassDepends - public HttpHeaders getHeaders() { - parseHeader(); - return headers; - } - - /** - * 获取所有的header名 - * - * @return header名数组 - */ - @ConvertDisabled - public String[] getHeaderNames() { - parseHeader(); - return headers.names(); - } - - /** - * 获取指定的header值 - * - * @param name header名 - * @return header值 - */ - public String getHeader(String name) { - return getHeader(name, null); - } - - /** - * 获取指定的header值, 没有返回默认值 - * - * @param name header名 - * @param defaultValue 默认值 - * @return header值 - */ - @ClassDepends - public String getHeader(String name, String defaultValue) { - parseHeader(); - return headers.firstValue(name, defaultValue); - } - - /** - * 获取指定的header的json值 - * - * @param 泛型 - * @param type 反序列化的类名 - * @param name header名 - * @return header值 - */ - @ClassDepends - public T getJsonHeader(java.lang.reflect.Type type, String name) { - String v = getHeader(name); - return isEmpty(v) ? null : jsonConvert.convertFrom(type, v); - } - - /** - * 获取指定的header的json值 - * - * @param 泛型 - * @param convert JsonConvert对象 - * @param type 反序列化的类名 - * @param name header名 - * @return header值 - */ - @ClassDepends - public T getJsonHeader(JsonConvert convert, java.lang.reflect.Type type, String name) { - String v = getHeader(name); - return isEmpty(v) ? null : convert.convertFrom(type, v); - } - - /** - * 获取指定的header的boolean值, 没有返回默认boolean值 - * - * @param name header名 - * @param defaultValue 默认boolean值 - * @return header值 - */ - @ClassDepends - public boolean getBooleanHeader(String name, boolean defaultValue) { - String value = getHeader(name); - return isEmpty(value) ? defaultValue : Boolean.parseBoolean(value); - } - - /** - * 获取指定的header的short值, 没有返回默认short值 - * - * @param name header名 - * @param defaultValue 默认short值 - * @return header值 - */ - @ClassDepends - public short getShortHeader(String name, short defaultValue) { - String value = getHeader(name); - if (isEmpty(value)) { - return defaultValue; - } - try { - return Short.decode(value); - } catch (NumberFormatException e) { - return defaultValue; - } - } - - /** - * 获取指定的header的short值, 没有返回默认short值 - * - * @param radix 进制数 - * @param name header名 - * @param defaultValue 默认short值 - * @return header值 - */ - @ClassDepends - public short getShortHeader(int radix, String name, short defaultValue) { - String value = getHeader(name); - if (isEmpty(value)) { - return defaultValue; - } - try { - return (radix == 10 ? Short.decode(value) : Short.parseShort(value, radix)); - } catch (NumberFormatException e) { - return defaultValue; - } - } - - /** - * 获取指定的header的short值, 没有返回默认short值 - * - * @param name header名 - * @param defaultValue 默认short值 - * @return header值 - */ - @ClassDepends - public short getShortHeader(String name, int defaultValue) { - String value = getHeader(name); - if (isEmpty(value)) { - return (short) defaultValue; - } - try { - return Short.decode(value); - } catch (NumberFormatException e) { - return (short) defaultValue; - } - } - - /** - * 获取指定的header的short值, 没有返回默认short值 - * - * @param radix 进制数 - * @param name header名 - * @param defaultValue 默认short值 - * @return header值 - */ - @ClassDepends - public short getShortHeader(int radix, String name, int defaultValue) { - String value = getHeader(name); - if (isEmpty(value)) { - return (short) defaultValue; - } - try { - return (radix == 10 ? Short.decode(value) : Short.parseShort(value, radix)); - } catch (NumberFormatException e) { - return (short) defaultValue; - } - } - - /** - * 获取指定的header的int值, 没有返回默认int值 - * - * @param name header名 - * @param defaultValue 默认int值 - * @return header值 - */ - @ClassDepends - public int getIntHeader(String name, int defaultValue) { - String value = getHeader(name); - if (isEmpty(value)) { - return defaultValue; - } - try { - return Integer.parseInt(value); - } catch (NumberFormatException e) { - return defaultValue; - } - } - - /** - * 获取指定的header的int值, 没有返回默认int值 - * - * @param radix 进制数 - * @param name header名 - * @param defaultValue 默认int值 - * @return header值 - */ - @ClassDepends - public int getIntHeader(int radix, String name, int defaultValue) { - String value = getHeader(name); - if (isEmpty(value)) { - return defaultValue; - } - try { - return (radix == 10 ? Integer.decode(value) : Integer.parseInt(value, radix)); - } catch (NumberFormatException e) { - return defaultValue; - } - } - - /** - * 获取指定的header的long值, 没有返回默认long值 - * - * @param name header名 - * @param defaultValue 默认long值 - * @return header值 - */ - @ClassDepends - public long getLongHeader(String name, long defaultValue) { - String value = getHeader(name); - if (isEmpty(value)) { - return defaultValue; - } - try { - return Long.decode(value); - } catch (NumberFormatException e) { - return defaultValue; - } - } - - /** - * 获取指定的header的long值, 没有返回默认long值 - * - * @param radix 进制数 - * @param name header名 - * @param defaultValue 默认long值 - * @return header值 - */ - @ClassDepends - public long getLongHeader(int radix, String name, long defaultValue) { - String value = getHeader(name); - if (isEmpty(value)) { - return defaultValue; - } - try { - return (radix == 10 ? Long.decode(value) : Long.parseLong(value, radix)); - } catch (NumberFormatException e) { - return defaultValue; - } - } - - /** - * 获取指定的header的float值, 没有返回默认float值 - * - * @param name header名 - * @param defaultValue 默认float值 - * @return header值 - */ - @ClassDepends - public float getFloatHeader(String name, float defaultValue) { - String value = getHeader(name); - if (isEmpty(value)) { - return defaultValue; - } - try { - return Float.parseFloat(value); - } catch (NumberFormatException e) { - return defaultValue; - } - } - - /** - * 获取指定的header的double值, 没有返回默认double值 - * - * @param name header名 - * @param defaultValue 默认double值 - * @return header值 - */ - @ClassDepends - public double getDoubleHeader(String name, double defaultValue) { - String value = getHeader(name); - if (isEmpty(value)) { - return defaultValue; - } - try { - return Double.parseDouble(value); - } catch (NumberFormatException e) { - return defaultValue; - } - } - - // ------------------------------------------------------------------------------ - /** - * 获取请求参数总对象 - * - * @return AnyValue - */ - @ClassDepends - public HttpParameters getParameters() { - parseBody(); - return params; - } - - /** - * 将请求参数转换成String, 字符串格式为: bean1={}&id=13&name=xxx
- * 不会返回null,没有参数返回空字符串 - * - * @return String - */ - @ConvertDisabled - public String getParametersToString() { - return getParametersToString(null); - } - - /** - * 将请求参数转换成String, 字符串格式为: bean1={}&id=13&name=xxx
- * 不会返回null,没有参数返回空字符串 - * - * @param prefix 拼接前缀, 如果无参数,返回的字符串不会含有拼接前缀 - * @return String - */ - public String getParametersToString(String prefix) { - byte[] rbs = queryBytes; - if (rbs == null || rbs.length < 1) { - return ""; - } - Charset charset = this.context.getCharset(); - String str = charset == null ? new String(rbs, StandardCharsets.UTF_8) : new String(rbs, charset); - return (prefix == null) ? str : (prefix + str); - } - - /** - * 获取所有参数名 - * - * @return 参数名数组 - */ - @ConvertDisabled - public String[] getParameterNames() { - parseBody(); - return params.names(); - } - - /** - * 获取指定的参数值 - * - * @param name 参数名 - * @return 参数值 - */ - public String getParameter(String name) { - parseBody(); - return params.get(name); - } - - /** - * 获取指定的参数值, 没有返回默认值 - * - * @param name 参数名 - * @param defaultValue 默认值 - * @return 参数值 - */ - public String getParameter(String name, String defaultValue) { - parseBody(); - return params.get(name, defaultValue); - } - - /** - * 获取指定的参数json值 - * - * @param 泛型 - * @param type 反序列化的类名 - * @param name 参数名 - * @return 参数值 - */ - public T getJsonParameter(java.lang.reflect.Type type, String name) { - String v = getParameter(name); - return v == null || v.isEmpty() ? null : jsonConvert.convertFrom(type, v); - } - - /** - * 获取指定的参数json值 - * - * @param 泛型 - * @param convert JsonConvert对象 - * @param type 反序列化的类名 - * @param name 参数名 - * @return 参数值 - */ - public T getJsonParameter(JsonConvert convert, java.lang.reflect.Type type, String name) { - String v = getParameter(name); - return v == null || v.isEmpty() ? null : convert.convertFrom(type, v); - } - - /** - * 获取指定的参数boolean值, 没有返回默认boolean值 - * - * @param name 参数名 - * @param defaultValue 默认boolean值 - * @return 参数值 - */ - public boolean getBooleanParameter(String name, boolean defaultValue) { - parseBody(); - String value = params.get(name); - return value == null || value.length() == 0 ? defaultValue : Boolean.parseBoolean(value); - } - - /** - * 获取指定的参数short值, 没有返回默认short值 - * - * @param name 参数名 - * @param defaultValue 默认short值 - * @return 参数值 - */ - public short getShortParameter(String name, short defaultValue) { - parseBody(); - String value = params.get(name); - if (value == null || value.length() == 0) { - return defaultValue; - } - try { - return Short.decode(value); - } catch (NumberFormatException e) { - return defaultValue; - } - } - - /** - * 获取指定的参数short值, 没有返回默认short值 - * - * @param radix 进制数 - * @param name 参数名 - * @param defaultValue 默认short值 - * @return 参数值 - */ - public short getShortParameter(int radix, String name, short defaultValue) { - parseBody(); - String value = params.get(name); - if (value == null || value.length() == 0) { - return defaultValue; - } - try { - return (radix == 10 ? Short.decode(value) : Short.parseShort(value, radix)); - } catch (NumberFormatException e) { - return defaultValue; - } - } - - /** - * 获取指定的参数short值, 没有返回默认short值 - * - * @param name 参数名 - * @param defaultValue 默认short值 - * @return 参数值 - */ - public short getShortParameter(String name, int defaultValue) { - parseBody(); - String value = params.get(name); - if (value == null || value.length() == 0) { - return (short) defaultValue; - } - try { - return Short.decode(value); - } catch (NumberFormatException e) { - return (short) defaultValue; - } - } - - /** - * 获取指定的参数int值, 没有返回默认int值 - * - * @param name 参数名 - * @param defaultValue 默认int值 - * @return 参数值 - */ - public int getIntParameter(String name, int defaultValue) { - parseBody(); - String value = params.get(name); - if (value == null || value.length() == 0) { - return defaultValue; - } - try { - return Integer.decode(value); - } catch (NumberFormatException e) { - return defaultValue; - } - } - - /** - * 获取指定的参数int值, 没有返回默认int值 - * - * @param radix 进制数 - * @param name 参数名 - * @param defaultValue 默认int值 - * @return 参数值 - */ - public int getIntParameter(int radix, String name, int defaultValue) { - parseBody(); - String value = params.get(name); - if (value == null || value.length() == 0) { - return defaultValue; - } - try { - return (radix == 10 ? Integer.decode(value) : Integer.parseInt(value, radix)); - } catch (NumberFormatException e) { - return defaultValue; - } - } - - /** - * 获取指定的参数long值, 没有返回默认long值 - * - * @param name 参数名 - * @param defaultValue 默认long值 - * @return 参数值 - */ - public long getLongParameter(String name, long defaultValue) { - parseBody(); - String value = params.get(name); - if (value == null || value.length() == 0) { - return defaultValue; - } - try { - return Long.decode(value); - } catch (NumberFormatException e) { - return defaultValue; - } - } - - /** - * 获取指定的参数long值, 没有返回默认long值 - * - * @param radix 进制数 - * @param name 参数名 - * @param defaultValue 默认long值 - * @return 参数值 - */ - public long getLongParameter(int radix, String name, long defaultValue) { - parseBody(); - String value = params.get(name); - if (value == null || value.length() == 0) { - return defaultValue; - } - try { - return (radix == 10 ? Long.decode(value) : Long.parseLong(value, radix)); - } catch (NumberFormatException e) { - return defaultValue; - } - } - - /** - * 获取指定的参数float值, 没有返回默认float值 - * - * @param name 参数名 - * @param defaultValue 默认float值 - * @return 参数值 - */ - public float getFloatParameter(String name, float defaultValue) { - parseBody(); - String value = params.get(name); - if (value == null || value.length() == 0) { - return defaultValue; - } - try { - return Float.parseFloat(value); - } catch (NumberFormatException e) { - return defaultValue; - } - } - - /** - * 获取指定的参数double值, 没有返回默认double值 - * - * @param name 参数名 - * @param defaultValue 默认double值 - * @return 参数值 - */ - public double getDoubleParameter(String name, double defaultValue) { - parseBody(); - String value = params.get(name); - if (value == null || value.length() == 0) { - return defaultValue; - } - try { - return Double.parseDouble(value); - } catch (NumberFormatException e) { - return defaultValue; - } - } - - /** - * 获取翻页对象 同 getFlipper("flipper", false, 0); - * - * @return Flipper翻页对象 - */ - public org.redkale.source.Flipper getFlipper() { - return getFlipper(false, 0); - } - - /** - * 获取翻页对象 同 getFlipper("flipper", autoCreate, 0); - * - * @param autoCreate 无参数时是否创建新Flipper对象 - * @return Flipper翻页对象 - */ - public org.redkale.source.Flipper getFlipper(boolean autoCreate) { - return getFlipper(autoCreate, 0); - } - - /** - * 获取翻页对象 同 getFlipper("flipper", false, maxLimit); - * - * @param maxLimit 最大行数, 小于1则值为Flipper.DEFAULT_LIMIT - * @return Flipper翻页对象 - */ - public org.redkale.source.Flipper getFlipper(int maxLimit) { - return getFlipper(false, maxLimit); - } - - /** - * 获取翻页对象 同 getFlipper("flipper", autoCreate, maxLimit) - * - * @param autoCreate 无参数时是否创建新Flipper对象 - * @param maxLimit 最大行数, 小于1则值为Flipper.DEFAULT_LIMIT - * @return Flipper翻页对象 - */ - public org.redkale.source.Flipper getFlipper(boolean autoCreate, int maxLimit) { - return getFlipper("flipper", autoCreate, maxLimit); - } - - /** - * 获取翻页对象 https://redkale.org/pipes/users/list?flipper={'offset':0,'limit':20, 'sort':'createtime ASC'}
- * - * @param name Flipper对象的参数名,默认为 "flipper" - * @param autoCreate 无参数时是否创建新Flipper对象 - * @param maxLimit 最大行数, 小于1则值为Flipper.DEFAULT_LIMIT - * @return Flipper翻页对象 - */ - public org.redkale.source.Flipper getFlipper(String name, boolean autoCreate, int maxLimit) { - org.redkale.source.Flipper flipper = getJsonParameter(org.redkale.source.Flipper.class, name); - if (flipper == null) { - // if (maxLimit < 1) maxLimit = org.redkale.source.Flipper.DEFAULT_LIMIT; - // String limitstr = getParameter("limit"); - // if (limitstr != null && !limitstr.isEmpty()) { - // String offsetstr = getParameter("offset"); - // if (offsetstr != null && !offsetstr.isEmpty()) { - // int limit = Integer.parseInt(limitstr); - // int offset = Integer.parseInt(offsetstr); - // String sort = getParameter("sort"); - // if (limit > maxLimit) limit = maxLimit; - // flipper = new org.redkale.source.Flipper(limit, offset, sort); - // } - // } - } else if (flipper.getLimit() < 1 || (maxLimit > 0 && flipper.getLimit() > maxLimit)) { - flipper.setLimit(maxLimit); - } - if (flipper != null || !autoCreate) { - return flipper; - } - if (maxLimit < 1) { - maxLimit = org.redkale.source.Flipper.DEFAULT_LIMIT; - } - return new org.redkale.source.Flipper(maxLimit); - } -} +/* + * To change this license headers, 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.http; + +import static org.redkale.util.Utility.isEmpty; +import static org.redkale.util.Utility.isNotEmpty; + +import java.io.*; +import java.lang.annotation.Annotation; +import java.net.*; +import java.nio.ByteBuffer; +import java.nio.charset.*; +import java.util.*; +import java.util.function.Supplier; +import java.util.logging.Level; +import org.redkale.annotation.ClassDepends; +import org.redkale.annotation.Comment; +import org.redkale.convert.*; +import org.redkale.convert.json.JsonConvert; +import org.redkale.net.Request; +import org.redkale.util.*; + +/** + * Http请求包 与javax.servlet.http.HttpServletRequest 基本类似。
+ * 同时提供json的解析接口: public Object getJsonParameter(Type type, String name)
+ * Redkale提倡带简单的参数的GET请求采用类似REST风格, 因此提供了 getPathParam 系列接口。
+ * 例如简单的翻页查询
+ * /pipes/user/query/offset:0/limit:20
+ * 获取页号: int offset = request.getPathParam("offset:", 0);
+ * 获取行数: int limit = request.getPathParam("limit:", 10);
+ * + *

详情见: https://redkale.org + * + * @author zhangjx + */ +public class HttpRequest extends Request { + + private static final boolean PIPELINE_SAME_HEADERS = + Boolean.getBoolean("redkale.http.request.pipeline.sameheaders"); + + protected static final Serializable CURRUSERID_NIL = new Serializable() {}; + + protected static final int READ_STATE_ROUTE = 1; + + protected static final int READ_STATE_HEADER = 2; + + protected static final int READ_STATE_BODY = 3; + + protected static final int READ_STATE_END = 4; + + protected static final byte[] EMPTY_BYTES = new byte[0]; + + protected static final String METHOD_GET = "GET"; + + protected static final String METHOD_PUT = "PUT"; + + protected static final String METHOD_POST = "POST"; + + protected static final String METHOD_HEAD = "HEAD"; + + protected static final String METHOD_OPTIONS = "OPTIONS"; + + protected static final String HTTP_1_1 = "HTTP/1.1"; + + protected static final String HTTP_2_0 = "HTTP/2.0"; + + protected static final String HEAD_COOKIE = "Cookie"; + + protected static final String HEAD_CONNECTION = "Connection"; + + protected static final String HEAD_CONTENT_TYPE = "Content-Type"; + + protected static final String HEAD_CONTENT_LENGTH = "Content-Length"; + + protected static final String HEAD_ACCEPT = "Accept"; + + protected static final String HEAD_HOST = "Host"; + + protected static final String HEAD_UPGRADE = "Upgrade"; + + protected static final String HEAD_USER_AGENT = "User-Agent"; + + protected static final String HEAD_EXPECT = "Expect"; + + public static final String SESSIONID_NAME = "JSESSIONID"; + + // ---------- header 相关参数 开始 ---------- + protected int headerLength; + + protected int headerHalfLen; + + protected String contentType; + + protected long contentLength = -1; + + protected String host; + + @Comment("原始的cookie字符串,解析后值赋给HttpCookie[] cookies") + protected String cookie; + + protected HttpCookie[] cookies; + + private boolean maybews = false; // 是否可能是WebSocket + + private boolean expect = false; // 是否Expect:100-continue + + protected boolean rpc; + + protected int readState = READ_STATE_ROUTE; + + // @since 2.1.0 + protected Serializable currentUserid = CURRUSERID_NIL; + + protected Supplier currentUserSupplier; + + protected ConvertType reqConvertType; + + protected Convert reqConvert; + + protected ConvertType respConvertType; + + protected Convert respConvert; + + protected final HttpHeaders headers = HttpHeaders.create(); + + // ---------- header 相关参数 结束 ---------- + @Comment("Method GET/POST/...") + protected String method; + + protected boolean getmethod; + + protected String protocol; + + protected String requestPath; + + protected byte[] queryBytes; + + protected String newSessionid; + + protected final HttpParameters params = HttpParameters.create(); + + protected boolean boundary = false; + + protected int moduleid; + + protected int actionid; + + protected Annotation[] annotations; + + protected String remoteAddr; + + protected String locale; + + private String lastPathString; + + private byte[] lastPathBytes; + + private final ByteArray array; + + private byte[] headerBytes; + + private boolean headerParsed = false; + + private boolean bodyParsed = false; + + private final String remoteAddrHeader; + + private final String localHeader; + + private final String localParameter; + + final HttpRpcAuthenticator rpcAuthenticator; + + HttpServlet.ActionEntry actionEntry; // 仅供HttpServlet传递Entry使用 + + public HttpRequest(HttpContext context) { + this(context, new ByteArray()); + } + + protected HttpRequest(HttpContext context, ByteArray array) { + super(context); + this.array = array; + this.remoteAddrHeader = context.remoteAddrHeader; + this.localHeader = context.localHeader; + this.localParameter = context.localParameter; + this.rpcAuthenticator = context.rpcAuthenticator; + } + + @SuppressWarnings("OverridableMethodCallInConstructor") + protected HttpRequest(HttpContext context, WebRequest req) { + super(context); + this.array = new ByteArray(); + this.remoteAddrHeader = null; + this.localHeader = null; + this.localParameter = null; + this.rpcAuthenticator = null; + if (req != null) { + initWebRequest(req, true); + } + } + + protected HttpRequest initWebRequest(WebRequest req, boolean needPath) { + if (req != null) { + this.rpc = req.rpc; + this.traceid = req.getTraceid(); + if (req.getBody() != null) { + this.array.put(req.getBody()); + } + if (req.getHeaders() != null) { + this.headers.setAll(req.getHeaders()); + } + this.reqConvertType = req.getReqConvertType(); + this.reqConvert = + req.getReqConvertType() == null ? null : ConvertFactory.findConvert(req.getReqConvertType()); + this.respConvertType = req.getRespConvertType(); + this.respConvert = + req.getRespConvertType() == null ? null : ConvertFactory.findConvert(req.getRespConvertType()); + if (req.getParams() != null) { + this.params.putAll(req.getParams()); + } + if (req.getCurrentUserid() != null) { + this.currentUserid = req.getCurrentUserid(); + } + this.contentType = req.getContentType(); + this.remoteAddr = req.getRemoteAddr(); + this.locale = req.getLocale(); + this.requestPath = needPath ? req.requestPath() : req.getPath(); + this.method = req.getMethod(); + if (isNotEmpty(req.getSessionid())) { + this.cookies = new HttpCookie[] {new HttpCookie(SESSIONID_NAME, req.getSessionid())}; + } + } + return this; + } + + public WebRequest createSimpleRequest(String contextPath) { + WebRequest req = new WebRequest(); + req.setBody(array.length() == 0 ? null : array.getBytes()); + if (!getHeaders().isEmpty()) { + req.setHeaders(headers); + if (headers.contains(Rest.REST_HEADER_RPC)) { // 外部request不能包含RPC的header信息 + req.removeHeader(Rest.REST_HEADER_RPC); + } + if (headers.contains(Rest.REST_HEADER_RESNAME)) { // 外部request不能包含RPC的header信息 + req.removeHeader(Rest.REST_HEADER_RESNAME); + } + if (headers.contains(Rest.REST_HEADER_CURRUSERID)) { // 外部request不能包含RPC的header信息 + req.removeHeader(Rest.REST_HEADER_CURRUSERID); + } + } + parseBody(); + req.setParams(params.isEmpty() ? null : params); + req.setRemoteAddr(getRemoteAddr()); + req.setLocale(getLocale()); + req.setContentType(getContentType()); + req.setContextPath(contextPath); + req.setMethod(this.method); + String path0 = this.requestPath; + if (isNotEmpty(contextPath) && path0.startsWith(contextPath)) { + path0 = path0.substring(contextPath.length()); + } + req.setPath(path0); + req.setSessionid(getSessionid(false)); + req.setRpc(this.rpc); + req.setTraceid(this.traceid); + return req; + } + + protected boolean isWebSocket() { + return maybews && getmethod && "Upgrade".equalsIgnoreCase(getHeader("Connection")); + } + + protected boolean isExpect() { + return expect; + } + + protected void setKeepAlive(boolean keepAlive) { + this.keepAlive = keepAlive; + } + + protected ConvertType getRespConvertType() { + return this.respConvertType; + } + + protected Convert getRespConvert() { + return this.respConvert == null ? this.jsonConvert : this.respConvert; + } + + @Override + protected int readHeader(final ByteBuffer buf, final Request last) { + final ByteBuffer buffer = buf; + ByteArray bytes = array; + if (this.readState == READ_STATE_ROUTE) { + int rs = readMethodUriLine(buffer); + if (rs != 0) { + return rs; + } + this.readState = READ_STATE_HEADER; + } + if (this.readState == READ_STATE_HEADER) { + if (last != null && ((HttpRequest) last).headerLength > 0) { + final HttpRequest httplast = (HttpRequest) last; + int bufremain = buffer.remaining(); + int remainHalf = httplast.headerLength - this.headerHalfLen; + if (remainHalf > bufremain) { + bytes.put(buffer); + this.headerHalfLen += bufremain; + buffer.clear(); + return 1; + } + buffer.position(buffer.position() + remainHalf); + this.contentType = httplast.contentType; + this.contentLength = httplast.contentLength; + this.host = httplast.host; + this.cookie = httplast.cookie; + this.cookies = httplast.cookies; + this.keepAlive = httplast.keepAlive; + this.maybews = httplast.maybews; + this.expect = httplast.expect; + this.rpc = httplast.rpc; + this.traceid = httplast.traceid; + this.currentUserid = httplast.currentUserid; + this.reqConvertType = httplast.reqConvertType; + this.reqConvert = httplast.reqConvert; + this.respConvertType = httplast.respConvertType; + this.respConvert = httplast.respConvert; + this.headerLength = httplast.headerLength; + this.headerHalfLen = httplast.headerHalfLen; + this.headerBytes = httplast.headerBytes; + this.headerParsed = httplast.headerParsed; + this.headers.setAll(httplast.headers); + } else if (context.lazyHeaders && getmethod) { // 非GET必须要读header,会有Content-Length + int rs = loadHeaderBytes(buffer); + if (rs != 0) { + buffer.clear(); + return rs; + } + this.headerParsed = false; + } else { + int startpos = buffer.position(); + int rs = readHeaderLines(buffer, bytes); + if (rs != 0) { + this.headerHalfLen = bytes.length(); + buffer.clear(); + return rs; + } + this.headerParsed = true; + this.headerLength = buffer.position() - startpos + this.headerHalfLen; + this.headerHalfLen = this.headerLength; + } + bytes.clear(); + if (this.contentType != null && this.contentType.contains("boundary=")) { + this.boundary = true; + } + if (this.boundary) { + this.keepAlive = false; // 文件上传必须设置keepAlive为false,因为文件过大时用户不一定会skip掉多余的数据 + } + // completed=true时ProtocolCodec会继续读下一个request + this.completed = !this.boundary && !maybews && this.headerParsed; + this.readState = READ_STATE_BODY; + } + if (this.readState == READ_STATE_BODY) { + if (this.contentLength > 0 && (this.contentType == null || !this.boundary)) { + if (this.contentLength > context.getMaxBody()) { + return -1; + } + bytes.put(buffer, Math.min((int) this.contentLength, buffer.remaining())); + int lr = (int) this.contentLength - bytes.length(); + if (lr == 0) { + this.readState = READ_STATE_END; + if (bytes.isEmpty()) { + this.bodyParsed = true; // no body data + } + } else { + buffer.clear(); + } + return lr > 0 ? lr : 0; + } + if (buffer.hasRemaining() && (this.boundary || !this.keepAlive)) { + bytes.put(buffer, buffer.remaining()); // 文件上传、HTTP1.0或Connection:close + } + this.readState = READ_STATE_END; + if (bytes.isEmpty()) { + this.bodyParsed = true; // no body data + } + } + // 暂不考虑是keep-alive且存在body却没有指定Content-Length的情况 + return 0; + } + + private int loadHeaderBytes(final ByteBuffer buf) { + final ByteBuffer buffer = buf; + ByteArray bytes = array; + int remain = buffer.remaining(); + byte b1, b2, b3, b4; + for (; ; ) { + if (remain-- < 4) { // bytes不存放\r\n\r\n这4个字节 + bytes.put(buffer); + buffer.clear(); + if (bytes.length() > 0) { + byte rn1 = 0, rn2 = 0, rn3 = 0; + byte b = bytes.getLastByte(); + if (b == '\r' || b == '\n') { + rn3 = b; + bytes.backCount(); + if (bytes.length() > 0) { + b = bytes.getLastByte(); + if (b == '\r' || b == '\n') { + rn2 = b; + bytes.backCount(); + if (bytes.length() > 0) { + b = bytes.getLastByte(); + if (b == '\r' || b == '\n') { + rn1 = b; + bytes.backCount(); + } + } + } + } + } + if (rn1 != 0) { + buffer.put(rn1); + } + if (rn2 != 0) { + buffer.put(rn2); + } + if (rn3 != 0) { + buffer.put(rn3); + } + } + return 1; + } + b1 = buffer.get(); + bytes.put(b1); + if (b1 == '\r') { + remain--; + b2 = buffer.get(); + bytes.put(b2); + if (b2 == '\n') { + remain--; + b3 = buffer.get(); + bytes.put(b3); + if (b3 == '\r') { + remain--; + b4 = buffer.get(); + bytes.put(b4); + if (b4 == '\n') { + this.headerBytes = Utility.append(this.headerBytes, bytes.content(), 0, bytes.length()); + this.headerLength = this.headerBytes.length; + this.headerHalfLen = this.headerLength; + bytes.clear(); + return 0; + } + } + } + } + } + } + + // 解析 GET /xxx HTTP/1.1 + private int readMethodUriLine(final ByteBuffer buf) { + final ByteBuffer buffer = buf; + Charset charset = this.context.getCharset(); + int remain = buffer.remaining(); + int size; + ByteArray bytes = array; + // 读method + if (this.method == null) { + boolean flag = false; + if (remain >= 5) { + byte b1 = buffer.get(); + byte b2 = buffer.get(); + if (b2 == ' ') { + remain -= 2; + this.method = Character.toString(b1); + this.getmethod = false; + } else { + byte b3 = buffer.get(); + if (b3 == ' ') { + remain -= 3; + this.method = new String(new byte[] {b1, b2}); + this.getmethod = false; + } else { + byte b4 = buffer.get(); + if (b4 == ' ') { + remain -= 4; + if (b1 == 'G' && b2 == 'E' && b3 == 'T') { + this.method = METHOD_GET; + this.getmethod = true; + } else if (b1 == 'P' && b2 == 'U' && b3 == 'T') { + this.method = METHOD_PUT; + this.getmethod = false; + } else { + this.method = new String(new byte[] {b1, b2, b3}); + this.getmethod = false; + } + } else { + byte b5 = buffer.get(); + remain -= 5; + if (b5 == ' ') { + if (b1 == 'P' && b2 == 'O' && b3 == 'S' && b3 == 'T') { + this.method = METHOD_POST; + this.getmethod = false; + } else if (b1 == 'H' && b2 == 'E' && b3 == 'A' && b3 == 'D') { + this.method = METHOD_HEAD; + this.getmethod = false; + } else { + this.method = new String(new byte[] {b1, b2, b3, b4}); + this.getmethod = false; + } + } else { + flag = true; + bytes.put(b1, b2, b3, b4, b5); + } + } + } + } + } + if (flag) { + for (; ; ) { + if (remain-- < 1) { + buffer.clear(); + return 1; + } + byte b = buffer.get(); + if (b == ' ') { + break; + } + bytes.put(b); + } + size = bytes.length(); + byte[] content = bytes.content(); + if (size == 3) { + if (content[0] == 'G' && content[1] == 'E' && content[2] == 'T') { + this.method = METHOD_GET; + this.getmethod = true; + } else if (content[0] == 'P' && content[1] == 'U' && content[2] == 'T') { + this.method = METHOD_PUT; + this.getmethod = false; + } else { + this.method = bytes.toString(true, charset); + this.getmethod = false; + } + } else if (size == 4) { + this.getmethod = false; + if (content[0] == 'P' && content[1] == 'O' && content[2] == 'S' && content[3] == 'T') { + this.method = METHOD_POST; + } else if (content[0] == 'H' && content[1] == 'E' && content[2] == 'A' && content[3] == 'D') { + this.method = METHOD_HEAD; + } else { + this.method = bytes.toString(true, charset); + } + } else if (size == 7) { + this.getmethod = false; + if (content[0] == 'O' + && content[1] == 'P' + && content[2] == 'T' + && content[3] == 'I' + && content[4] == 'O' + && content[5] == 'N' + && content[6] == 'S') { + this.method = METHOD_OPTIONS; + } else { + this.method = bytes.toString(true, charset); + } + } else { + this.method = bytes.toString(true, charset); + this.getmethod = false; + } + bytes.clear(); + } + } + + // 读uri + if (this.requestPath == null) { + int qst = -1; // ?的位置 + boolean decodeable = false; + boolean latin1 = true; + for (; ; ) { + if (remain-- < 1) { + buffer.clear(); + return 1; + } + byte b = buffer.get(); + if (b == ' ') { + break; + } + if (b == '?' && qst < 0) { + qst = bytes.length(); + } else if (!decodeable && (b == '+' || b == '%')) { + decodeable = true; + } else if (latin1 && (b < 0x20 || b >= 0x80)) { + latin1 = false; + } + bytes.put(b); + } + size = bytes.length(); + if (qst > 0) { // 带?参数 + this.requestPath = decodeable + ? toDecodeString(bytes, 0, qst, charset) + : context.loadUriPath(bytes, qst, latin1, charset); // bytes.toString(latin1, 0, qst, charset); + int qlen = size - qst - 1; + this.queryBytes = bytes.getBytes(qst + 1, qlen); + this.lastPathString = null; + this.lastPathBytes = null; + try { + addParameter(bytes, false, qst + 1, qlen); + } catch (Exception e) { + this.context + .getLogger() + .log(Level.WARNING, "HttpRequest.addParameter error: " + bytes.toString(), e); + } + } else { + if (decodeable) { // 需要转义 + this.requestPath = toDecodeString(bytes, 0, bytes.length(), charset); + this.lastPathString = null; + this.lastPathBytes = null; + } else if (context.lazyHeaders) { + byte[] lastURIBytes = lastPathBytes; + if (lastURIBytes != null && lastURIBytes.length == size && bytes.deepEquals(lastURIBytes)) { + this.requestPath = this.lastPathString; + } else { + this.requestPath = + context.loadUriPath(bytes, latin1, charset); // bytes.toString(latin1, charset); + this.lastPathString = this.requestPath; + this.lastPathBytes = bytes.getBytes(); + } + } else { + this.requestPath = context.loadUriPath(bytes, latin1, charset); // bytes.toString(latin1, charset); + this.lastPathString = null; + this.lastPathBytes = null; + } + this.queryBytes = EMPTY_BYTES; + } + bytes.clear(); + } + // 读protocol + for (; ; ) { + if (remain-- < 1) { + this.params.clear(); + buffer.clear(); + return 1; + } + byte b = buffer.get(); + if (b == '\r') { + if (remain-- < 1) { + this.params.clear(); + buffer.clear(); + buffer.put(b); + return 1; + } + if (buffer.get() != '\n') { + return -1; + } + break; + } + bytes.put(b); + } + size = bytes.length(); + byte[] content = bytes.content(); + if (size == 8 && content[0] == 'H' && content[5] == '1' && content[7] == '1') { + this.protocol = HTTP_1_1; + } else if (size == 8 && content[0] == 'H' && content[5] == '2' && content[7] == '0') { + this.protocol = HTTP_2_0; + } else { + this.protocol = bytes.toString(true, charset); + } + bytes.clear(); + return 0; + } + + // 解析Header Connection: keep-alive + private int readHeaderLines(final ByteBuffer buf, ByteArray bytes) { + final ByteBuffer buffer = buf; + Charset charset = this.context.getCharset(); + int remain = buffer.remaining(); + for (; ; ) { + bytes.clear(); + if (remain-- < 2) { + if (remain == 1) { + byte one = buffer.get(); + buffer.clear(); + buffer.put(one); + return 1; + } + buffer.clear(); + return 1; + } + remain--; + byte b1 = buffer.get(); + byte b2 = buffer.get(); + if (b1 == '\r' && b2 == '\n') { + return 0; + } + boolean latin1 = true; + if (latin1 && (b1 < 0x20 || b1 >= 0x80)) { + latin1 = false; + } + if (latin1 && (b2 < 0x20 || b2 >= 0x80)) { + latin1 = false; + } + bytes.put(b1, b2); + for (; ; ) { // name + if (remain-- < 1) { + buffer.clear(); + buffer.put(bytes.content(), 0, bytes.length()); + return 1; + } + byte b = buffer.get(); + if (b == ':') { + break; + } else if (latin1 && (b < 0x20 || b >= 0x80)) { + latin1 = false; + } + bytes.put(b); + } + String name = parseHeaderName(latin1, bytes, charset); + bytes.clear(); + boolean first = true; + int space = 0; + for (; ; ) { // value + if (remain-- < 1) { + buffer.clear(); + buffer.put(name.getBytes()); + buffer.put((byte) ':'); + if (space == 1) { + buffer.put((byte) ' '); + } else if (space > 0) { + for (int i = 0; i < space; i++) buffer.put((byte) ' '); + } + buffer.put(bytes.content(), 0, bytes.length()); + return 1; + } + byte b = buffer.get(); + if (b == '\r') { + if (remain-- < 1) { + buffer.clear(); + buffer.put(name.getBytes()); + buffer.put((byte) ':'); + if (space == 1) { + buffer.put((byte) ' '); + } else if (space > 0) { + for (int i = 0; i < space; i++) buffer.put((byte) ' '); + } + buffer.put(bytes.content(), 0, bytes.length()); + buffer.put((byte) '\r'); + return 1; + } + if (buffer.get() != '\n') { + return -1; + } + break; + } + if (first) { + if (b <= ' ') { + space++; + continue; + } + first = false; + } + bytes.put(b); + } + String value; + int vlen = bytes.length(); + byte[] content = bytes.content(); + switch (name) { + case HEAD_CONTENT_TYPE: // Content-Type + this.contentType = bytes.toString(true, charset); + break; + case HEAD_CONTENT_LENGTH: // Content-Length + this.contentLength = Long.decode(bytes.toString(true, charset)); + break; + case HEAD_HOST: // Host + this.host = bytes.toString(charset); + break; + case HEAD_COOKIE: // Cookie + if (this.cookie == null || this.cookie.isEmpty()) { + this.cookie = bytes.toString(charset); + } else { + this.cookie += ";" + bytes.toString(charset); + } + break; + case HEAD_CONNECTION: // Connection + if (vlen > 0) { + if (vlen == 5 + && content[0] == 'c' + && content[1] == 'l' + && content[2] == 'o' + && content[3] == 's' + && content[4] == 'e') { + value = "close"; + this.setKeepAlive(false); + } else if (vlen == 10 + && content[0] == 'k' + && content[1] == 'e' + && content[2] == 'e' + && content[3] == 'p' + && content[4] == '-' + && content[5] == 'a' + && content[6] == 'l' + && content[7] == 'i' + && content[8] == 'v' + && content[9] == 'e') { + value = "keep-alive"; + this.setKeepAlive(true); + } else { + value = bytes.toString(charset); + this.setKeepAlive(true); + } + } else { + value = ""; + } + headers.setValid(HEAD_CONNECTION, value); + break; + case HEAD_UPGRADE: // Upgrade + this.maybews = vlen == 9 + && content[0] == 'w' + && content[1] == 'e' + && content[2] == 'b' + && content[3] == 's' + && content[4] == 'o' + && content[5] == 'c' + && content[6] == 'k' + && content[7] == 'e' + && content[8] == 't'; + headers.setValid(HEAD_UPGRADE, this.maybews ? "websocket" : bytes.toString(true, charset)); + break; + case HEAD_EXPECT: // Expect + this.expect = vlen == 12 + && content[0] == '1' + && content[1] == '0' + && content[2] == '0' + && content[3] == '-' + && content[4] == 'c' + && content[5] == 'o' + && content[6] == 'n' + && content[7] == 't' + && content[8] == 'i' + && content[9] == 'n' + && content[10] == 'u' + && content[11] == 'e'; + headers.setValid(HEAD_EXPECT, this.expect ? "100-continue" : bytes.toString(true, charset)); + break; + case Rest.REST_HEADER_RPC: // rest-rpc + this.rpc = vlen == 4 + && content[0] == 't' + && content[1] == 'r' + && content[2] == 'u' + && content[3] == 'e'; + headers.setValid( + name, + this.rpc + ? "true" + : (vlen == 5 + && content[0] == 'f' + && content[1] == 'a' + && content[2] == 'l' + && content[3] == 's' + && content[4] == 'e' + ? "false" + : bytes.toString(true, charset))); + break; + case Rest.REST_HEADER_TRACEID: // rest-traceid + value = bytes.toString(true, charset); + this.traceid = value; + headers.setValid(name, value); + break; + case Rest.REST_HEADER_CURRUSERID: // rest-curruserid + value = bytes.toString(true, charset); + this.currentUserid = value; + headers.setValid(name, value); + break; + case Rest.REST_HEADER_REQ_CONVERT: // rest-req-convert-type + value = bytes.toString(true, charset); + reqConvertType = ConvertType.valueOf(value); + reqConvert = ConvertFactory.findConvert(reqConvertType); + headers.setValid(name, value); + break; + case Rest.REST_HEADER_RESP_CONVERT: // rest-resp-convert-type + value = bytes.toString(true, charset); + respConvertType = ConvertType.valueOf(value); + respConvert = ConvertFactory.findConvert(respConvertType); + headers.setValid(name, value); + break; + default: + headers.addValid(name, bytes.toString(charset)); + } + } + } + + private void parseHeader() { + if (headerParsed) { + return; + } + headerParsed = true; + if (headerBytes == null) { + return; + } + if (array.isEmpty()) { + readHeaderLines(ByteBuffer.wrap(headerBytes), array); + array.clear(); + } else { // array存有body数据 + readHeaderLines(ByteBuffer.wrap(headerBytes), new ByteArray()); + } + } + + static String parseHeaderName(boolean latin1, ByteArray bytes, Charset charset) { + final int size = bytes.length(); + final byte[] bs = bytes.content(); + final byte first = bs[0]; + if ((first == 'H' || first == 'h') && size == 4) { // Host + if (bs[1] == 'o' && bs[2] == 's' && bs[3] == 't') { + return HEAD_HOST; + } + } else if ((first == 'A' || first == 'a') && size == 6) { // Accept + if (bs[1] == 'c' && bs[2] == 'c' && bs[3] == 'e' && bs[4] == 'p' && bs[5] == 't') { + return HEAD_ACCEPT; + } + } else if (first == 'C' || first == 'c') { + if (size == 10) { // Connection + if (bs[1] == 'o' + && bs[2] == 'n' + && bs[3] == 'n' + && bs[4] == 'e' + && bs[5] == 'c' + && bs[6] == 't' + && bs[7] == 'i' + && bs[8] == 'o' + && bs[9] == 'n') { + return HEAD_CONNECTION; + } + } else if (size == 12) { // Content-Type + if (bs[1] == 'o' + && bs[2] == 'n' + && bs[3] == 't' + && bs[4] == 'e' + && bs[5] == 'n' + && bs[6] == 't' + && bs[7] == '-' + && (bs[8] == 'T' || bs[8] == 't') + && bs[9] == 'y' + && bs[10] == 'p' + && bs[11] == 'e') { + return HEAD_CONTENT_TYPE; + } + } else if (size == 14) { // Content-Length + if (bs[1] == 'o' + && bs[2] == 'n' + && bs[3] == 't' + && bs[4] == 'e' + && bs[5] == 'n' + && bs[6] == 't' + && bs[7] == '-' + && (bs[8] == 'L' || bs[8] == 'l') + && bs[9] == 'e' + && bs[10] == 'n' + && bs[11] == 'g' + && bs[12] == 't' + && bs[13] == 'h') { + return HEAD_CONTENT_LENGTH; + } + } else if (size == 6) { // Cookie + if (bs[1] == 'o' && bs[2] == 'o' && bs[3] == 'k' && bs[4] == 'i' && bs[5] == 'e') { + return HEAD_COOKIE; + } + } + } else if (first == 'U' || first == 'u') { + if (size == 7) { // Upgrade + if (bs[1] == 'p' && bs[2] == 'g' && bs[3] == 'r' && bs[4] == 'a' && bs[5] == 'd' && bs[6] == 'e') { + return HEAD_UPGRADE; + } + } else if (size == 10) { // User-Agent + if (bs[1] == 's' + && bs[2] == 'e' + && bs[3] == 'r' + && bs[4] == '-' + && (bs[5] == 'A' || bs[5] == 'a') + && bs[6] == 'g' + && bs[7] == 'e' + && bs[8] == 'n' + && bs[9] == 't') { + return HEAD_USER_AGENT; + } + } + } else if ((first == 'E' || first == 'e') && size == 6) { // Expect + if (bs[1] == 'x' && bs[2] == 'p' && bs[3] == 'e' && bs[4] == 'c' && bs[5] == 't') { + return HEAD_EXPECT; + } + } + return bytes.toString(latin1, charset); + } + + @Override + protected HttpRequest copyHeader() { + if (!PIPELINE_SAME_HEADERS || !context.lazyHeaders) { + return null; + } + HttpRequest req = new HttpRequest(context, this.array); + req.headerLength = this.headerLength; + req.headerBytes = this.headerBytes; + req.headerParsed = this.headerParsed; + req.contentType = this.contentType; + req.contentLength = this.contentLength; + req.host = this.host; + req.cookie = this.cookie; + req.cookies = this.cookies; + req.keepAlive = this.keepAlive; + req.maybews = this.maybews; + req.expect = this.expect; + req.rpc = this.rpc; + req.traceid = this.traceid; + req.currentUserid = this.currentUserid; + req.currentUserSupplier = this.currentUserSupplier; + req.reqConvertType = this.reqConvertType; + req.reqConvert = this.reqConvert; + req.respConvert = this.respConvert; + req.respConvertType = this.respConvertType; + req.headers.setAll(this.headers); + return req; + } + + @Override + protected Serializable getRequestid() { + return null; + } + + @Override + protected void prepare() { + this.keepAlive = true; // 默认HTTP/1.1 + } + + @Override + protected void recycle() { + // header + this.headerLength = 0; + this.headerHalfLen = 0; + this.headerBytes = null; + this.headerParsed = false; + this.contentType = null; + this.contentLength = -1; + this.host = null; + this.cookie = null; + this.cookies = null; + this.maybews = false; + this.expect = false; + this.rpc = false; + this.readState = READ_STATE_ROUTE; + this.currentUserid = CURRUSERID_NIL; + this.currentUserSupplier = null; + this.reqConvertType = null; + this.reqConvert = null; + this.respConvert = jsonConvert; + this.respConvertType = null; + this.headers.clear(); + // 其他 + this.newSessionid = null; + this.method = null; + this.getmethod = false; + this.protocol = null; + this.requestPath = null; + this.queryBytes = null; + this.boundary = false; + this.bodyParsed = false; + this.moduleid = 0; + this.actionid = 0; + this.annotations = null; + this.remoteAddr = null; + this.params.clear(); + this.array.clear(); + // 内部 + this.actionEntry = null; + super.recycle(); + } + + protected void skipBodyParse() { + this.bodyParsed = true; + } + + private void parseBody() { + if (this.boundary || bodyParsed) { + return; + } + bodyParsed = true; + if (this.getContentType() != null && this.contentType.toLowerCase().contains("x-www-form-urlencoded")) { + addParameter(array, true, 0, array.length()); + } + } + + private void addParameter(final ByteArray array, final boolean body, final int offset, final int len) { + if (len < 1) { + return; + } + Charset charset = this.context.getCharset(); + int limit = offset + len; + int keypos = array.indexOf(offset, limit, '='); + int valpos = array.indexOf(offset, limit, '&'); + if (keypos <= 0 || (valpos >= 0 && valpos < keypos)) { + if (valpos > 0) { + addParameter(array, body, valpos + 1, limit - valpos - 1); + } + return; + } + String name = toDecodeString(array, offset, keypos - offset, charset); + if (body && !name.isEmpty() && name.charAt(0) == '<') { + return; // 内容可能是xml格式; 如: = 0) { + addParameter(array, body, valpos + 1, limit - valpos - 1); + } + } + + protected HttpRequest setMethod(String method) { + this.method = method; + this.getmethod = METHOD_GET.equalsIgnoreCase(method); + return this; + } + + protected HttpRequest setRequestPath(String path) { + this.requestPath = path; + return this; + } + + protected HttpRequest setRemoteAddr(String remoteAddr) { + this.remoteAddr = remoteAddr; + return this; + } + + protected HttpRequest setLocale(String locale) { + this.locale = locale; + return this; + } + + protected HttpRequest setParameter(String name, String value) { + this.params.put(name, value); + return this; + } + + protected HttpRequest setHeader(String name, String value) { + this.headers.setValid(name, value); + return this; + } + + protected HttpRequest addHeader(String name, String value) { + this.headers.add(name, value); + return this; + } + + protected HttpRequest removeParameter(String name) { + this.params.remove(name); + return this; + } + + protected HttpRequest removeHeader(String name) { + this.headers.remove(name); + return this; + } + + protected static String toDecodeString(ByteArray array, int offset, int len, final Charset charset) { + byte[] content = array.content(); + if (len == 1) { + return Character.toString(content[offset]); + } else if (len == 2 && content[offset] >= 0x20 && content[offset] < 0x80) { + return new String(content, 0, offset, len); + } else if (len == 3 && content[offset + 1] >= 0x20 && content[offset + 1] < 0x80) { + return new String(content, 0, offset, len); + } + int start = offset; + final int end = offset + len; + boolean flag = false; // 是否需要转义 + byte[] bs = content; + for (int i = offset; i < end; i++) { + if (content[i] == '+' || content[i] == '%') { + flag = true; + break; + } + } + if (flag) { + int index = 0; + bs = new byte[len]; + for (int i = offset; i < end; i++) { + switch (content[i]) { + case '+': + bs[index] = ' '; + break; + case '%': + bs[index] = (byte) ((hexBit(content[++i]) * 16 + hexBit(content[++i]))); + break; + default: + bs[index] = content[i]; + break; + } + index++; + } + start = 0; + len = index; + } + return new String(bs, start, len, charset == null ? StandardCharsets.UTF_8 : charset); + } + + private static int hexBit(byte b) { + if ('0' <= b && '9' >= b) { + return b - '0'; + } + if ('a' <= b && 'z' >= b) { + return b - 'a' + 10; + } + if ('A' <= b && 'Z' >= b) { + return b - 'A' + 10; + } + return b; + } + + @Override + protected T setProperty(String name, T value) { + return super.setProperty(name, value); + } + + @Override + @SuppressWarnings("unchecked") + protected T getProperty(String name) { + return super.getProperty(name); + } + + @Override + protected T removeProperty(String name) { + return super.removeProperty(name); + } + + /** + * 设置当前用户ID, 通常在HttpServlet.preExecute方法里设置currentUserid
+ * 数据类型只能是int、long、String、JavaBean + * + * @param 泛型 + * @param userid 用户ID + * @return HttpRequest + * @since 2.1.0 + */ + public HttpRequest setCurrentUserid(T userid) { + this.currentUserid = userid; + return this; + } + + /** + * 获取当前用户ID的int值
+ * + * @return 用户ID + * @since 2.4.0 + */ + @ClassDepends + @SuppressWarnings("unchecked") + public int currentIntUserid() { + if (currentUserid == CURRUSERID_NIL || currentUserid == null) { + return 0; + } + if (this.currentUserid instanceof Number) { + return ((Number) this.currentUserid).intValue(); + } + String uid = this.currentUserid.toString(); + return uid.isEmpty() ? 0 : Integer.parseInt(uid); + } + + /** + * 获取当前用户ID的long值
+ * + * @return 用户ID + * @since 2.7.0 + */ + @ClassDepends + @SuppressWarnings("unchecked") + public long currentLongUserid() { + if (currentUserid == CURRUSERID_NIL || currentUserid == null) { + return 0L; + } + if (this.currentUserid instanceof Number) { + return ((Number) this.currentUserid).longValue(); + } + String uid = this.currentUserid.toString(); + return uid.isEmpty() ? 0L : Long.parseLong(uid); + } + + /** + * 获取当前用户ID的String值
+ * + * @return 用户ID + * @since 2.8.0 + */ + @ClassDepends + @SuppressWarnings("unchecked") + public String currentStringUserid() { + if (currentUserid == CURRUSERID_NIL || currentUserid == null) { + return null; + } + return this.currentUserid.toString(); + } + + /** + * 获取当前用户ID
+ * + * @param 数据类型只能是int、long、String、JavaBean + * @param type 类型 + * @return 用户ID + * @since 2.1.0 + */ + @ClassDepends + @SuppressWarnings("unchecked") + public T currentUserid(Class type) { + if (currentUserid == CURRUSERID_NIL || currentUserid == null) { + if (type == int.class || type == Integer.class) { + return (T) (Integer) (int) 0; + } + if (type == long.class || type == Long.class) { + return (T) (Long) (long) 0; + } + return null; + } + if (type == int.class || type == Integer.class) { + if (this.currentUserid instanceof Number) { + return (T) (Integer) ((Number) this.currentUserid).intValue(); + } + String uid = this.currentUserid.toString(); + return (T) (Integer) (uid.isEmpty() ? 0 : Integer.parseInt(uid)); + } + if (type == long.class || type == Long.class) { + if (this.currentUserid instanceof Number) { + return (T) (Long) ((Number) this.currentUserid).longValue(); + } + String uid = this.currentUserid.toString(); + return (T) (Long) (uid.isEmpty() ? 0L : Long.parseLong(uid)); + } + if (type == String.class) { + return (T) this.currentUserid.toString(); + } + if (this.currentUserid instanceof CharSequence) { + return JsonConvert.root().convertFrom(type, this.currentUserid.toString()); + } + return (T) this.currentUserid; + } + + /** + * 建议使用 setCurrentUserid, 通过userid从Service或缓存中获取用户信息
+ * 设置当前用户信息, 通常在HttpServlet.preExecute方法里设置currentUser
+ * 数据类型由@HttpUserType指定 + * + * @param supplier currentUser对象方法 + * @since 2.4.0 + * @return HttpRequest + */ + public HttpRequest setCurrentUserSupplier(Supplier supplier) { + this.currentUserSupplier = supplier; + return this; + } + + /** + * 建议使用 currentUserid, 通过userid从Service或缓存中获取用户信息
+ * 获取当前用户信息
+ * 数据类型由@HttpUserType指定 + * + * @param @HttpUserType指定的用户信息类型 + * @return 用户信息 + */ + @SuppressWarnings("unchecked") + public T currentUser() { + Supplier supplier = this.currentUserSupplier; + return (T) (supplier == null ? null : supplier.get()); + } + + /** + * 获取模块ID,来自@HttpServlet.moduleid() + * + * @return 模块ID + */ + @ConvertDisabled + public int getModuleid() { + return this.moduleid; + } + + /** + * 获取操作ID,来自@HttpMapping.actionid() + * + * @return 模块ID + */ + @ConvertDisabled + public int getActionid() { + return this.actionid; + } + + /** + * 获取当前操作Method上的注解集合 + * + * @return Annotation[] + */ + @ConvertDisabled + public Annotation[] getAnnotations() { + if (this.annotations == null) { + return new Annotation[0]; + } + Annotation[] newanns = new Annotation[this.annotations.length]; + System.arraycopy(this.annotations, 0, newanns, 0, newanns.length); + return newanns; + } + + /** + * 获取当前操作Method上的注解 + * + * @param 注解泛型 + * @param annotationClass 注解类型 + * @return Annotation + */ + public T getAnnotation(Class annotationClass) { + if (this.annotations == null) { + return null; + } + for (Annotation ann : this.annotations) { + if (ann.getClass() == annotationClass) { + return (T) ann; + } + } + return null; + } + + /** + * 获取当前操作Method上的注解集合 + * + * @param 注解泛型 + * @param annotationClass 注解类型 + * @return Annotation[] + */ + public T[] getAnnotationsByType(Class annotationClass) { + if (this.annotations == null) { + return Creator.newArray(annotationClass, 0); + } + T[] news = Creator.newArray(annotationClass, this.annotations.length); + int index = 0; + for (Annotation ann : this.annotations) { + if (ann.getClass() == annotationClass) { + news[index++] = (T) ann; + } + } + if (index < 1) { + return Creator.newArray(annotationClass, 0); + } + return Arrays.copyOf(news, index); + } + + /** + * 获取客户端地址IP + * + * @return 地址 + */ + @ConvertDisabled + public SocketAddress getRemoteAddress() { + return this.channel == null || !this.channel.isOpen() ? null : this.channel.getRemoteAddress(); + } + + /** + * 获取客户端地址IP, 与getRemoteAddress() 的区别在于:本方法优先取header中指定为RemoteAddress名的值,没有则返回getRemoteAddress()的getHostAddress()。 + *
+ * 本方法适用于服务前端有如nginx的代理服务器进行中转,通过 getRemoteAddress()是获取不到客户端的真实IP。 + * + * @return 地址 + */ + public String getRemoteAddr() { + if (this.remoteAddr != null) { + return this.remoteAddr; + } + parseHeader(); + if (remoteAddrHeader != null) { + String val = getHeader(remoteAddrHeader); + if (val != null) { + this.remoteAddr = val; + return val; + } + } + SocketAddress addr = getRemoteAddress(); + if (addr == null) { + return ""; + } + if (addr instanceof InetSocketAddress) { + this.remoteAddr = ((InetSocketAddress) addr).getAddress().getHostAddress(); + return this.remoteAddr; + } + this.remoteAddr = String.valueOf(addr); + return this.remoteAddr; + } + + /** + * 获取国际化Locale,值可以取之于header或parameter + * + * @return 国际化Locale + */ + public String getLocale() { + if (this.locale != null) { + return this.locale; + } + if (localHeader != null) { + String val = getHeader(localHeader); + if (val != null) { + this.locale = val; + return val; + } + } + if (localParameter != null) { + String val = getParameter(localParameter); + if (val != null) { + this.locale = val; + return val; + } + } + return this.locale; + } + + /** + * 获取请求内容指定的编码字符串 + * + * @param charset 编码 + * @return 内容 + */ + public String getBody(final Charset charset) { + return charset == null ? array.toString() : array.toString(charset); + } + + /** + * 获取请求内容的UTF-8编码字符串 + * + * @return 内容 + */ + @ConvertDisabled + public String getBodyUTF8() { + return array.toString(StandardCharsets.UTF_8); + } + + /** + * 获取请求内容的JavaBean对象 + * + * @param 泛型 + * @param type 类型 + * @return 内容 + */ + public T getBodyJson(java.lang.reflect.Type type) { + if (array == null || array.isEmpty()) { + return null; + } + Convert convert = this.reqConvert; + if (convert == null) { + convert = context.getJsonConvert(); + } + if (type == byte[].class) { + return (T) array.getBytes(); + } + return (T) convert.convertFrom(type, array.content()); + } + + /** + * 获取请求内容的JavaBean对象 + * + * @param 泛型 + * @param convert Convert + * @param type 类型 + * @return 内容 + */ + public T getBodyJson(Convert convert, java.lang.reflect.Type type) { + if (array.isEmpty()) { + return null; + } + if (type == byte[].class) { + return (T) array.getBytes(); + } + return (T) convert.convertFrom(type, array.content()); + } + + /** + * 获取请求内容的byte[] + * + * @return 内容 + */ + public byte[] getBody() { + return array.length() == 0 ? null : array.getBytes(); + } + + /** + * 直接获取body对象 + * + * @return body对象 + */ + @ConvertDisabled + protected ByteArray getDirectBody() { + return array; + } + + @Override + public String toString() { + parseBody(); + return this.getClass().getSimpleName() + "{\r\n method: " + this.method + ", \r\n path: " + + this.requestPath + + (this.reqConvertType != null ? (", \r\n reqConvertType: " + this.reqConvertType) : "") + + (this.respConvertType != null ? (", \r\n respConvertType: " + this.respConvertType) : "") + + (this.currentUserid != CURRUSERID_NIL + ? (", \r\n currentUserid: " + + (this.currentUserid == CURRUSERID_NIL ? null : this.currentUserid)) + : "") + + (this.getRemoteAddr() != null ? (", \r\n remoteAddr: " + this.getRemoteAddr()) : "") + + (this.cookie != null ? (", \r\n cookies: " + this.cookie) : "") + + (this.getContentType() != null ? (", \r\n contentType: " + this.contentType) : "") + + (this.protocol != null ? (", \r\n protocol: " + this.protocol) : "") + + (this.getHost() != null ? (", \r\n host: " + this.host) : "") + + (this.getContentLength() >= 0 ? (", \r\n contentLength: " + this.contentLength) : "") + + (this.array.length() > 0 ? (", \r\n bodyLength: " + this.array.length()) : "") + + (this.boundary || this.array.isEmpty() + ? "" + : (", \r\n bodyContent: " + + (this.respConvertType == null || this.respConvertType == ConvertType.JSON + ? this.getBodyUTF8() + : Arrays.toString(getBody())))) + + ", \r\n params: " + toMapString(this.params.map, 4) + + ", \r\n header: " + toMapString(this.headers.map, 4) + + "\r\n}"; // this.headers.toString(4) + } + + private static CharSequence toMapString(Map map, int indent) { + final String space = " ".repeat(indent); + StringBuilder sb = new StringBuilder(); + sb.append("{\r\n"); + if (map != null) { + for (Map.Entry en : map.entrySet()) { + Object val = en.getValue(); + if (val instanceof Collection) { + for (Object item : (Collection) val) { + sb.append(space) + .append(" '") + .append(en.getKey()) + .append("': '") + .append(item) + .append("',\r\n"); + } + } else { + sb.append(space) + .append(" '") + .append(en.getKey()) + .append("': '") + .append(val) + .append("',\r\n"); + } + } + } + sb.append(space).append('}'); + return sb; + } + + /** + * 获取文件上传对象 + * + * @return 文件上传对象 + */ + @ConvertDisabled + public final MultiContext getMultiContext() { + final InputStream in = newInputStream(); + return new MultiContext( + context.getCharset(), + this.getContentType(), + this.params.map(), + new BufferedInputStream(in, Math.max(array.length(), 8192)) { + { + array.copyTo(this.buf); + this.count = array.length(); + } + }, + null); + } + + /** + * 是否上传文件请求 + * + * @return boolean + */ + public final boolean isMultipart() { + return boundary; + } + + /** + * 获取文件上传信息列表 + * + * @return 文件上传对象集合 + * @throws IOException IO异常 + */ + @ConvertDisabled + public final Iterable multiParts() throws IOException { + return getMultiContext().parts(); + } + + /** + * 获取sessionid + * + * @param autoCreate 无sessionid是否自动创建 + * @return sessionid + */ + @ConvertDisabled + public String getSessionid(boolean autoCreate) { + String sessionid = getCookie(SESSIONID_NAME, null); + if (autoCreate && (sessionid == null || sessionid.isEmpty())) { + sessionid = context.createSessionid(); + this.newSessionid = sessionid; + } + return sessionid; + } + + /** + * 更新sessionid + * + * @return 新的sessionid值 + */ + public String changeSessionid() { + this.newSessionid = context.createSessionid(); + return newSessionid; + } + + /** + * 指定值更新sessionid + * + * @param newSessionid 新sessionid值 + * @return 新的sessionid值 + */ + public String changeSessionid(String newSessionid) { + this.newSessionid = newSessionid == null ? context.createSessionid() : newSessionid.trim(); + return newSessionid; + } + + /** 使sessionid失效 */ + public void invalidateSession() { + this.newSessionid = ""; // 为空表示删除sessionid + } + + /** + * 获取所有Cookie对象 + * + * @return cookie对象数组 + */ + public HttpCookie[] getCookies() { + parseHeader(); + if (this.cookies == null) { + this.cookies = parseCookies(this.cookie); + } + return this.cookies.length == 0 ? null : this.cookies; + } + + /** + * 获取Cookie值 + * + * @param name cookie名 + * @return cookie值 + */ + public String getCookie(String name) { + return getCookie(name, null); + } + + /** + * 获取Cookie值, 没有返回默认值 + * + * @param name cookie名 + * @param dfvalue 默认cookie值 + * @return cookie值 + */ + public String getCookie(String name, String dfvalue) { + HttpCookie[] cs = getCookies(); + if (cs == null) { + return dfvalue; + } + for (HttpCookie c : cs) { + if (name.equals(c.getName())) { + return c.getValue(); + } + } + return dfvalue; + } + + private static HttpCookie[] parseCookies(String cookiestr) { + if (cookiestr == null || cookiestr.isEmpty()) { + return new HttpCookie[0]; + } + String str = cookiestr.replaceAll("(^;)|(;$)", "").replaceAll(";+", ";"); + if (str.isEmpty()) { + return new HttpCookie[0]; + } + String[] strs = str.split(";"); + HttpCookie[] cookies = new HttpCookie[strs.length]; + for (int i = 0; i < strs.length; i++) { + String s = strs[i]; + int pos = s.indexOf('='); + String v = (pos < 0 ? "" : s.substring(pos + 1)); + if (v.indexOf('"') == 0 && v.lastIndexOf('"') == v.length() - 1) { + v = v.substring(1, v.length() - 1); + } + cookies[i] = new HttpCookie((pos < 0 ? s : s.substring(0, pos)), v); + } + return cookies; + } + + /** + * 获取协议名 http、https、ws、wss等 + * + * @return protocol + */ + public String getProtocol() { + return protocol; + } + + /** + * 获取请求方法 GET、POST等 + * + * @return method + */ + public String getMethod() { + return method; + } + + /** + * 获取Content-Type的header值 + * + * @return contentType + */ + public String getContentType() { + if (contentType == null) { + parseHeader(); + } + return contentType; + } + + /** + * 获取请求内容的长度, 为-1表示内容长度不确定 + * + * @return 内容长度 + */ + public long getContentLength() { + if (contentLength < 1) { + parseHeader(); + } + return contentLength; + } + + /** + * 获取Host的Header值 + * + * @return Host + */ + public String getHost() { + if (host == null) { + parseHeader(); + } + return host; + } + + /** + * 获取请求的URL + * + * @return 请求的URL + */ + public String getRequestPath() { + return requestPath; + } + + /** + * 获取请求参数的byte[] + * + * @return byte[] + */ + public byte[] getQueryBytes() { + return queryBytes; + } + + /** + * 截取getRequestPath最后的一个/后面的部分 + * + * @return String + */ + @ConvertDisabled + public String getPathLastParam() { + if (requestPath == null) { + return ""; + } + return requestPath.substring(requestPath.lastIndexOf('/') + 1); + } + + /** + * 获取请求URL最后的一个/后面的部分的short值
+ * 例如请求URL /pipes/user/query/2
+ * 获取type参数: short type = request.getPathLastParam((short)0); //type = 2 + * + * @param defvalue 默认short值 + * @return short值 + */ + public short getPathLastParam(short defvalue) { + String val = getPathLastParam(); + if (val.isEmpty()) { + return defvalue; + } + try { + return Short.parseShort(val); + } catch (NumberFormatException e) { + return defvalue; + } + } + + /** + * 获取请求URL最后的一个/后面的部分的short值
+ * 例如请求URL /pipes/user/query/2
+ * 获取type参数: short type = request.getPathLastParam(16, (short)0); //type = 2 + * + * @param radix 进制数 + * @param defvalue 默认short值 + * @return short值 + */ + public short getPathLastParam(int radix, short defvalue) { + String val = getPathLastParam(); + if (val.isEmpty()) { + return defvalue; + } + try { + return Short.parseShort(val, radix); + } catch (NumberFormatException e) { + return defvalue; + } + } + + /** + * 获取请求URL最后的一个/后面的部分的int值
+ * 例如请求URL /pipes/user/query/2
+ * 获取type参数: int type = request.getPathLastParam(0); //type = 2 + * + * @param defvalue 默认int值 + * @return int值 + */ + public int getPathLastParam(int defvalue) { + String val = getPathLastParam(); + try { + return val.isEmpty() ? defvalue : Integer.parseInt(val); + } catch (NumberFormatException e) { + return defvalue; + } + } + + /** + * 获取请求URL最后的一个/后面的部分的int值
+ * 例如请求URL /pipes/user/query/2
+ * 获取type参数: int type = request.getPathLastParam(16, 0); //type = 2 + * + * @param radix 进制数 + * @param defvalue 默认int值 + * @return int值 + */ + public int getPathLastParam(int radix, int defvalue) { + String val = getPathLastParam(); + try { + return val.isEmpty() ? defvalue : Integer.parseInt(val, radix); + } catch (NumberFormatException e) { + return defvalue; + } + } + + /** + * 获取请求URL最后的一个/后面的部分的float值
+ * 例如请求URL /pipes/user/query/2
+ * 获取type参数: float type = request.getPathLastParam(0.0f); //type = 2.0f + * + * @param defvalue 默认float值 + * @return float值 + */ + public float getPathLastParam(float defvalue) { + String val = getPathLastParam(); + try { + return val.isEmpty() ? defvalue : Float.parseFloat(val); + } catch (NumberFormatException e) { + return defvalue; + } + } + + /** + * 获取请求URL最后的一个/后面的部分的int值
+ * 例如请求URL /pipes/user/query/2
+ * 获取type参数: long type = request.getPathLastParam(0L); //type = 2 + * + * @param defvalue 默认long值 + * @return long值 + */ + public long getPathLastParam(long defvalue) { + String val = getPathLastParam(); + try { + return val.isEmpty() ? defvalue : Long.parseLong(val); + } catch (NumberFormatException e) { + return defvalue; + } + } + + /** + * 获取请求URL最后的一个/后面的部分的int值
+ * 例如请求URL /pipes/user/query/2
+ * 获取type参数: long type = request.getPathLastParam(16, 0L); //type = 2 + * + * @param radix 进制数 + * @param defvalue 默认long值 + * @return long值 + */ + public long getPathLastParam(int radix, long defvalue) { + String val = getPathLastParam(); + try { + return val.isEmpty() ? defvalue : Long.parseLong(val, radix); + } catch (NumberFormatException e) { + return defvalue; + } + } + + /** + * 获取请求URL最后的一个/后面的部分的double值
+ * 例如请求URL /pipes/user/query/2
+ * 获取type参数: double type = request.getPathLastParam(0.0); //type = 2.0 + * + * @param defvalue 默认double值 + * @return double值 + */ + public double getPathLastParam(double defvalue) { + String val = getPathLastParam(); + try { + return val.isEmpty() ? defvalue : Double.parseDouble(val); + } catch (NumberFormatException e) { + return defvalue; + } + } + + /** + * 从prefix之后截取getPath再对"/"进行分隔 + * + *

+ * + * @param prefix 前缀 + * @return String[] + */ + public String[] getPathParams(String prefix) { + if (requestPath == null || prefix == null) { + return new String[0]; + } + return requestPath + .substring(requestPath.indexOf(prefix) + prefix.length() + (prefix.endsWith("/") ? 0 : 1)) + .split("/"); + } + + /** + * 获取请求URL分段中含prefix段的值
+ * 例如请求URL /pipes/user/query/name:hello
+ * 获取name参数: String name = request.getPathParam("name:", "none"); + * + * @param prefix prefix段前缀 + * @param defvalue 默认值 + * @return prefix截断后的值 + */ + public String getPathParam(String prefix, String defvalue) { + if (requestPath == null || prefix == null || prefix.isEmpty()) { + return defvalue; + } + int pos = requestPath.indexOf(prefix); + if (pos < 0) { + return defvalue; + } + String sub = requestPath.substring(pos + prefix.length()); + pos = sub.indexOf('/'); + return pos < 0 ? sub : sub.substring(0, pos); + } + + /** + * 获取请求URL分段中含prefix段的short值
+ * 例如请求URL /pipes/user/query/type:10
+ * 获取type参数: short type = request.getPathParam("type:", (short)0); + * + * @param prefix prefix段前缀 + * @param defvalue 默认short值 + * @return short值 + */ + public short getPathParam(String prefix, short defvalue) { + String val = getPathParam(prefix, null); + try { + return val == null ? defvalue : Short.parseShort(val); + } catch (NumberFormatException e) { + return defvalue; + } + } + + /** + * 获取请求URL分段中含prefix段的short值
+ * 例如请求URL /pipes/user/query/type:a
+ * 获取type参数: short type = request.getPathParam(16, "type:", (short)0); //type = 10 + * + * @param radix 进制数 + * @param prefix prefix段前缀 + * @param defvalue 默认short值 + * @return short值 + */ + public short getPathParam(int radix, String prefix, short defvalue) { + String val = getPathParam(prefix, null); + try { + return val == null ? defvalue : Short.parseShort(val, radix); + } catch (NumberFormatException e) { + return defvalue; + } + } + + /** + * 获取请求URL分段中含prefix段的int值
+ * 例如请求URL /pipes/user/query/offset:0/limit:50
+ * 获取offset参数: int offset = request.getPathParam("offset:", 0);
+ * 获取limit参数: int limit = request.getPathParam("limit:", 20);
+ * + * @param prefix prefix段前缀 + * @param defvalue 默认int值 + * @return int值 + */ + public int getPathParam(String prefix, int defvalue) { + String val = getPathParam(prefix, null); + try { + return val == null ? defvalue : Integer.parseInt(val); + } catch (NumberFormatException e) { + return defvalue; + } + } + + /** + * 获取请求URL分段中含prefix段的int值
+ * 例如请求URL /pipes/user/query/offset:0/limit:50
+ * 获取offset参数: int offset = request.getPathParam("offset:", 0);
+ * 获取limit参数: int limit = request.getPathParam(16, "limit:", 20); // limit = 16
+ * + * @param radix 进制数 + * @param prefix prefix段前缀 + * @param defvalue 默认int值 + * @return int值 + */ + public int getPathParam(int radix, String prefix, int defvalue) { + String val = getPathParam(prefix, null); + try { + return val == null ? defvalue : Integer.parseInt(val, radix); + } catch (NumberFormatException e) { + return defvalue; + } + } + + /** + * 获取请求URL分段中含prefix段的float值
+ * 例如请求URL /pipes/user/query/point:40.0
+ * 获取time参数: float point = request.getPathParam("point:", 0.0f); + * + * @param prefix prefix段前缀 + * @param defvalue 默认float值 + * @return float值 + */ + public float getPathParam(String prefix, float defvalue) { + String val = getPathParam(prefix, null); + try { + return val == null ? defvalue : Float.parseFloat(val); + } catch (NumberFormatException e) { + return defvalue; + } + } + + /** + * 获取请求URL分段中含prefix段的long值
+ * 例如请求URL /pipes/user/query/time:1453104341363/id:40
+ * 获取time参数: long time = request.getPathParam("time:", 0L); + * + * @param prefix prefix段前缀 + * @param defvalue 默认long值 + * @return long值 + */ + public long getPathParam(String prefix, long defvalue) { + String val = getPathParam(prefix, null); + try { + return val == null ? defvalue : Long.parseLong(val); + } catch (NumberFormatException e) { + return defvalue; + } + } + + /** + * 获取请求URL分段中含prefix段的long值
+ * 例如请求URL /pipes/user/query/time:1453104341363/id:40
+ * 获取time参数: long time = request.getPathParam(16, "time:", 0L); + * + * @param radix 进制数 + * @param prefix prefix段前缀 + * @param defvalue 默认long值 + * @return long值 + */ + public long getPathParam(int radix, String prefix, long defvalue) { + String val = getPathParam(prefix, null); + try { + return val == null ? defvalue : Long.parseLong(val, radix); + } catch (NumberFormatException e) { + return defvalue; + } + } + + /** + * 获取请求URL分段中含prefix段的double值
+ * 例如请求URL /pipes/user/query/point:40.0
+ * 获取time参数: double point = request.getPathParam("point:", 0.0); + * + * @param prefix prefix段前缀 + * @param defvalue 默认double值 + * @return double值 + */ + public double getPathParam(String prefix, double defvalue) { + String val = getPathParam(prefix, null); + try { + return val == null ? defvalue : Double.parseDouble(val); + } catch (NumberFormatException e) { + return defvalue; + } + } + + // ------------------------------------------------------------------------------ + /** + * 获取请求Header总对象 + * + * @return AnyValue + */ + @ClassDepends + public HttpHeaders getHeaders() { + parseHeader(); + return headers; + } + + /** + * 获取所有的header名 + * + * @return header名数组 + */ + @ConvertDisabled + public String[] getHeaderNames() { + parseHeader(); + return headers.names(); + } + + /** + * 获取指定的header值 + * + * @param name header名 + * @return header值 + */ + public String getHeader(String name) { + return getHeader(name, null); + } + + /** + * 获取指定的header值, 没有返回默认值 + * + * @param name header名 + * @param defaultValue 默认值 + * @return header值 + */ + @ClassDepends + public String getHeader(String name, String defaultValue) { + parseHeader(); + return headers.firstValue(name, defaultValue); + } + + /** + * 获取指定的header的json值 + * + * @param 泛型 + * @param type 反序列化的类名 + * @param name header名 + * @return header值 + */ + @ClassDepends + public T getJsonHeader(java.lang.reflect.Type type, String name) { + String v = getHeader(name); + return isEmpty(v) ? null : jsonConvert.convertFrom(type, v); + } + + /** + * 获取指定的header的json值 + * + * @param 泛型 + * @param convert JsonConvert对象 + * @param type 反序列化的类名 + * @param name header名 + * @return header值 + */ + @ClassDepends + public T getJsonHeader(JsonConvert convert, java.lang.reflect.Type type, String name) { + String v = getHeader(name); + return isEmpty(v) ? null : convert.convertFrom(type, v); + } + + /** + * 获取指定的header的boolean值, 没有返回默认boolean值 + * + * @param name header名 + * @param defaultValue 默认boolean值 + * @return header值 + */ + @ClassDepends + public boolean getBooleanHeader(String name, boolean defaultValue) { + String value = getHeader(name); + return isEmpty(value) ? defaultValue : Boolean.parseBoolean(value); + } + + /** + * 获取指定的header的short值, 没有返回默认short值 + * + * @param name header名 + * @param defaultValue 默认short值 + * @return header值 + */ + @ClassDepends + public short getShortHeader(String name, short defaultValue) { + String value = getHeader(name); + if (isEmpty(value)) { + return defaultValue; + } + try { + return Short.decode(value); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + /** + * 获取指定的header的short值, 没有返回默认short值 + * + * @param radix 进制数 + * @param name header名 + * @param defaultValue 默认short值 + * @return header值 + */ + @ClassDepends + public short getShortHeader(int radix, String name, short defaultValue) { + String value = getHeader(name); + if (isEmpty(value)) { + return defaultValue; + } + try { + return (radix == 10 ? Short.decode(value) : Short.parseShort(value, radix)); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + /** + * 获取指定的header的short值, 没有返回默认short值 + * + * @param name header名 + * @param defaultValue 默认short值 + * @return header值 + */ + @ClassDepends + public short getShortHeader(String name, int defaultValue) { + String value = getHeader(name); + if (isEmpty(value)) { + return (short) defaultValue; + } + try { + return Short.decode(value); + } catch (NumberFormatException e) { + return (short) defaultValue; + } + } + + /** + * 获取指定的header的short值, 没有返回默认short值 + * + * @param radix 进制数 + * @param name header名 + * @param defaultValue 默认short值 + * @return header值 + */ + @ClassDepends + public short getShortHeader(int radix, String name, int defaultValue) { + String value = getHeader(name); + if (isEmpty(value)) { + return (short) defaultValue; + } + try { + return (radix == 10 ? Short.decode(value) : Short.parseShort(value, radix)); + } catch (NumberFormatException e) { + return (short) defaultValue; + } + } + + /** + * 获取指定的header的int值, 没有返回默认int值 + * + * @param name header名 + * @param defaultValue 默认int值 + * @return header值 + */ + @ClassDepends + public int getIntHeader(String name, int defaultValue) { + String value = getHeader(name); + if (isEmpty(value)) { + return defaultValue; + } + try { + return Integer.parseInt(value); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + /** + * 获取指定的header的int值, 没有返回默认int值 + * + * @param radix 进制数 + * @param name header名 + * @param defaultValue 默认int值 + * @return header值 + */ + @ClassDepends + public int getIntHeader(int radix, String name, int defaultValue) { + String value = getHeader(name); + if (isEmpty(value)) { + return defaultValue; + } + try { + return (radix == 10 ? Integer.decode(value) : Integer.parseInt(value, radix)); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + /** + * 获取指定的header的long值, 没有返回默认long值 + * + * @param name header名 + * @param defaultValue 默认long值 + * @return header值 + */ + @ClassDepends + public long getLongHeader(String name, long defaultValue) { + String value = getHeader(name); + if (isEmpty(value)) { + return defaultValue; + } + try { + return Long.decode(value); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + /** + * 获取指定的header的long值, 没有返回默认long值 + * + * @param radix 进制数 + * @param name header名 + * @param defaultValue 默认long值 + * @return header值 + */ + @ClassDepends + public long getLongHeader(int radix, String name, long defaultValue) { + String value = getHeader(name); + if (isEmpty(value)) { + return defaultValue; + } + try { + return (radix == 10 ? Long.decode(value) : Long.parseLong(value, radix)); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + /** + * 获取指定的header的float值, 没有返回默认float值 + * + * @param name header名 + * @param defaultValue 默认float值 + * @return header值 + */ + @ClassDepends + public float getFloatHeader(String name, float defaultValue) { + String value = getHeader(name); + if (isEmpty(value)) { + return defaultValue; + } + try { + return Float.parseFloat(value); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + /** + * 获取指定的header的double值, 没有返回默认double值 + * + * @param name header名 + * @param defaultValue 默认double值 + * @return header值 + */ + @ClassDepends + public double getDoubleHeader(String name, double defaultValue) { + String value = getHeader(name); + if (isEmpty(value)) { + return defaultValue; + } + try { + return Double.parseDouble(value); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + // ------------------------------------------------------------------------------ + /** + * 获取请求参数总对象 + * + * @return AnyValue + */ + @ClassDepends + public HttpParameters getParameters() { + parseBody(); + return params; + } + + /** + * 将请求参数转换成String, 字符串格式为: bean1={}&id=13&name=xxx
+ * 不会返回null,没有参数返回空字符串 + * + * @return String + */ + @ConvertDisabled + public String getParametersToString() { + return getParametersToString(null); + } + + /** + * 将请求参数转换成String, 字符串格式为: bean1={}&id=13&name=xxx
+ * 不会返回null,没有参数返回空字符串 + * + * @param prefix 拼接前缀, 如果无参数,返回的字符串不会含有拼接前缀 + * @return String + */ + public String getParametersToString(String prefix) { + byte[] rbs = queryBytes; + if (rbs == null || rbs.length < 1) { + return ""; + } + Charset charset = this.context.getCharset(); + String str = charset == null ? new String(rbs, StandardCharsets.UTF_8) : new String(rbs, charset); + return (prefix == null) ? str : (prefix + str); + } + + /** + * 获取所有参数名 + * + * @return 参数名数组 + */ + @ConvertDisabled + public String[] getParameterNames() { + parseBody(); + return params.names(); + } + + /** + * 获取指定的参数值 + * + * @param name 参数名 + * @return 参数值 + */ + public String getParameter(String name) { + parseBody(); + return params.get(name); + } + + /** + * 获取指定的参数值, 没有返回默认值 + * + * @param name 参数名 + * @param defaultValue 默认值 + * @return 参数值 + */ + public String getParameter(String name, String defaultValue) { + parseBody(); + return params.get(name, defaultValue); + } + + /** + * 获取指定的参数json值 + * + * @param 泛型 + * @param type 反序列化的类名 + * @param name 参数名 + * @return 参数值 + */ + public T getJsonParameter(java.lang.reflect.Type type, String name) { + String v = getParameter(name); + return v == null || v.isEmpty() ? null : jsonConvert.convertFrom(type, v); + } + + /** + * 获取指定的参数json值 + * + * @param 泛型 + * @param convert JsonConvert对象 + * @param type 反序列化的类名 + * @param name 参数名 + * @return 参数值 + */ + public T getJsonParameter(JsonConvert convert, java.lang.reflect.Type type, String name) { + String v = getParameter(name); + return v == null || v.isEmpty() ? null : convert.convertFrom(type, v); + } + + /** + * 获取指定的参数boolean值, 没有返回默认boolean值 + * + * @param name 参数名 + * @param defaultValue 默认boolean值 + * @return 参数值 + */ + public boolean getBooleanParameter(String name, boolean defaultValue) { + parseBody(); + String value = params.get(name); + return value == null || value.length() == 0 ? defaultValue : Boolean.parseBoolean(value); + } + + /** + * 获取指定的参数short值, 没有返回默认short值 + * + * @param name 参数名 + * @param defaultValue 默认short值 + * @return 参数值 + */ + public short getShortParameter(String name, short defaultValue) { + parseBody(); + String value = params.get(name); + if (value == null || value.length() == 0) { + return defaultValue; + } + try { + return Short.decode(value); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + /** + * 获取指定的参数short值, 没有返回默认short值 + * + * @param radix 进制数 + * @param name 参数名 + * @param defaultValue 默认short值 + * @return 参数值 + */ + public short getShortParameter(int radix, String name, short defaultValue) { + parseBody(); + String value = params.get(name); + if (value == null || value.length() == 0) { + return defaultValue; + } + try { + return (radix == 10 ? Short.decode(value) : Short.parseShort(value, radix)); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + /** + * 获取指定的参数short值, 没有返回默认short值 + * + * @param name 参数名 + * @param defaultValue 默认short值 + * @return 参数值 + */ + public short getShortParameter(String name, int defaultValue) { + parseBody(); + String value = params.get(name); + if (value == null || value.length() == 0) { + return (short) defaultValue; + } + try { + return Short.decode(value); + } catch (NumberFormatException e) { + return (short) defaultValue; + } + } + + /** + * 获取指定的参数int值, 没有返回默认int值 + * + * @param name 参数名 + * @param defaultValue 默认int值 + * @return 参数值 + */ + public int getIntParameter(String name, int defaultValue) { + parseBody(); + String value = params.get(name); + if (value == null || value.length() == 0) { + return defaultValue; + } + try { + return Integer.decode(value); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + /** + * 获取指定的参数int值, 没有返回默认int值 + * + * @param radix 进制数 + * @param name 参数名 + * @param defaultValue 默认int值 + * @return 参数值 + */ + public int getIntParameter(int radix, String name, int defaultValue) { + parseBody(); + String value = params.get(name); + if (value == null || value.length() == 0) { + return defaultValue; + } + try { + return (radix == 10 ? Integer.decode(value) : Integer.parseInt(value, radix)); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + /** + * 获取指定的参数long值, 没有返回默认long值 + * + * @param name 参数名 + * @param defaultValue 默认long值 + * @return 参数值 + */ + public long getLongParameter(String name, long defaultValue) { + parseBody(); + String value = params.get(name); + if (value == null || value.length() == 0) { + return defaultValue; + } + try { + return Long.decode(value); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + /** + * 获取指定的参数long值, 没有返回默认long值 + * + * @param radix 进制数 + * @param name 参数名 + * @param defaultValue 默认long值 + * @return 参数值 + */ + public long getLongParameter(int radix, String name, long defaultValue) { + parseBody(); + String value = params.get(name); + if (value == null || value.length() == 0) { + return defaultValue; + } + try { + return (radix == 10 ? Long.decode(value) : Long.parseLong(value, radix)); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + /** + * 获取指定的参数float值, 没有返回默认float值 + * + * @param name 参数名 + * @param defaultValue 默认float值 + * @return 参数值 + */ + public float getFloatParameter(String name, float defaultValue) { + parseBody(); + String value = params.get(name); + if (value == null || value.length() == 0) { + return defaultValue; + } + try { + return Float.parseFloat(value); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + /** + * 获取指定的参数double值, 没有返回默认double值 + * + * @param name 参数名 + * @param defaultValue 默认double值 + * @return 参数值 + */ + public double getDoubleParameter(String name, double defaultValue) { + parseBody(); + String value = params.get(name); + if (value == null || value.length() == 0) { + return defaultValue; + } + try { + return Double.parseDouble(value); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + /** + * 获取翻页对象 同 getFlipper("flipper", false, 0); + * + * @return Flipper翻页对象 + */ + public org.redkale.source.Flipper getFlipper() { + return getFlipper(false, 0); + } + + /** + * 获取翻页对象 同 getFlipper("flipper", autoCreate, 0); + * + * @param autoCreate 无参数时是否创建新Flipper对象 + * @return Flipper翻页对象 + */ + public org.redkale.source.Flipper getFlipper(boolean autoCreate) { + return getFlipper(autoCreate, 0); + } + + /** + * 获取翻页对象 同 getFlipper("flipper", false, maxLimit); + * + * @param maxLimit 最大行数, 小于1则值为Flipper.DEFAULT_LIMIT + * @return Flipper翻页对象 + */ + public org.redkale.source.Flipper getFlipper(int maxLimit) { + return getFlipper(false, maxLimit); + } + + /** + * 获取翻页对象 同 getFlipper("flipper", autoCreate, maxLimit) + * + * @param autoCreate 无参数时是否创建新Flipper对象 + * @param maxLimit 最大行数, 小于1则值为Flipper.DEFAULT_LIMIT + * @return Flipper翻页对象 + */ + public org.redkale.source.Flipper getFlipper(boolean autoCreate, int maxLimit) { + return getFlipper("flipper", autoCreate, maxLimit); + } + + /** + * 获取翻页对象 https://redkale.org/pipes/users/list?flipper={'offset':0,'limit':20, 'sort':'createtime ASC'}
+ * + * @param name Flipper对象的参数名,默认为 "flipper" + * @param autoCreate 无参数时是否创建新Flipper对象 + * @param maxLimit 最大行数, 小于1则值为Flipper.DEFAULT_LIMIT + * @return Flipper翻页对象 + */ + public org.redkale.source.Flipper getFlipper(String name, boolean autoCreate, int maxLimit) { + org.redkale.source.Flipper flipper = getJsonParameter(org.redkale.source.Flipper.class, name); + if (flipper == null) { + // if (maxLimit < 1) maxLimit = org.redkale.source.Flipper.DEFAULT_LIMIT; + // String limitstr = getParameter("limit"); + // if (limitstr != null && !limitstr.isEmpty()) { + // String offsetstr = getParameter("offset"); + // if (offsetstr != null && !offsetstr.isEmpty()) { + // int limit = Integer.parseInt(limitstr); + // int offset = Integer.parseInt(offsetstr); + // String sort = getParameter("sort"); + // if (limit > maxLimit) limit = maxLimit; + // flipper = new org.redkale.source.Flipper(limit, offset, sort); + // } + // } + } else if (flipper.getLimit() < 1 || (maxLimit > 0 && flipper.getLimit() > maxLimit)) { + flipper.setLimit(maxLimit); + } + if (flipper != null || !autoCreate) { + return flipper; + } + if (maxLimit < 1) { + maxLimit = org.redkale.source.Flipper.DEFAULT_LIMIT; + } + return new org.redkale.source.Flipper(maxLimit); + } +} diff --git a/src/main/java/org/redkale/net/http/HttpServer.java b/src/main/java/org/redkale/net/http/HttpServer.java index a5712d318..ae6372873 100644 --- a/src/main/java/org/redkale/net/http/HttpServer.java +++ b/src/main/java/org/redkale/net/http/HttpServer.java @@ -1,639 +1,639 @@ -/* - * 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.http; - -import static java.time.format.DateTimeFormatter.RFC_1123_DATE_TIME; - -import java.io.IOException; -import java.lang.reflect.Field; -import java.net.HttpCookie; -import java.text.*; -import java.time.ZoneId; -import java.util.*; -import java.util.concurrent.*; -import java.util.concurrent.atomic.LongAdder; -import java.util.concurrent.locks.ReentrantLock; -import java.util.function.BiConsumer; -import java.util.function.Supplier; -import java.util.logging.Level; -import org.redkale.boot.Application; -import org.redkale.inject.ResourceFactory; -import org.redkale.mq.spi.MessageAgent; -import org.redkale.net.Server; -import org.redkale.net.http.HttpContext.HttpContextConfig; -import org.redkale.net.http.HttpResponse.HttpResponseConfig; -import org.redkale.net.sncp.Sncp; -import org.redkale.service.Service; -import org.redkale.util.*; - -/** - * Http服务器 - * - *

详情见: https://redkale.org - * - * @author zhangjx - */ -public class HttpServer extends Server { - - private ScheduledThreadPoolExecutor dateScheduler; - - private HttpResponseConfig respConfig; - - private ByteBufferPool safeBufferPool; - - private final ReentrantLock addLock = new ReentrantLock(); - - // 配置 APP_EXECUTOR资源为null - // RESNAME_APP_EXECUTOR - protected ExecutorService workExecutor; - - public HttpServer() { - this(null, System.currentTimeMillis(), ResourceFactory.create()); - } - - public HttpServer(ResourceFactory resourceFactory) { - this(null, System.currentTimeMillis(), resourceFactory); - } - - public HttpServer(Application application) { - this( - application, - System.currentTimeMillis(), - application.getResourceFactory().createChild()); - } - - public HttpServer(Application application, long serverStartTime, ResourceFactory resourceFactory) { - super(application, serverStartTime, "TCP", resourceFactory, new HttpDispatcherServlet()); - this.workExecutor = application == null ? null : application.getWorkExecutor(); - } - - @Override - public void init(AnyValue config) throws Exception { - super.init(config); - if (context.rpcAuthenticator != null) { - context.rpcAuthenticator.init(context.rpcAuthenticatorConfig); - } - } - - @Override - protected void postStart() { - ((HttpDispatcherServlet) this.dispatcher).postStart(this.context, config); - } - - @Override - public void destroy(final AnyValue config) throws Exception { - super.destroy(config); - if (this.dateScheduler != null) { - this.dateScheduler.shutdownNow(); - this.dateScheduler = null; - } - if (context.rpcAuthenticator != null) { - context.rpcAuthenticator.destroy(context.rpcAuthenticatorConfig); - } - HttpResponseConfig respConf = this.respConfig; - HttpRender httpRender = respConf.httpRender; - if (httpRender != null) { - httpRender.destroy(context, respConf.renderConfig); - } - } - - @Override - protected String startExtLog() { - return context.lazyHeaders ? ", lazyHeaders: true" : ""; - } - - public List getHttpServlets() { - return this.dispatcher.getServlets(); - } - - public List getHttpFilters() { - return this.dispatcher.getFilters(); - } - - public HttpResponseConfig getResponseConfig() { - return respConfig; - } - - /** - * 获取静态资源HttpServlet - * - * @return HttpServlet - */ - public HttpResourceServlet getResourceServlet() { - return (HttpResourceServlet) ((HttpDispatcherServlet) this.dispatcher).resourceHttpServlet; - } - - /** - * 删除HttpServlet - * - * @param service Service - * @return HttpServlet - */ - public HttpServlet removeHttpServlet(Service service) { - return ((HttpDispatcherServlet) this.dispatcher).removeHttpServlet(service); - } - - /** - * 删除HttpServlet - * - * @param 泛型 - * @param websocketOrServletType Class - * @return HttpServlet - */ - public HttpServlet removeHttpServlet(Class websocketOrServletType) { - return ((HttpDispatcherServlet) this.dispatcher).removeHttpServlet(websocketOrServletType); - } - - /** - * 屏蔽请求URL的正则表达式 - * - * @param urlreg 正则表达式 - * @return 是否成功 - */ - public boolean addForbidURIReg(final String urlreg) { - return ((HttpDispatcherServlet) this.dispatcher).addForbidURIRegx(urlreg); - } - - /** - * 删除屏蔽请求URL的正则表达式 - * - * @param urlreg 正则表达式 - * @return 是否成功 - */ - public boolean removeForbidURIReg(final String urlreg) { - return ((HttpDispatcherServlet) this.dispatcher).removeForbidURIReg(urlreg); - } - - /** - * 删除HttpFilter - * - * @param 泛型 - * @param filterClass HttpFilter类 - * @return HttpFilter - */ - public T removeHttpFilter(Class filterClass) { - return (T) this.dispatcher.removeFilter(filterClass); - } - - /** - * 添加HttpFilter - * - * @param filter HttpFilter - * @param conf AnyValue - * @return HttpServer - */ - public HttpServer addHttpFilter(HttpFilter filter, AnyValue conf) { - this.dispatcher.addFilter(filter, conf); - return this; - } - - /** - * 添加HttpServlet - * - * @param mapping 匹配规则 - * @param servlet HttpServlet - * @return HttpServer - */ - public HttpServer addHttpServlet(String mapping, HttpServlet servlet) { - this.dispatcher.addServlet(servlet, null, null, mapping); - return this; - } - - /** - * 添加HttpServlet - * - * @param mapping 匹配规则 - * @param consumer HttpServlet - * @return HttpServer - */ - public HttpServer addHttpServlet(String mapping, BiConsumer consumer) { - this.dispatcher.addServlet( - new HttpServlet() { - @Override - public void execute(HttpRequest request, HttpResponse response) throws IOException { - consumer.accept(request, response); - } - }, - null, - null, - mapping); - return this; - } - - /** - * 添加HttpServlet - * - * @param prefix url前缀 - * @param servlet HttpServlet - * @param mappings 匹配规则 - * @return HttpServer - */ - public HttpServer addHttpServlet(String prefix, HttpServlet servlet, String... mappings) { - this.dispatcher.addServlet(servlet, prefix, null, mappings); - return this; - } - - /** - * 添加HttpServlet - * - * @param servlet HttpServlet - * @param mappings 匹配规则 - * @return HttpServer - */ - public HttpServer addHttpServlet(HttpServlet servlet, String... mappings) { - this.dispatcher.addServlet(servlet, null, null, mappings); - return this; - } - - /** - * 添加HttpServlet - * - * @param prefix url前缀 - * @param servlet HttpServlet - * @param conf 配置信息 - * @param mappings 匹配规则 - * @return HttpServer - */ - public HttpServer addHttpServlet(HttpServlet servlet, final String prefix, AnyValue conf, String... mappings) { - this.dispatcher.addServlet(servlet, prefix, conf, mappings); - return this; - } - - /** - * 添加WebSocketServlet - * - * @param WebSocket - * @param HttpServlet - * @param classLoader ClassLoader - * @param webSocketType WebSocket的类型 - * @param messageAgent MessageAgent - * @param prefix url前缀 - * @param conf 配置信息 - * @return RestServlet - */ - public T addRestWebSocketServlet( - final ClassLoader classLoader, - final Class webSocketType, - final MessageAgent messageAgent, - final String prefix, - final AnyValue conf) { - - T servlet = Rest.createRestWebSocketServlet(classLoader, webSocketType, messageAgent); - if (servlet != null) { - this.dispatcher.addServlet(servlet, prefix, conf); - } - return servlet; - } - - /** - * 添加RestServlet - * - * @param Service - * @param HttpServlet - * @param classLoader ClassLoader - * @param service Service对象 - * @param userType 用户数据类型 - * @param baseServletType RestServlet基类 - * @param prefix url前缀 - * @return RestServlet - */ - public T addRestServlet( - final ClassLoader classLoader, - final S service, - final Class userType, - final Class baseServletType, - final String prefix) { - - return addRestServlet(classLoader, null, service, userType, baseServletType, prefix); - } - - /** - * 添加RestServlet - * - * @param Service - * @param HttpServlet - * @param classLoader ClassLoader - * @param name 资源名 - * @param service Service对象 - * @param userType 用户数据类型 - * @param baseServletType RestServlet基类 - * @param prefix url前缀 - * @return RestServlet - */ - @SuppressWarnings("unchecked") - public T addRestServlet( - final ClassLoader classLoader, - final String name, - final S service, - final Class userType, - final Class baseServletType, - final String prefix) { - - T servlet = null; - addLock.lock(); - try { - final boolean sncp = Sncp.isSncpDyn(service); - final String resname = name == null ? (sncp ? Sncp.getResourceName(service) : "") : name; - final Class serviceType = Sncp.getResourceType(service); - - for (final HttpServlet item : this.dispatcher.getServlets()) { - Rest.RestDynSourceType dst = item.getClass().getAnnotation(Rest.RestDynSourceType.class); - if (dst != null && serviceType.equals(dst.value())) { - servlet = (T) item; - break; - } - } - final boolean first = servlet == null; - if (servlet == null) { - servlet = Rest.createRestServlet(classLoader, userType, baseServletType, serviceType, resname); - if (servlet != null) { - servlet._reqtopic = Rest.generateHttpReqTopic(Rest.getRestModule(service), application.getNodeid()); - } - } - if (servlet == null) { - return null; // 没有HttpMapping方法的HttpServlet调用Rest.createRestServlet就会返回null - } - try { // 若提供动态变更Service服务功能,则改Rest服务无法做出相应更新 - Field oneField = servlet.getClass().getDeclaredField(Rest.REST_SERVICE_FIELD_NAME); - oneField.setAccessible(true); - - Field mapField = servlet.getClass().getDeclaredField(Rest.REST_SERVICEMAP_FIELD_NAME); - mapField.setAccessible(true); - - Service oneService = (Service) oneField.get(servlet); - if (resname.isEmpty() || oneService == null) { - oneField.set(servlet, service); - } - Map map = (Map) mapField.get(servlet); - if (!resname.isEmpty() || oneService != null || map != null) { - if (map == null) { - map = new HashMap(); - } - map.put(resname, service); - if (oneService != null) { - map.put(Sncp.getResourceName(oneService), oneService); - } - mapField.set(servlet, map); - } - } catch (Exception e) { - throw new HttpException(serviceType + " generate rest servlet error", e); - } - if (first) { - this.dispatcher.addServlet(servlet, prefix, sncp ? Sncp.getResourceConf(service) : null); - } - } finally { - addLock.unlock(); - } - return servlet; - } - - @Override - @SuppressWarnings("unchecked") - protected HttpContext createContext() { - final int port = this.address.getPort(); - // this.bufferCapacity = Math.max(this.bufferCapacity, 16 * 1024 + 16); //兼容 HTTP 2.0; - this.bufferCapacity = Math.max(this.bufferCapacity, 1024); - final List defaultAddHeaders = new ArrayList<>(); - final List defaultSetHeaders = new ArrayList<>(); - boolean autoOptions = false; - int datePeriod = 0; - String plainContentType = null; - String jsonContentType = null; - HttpCookie defaultCookie = null; - String remoteAddrHeader = null; - String localHeader = null; - String localParameter = null; - AnyValue rpcAuthenticatorConfig = null; - - if (config != null) { - AnyValue reqs = config.getAnyValue("request"); - if (reqs != null) { - rpcAuthenticatorConfig = reqs.getAnyValue("rpc"); - AnyValue raddr = reqs.getAnyValue("remoteaddr"); - remoteAddrHeader = raddr == null ? null : raddr.getValue("value"); - if (remoteAddrHeader != null) { - if (remoteAddrHeader.startsWith("request.headers.")) { - remoteAddrHeader = remoteAddrHeader.substring("request.headers.".length()); - } else { - remoteAddrHeader = null; - } - } - AnyValue rlocale = reqs.getAnyValue("locale"); - String vlocale = rlocale == null ? null : rlocale.getValue("value"); - if (vlocale != null && !vlocale.isEmpty()) { - if (vlocale.startsWith("request.headers.")) { - localHeader = vlocale.substring("request.headers.".length()); - } else if (vlocale.startsWith("request.parameters.")) { - localParameter = vlocale.substring("request.parameters.".length()); - } else { - logger.log( - Level.SEVERE, - "request config locale.value not start with request.headers. or request.parameters. but " - + vlocale); - } - } - } - - AnyValue resps = config.getAnyValue("response"); - if (resps != null) { - AnyValue contenttypes = resps.getAnyValue("content-type"); - if (contenttypes == null) { - contenttypes = resps.getAnyValue("contenttype"); // 兼容旧的 - } - if (contenttypes != null) { - plainContentType = contenttypes.getValue("plain"); - jsonContentType = contenttypes.getValue("json"); - } - AnyValue[] addHeaders = resps.getAnyValues("addheader"); - if (addHeaders.length > 0) { - for (AnyValue addHeader : addHeaders) { - String val = addHeader.getValue("value"); - if (val == null) { - continue; - } - if (val.startsWith("request.parameters.")) { - defaultAddHeaders.add(new String[] { - addHeader.getValue("name"), val, val.substring("request.parameters.".length()), null - }); - } else if (val.startsWith("request.headers.")) { - defaultAddHeaders.add(new String[] { - addHeader.getValue("name"), val, val.substring("request.headers.".length()) - }); - } else if (val.startsWith("system.property.")) { - String v = System.getProperty(val.substring("system.property.".length())); - if (v != null) { - defaultAddHeaders.add(new String[] {addHeader.getValue("name"), v}); - } - } else { - defaultAddHeaders.add(new String[] {addHeader.getValue("name"), val}); - } - } - } - AnyValue[] setHeaders = resps.getAnyValues("setheader"); - if (setHeaders.length > 0) { - for (AnyValue setHeader : setHeaders) { - String val = setHeader.getValue("value"); - if (val == null) { - continue; - } - if (val.startsWith("request.parameters.")) { - defaultSetHeaders.add(new String[] { - setHeader.getValue("name"), val, val.substring("request.parameters.".length()), null - }); - } else if (val.startsWith("request.headers.")) { - defaultSetHeaders.add(new String[] { - setHeader.getValue("name"), val, val.substring("request.headers.".length()) - }); - } else if (val.startsWith("system.property.")) { - String v = System.getProperty(val.substring("system.property.".length())); - if (v != null) { - defaultSetHeaders.add(new String[] {setHeader.getValue("name"), v}); - } - } else { - defaultSetHeaders.add(new String[] {setHeader.getValue("name"), val}); - } - } - } - AnyValue defcookieValue = resps.getAnyValue("defcookie"); - if (defcookieValue != null) { - String domain = defcookieValue.getValue("domain"); - String path = defcookieValue.getValue("path"); - if (domain != null || path != null) { - defaultCookie = new HttpCookie("DEFAULTCOOKIE", ""); - defaultCookie.setDomain(domain); - defaultCookie.setPath(path); - } - } - AnyValue options = resps.getAnyValue("options"); - autoOptions = options != null && options.getBoolValue("auto", false); - - AnyValue dates = resps.getAnyValue("date"); - datePeriod = dates == null ? 0 : dates.getIntValue("period", 0); - } - } - Supplier dateSupplier = null; - if (datePeriod == 0) { - final ZoneId gmtZone = ZoneId.of("GMT"); - dateSupplier = () -> - ("Date: " + RFC_1123_DATE_TIME.format(java.time.ZonedDateTime.now(gmtZone)) + "\r\n").getBytes(); - } else if (datePeriod > 0) { - if (this.dateScheduler == null) { - this.dateScheduler = new ScheduledThreadPoolExecutor(1, (Runnable r) -> { - final Thread t = new Thread(r, "Redkale-HTTP:" + port + "-DateSchedule-Thread"); - t.setDaemon(true); - return t; - }); - this.dateScheduler.setRemoveOnCancelPolicy(true); - final ObjectRef dateRef = new ObjectRef<>(); - final DateFormat gmtDateFormat = new SimpleDateFormat("EEE, d MMM y HH:mm:ss z", Locale.ENGLISH); - gmtDateFormat.setTimeZone(TimeZone.getTimeZone("GMT")); - dateRef.set(("Date: " + gmtDateFormat.format(new Date()) + "\r\n").getBytes()); - final int dp = datePeriod; - this.dateScheduler.scheduleAtFixedRate( - () -> { - try { - dateRef.set(("Date: " + gmtDateFormat.format(new Date()) + "\r\n").getBytes()); - } catch (Throwable t) { - logger.log( - Level.SEVERE, - "HttpServer schedule(interval=" + dp + "ms) date-format error", - t); - } - }, - 1000 - System.currentTimeMillis() % 1000, - datePeriod, - TimeUnit.MILLISECONDS); - dateSupplier = () -> dateRef.get(); - } - } - HttpRender httpRender = null; - AnyValue renderConfig = null; - { // 设置TemplateEngine - renderConfig = config.getAnyValue("render"); - if (renderConfig != null) { - String renderType = renderConfig.getValue("value"); - try { - Class clazz = Thread.currentThread().getContextClassLoader().loadClass(renderType); - RedkaleClassLoader.putReflectionDeclaredConstructors(clazz, clazz.getName()); - HttpRender render = - (HttpRender) clazz.getDeclaredConstructor().newInstance(); - getResourceFactory().inject(render); - httpRender = render; - } catch (Throwable e) { - logger.log(Level.WARNING, "init HttpRender(" + renderType + ") error", e); - } - } - } - - final String addrHeader = remoteAddrHeader; - - this.respConfig = new HttpResponseConfig(); - respConfig.plainContentType = plainContentType; - respConfig.jsonContentType = jsonContentType; - respConfig.defaultAddHeaders = - defaultAddHeaders.isEmpty() ? null : defaultAddHeaders.toArray(new String[defaultAddHeaders.size()][]); - respConfig.defaultSetHeaders = - defaultSetHeaders.isEmpty() ? null : defaultSetHeaders.toArray(new String[defaultSetHeaders.size()][]); - respConfig.defaultCookie = defaultCookie; - respConfig.autoOptions = autoOptions; - respConfig.dateSupplier = dateSupplier; - respConfig.httpRender = httpRender; - respConfig.renderConfig = renderConfig; - respConfig.init(config); - - final HttpContextConfig contextConfig = new HttpContextConfig(); - initContextConfig(contextConfig); - contextConfig.remoteAddrHeader = addrHeader; - contextConfig.localHeader = localHeader; - contextConfig.localParameter = localParameter; - contextConfig.rpcAuthenticatorConfig = rpcAuthenticatorConfig; - if (rpcAuthenticatorConfig != null) { - String impl = rpcAuthenticatorConfig.getValue("authenticator", "").trim(); - if (impl.isEmpty()) { - throw new HttpException("init HttpRpcAuthenticator(" + impl + ") error"); - } - try { - Class implClass = serverClassLoader.loadClass(impl); - if (!HttpRpcAuthenticator.class.isAssignableFrom(implClass)) { - throw new HttpException("" + impl + " not HttpRpcAuthenticator implement class"); - } - RedkaleClassLoader.putReflectionPublicConstructors(implClass, implClass.getName()); - contextConfig.rpcAuthenticator = - (HttpRpcAuthenticator) implClass.getConstructor().newInstance(); - } catch (RuntimeException ex) { - throw ex; - } catch (Exception e) { - throw new HttpException("init HttpRpcAuthenticator(" + impl + ") error", e); - } - } - return new HttpContext(contextConfig); - } - - @Override - protected void postPrepareInit() { - HttpRender httpRender = this.respConfig.httpRender; - if (httpRender != null) { - httpRender.init(context, this.respConfig.renderConfig); - } - } - - @Override - protected ByteBufferPool createSafeBufferPool(LongAdder createCounter, LongAdder cycleCounter, int bufferPoolSize) { - this.safeBufferPool = - ByteBufferPool.createSafePool(createCounter, cycleCounter, bufferPoolSize, this.bufferCapacity); - return this.safeBufferPool; - } - - @Override - protected ObjectPool createSafeResponsePool( - LongAdder createCounter, LongAdder cycleCounter, int responsePoolSize) { - Creator creator = - (Object... params) -> new HttpResponse(this.context, new HttpRequest(this.context), this.respConfig); - ObjectPool pool = ObjectPool.createSafePool( - createCounter, cycleCounter, responsePoolSize, creator, HttpResponse::prepare, HttpResponse::recycle); - return pool; - } -} +/* + * 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.http; + +import static java.time.format.DateTimeFormatter.RFC_1123_DATE_TIME; + +import java.io.IOException; +import java.lang.reflect.Field; +import java.net.HttpCookie; +import java.text.*; +import java.time.ZoneId; +import java.util.*; +import java.util.concurrent.*; +import java.util.concurrent.atomic.LongAdder; +import java.util.concurrent.locks.ReentrantLock; +import java.util.function.BiConsumer; +import java.util.function.Supplier; +import java.util.logging.Level; +import org.redkale.boot.Application; +import org.redkale.inject.ResourceFactory; +import org.redkale.mq.spi.MessageAgent; +import org.redkale.net.Server; +import org.redkale.net.http.HttpContext.HttpContextConfig; +import org.redkale.net.http.HttpResponse.HttpResponseConfig; +import org.redkale.net.sncp.Sncp; +import org.redkale.service.Service; +import org.redkale.util.*; + +/** + * Http服务器 + * + *

详情见: https://redkale.org + * + * @author zhangjx + */ +public class HttpServer extends Server { + + private ScheduledThreadPoolExecutor dateScheduler; + + private HttpResponseConfig respConfig; + + private ByteBufferPool safeBufferPool; + + private final ReentrantLock addLock = new ReentrantLock(); + + // 配置 APP_EXECUTOR资源为null + // RESNAME_APP_EXECUTOR + protected ExecutorService workExecutor; + + public HttpServer() { + this(null, System.currentTimeMillis(), ResourceFactory.create()); + } + + public HttpServer(ResourceFactory resourceFactory) { + this(null, System.currentTimeMillis(), resourceFactory); + } + + public HttpServer(Application application) { + this( + application, + System.currentTimeMillis(), + application.getResourceFactory().createChild()); + } + + public HttpServer(Application application, long serverStartTime, ResourceFactory resourceFactory) { + super(application, serverStartTime, "TCP", resourceFactory, new HttpDispatcherServlet()); + this.workExecutor = application == null ? null : application.getWorkExecutor(); + } + + @Override + public void init(AnyValue config) throws Exception { + super.init(config); + if (context.rpcAuthenticator != null) { + context.rpcAuthenticator.init(context.rpcAuthenticatorConfig); + } + } + + @Override + protected void postStart() { + ((HttpDispatcherServlet) this.dispatcher).postStart(this.context, config); + } + + @Override + public void destroy(final AnyValue config) throws Exception { + super.destroy(config); + if (this.dateScheduler != null) { + this.dateScheduler.shutdownNow(); + this.dateScheduler = null; + } + if (context.rpcAuthenticator != null) { + context.rpcAuthenticator.destroy(context.rpcAuthenticatorConfig); + } + HttpResponseConfig respConf = this.respConfig; + HttpRender httpRender = respConf.httpRender; + if (httpRender != null) { + httpRender.destroy(context, respConf.renderConfig); + } + } + + @Override + protected String startExtLog() { + return context.lazyHeaders ? ", lazyHeaders: true" : ""; + } + + public List getHttpServlets() { + return this.dispatcher.getServlets(); + } + + public List getHttpFilters() { + return this.dispatcher.getFilters(); + } + + public HttpResponseConfig getResponseConfig() { + return respConfig; + } + + /** + * 获取静态资源HttpServlet + * + * @return HttpServlet + */ + public HttpResourceServlet getResourceServlet() { + return (HttpResourceServlet) ((HttpDispatcherServlet) this.dispatcher).resourceHttpServlet; + } + + /** + * 删除HttpServlet + * + * @param service Service + * @return HttpServlet + */ + public HttpServlet removeHttpServlet(Service service) { + return ((HttpDispatcherServlet) this.dispatcher).removeHttpServlet(service); + } + + /** + * 删除HttpServlet + * + * @param 泛型 + * @param websocketOrServletType Class + * @return HttpServlet + */ + public HttpServlet removeHttpServlet(Class websocketOrServletType) { + return ((HttpDispatcherServlet) this.dispatcher).removeHttpServlet(websocketOrServletType); + } + + /** + * 屏蔽请求URL的正则表达式 + * + * @param urlreg 正则表达式 + * @return 是否成功 + */ + public boolean addForbidURIReg(final String urlreg) { + return ((HttpDispatcherServlet) this.dispatcher).addForbidURIRegx(urlreg); + } + + /** + * 删除屏蔽请求URL的正则表达式 + * + * @param urlreg 正则表达式 + * @return 是否成功 + */ + public boolean removeForbidURIReg(final String urlreg) { + return ((HttpDispatcherServlet) this.dispatcher).removeForbidURIReg(urlreg); + } + + /** + * 删除HttpFilter + * + * @param 泛型 + * @param filterClass HttpFilter类 + * @return HttpFilter + */ + public T removeHttpFilter(Class filterClass) { + return (T) this.dispatcher.removeFilter(filterClass); + } + + /** + * 添加HttpFilter + * + * @param filter HttpFilter + * @param conf AnyValue + * @return HttpServer + */ + public HttpServer addHttpFilter(HttpFilter filter, AnyValue conf) { + this.dispatcher.addFilter(filter, conf); + return this; + } + + /** + * 添加HttpServlet + * + * @param mapping 匹配规则 + * @param servlet HttpServlet + * @return HttpServer + */ + public HttpServer addHttpServlet(String mapping, HttpServlet servlet) { + this.dispatcher.addServlet(servlet, null, null, mapping); + return this; + } + + /** + * 添加HttpServlet + * + * @param mapping 匹配规则 + * @param consumer HttpServlet + * @return HttpServer + */ + public HttpServer addHttpServlet(String mapping, BiConsumer consumer) { + this.dispatcher.addServlet( + new HttpServlet() { + @Override + public void execute(HttpRequest request, HttpResponse response) throws IOException { + consumer.accept(request, response); + } + }, + null, + null, + mapping); + return this; + } + + /** + * 添加HttpServlet + * + * @param prefix url前缀 + * @param servlet HttpServlet + * @param mappings 匹配规则 + * @return HttpServer + */ + public HttpServer addHttpServlet(String prefix, HttpServlet servlet, String... mappings) { + this.dispatcher.addServlet(servlet, prefix, null, mappings); + return this; + } + + /** + * 添加HttpServlet + * + * @param servlet HttpServlet + * @param mappings 匹配规则 + * @return HttpServer + */ + public HttpServer addHttpServlet(HttpServlet servlet, String... mappings) { + this.dispatcher.addServlet(servlet, null, null, mappings); + return this; + } + + /** + * 添加HttpServlet + * + * @param prefix url前缀 + * @param servlet HttpServlet + * @param conf 配置信息 + * @param mappings 匹配规则 + * @return HttpServer + */ + public HttpServer addHttpServlet(HttpServlet servlet, final String prefix, AnyValue conf, String... mappings) { + this.dispatcher.addServlet(servlet, prefix, conf, mappings); + return this; + } + + /** + * 添加WebSocketServlet + * + * @param WebSocket + * @param HttpServlet + * @param classLoader ClassLoader + * @param webSocketType WebSocket的类型 + * @param messageAgent MessageAgent + * @param prefix url前缀 + * @param conf 配置信息 + * @return RestServlet + */ + public T addRestWebSocketServlet( + final ClassLoader classLoader, + final Class webSocketType, + final MessageAgent messageAgent, + final String prefix, + final AnyValue conf) { + + T servlet = Rest.createRestWebSocketServlet(classLoader, webSocketType, messageAgent); + if (servlet != null) { + this.dispatcher.addServlet(servlet, prefix, conf); + } + return servlet; + } + + /** + * 添加RestServlet + * + * @param Service + * @param HttpServlet + * @param classLoader ClassLoader + * @param service Service对象 + * @param userType 用户数据类型 + * @param baseServletType RestServlet基类 + * @param prefix url前缀 + * @return RestServlet + */ + public T addRestServlet( + final ClassLoader classLoader, + final S service, + final Class userType, + final Class baseServletType, + final String prefix) { + + return addRestServlet(classLoader, null, service, userType, baseServletType, prefix); + } + + /** + * 添加RestServlet + * + * @param Service + * @param HttpServlet + * @param classLoader ClassLoader + * @param name 资源名 + * @param service Service对象 + * @param userType 用户数据类型 + * @param baseServletType RestServlet基类 + * @param prefix url前缀 + * @return RestServlet + */ + @SuppressWarnings("unchecked") + public T addRestServlet( + final ClassLoader classLoader, + final String name, + final S service, + final Class userType, + final Class baseServletType, + final String prefix) { + + T servlet = null; + addLock.lock(); + try { + final boolean sncp = Sncp.isSncpDyn(service); + final String resname = name == null ? (sncp ? Sncp.getResourceName(service) : "") : name; + final Class serviceType = Sncp.getResourceType(service); + + for (final HttpServlet item : this.dispatcher.getServlets()) { + Rest.RestDynSourceType dst = item.getClass().getAnnotation(Rest.RestDynSourceType.class); + if (dst != null && serviceType.equals(dst.value())) { + servlet = (T) item; + break; + } + } + final boolean first = servlet == null; + if (servlet == null) { + servlet = Rest.createRestServlet(classLoader, userType, baseServletType, serviceType, resname); + if (servlet != null) { + servlet._reqtopic = Rest.generateHttpReqTopic(Rest.getRestModule(service), application.getNodeid()); + } + } + if (servlet == null) { + return null; // 没有HttpMapping方法的HttpServlet调用Rest.createRestServlet就会返回null + } + try { // 若提供动态变更Service服务功能,则改Rest服务无法做出相应更新 + Field oneField = servlet.getClass().getDeclaredField(Rest.REST_SERVICE_FIELD_NAME); + oneField.setAccessible(true); + + Field mapField = servlet.getClass().getDeclaredField(Rest.REST_SERVICEMAP_FIELD_NAME); + mapField.setAccessible(true); + + Service oneService = (Service) oneField.get(servlet); + if (resname.isEmpty() || oneService == null) { + oneField.set(servlet, service); + } + Map map = (Map) mapField.get(servlet); + if (!resname.isEmpty() || oneService != null || map != null) { + if (map == null) { + map = new HashMap(); + } + map.put(resname, service); + if (oneService != null) { + map.put(Sncp.getResourceName(oneService), oneService); + } + mapField.set(servlet, map); + } + } catch (Exception e) { + throw new HttpException(serviceType + " generate rest servlet error", e); + } + if (first) { + this.dispatcher.addServlet(servlet, prefix, sncp ? Sncp.getResourceConf(service) : null); + } + } finally { + addLock.unlock(); + } + return servlet; + } + + @Override + @SuppressWarnings("unchecked") + protected HttpContext createContext() { + final int port = this.address.getPort(); + // this.bufferCapacity = Math.max(this.bufferCapacity, 16 * 1024 + 16); //兼容 HTTP 2.0; + this.bufferCapacity = Math.max(this.bufferCapacity, 1024); + final List defaultAddHeaders = new ArrayList<>(); + final List defaultSetHeaders = new ArrayList<>(); + boolean autoOptions = false; + int datePeriod = 0; + String plainContentType = null; + String jsonContentType = null; + HttpCookie defaultCookie = null; + String remoteAddrHeader = null; + String localHeader = null; + String localParameter = null; + AnyValue rpcAuthenticatorConfig = null; + + if (config != null) { + AnyValue reqs = config.getAnyValue("request"); + if (reqs != null) { + rpcAuthenticatorConfig = reqs.getAnyValue("rpc"); + AnyValue raddr = reqs.getAnyValue("remoteaddr"); + remoteAddrHeader = raddr == null ? null : raddr.getValue("value"); + if (remoteAddrHeader != null) { + if (remoteAddrHeader.startsWith("request.headers.")) { + remoteAddrHeader = remoteAddrHeader.substring("request.headers.".length()); + } else { + remoteAddrHeader = null; + } + } + AnyValue rlocale = reqs.getAnyValue("locale"); + String vlocale = rlocale == null ? null : rlocale.getValue("value"); + if (vlocale != null && !vlocale.isEmpty()) { + if (vlocale.startsWith("request.headers.")) { + localHeader = vlocale.substring("request.headers.".length()); + } else if (vlocale.startsWith("request.parameters.")) { + localParameter = vlocale.substring("request.parameters.".length()); + } else { + logger.log( + Level.SEVERE, + "request config locale.value not start with request.headers. or request.parameters. but " + + vlocale); + } + } + } + + AnyValue resps = config.getAnyValue("response"); + if (resps != null) { + AnyValue contenttypes = resps.getAnyValue("content-type"); + if (contenttypes == null) { + contenttypes = resps.getAnyValue("contenttype"); // 兼容旧的 + } + if (contenttypes != null) { + plainContentType = contenttypes.getValue("plain"); + jsonContentType = contenttypes.getValue("json"); + } + AnyValue[] addHeaders = resps.getAnyValues("addheader"); + if (addHeaders.length > 0) { + for (AnyValue addHeader : addHeaders) { + String val = addHeader.getValue("value"); + if (val == null) { + continue; + } + if (val.startsWith("request.parameters.")) { + defaultAddHeaders.add(new String[] { + addHeader.getValue("name"), val, val.substring("request.parameters.".length()), null + }); + } else if (val.startsWith("request.headers.")) { + defaultAddHeaders.add(new String[] { + addHeader.getValue("name"), val, val.substring("request.headers.".length()) + }); + } else if (val.startsWith("system.property.")) { + String v = System.getProperty(val.substring("system.property.".length())); + if (v != null) { + defaultAddHeaders.add(new String[] {addHeader.getValue("name"), v}); + } + } else { + defaultAddHeaders.add(new String[] {addHeader.getValue("name"), val}); + } + } + } + AnyValue[] setHeaders = resps.getAnyValues("setheader"); + if (setHeaders.length > 0) { + for (AnyValue setHeader : setHeaders) { + String val = setHeader.getValue("value"); + if (val == null) { + continue; + } + if (val.startsWith("request.parameters.")) { + defaultSetHeaders.add(new String[] { + setHeader.getValue("name"), val, val.substring("request.parameters.".length()), null + }); + } else if (val.startsWith("request.headers.")) { + defaultSetHeaders.add(new String[] { + setHeader.getValue("name"), val, val.substring("request.headers.".length()) + }); + } else if (val.startsWith("system.property.")) { + String v = System.getProperty(val.substring("system.property.".length())); + if (v != null) { + defaultSetHeaders.add(new String[] {setHeader.getValue("name"), v}); + } + } else { + defaultSetHeaders.add(new String[] {setHeader.getValue("name"), val}); + } + } + } + AnyValue defcookieValue = resps.getAnyValue("defcookie"); + if (defcookieValue != null) { + String domain = defcookieValue.getValue("domain"); + String path = defcookieValue.getValue("path"); + if (domain != null || path != null) { + defaultCookie = new HttpCookie("DEFAULTCOOKIE", ""); + defaultCookie.setDomain(domain); + defaultCookie.setPath(path); + } + } + AnyValue options = resps.getAnyValue("options"); + autoOptions = options != null && options.getBoolValue("auto", false); + + AnyValue dates = resps.getAnyValue("date"); + datePeriod = dates == null ? 0 : dates.getIntValue("period", 0); + } + } + Supplier dateSupplier = null; + if (datePeriod == 0) { + final ZoneId gmtZone = ZoneId.of("GMT"); + dateSupplier = () -> + ("Date: " + RFC_1123_DATE_TIME.format(java.time.ZonedDateTime.now(gmtZone)) + "\r\n").getBytes(); + } else if (datePeriod > 0) { + if (this.dateScheduler == null) { + this.dateScheduler = new ScheduledThreadPoolExecutor(1, (Runnable r) -> { + final Thread t = new Thread(r, "Redkale-HTTP:" + port + "-DateSchedule-Thread"); + t.setDaemon(true); + return t; + }); + this.dateScheduler.setRemoveOnCancelPolicy(true); + final ObjectRef dateRef = new ObjectRef<>(); + final DateFormat gmtDateFormat = new SimpleDateFormat("EEE, d MMM y HH:mm:ss z", Locale.ENGLISH); + gmtDateFormat.setTimeZone(TimeZone.getTimeZone("GMT")); + dateRef.set(("Date: " + gmtDateFormat.format(new Date()) + "\r\n").getBytes()); + final int dp = datePeriod; + this.dateScheduler.scheduleAtFixedRate( + () -> { + try { + dateRef.set(("Date: " + gmtDateFormat.format(new Date()) + "\r\n").getBytes()); + } catch (Throwable t) { + logger.log( + Level.SEVERE, + "HttpServer schedule(interval=" + dp + "ms) date-format error", + t); + } + }, + 1000 - System.currentTimeMillis() % 1000, + datePeriod, + TimeUnit.MILLISECONDS); + dateSupplier = () -> dateRef.get(); + } + } + HttpRender httpRender = null; + AnyValue renderConfig = null; + { // 设置TemplateEngine + renderConfig = config.getAnyValue("render"); + if (renderConfig != null) { + String renderType = renderConfig.getValue("value"); + try { + Class clazz = Thread.currentThread().getContextClassLoader().loadClass(renderType); + RedkaleClassLoader.putReflectionDeclaredConstructors(clazz, clazz.getName()); + HttpRender render = + (HttpRender) clazz.getDeclaredConstructor().newInstance(); + getResourceFactory().inject(render); + httpRender = render; + } catch (Throwable e) { + logger.log(Level.WARNING, "init HttpRender(" + renderType + ") error", e); + } + } + } + + final String addrHeader = remoteAddrHeader; + + this.respConfig = new HttpResponseConfig(); + respConfig.plainContentType = plainContentType; + respConfig.jsonContentType = jsonContentType; + respConfig.defaultAddHeaders = + defaultAddHeaders.isEmpty() ? null : defaultAddHeaders.toArray(new String[defaultAddHeaders.size()][]); + respConfig.defaultSetHeaders = + defaultSetHeaders.isEmpty() ? null : defaultSetHeaders.toArray(new String[defaultSetHeaders.size()][]); + respConfig.defaultCookie = defaultCookie; + respConfig.autoOptions = autoOptions; + respConfig.dateSupplier = dateSupplier; + respConfig.httpRender = httpRender; + respConfig.renderConfig = renderConfig; + respConfig.init(config); + + final HttpContextConfig contextConfig = new HttpContextConfig(); + initContextConfig(contextConfig); + contextConfig.remoteAddrHeader = addrHeader; + contextConfig.localHeader = localHeader; + contextConfig.localParameter = localParameter; + contextConfig.rpcAuthenticatorConfig = rpcAuthenticatorConfig; + if (rpcAuthenticatorConfig != null) { + String impl = rpcAuthenticatorConfig.getValue("authenticator", "").trim(); + if (impl.isEmpty()) { + throw new HttpException("init HttpRpcAuthenticator(" + impl + ") error"); + } + try { + Class implClass = serverClassLoader.loadClass(impl); + if (!HttpRpcAuthenticator.class.isAssignableFrom(implClass)) { + throw new HttpException("" + impl + " not HttpRpcAuthenticator implement class"); + } + RedkaleClassLoader.putReflectionPublicConstructors(implClass, implClass.getName()); + contextConfig.rpcAuthenticator = + (HttpRpcAuthenticator) implClass.getConstructor().newInstance(); + } catch (RuntimeException ex) { + throw ex; + } catch (Exception e) { + throw new HttpException("init HttpRpcAuthenticator(" + impl + ") error", e); + } + } + return new HttpContext(contextConfig); + } + + @Override + protected void postPrepareInit() { + HttpRender httpRender = this.respConfig.httpRender; + if (httpRender != null) { + httpRender.init(context, this.respConfig.renderConfig); + } + } + + @Override + protected ByteBufferPool createSafeBufferPool(LongAdder createCounter, LongAdder cycleCounter, int bufferPoolSize) { + this.safeBufferPool = + ByteBufferPool.createSafePool(createCounter, cycleCounter, bufferPoolSize, this.bufferCapacity); + return this.safeBufferPool; + } + + @Override + protected ObjectPool createSafeResponsePool( + LongAdder createCounter, LongAdder cycleCounter, int responsePoolSize) { + Creator creator = + (Object... params) -> new HttpResponse(this.context, new HttpRequest(this.context), this.respConfig); + ObjectPool pool = ObjectPool.createSafePool( + createCounter, cycleCounter, responsePoolSize, creator, HttpResponse::prepare, HttpResponse::recycle); + return pool; + } +} diff --git a/src/main/java/org/redkale/net/http/Rest.java b/src/main/java/org/redkale/net/http/Rest.java index b13b98281..e0e3ef61b 100644 --- a/src/main/java/org/redkale/net/http/Rest.java +++ b/src/main/java/org/redkale/net/http/Rest.java @@ -1,4535 +1,4535 @@ -/* - * 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.http; - -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; -import static org.redkale.asm.ClassWriter.COMPUTE_FRAMES; -import static org.redkale.asm.Opcodes.*; -import static org.redkale.util.Utility.isEmpty; - -import java.io.*; -import java.lang.annotation.*; -import java.lang.reflect.*; -import java.net.InetSocketAddress; -import java.nio.channels.CompletionHandler; -import java.util.*; -import java.util.concurrent.CompletionStage; -import org.redkale.annotation.*; -import org.redkale.annotation.ClassDepends; -import org.redkale.annotation.Comment; -import org.redkale.asm.*; -import org.redkale.asm.Type; -import org.redkale.convert.*; -import org.redkale.convert.json.*; -import org.redkale.inject.ResourceFactory; -import org.redkale.mq.spi.MessageAgent; -import org.redkale.net.*; -import org.redkale.net.sncp.Sncp; -import org.redkale.service.*; -import org.redkale.source.Flipper; -import org.redkale.util.*; -import org.redkale.util.RedkaleClassLoader.DynBytesClassLoader; - -/** - * 详情见: https://redkale.org - * - * @author zhangjx - */ -@SuppressWarnings("unchecked") -public final class Rest { - - // 请求是否为rpc协议,值类型: 布尔,取值为true、false - public static final String REST_HEADER_RPC = "Rest-Rpc"; - - // traceid,值类型: 字符串 - public static final String REST_HEADER_TRACEID = "Rest-Traceid"; - - // 当前用户ID值,值类型: 字符串 - public static final String REST_HEADER_CURRUSERID = "Rest-Curruserid"; - - // 请求所需的RestService的资源名,值类型: 字符串 - public static final String REST_HEADER_RESNAME = "Rest-Resname"; - - // 请求参数的反序列化种类,值类型: 字符串,取值为ConvertType枚举值名 - public static final String REST_HEADER_REQ_CONVERT = "Rest-Req-Convert"; - - // 响应结果的序列化种类,值类型: 字符串,取值为ConvertType枚举值名 - public static final String REST_HEADER_RESP_CONVERT = "Rest-Resp-Convert"; - - // --------------------------------------------------------------------------------------------------- - static final String REST_TOSTRINGOBJ_FIELD_NAME = "_redkale_toStringSupplier"; - - static final String REST_CONVERT_FIELD_PREFIX = "_redkale_restConvert_"; - - static final String REST_SERVICE_FIELD_NAME = "_redkale_service"; - - static final String REST_SERVICEMAP_FIELD_NAME = - "_redkale_serviceMap"; // 如果只有name=""的Service资源,则实例中_servicemap必须为null - - private static final String REST_PARAMTYPES_FIELD_NAME = - "_redkale_paramTypes"; // 存在泛型的参数数组 Type[][] 第1维度是方法的下标, 第二维度是参数的下标 - - private static final String REST_RETURNTYPES_FIELD_NAME = "_redkale_returnTypes"; // 存在泛型的结果数组 - - private static final java.lang.reflect.Type TYPE_RETRESULT_STRING = new TypeToken>() {}.getType(); - - private static final Set EXCLUDERMETHODS = new HashSet<>(); - - static { - for (Method m : Object.class.getMethods()) { - EXCLUDERMETHODS.add(m.getName()); - } - } - - /** 用于标记由Rest.createRestServlet 方法创建的RestServlet */ - @Inherited - @Documented - @Target({TYPE}) - @Retention(RUNTIME) - public static @interface RestDyn { - - // 是否不需要解析HttpHeader,对应HttpContext.lazyHeaders - boolean simple() default false; - - // 动态生成的类的子类需要关联一下,否则在运行过程中可能出现NoClassDefFoundError - Class[] types() default {}; - } - - /** 用于标记由Rest.createRestServlet 方法创建的RestServlet */ - @Inherited - @Documented - @Target({TYPE}) - @Retention(RUNTIME) - public static @interface RestDynSourceType { - - Class value(); - } - - private Rest() {} - - public static JsonFactory createJsonFactory(RestConvert[] converts, RestConvertCoder[] coders) { - return createJsonFactory(-1, converts, coders); - } - - public static JsonFactory createJsonFactory(int features, RestConvert[] converts, RestConvertCoder[] coders) { - if ((converts == null || converts.length < 1) && (coders == null || coders.length < 1)) { - return JsonFactory.root(); - } - final JsonFactory childFactory = JsonFactory.create(); - if (features > -1) { - childFactory.withFeatures(features); - } - List types = new ArrayList<>(); - Set reloadTypes = new HashSet<>(); - if (coders != null) { - for (RestConvertCoder rcc : coders) { - reloadTypes.add(rcc.type()); - childFactory.register(rcc.type(), rcc.field(), (SimpledCoder) - Creator.create(rcc.coder()).create()); - } - } - if (converts != null) { - for (RestConvert rc : converts) { - if (rc.type() == void.class || rc.type() == Void.class) { - return JsonFactory.create().skipAllIgnore(true); - } - if (types.contains(rc.type())) { - throw new RestException("@RestConvert type(" + rc.type() + ") repeat"); - } - if (rc.skipIgnore()) { - childFactory.registerSkipIgnore(rc.type()); - childFactory.reloadCoder(rc.type()); - } else if (rc.onlyColumns().length > 0) { - childFactory.registerIgnoreAll(rc.type(), rc.onlyColumns()); - childFactory.reloadCoder(rc.type()); - } else { - childFactory.register(rc.type(), false, rc.convertColumns()); - childFactory.register(rc.type(), true, rc.ignoreColumns()); - childFactory.reloadCoder(rc.type()); - } - types.add(rc.type()); - if (rc.features() > -1) { - childFactory.withFeatures(rc.features()); - } - } - } - for (Class type : reloadTypes) { - childFactory.reloadCoder(type); - } - return childFactory; - } - - static String getWebModuleNameLowerCase(Class serviceType) { - final RestService controller = serviceType.getAnnotation(RestService.class); - if (controller == null) { - return serviceType.getSimpleName().replaceAll("Service.*$", "").toLowerCase(); - } - if (controller.ignore()) { - return null; - } - return (!controller.name().isEmpty()) - ? controller.name().trim() - : serviceType.getSimpleName().replaceAll("Service.*$", "").toLowerCase(); - } - - static String getWebModuleName(Class serviceType) { - final RestService controller = serviceType.getAnnotation(RestService.class); - if (controller == null) { - return serviceType.getSimpleName().replaceAll("Service.*$", ""); - } - if (controller.ignore()) { - return null; - } - return (!controller.name().isEmpty()) - ? controller.name().trim() - : serviceType.getSimpleName().replaceAll("Service.*$", ""); - } - - /** - * 判断HttpServlet是否为Rest动态生成的 - * - * @param servlet 检测的HttpServlet - * @return 是否是动态生成的RestHttpServlet - */ - public static boolean isRestDyn(HttpServlet servlet) { - return servlet.getClass().getAnnotation(RestDyn.class) != null; - } - - /** - * 判断HttpServlet是否为Rest动态生成的,且simple, 不需要读取http-header的方法视为simple=true - * - * @param servlet 检测的HttpServlet - * @return 是否是动态生成的RestHttpServlet - */ - static boolean isSimpleRestDyn(HttpServlet servlet) { - RestDyn dyn = servlet.getClass().getAnnotation(RestDyn.class); - return dyn != null && dyn.simple(); - } - - /** - * 获取Rest动态生成HttpServlet里的Service对象,若不是Rest动态生成的HttpServlet,返回null - * - * @param servlet HttpServlet - * @return Service - */ - public static Service getService(HttpServlet servlet) { - if (servlet == null) { - return null; - } - if (!isRestDyn(servlet)) { - return null; - } - try { - Field ts = servlet.getClass().getDeclaredField(REST_SERVICE_FIELD_NAME); - ts.setAccessible(true); - return (Service) ts.get(servlet); - } catch (Exception e) { - return null; - } - } - - public static Map getServiceMap(HttpServlet servlet) { - if (servlet == null) { - return null; - } - try { - Field ts = servlet.getClass().getDeclaredField(REST_SERVICEMAP_FIELD_NAME); - ts.setAccessible(true); - return (Map) ts.get(servlet); - } catch (Exception e) { - return null; - } - } - - public static void setServiceMap(HttpServlet servlet, Map map) { - if (servlet == null) { - return; - } - try { - Field ts = servlet.getClass().getDeclaredField(REST_SERVICEMAP_FIELD_NAME); - ts.setAccessible(true); - ts.set(servlet, map); - } catch (Exception e) { - throw new RestException(e); - } - } - - public static String getRestModule(Service service) { - final RestService controller = service.getClass().getAnnotation(RestService.class); - if (controller != null && !controller.name().isEmpty()) { - return controller.name(); - } - final Class serviceType = Sncp.getResourceType(service); - return serviceType.getSimpleName().replaceAll("Service.*$", "").toLowerCase(); - } - - // 格式: http.req.module.user - public static String generateHttpReqTopic(String module, String nodeid) { - return getHttpReqTopicPrefix() + "module." + module.toLowerCase(); - } - - // 格式: http.req.module.user - public static String generateHttpReqTopic(String module, String resname, String nodeid) { - return getHttpReqTopicPrefix() + "module." + module.toLowerCase() - + (resname == null || resname.isEmpty() ? "" : ("-" + resname)); - } - - public static String generateHttpReqTopic(Service service, String nodeid) { - String resname = Sncp.getResourceName(service); - String module = getRestModule(service).toLowerCase(); - return getHttpReqTopicPrefix() + "module." + module + (resname.isEmpty() ? "" : ("-" + resname)); - } - - public static String getHttpReqTopicPrefix() { - return "http.req."; - } - - public static String getHttpRespTopicPrefix() { - return "http.resp."; - } - - // 仅供Rest动态构建里 currentUserid() 使用 - @ClassDepends - public static T orElse(T t, T defValue) { - return t == null ? defValue : t; - } - - public static T createRestWebSocketServlet( - final ClassLoader classLoader, final Class webSocketType, MessageAgent messageAgent) { - if (webSocketType == null) { - throw new RestException("Rest WebSocket Class is null on createRestWebSocketServlet"); - } - if (Modifier.isAbstract(webSocketType.getModifiers())) { - throw new RestException( - "Rest WebSocket Class(" + webSocketType + ") cannot abstract on createRestWebSocketServlet"); - } - if (Modifier.isFinal(webSocketType.getModifiers())) { - throw new RestException( - "Rest WebSocket Class(" + webSocketType + ") cannot final on createRestWebSocketServlet"); - } - final RestWebSocket rws = webSocketType.getAnnotation(RestWebSocket.class); - if (rws == null || rws.ignore()) { - throw new RestException("Rest WebSocket Class(" + webSocketType - + ") have not @RestWebSocket or @RestWebSocket.ignore=true on createRestWebSocketServlet"); - } - boolean valid = false; - for (Constructor c : webSocketType.getDeclaredConstructors()) { - if (c.getParameterCount() == 0 - && (Modifier.isPublic(c.getModifiers()) || Modifier.isProtected(c.getModifiers()))) { - valid = true; - break; - } - } - if (!valid) { - throw new RestException("Rest WebSocket Class(" + webSocketType - + ") must have public or protected Constructor on createRestWebSocketServlet"); - } - final String rwsname = ResourceFactory.getResourceName(rws.name()); - if (!checkName(rws.catalog())) { - throw new RestException(webSocketType.getName() + " have illegal " + RestWebSocket.class.getSimpleName() - + ".catalog, only 0-9 a-z A-Z _ cannot begin 0-9"); - } - if (!checkName(rwsname)) { - throw new RestException(webSocketType.getName() + " have illegal " + RestWebSocket.class.getSimpleName() - + ".name, only 0-9 a-z A-Z _ cannot begin 0-9"); - } - - // ---------------------------------------------------------------------------------------- - final Set resourcesFieldSet = new LinkedHashSet<>(); - final ClassLoader loader = classLoader == null ? Thread.currentThread().getContextClassLoader() : classLoader; - final Set resourcesFieldNameSet = new HashSet<>(); - Class clzz = webSocketType; - do { - for (Field field : clzz.getDeclaredFields()) { - if (field.getAnnotation(Resource.class) == null - && field.getAnnotation(javax.annotation.Resource.class) == null) { - continue; - } - if (resourcesFieldNameSet.contains(field.getName())) { - continue; - } - if (Modifier.isStatic(field.getModifiers())) { - throw new RestException(field + " cannot static on createRestWebSocketServlet"); - } - if (Modifier.isFinal(field.getModifiers())) { - throw new RestException(field + " cannot final on createRestWebSocketServlet"); - } - if (!Modifier.isPublic(field.getModifiers()) && !Modifier.isProtected(field.getModifiers())) { - throw new RestException(field + " must be public or protected on createRestWebSocketServlet"); - } - resourcesFieldNameSet.add(field.getName()); - resourcesFieldSet.add(field); - } - } while ((clzz = clzz.getSuperclass()) != Object.class); - - // ---------------------------------------------------------------------------------------- - boolean namePresent = false; - try { - Method m0 = null; - for (Method method : webSocketType.getMethods()) { - if (method.getParameterCount() > 0) { - m0 = method; - break; - } - } - namePresent = m0 == null || m0.getParameters()[0].isNamePresent(); - } catch (Exception e) { - // do nothing - } - final Map asmParamMap = - namePresent ? null : AsmMethodBoost.getMethodBeans(webSocketType); - final Set messageNames = new HashSet<>(); - Method wildcardMethod = null; - List mmethods = new ArrayList<>(); - for (Method method : webSocketType.getMethods()) { - RestOnMessage rom = method.getAnnotation(RestOnMessage.class); - if (rom == null) { - continue; - } - String name = rom.name(); - if (!"*".equals(name) && !checkName(name)) { - throw new RestException("@RestOnMessage.name contains illegal characters on (" + method + ")"); - } - if (Modifier.isFinal(method.getModifiers())) { - throw new RestException("@RestOnMessage method can not final but (" + method + ")"); - } - if (Modifier.isStatic(method.getModifiers())) { - throw new RestException("@RestOnMessage method can not static but (" + method + ")"); - } - if (method.getReturnType() != void.class) { - throw new RestException("@RestOnMessage method must return void but (" + method + ")"); - } - if (method.getExceptionTypes().length > 0) { - throw new RestException("@RestOnMessage method can not throw exception but (" + method + ")"); - } - if (name.isEmpty()) { - throw new RestException(method + " RestOnMessage.name is empty createRestWebSocketServlet"); - } - if (messageNames.contains(name)) { - throw new RestException(method + " repeat RestOnMessage.name(" + name + ") createRestWebSocketServlet"); - } - messageNames.add(name); - if ("*".equals(name)) { - wildcardMethod = method; - } else { - mmethods.add(method); - } - } - final List messageMethods = new ArrayList<>(); - messageMethods.addAll(mmethods); - // wildcardMethod 必须放最后, _DynRestOnMessageConsumer 是按messageMethods顺序来判断的 - if (wildcardMethod != null) { - messageMethods.add(wildcardMethod); - } - // ---------------------------------------------------------------------------------------- - final String resDesc = Type.getDescriptor(Resource.class); - final String wsDesc = Type.getDescriptor(WebSocket.class); - final String wsParamDesc = Type.getDescriptor(WebSocketParam.class); - final String jsonConvertDesc = Type.getDescriptor(JsonConvert.class); - final String convertDisabledDesc = Type.getDescriptor(ConvertDisabled.class); - final String webSocketParamName = Type.getInternalName(WebSocketParam.class); - final String supDynName = WebSocketServlet.class.getName().replace('.', '/'); - final String webServletDesc = Type.getDescriptor(WebServlet.class); - final String webSocketInternalName = Type.getInternalName(webSocketType); - - final String newDynName = "org/redkaledyn/http/restws/" + "_DynWebScoketServlet__" - + webSocketType.getName().replace('.', '_').replace('$', '_'); - - final String newDynWebSokcetSimpleName = "_Dyn" + webSocketType.getSimpleName(); - final String newDynWebSokcetFullName = newDynName + "$" + newDynWebSokcetSimpleName; - - final String newDynMessageSimpleName = "_Dyn" + webSocketType.getSimpleName() + "Message"; - final String newDynMessageFullName = newDynName + "$" + newDynMessageSimpleName; - - final String newDynConsumerSimpleName = "_DynRestOnMessageConsumer"; - final String newDynConsumerFullName = newDynName + "$" + newDynConsumerSimpleName; - try { - Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.')); - if (clz == null) { - clz = loader.loadClass(newDynName.replace('/', '.')); - } - T servlet = (T) clz.getDeclaredConstructor().newInstance(); - Map msgclassToAnnotations = new HashMap<>(); - for (int i = 0; i < messageMethods.size(); i++) { // _DyncXXXWebSocketMessage 子消息List - Method method = messageMethods.get(i); - String endfix = "_" + method.getName() + "_" + (i > 9 ? i : ("0" + i)); - String newDynSuperMessageFullName = newDynMessageFullName + (method == wildcardMethod ? "" : endfix); - msgclassToAnnotations.put(newDynSuperMessageFullName, method.getAnnotations()); - } - clz.getField("_redkale_annotations").set(null, msgclassToAnnotations); - if (rws.cryptor() != Cryptor.class) { - Cryptor cryptor = rws.cryptor().getDeclaredConstructor().newInstance(); - Field cryptorField = clz.getSuperclass().getDeclaredField("cryptor"); // WebSocketServlet - cryptorField.setAccessible(true); - cryptorField.set(servlet, cryptor); - } - if (messageAgent != null) { - ((WebSocketServlet) servlet).messageAgent = messageAgent; - } - return servlet; - } catch (Throwable e) { - // do nothing - } - - final List resourcesFields = new ArrayList<>(resourcesFieldSet); - StringBuilder sb1 = new StringBuilder(); - StringBuilder sb2 = new StringBuilder(); - for (int i = 0; i < resourcesFields.size(); i++) { - Field field = resourcesFields.get(i); - sb1.append(Type.getDescriptor(field.getType())); - sb2.append(Utility.getTypeDescriptor(field.getGenericType())); - } - final String resourceDescriptor = sb1.toString(); - final String resourceGenericDescriptor = sb1.length() == sb2.length() ? null : sb2.toString(); - // ---------------------------------------------------------------------------------------- - - ClassWriter cw = new ClassWriter(COMPUTE_FRAMES); - FieldVisitor fv; - MethodDebugVisitor mv; - AnnotationVisitor av0; - cw.visit(V11, ACC_PUBLIC + ACC_SUPER, newDynName, null, supDynName, null); - { // RestDyn - av0 = cw.visitAnnotation(Type.getDescriptor(RestDyn.class), true); - av0.visit("simple", false); // WebSocketServlet必须要解析http-header - { - AnnotationVisitor av1 = av0.visitArray("types"); - av1.visit(null, Type.getType("L" + newDynConsumerFullName.replace('.', '/') + ";")); - av1.visit(null, Type.getType("L" + newDynWebSokcetFullName.replace('.', '/') + ";")); - av1.visit( - null, - Type.getType("L" + newDynMessageFullName.replace('.', '/') - + ";")); // 位置固定第三个,下面用Message类进行loadDecoder会用到 - av1.visitEnd(); - } - av0.visitEnd(); - } - { // RestDynSourceType - av0 = cw.visitAnnotation(Type.getDescriptor(RestDynSourceType.class), true); - av0.visit("value", Type.getType(Type.getDescriptor(webSocketType))); - av0.visitEnd(); - } - { // 注入 @WebServlet 注解 - String urlpath = (rws.catalog().isEmpty() ? "/" : ("/" + rws.catalog() + "/")) + rwsname; - av0 = cw.visitAnnotation(webServletDesc, true); - { - AnnotationVisitor av1 = av0.visitArray("value"); - av1.visit(null, urlpath); - av1.visitEnd(); - } - av0.visit("name", rwsname); - av0.visit("moduleid", 0); - av0.visit("repair", rws.repair()); - av0.visit("comment", rws.comment()); - av0.visitEnd(); - } - { // 内部类 - cw.visitInnerClass(newDynConsumerFullName, newDynName, newDynConsumerSimpleName, ACC_PUBLIC + ACC_STATIC); - - cw.visitInnerClass(newDynWebSokcetFullName, newDynName, newDynWebSokcetSimpleName, ACC_PUBLIC + ACC_STATIC); - - cw.visitInnerClass(newDynMessageFullName, newDynName, newDynMessageSimpleName, ACC_PUBLIC + ACC_STATIC); - - for (int i = 0; i < messageMethods.size(); i++) { - Method method = messageMethods.get(i); - String endfix = "_" + method.getName() + "_" + (i > 9 ? i : ("0" + i)); - String newDynSuperMessageFullName = newDynMessageFullName + (method == wildcardMethod ? "" : endfix); - cw.visitInnerClass( - newDynSuperMessageFullName, - newDynName, - newDynMessageSimpleName + endfix, - ACC_PUBLIC + ACC_STATIC); - } - } - { // @Resource - for (int i = 0; i < resourcesFields.size(); i++) { - Field field = resourcesFields.get(i); - Resource res = field.getAnnotation(Resource.class); - javax.annotation.Resource res2 = field.getAnnotation(javax.annotation.Resource.class); - java.lang.reflect.Type fieldType = field.getGenericType(); - fv = cw.visitField( - ACC_PRIVATE, - "_redkale_resource_" + i, - Type.getDescriptor(field.getType()), - fieldType == field.getType() ? null : Utility.getTypeDescriptor(fieldType), - null); - { - av0 = fv.visitAnnotation(resDesc, true); - av0.visit("name", res != null ? res.name() : res2.name()); - av0.visit("required", res == null || res.required()); - av0.visitEnd(); - } - fv.visitEnd(); - } - } - { // _redkale_annotations - fv = cw.visitField( - ACC_PUBLIC + ACC_STATIC, - "_redkale_annotations", - "Ljava/util/Map;", - "Ljava/util/Map;", - null); - fv.visitEnd(); - } - { // _DynWebSocketServlet构造函数 - mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "", "()V", null, null)); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, supDynName, "", "()V", false); - mv.visitVarInsn(ALOAD, 0); - mv.visitLdcInsn(Type.getObjectType(newDynName + "$" + newDynWebSokcetSimpleName + "Message")); - mv.visitFieldInsn(PUTFIELD, newDynName, "messageRestType", "Ljava/lang/reflect/Type;"); - - mv.visitVarInsn(ALOAD, 0); - Asms.visitInsn(mv, rws.liveinterval()); - mv.visitFieldInsn(PUTFIELD, newDynName, "liveinterval", "I"); - - mv.visitVarInsn(ALOAD, 0); - Asms.visitInsn(mv, rws.wsmaxconns()); - mv.visitFieldInsn(PUTFIELD, newDynName, "wsmaxconns", "I"); - - mv.visitVarInsn(ALOAD, 0); - Asms.visitInsn(mv, rws.wsmaxbody()); - mv.visitFieldInsn(PUTFIELD, newDynName, "wsmaxbody", "I"); - - mv.visitVarInsn(ALOAD, 0); - mv.visitInsn(rws.single() ? ICONST_1 : ICONST_0); - mv.visitFieldInsn(PUTFIELD, newDynName, "single", "Z"); - - mv.visitVarInsn(ALOAD, 0); - mv.visitInsn(rws.anyuser() ? ICONST_1 : ICONST_0); - mv.visitFieldInsn(PUTFIELD, newDynName, "anyuser", "Z"); - - mv.visitInsn(RETURN); - mv.visitMaxs(3, 1); - mv.visitEnd(); - } - { // createWebSocket 方法 - mv = new MethodDebugVisitor(cw.visitMethod( - ACC_PROTECTED, - "createWebSocket", - "()" + wsDesc, - "()L" - + WebSocket.class.getName().replace('.', '/') + ";", - null)); - mv.visitTypeInsn(NEW, newDynName + "$" + newDynWebSokcetSimpleName); - mv.visitInsn(DUP); - for (int i = 0; i < resourcesFields.size(); i++) { - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn( - GETFIELD, - newDynName, - "_redkale_resource_" + i, - Type.getDescriptor(resourcesFields.get(i).getType())); - } - mv.visitMethodInsn( - INVOKESPECIAL, newDynWebSokcetFullName, "", "(" + resourceDescriptor + ")V", false); - mv.visitInsn(ARETURN); - mv.visitMaxs(2 + resourcesFields.size(), 1); - mv.visitEnd(); - } - { // createRestOnMessageConsumer - mv = new MethodDebugVisitor(cw.visitMethod( - ACC_PROTECTED, - "createRestOnMessageConsumer", - "()Ljava/util/function/BiConsumer;", - "()Ljava/util/function/BiConsumer<" + wsDesc + "Ljava/lang/Object;>;", - null)); - mv.visitTypeInsn(NEW, newDynConsumerFullName); - mv.visitInsn(DUP); - mv.visitMethodInsn(INVOKESPECIAL, newDynConsumerFullName, "", "()V", false); - mv.visitInsn(ARETURN); - mv.visitMaxs(2, 1); - mv.visitEnd(); - } - { // resourceName - mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "resourceName", "()Ljava/lang/String;", null, null)); - mv.visitLdcInsn(rwsname); - mv.visitInsn(ARETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - - DynBytesClassLoader newLoader = new DynBytesClassLoader(loader); - Map msgclassToAnnotations = new HashMap<>(); - for (int i = 0; i < messageMethods.size(); i++) { // _DyncXXXWebSocketMessage 子消息List - final Method method = messageMethods.get(i); - String endfix = "_" + method.getName() + "_" + (i > 9 ? i : ("0" + i)); - String newDynSuperMessageFullName = newDynMessageFullName + (method == wildcardMethod ? "" : endfix); - msgclassToAnnotations.put(newDynSuperMessageFullName, method.getAnnotations()); - - ClassWriter cw2 = new ClassWriter(COMPUTE_FRAMES); - cw2.visit( - V11, - ACC_PUBLIC + ACC_FINAL + ACC_SUPER, - newDynSuperMessageFullName, - null, - "java/lang/Object", - new String[] {webSocketParamName, "java/lang/Runnable"}); - cw2.visitInnerClass( - newDynSuperMessageFullName, newDynName, newDynMessageSimpleName + endfix, ACC_PUBLIC + ACC_STATIC); - Set paramNames = new HashSet<>(); - AsmMethodBean methodBean = asmParamMap == null ? null : AsmMethodBean.get(asmParamMap, method); - List names = methodBean == null ? null : methodBean.getParams(); - Parameter[] params = method.getParameters(); - final LinkedHashMap paramap = new LinkedHashMap(); // 必须使用LinkedHashMap确保顺序 - for (int j = 0; j < params.length; j++) { // 字段列表 - Parameter param = params[j]; - String paramName = param.getName(); - RestParam rp = param.getAnnotation(RestParam.class); - Param pm = param.getAnnotation(Param.class); - if (rp != null && !rp.name().isEmpty()) { - paramName = rp.name(); - } else if (pm != null && !pm.value().isEmpty()) { - paramName = pm.value(); - } else if (names != null && names.size() > j) { - paramName = names.get(j).getName(); - } - if (paramNames.contains(paramName)) { - throw new RestException(method + " has same @RestParam.name"); - } - paramNames.add(paramName); - paramap.put(paramName, param); - fv = cw2.visitField( - ACC_PUBLIC, - paramName, - Type.getDescriptor(param.getType()), - param.getType() == param.getParameterizedType() - ? null - : Utility.getTypeDescriptor(param.getParameterizedType()), - null); - fv.visitEnd(); - } - if (method == wildcardMethod) { - for (int j = 0; j < messageMethods.size(); j++) { - Method method2 = messageMethods.get(j); - if (method2 == wildcardMethod) { - continue; - } - String endfix2 = "_" + method2.getName() + "_" + (j > 9 ? j : ("0" + j)); - String newDynSuperMessageFullName2 = - newDynMessageFullName + (method2 == wildcardMethod ? "" : endfix2); - cw2.visitInnerClass( - newDynSuperMessageFullName2, - newDynName, - newDynMessageSimpleName + endfix2, - ACC_PUBLIC + ACC_STATIC); - fv = cw2.visitField( - ACC_PUBLIC, - method2.getAnnotation(RestOnMessage.class).name(), - "L" + newDynSuperMessageFullName2 + ";", - null, - null); - fv.visitEnd(); - } - } - { // _redkale_websocket - fv = cw2.visitField(ACC_PUBLIC, "_redkale_websocket", "L" + newDynWebSokcetFullName + ";", null, null); - av0 = fv.visitAnnotation(convertDisabledDesc, true); - av0.visitEnd(); - fv.visitEnd(); - } - { // 空构造函数 - mv = new MethodDebugVisitor(cw2.visitMethod(ACC_PUBLIC, "", "()V", null, null)); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); - mv.visitInsn(RETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - { // getNames - mv = new MethodDebugVisitor( - cw2.visitMethod(ACC_PUBLIC, "getNames", "()[Ljava/lang/String;", null, null)); - av0 = mv.visitAnnotation(convertDisabledDesc, true); - av0.visitEnd(); - Asms.visitInsn(mv, paramap.size()); - mv.visitTypeInsn(ANEWARRAY, "java/lang/String"); - int index = -1; - for (Map.Entry en : paramap.entrySet()) { - mv.visitInsn(DUP); - Asms.visitInsn(mv, ++index); - mv.visitLdcInsn(en.getKey()); - mv.visitInsn(AASTORE); - } - mv.visitInsn(ARETURN); - mv.visitMaxs(paramap.size() + 2, 1); - mv.visitEnd(); - } - { // getValue - mv = new MethodDebugVisitor(cw2.visitMethod( - ACC_PUBLIC, - "getValue", - "(Ljava/lang/String;)Ljava/lang/Object;", - "(Ljava/lang/String;)TT;", - null)); - for (Map.Entry en : paramap.entrySet()) { - Class paramType = en.getValue().getType(); - mv.visitLdcInsn(en.getKey()); - mv.visitVarInsn(ALOAD, 1); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z", false); - Label l1 = new Label(); - mv.visitJumpInsn(IFEQ, l1); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynSuperMessageFullName, en.getKey(), Type.getDescriptor(paramType)); - if (paramType.isPrimitive()) { - Class bigclaz = TypeToken.primitiveToWrapper(paramType); - mv.visitMethodInsn( - INVOKESTATIC, - bigclaz.getName().replace('.', '/'), - "valueOf", - "(" + Type.getDescriptor(paramType) + ")" + Type.getDescriptor(bigclaz), - false); - } - mv.visitInsn(ARETURN); - mv.visitLabel(l1); - } - mv.visitInsn(ACONST_NULL); - mv.visitInsn(ARETURN); - mv.visitMaxs(2, 2); - mv.visitEnd(); - } - { // getAnnotations - mv = new MethodDebugVisitor(cw2.visitMethod( - ACC_PUBLIC, "getAnnotations", "()[Ljava/lang/annotation/Annotation;", null, null)); - av0 = mv.visitAnnotation(convertDisabledDesc, true); - av0.visitEnd(); - mv.visitFieldInsn(GETSTATIC, newDynName, "_redkale_annotations", "Ljava/util/Map;"); - mv.visitLdcInsn(newDynSuperMessageFullName); - mv.visitMethodInsn( - INVOKEINTERFACE, "java/util/Map", "get", "(Ljava/lang/Object;)Ljava/lang/Object;", true); - mv.visitTypeInsn(CHECKCAST, "[Ljava/lang/annotation/Annotation;"); - mv.visitVarInsn(ASTORE, 1); - mv.visitVarInsn(ALOAD, 1); - Label l2 = new Label(); - mv.visitJumpInsn(IFNONNULL, l2); - mv.visitInsn(ICONST_0); - mv.visitTypeInsn(ANEWARRAY, "java/lang/annotation/Annotation"); - mv.visitInsn(ARETURN); - mv.visitLabel(l2); - mv.visitFrame(Opcodes.F_APPEND, 1, new Object[] {"[Ljava/lang/annotation/Annotation;"}, 0, null); - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(ALOAD, 1); - mv.visitInsn(ARRAYLENGTH); - mv.visitMethodInsn( - INVOKESTATIC, "java/util/Arrays", "copyOf", "([Ljava/lang/Object;I)[Ljava/lang/Object;", false); - mv.visitTypeInsn(CHECKCAST, "[Ljava/lang/annotation/Annotation;"); - mv.visitInsn(ARETURN); - mv.visitMaxs(2, 2); - mv.visitEnd(); - } - { // execute - mv = new MethodDebugVisitor( - cw2.visitMethod(ACC_PUBLIC, "execute", "(L" + newDynWebSokcetFullName + ";)V", null, null)); - mv.visitVarInsn(ALOAD, 0); - mv.visitVarInsn(ALOAD, 1); - mv.visitFieldInsn( - PUTFIELD, - newDynSuperMessageFullName, - "_redkale_websocket", - "L" + newDynWebSokcetFullName + ";"); - mv.visitVarInsn(ALOAD, 1); - mv.visitLdcInsn(method.getAnnotation(RestOnMessage.class).name()); - mv.visitVarInsn(ALOAD, 0); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn( - INVOKEVIRTUAL, - newDynWebSokcetFullName, - "preOnMessage", - "(Ljava/lang/String;" + wsParamDesc + "Ljava/lang/Runnable;)V", - false); - mv.visitInsn(RETURN); - mv.visitMaxs(4, 2); - mv.visitEnd(); - } - { // run - mv = new MethodDebugVisitor(cw2.visitMethod(ACC_PUBLIC, "run", "()V", null, null)); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn( - GETFIELD, - newDynSuperMessageFullName, - "_redkale_websocket", - "L" + newDynWebSokcetFullName + ";"); - - for (Map.Entry en : paramap.entrySet()) { - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn( - GETFIELD, - (newDynSuperMessageFullName), - en.getKey(), - Type.getDescriptor(en.getValue().getType())); - } - mv.visitMethodInsn( - INVOKEVIRTUAL, - newDynWebSokcetFullName, - method.getName(), - Type.getMethodDescriptor(method), - false); - - mv.visitInsn(RETURN); - mv.visitMaxs(3, 1); - mv.visitEnd(); - } - { // toString - mv = new MethodDebugVisitor( - cw2.visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null)); - mv.visitMethodInsn( - INVOKESTATIC, - JsonConvert.class.getName().replace('.', '/'), - "root", - "()" + jsonConvertDesc, - false); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn( - INVOKEVIRTUAL, - JsonConvert.class.getName().replace('.', '/'), - "convertTo", - "(Ljava/lang/Object;)Ljava/lang/String;", - false); - mv.visitInsn(ARETURN); - mv.visitMaxs(2, 1); - mv.visitEnd(); - } - cw2.visitEnd(); - byte[] bytes = cw2.toByteArray(); - Class cz = newLoader.loadClass((newDynSuperMessageFullName).replace('/', '.'), bytes); - RedkaleClassLoader.putDynClass((newDynSuperMessageFullName).replace('/', '.'), bytes, cz); - } - - if (wildcardMethod == null) { // _DynXXXWebSocketMessage class - ClassWriter cw2 = new ClassWriter(COMPUTE_FRAMES); - cw2.visit(V11, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynMessageFullName, null, "java/lang/Object", null); - - cw2.visitInnerClass(newDynMessageFullName, newDynName, newDynMessageSimpleName, ACC_PUBLIC + ACC_STATIC); - - for (int i = 0; i < messageMethods.size(); i++) { - Method method = messageMethods.get(i); - String endfix = "_" + method.getName() + "_" + (i > 9 ? i : ("0" + i)); - String newDynSuperMessageFullName = newDynMessageFullName + (method == wildcardMethod ? "" : endfix); - cw2.visitInnerClass( - newDynSuperMessageFullName, - newDynName, - newDynMessageSimpleName + endfix, - ACC_PUBLIC + ACC_STATIC); - - fv = cw2.visitField( - ACC_PUBLIC, - method.getAnnotation(RestOnMessage.class).name(), - "L" + newDynSuperMessageFullName + ";", - null, - null); - fv.visitEnd(); - } - { // 构造函数 - mv = new MethodDebugVisitor(cw2.visitMethod(ACC_PUBLIC, "", "()V", null, null)); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); - mv.visitInsn(RETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - { // toString - mv = new MethodDebugVisitor( - cw2.visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null)); - mv.visitMethodInsn( - INVOKESTATIC, - JsonConvert.class.getName().replace('.', '/'), - "root", - "()" + jsonConvertDesc, - false); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn( - INVOKEVIRTUAL, - JsonConvert.class.getName().replace('.', '/'), - "convertTo", - "(Ljava/lang/Object;)Ljava/lang/String;", - false); - mv.visitInsn(ARETURN); - mv.visitMaxs(2, 1); - mv.visitEnd(); - } - cw2.visitEnd(); - byte[] bytes = cw2.toByteArray(); - Class cz = newLoader.loadClass(newDynMessageFullName.replace('/', '.'), bytes); - RedkaleClassLoader.putDynClass(newDynMessageFullName.replace('/', '.'), bytes, cz); - } - - { // _DynXXXWebSocket class - ClassWriter cw2 = new ClassWriter(COMPUTE_FRAMES); - cw2.visit( - V11, - ACC_PUBLIC + ACC_FINAL + ACC_SUPER, - newDynWebSokcetFullName, - null, - webSocketInternalName, - null); - - cw2.visitInnerClass( - newDynWebSokcetFullName, newDynName, newDynWebSokcetSimpleName, ACC_PUBLIC + ACC_STATIC); - { - mv = new MethodDebugVisitor(cw2.visitMethod( - ACC_PUBLIC, - "", - "(" + resourceDescriptor + ")V", - resourceGenericDescriptor == null ? null : ("(" + resourceGenericDescriptor + ")V"), - null)); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, webSocketInternalName, "", "()V", false); - for (int i = 0; i < resourcesFields.size(); i++) { - Field field = resourcesFields.get(i); - mv.visitVarInsn(ALOAD, 0); - mv.visitVarInsn(ALOAD, i + 1); - mv.visitFieldInsn( - PUTFIELD, newDynWebSokcetFullName, field.getName(), Type.getDescriptor(field.getType())); - } - mv.visitInsn(RETURN); - mv.visitMaxs(2, 1 + resourcesFields.size()); - mv.visitEnd(); - } - { // RestDyn - av0 = cw2.visitAnnotation(Type.getDescriptor(RestDyn.class), true); - av0.visit("simple", false); - av0.visitEnd(); - } - cw2.visitEnd(); - byte[] bytes = cw2.toByteArray(); - Class cz = newLoader.loadClass(newDynWebSokcetFullName.replace('/', '.'), bytes); - RedkaleClassLoader.putDynClass(newDynWebSokcetFullName.replace('/', '.'), bytes, cz); - } - - { // _DynRestOnMessageConsumer class - ClassWriter cw2 = new ClassWriter(COMPUTE_FRAMES); - cw2.visit( - V11, - ACC_PUBLIC + ACC_FINAL + ACC_SUPER, - newDynConsumerFullName, - "Ljava/lang/Object;Ljava/util/function/BiConsumer<" + wsDesc + "Ljava/lang/Object;>;", - "java/lang/Object", - new String[] {"java/util/function/BiConsumer"}); - - cw2.visitInnerClass(newDynConsumerFullName, newDynName, newDynConsumerSimpleName, ACC_PUBLIC + ACC_STATIC); - cw2.visitInnerClass(newDynMessageFullName, newDynName, newDynMessageSimpleName, ACC_PUBLIC + ACC_STATIC); - for (int i = 0; i < messageMethods.size(); i++) { - Method method = messageMethods.get(i); - String endfix = "_" + method.getName() + "_" + (i > 9 ? i : ("0" + i)); - String newDynSuperMessageFullName = newDynMessageFullName + (method == wildcardMethod ? "" : endfix); - cw2.visitInnerClass( - newDynSuperMessageFullName, - newDynName, - newDynMessageSimpleName + endfix, - ACC_PUBLIC + ACC_STATIC); - } - - { // 构造函数 - mv = new MethodDebugVisitor(cw2.visitMethod(ACC_PUBLIC, "", "()V", null, null)); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); - mv.visitInsn(RETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - - { // accept函数 - mv = new MethodDebugVisitor( - cw2.visitMethod(ACC_PUBLIC, "accept", "(" + wsDesc + "Ljava/lang/Object;)V", null, null)); - mv.visitVarInsn(ALOAD, 1); - mv.visitTypeInsn(CHECKCAST, newDynWebSokcetFullName); - mv.visitVarInsn(ASTORE, 3); - - mv.visitVarInsn(ALOAD, 2); - mv.visitTypeInsn(CHECKCAST, newDynMessageFullName); - mv.visitVarInsn(ASTORE, 4); - - for (int i = 0; i < messageMethods.size(); i++) { - final Method method = messageMethods.get(i); - String endfix = "_" + method.getName() + "_" + (i > 9 ? i : ("0" + i)); - String newDynSuperMessageFullName = - newDynMessageFullName + (method == wildcardMethod ? "" : endfix); - final String messagename = - method.getAnnotation(RestOnMessage.class).name(); - if (method == wildcardMethod) { - mv.visitVarInsn(ALOAD, 4); - mv.visitVarInsn(ALOAD, 3); - mv.visitMethodInsn( - INVOKEVIRTUAL, - newDynSuperMessageFullName, - "execute", - "(L" + newDynWebSokcetFullName + ";)V", - false); - } else { - mv.visitVarInsn(ALOAD, 4); - mv.visitFieldInsn( - GETFIELD, newDynMessageFullName, messagename, "L" + newDynSuperMessageFullName + ";"); - Label ifLabel = new Label(); - mv.visitJumpInsn(IFNULL, ifLabel); - - mv.visitVarInsn(ALOAD, 4); - mv.visitFieldInsn( - GETFIELD, newDynMessageFullName, messagename, "L" + newDynSuperMessageFullName + ";"); - mv.visitVarInsn(ALOAD, 3); - mv.visitMethodInsn( - INVOKEVIRTUAL, - newDynSuperMessageFullName, - "execute", - "(L" + newDynWebSokcetFullName + ";)V", - false); - mv.visitInsn(RETURN); - mv.visitLabel(ifLabel); - } - } - mv.visitInsn(RETURN); - mv.visitMaxs(3, 3 + messageMethods.size()); - mv.visitEnd(); - } - { // 虚拟accept函数 - mv = new MethodDebugVisitor(cw2.visitMethod( - ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC, - "accept", - "(Ljava/lang/Object;Ljava/lang/Object;)V", - null, - null)); - mv.visitVarInsn(ALOAD, 0); - mv.visitVarInsn(ALOAD, 1); - mv.visitTypeInsn(CHECKCAST, WebSocket.class.getName().replace('.', '/')); - mv.visitVarInsn(ALOAD, 2); - mv.visitTypeInsn(CHECKCAST, "java/lang/Object"); - mv.visitMethodInsn( - INVOKEVIRTUAL, newDynConsumerFullName, "accept", "(" + wsDesc + "Ljava/lang/Object;)V", false); - mv.visitInsn(RETURN); - mv.visitMaxs(3, 3); - mv.visitEnd(); - } - cw2.visitEnd(); - byte[] bytes = cw2.toByteArray(); - Class cz = newLoader.loadClass(newDynConsumerFullName.replace('/', '.'), bytes); - RedkaleClassLoader.putDynClass(newDynConsumerFullName.replace('/', '.'), bytes, cz); - } - cw.visitEnd(); - - byte[] bytes = cw.toByteArray(); - Class newClazz = newLoader.loadClass(newDynName.replace('/', '.'), bytes); - RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, newClazz); - RedkaleClassLoader.putReflectionDeclaredConstructors(newClazz, newDynName.replace('/', '.')); - JsonFactory.root().loadDecoder(newClazz.getAnnotation(RestDyn.class).types()[2]); // 固定Message类 - - RedkaleClassLoader.putReflectionPublicMethods(webSocketType.getName()); - Class cwt = webSocketType; - do { - RedkaleClassLoader.putReflectionDeclaredFields(cwt.getName()); - } while ((cwt = cwt.getSuperclass()) != Object.class); - RedkaleClassLoader.putReflectionDeclaredConstructors(webSocketType, webSocketType.getName()); - - try { - T servlet = (T) newClazz.getDeclaredConstructor().newInstance(); - Field field = newClazz.getField("_redkale_annotations"); - field.set(null, msgclassToAnnotations); - RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), field); - if (rws.cryptor() != Cryptor.class) { - RedkaleClassLoader.putReflectionDeclaredConstructors( - rws.cryptor(), rws.cryptor().getName()); - Cryptor cryptor = rws.cryptor().getDeclaredConstructor().newInstance(); - Field cryptorField = newClazz.getSuperclass().getDeclaredField("cryptor"); // WebSocketServlet - RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), cryptorField); - cryptorField.setAccessible(true); - cryptorField.set(servlet, cryptor); - } - if (messageAgent != null) { - ((WebSocketServlet) servlet).messageAgent = messageAgent; - } - return servlet; - } catch (Exception e) { - throw new RestException(e); - } - } - - public static T createRestServlet( - final ClassLoader classLoader, - final Class userType0, - final Class baseServletType, - final Class serviceType, - String serviceResourceName) { - - if (baseServletType == null || serviceType == null) { - throw new RestException(" Servlet or Service is null Class on createRestServlet"); - } - if (!HttpServlet.class.isAssignableFrom(baseServletType)) { - throw new RestException(baseServletType + " is not HttpServlet Class on createRestServlet"); - } - int parentMod = baseServletType.getModifiers(); - if (!java.lang.reflect.Modifier.isPublic(parentMod)) { - throw new RestException(baseServletType + " is not Public Class on createRestServlet"); - } - Boolean parentNon0 = null; - { - NonBlocking snon = serviceType.getAnnotation(NonBlocking.class); - parentNon0 = snon == null ? null : snon.value(); - if (HttpServlet.class != baseServletType) { - Boolean preNonBlocking = null; - Boolean authNonBlocking = null; - RedkaleClassLoader.putReflectionDeclaredMethods(baseServletType.getName()); - for (Method m : baseServletType.getDeclaredMethods()) { - if (java.lang.reflect.Modifier.isAbstract(parentMod) - && java.lang.reflect.Modifier.isAbstract(m.getModifiers())) { // @since 2.4.0 - throw new RestException( - baseServletType + " cannot contains a abstract Method on " + baseServletType); - } - Class[] paramTypes = m.getParameterTypes(); - if (paramTypes.length != 2 - || paramTypes[0] != HttpRequest.class - || paramTypes[1] != HttpResponse.class) { - continue; - } - // ----------------------------------------------- - Class[] exps = m.getExceptionTypes(); - if (exps.length > 0 && (exps.length != 1 || exps[0] != IOException.class)) { - continue; - } - // ----------------------------------------------- - String methodName = m.getName(); - if ("preExecute".equals(methodName)) { - if (preNonBlocking == null) { - NonBlocking non = m.getAnnotation(NonBlocking.class); - preNonBlocking = non != null && non.value(); - } - continue; - } - if ("authenticate".equals(methodName)) { - if (authNonBlocking == null) { - NonBlocking non = m.getAnnotation(NonBlocking.class); - authNonBlocking = non != null && non.value(); - } - continue; - } - } - if (preNonBlocking != null && !preNonBlocking) { - parentNon0 = false; - } else if (authNonBlocking != null && !authNonBlocking) { - parentNon0 = false; - } else { - NonBlocking bnon = baseServletType.getAnnotation(NonBlocking.class); - if (bnon != null && !bnon.value()) { - parentNon0 = false; - } - } - } - } - - final String restInternalName = Type.getInternalName(Rest.class); - final String serviceDesc = Type.getDescriptor(serviceType); - final String webServletDesc = Type.getDescriptor(WebServlet.class); - final String resDesc = Type.getDescriptor(Resource.class); - final String reqDesc = Type.getDescriptor(HttpRequest.class); - final String respDesc = Type.getDescriptor(HttpResponse.class); - final String convertDesc = Type.getDescriptor(Convert.class); - final String nonblockDesc = Type.getDescriptor(NonBlocking.class); - final String typeDesc = Type.getDescriptor(java.lang.reflect.Type.class); - final String retDesc = Type.getDescriptor(RetResult.class); - final String httpResultDesc = Type.getDescriptor(HttpResult.class); - final String httpScopeDesc = Type.getDescriptor(HttpScope.class); - final String stageDesc = Type.getDescriptor(CompletionStage.class); - final String httpHeadersDesc = Type.getDescriptor(HttpHeaders.class); - final String httpParametersDesc = Type.getDescriptor(HttpParameters.class); - final String flipperDesc = Type.getDescriptor(Flipper.class); - final String httpServletName = HttpServlet.class.getName().replace('.', '/'); - final String actionEntryName = HttpServlet.ActionEntry.class.getName().replace('.', '/'); - final String attrDesc = Type.getDescriptor(org.redkale.util.Attribute.class); - final String multiContextDesc = Type.getDescriptor(MultiContext.class); - final String multiContextName = MultiContext.class.getName().replace('.', '/'); - final String mappingDesc = Type.getDescriptor(HttpMapping.class); - final String restConvertDesc = Type.getDescriptor(RestConvert.class); - final String restConvertsDesc = Type.getDescriptor(RestConvert.RestConverts.class); - final String restConvertCoderDesc = Type.getDescriptor(RestConvertCoder.class); - final String restConvertCodersDesc = Type.getDescriptor(RestConvertCoder.RestConvertCoders.class); - final String httpParamDesc = Type.getDescriptor(HttpParam.class); - final String httpParamsDesc = Type.getDescriptor(HttpParam.HttpParams.class); - final String sourcetypeDesc = Type.getDescriptor(HttpParam.HttpParameterStyle.class); - - final String reqInternalName = Type.getInternalName(HttpRequest.class); - final String respInternalName = Type.getInternalName(HttpResponse.class); - final String attrInternalName = Type.getInternalName(org.redkale.util.Attribute.class); - final String retInternalName = Type.getInternalName(RetResult.class); - final String serviceTypeInternalName = Type.getInternalName(serviceType); - - HttpUserType hut = baseServletType.getAnnotation(HttpUserType.class); - final Class userType = - (userType0 == null || userType0 == Object.class) ? (hut == null ? null : hut.value()) : userType0; - if (userType != null - && (userType.isPrimitive() - || userType.getName().startsWith("java.") - || userType.getName().startsWith("javax."))) { - throw new RestException(HttpUserType.class.getSimpleName() + " must be a JavaBean but found " + userType); - } - - final String supDynName = baseServletType.getName().replace('.', '/'); - final RestService controller = serviceType.getAnnotation(RestService.class); - if (controller != null && controller.ignore()) { - throw new RestException(serviceType + " is ignore Rest Service Class"); // 标记为ignore=true不创建Servlet - } - final boolean serRpcOnly = controller != null && controller.rpcOnly(); - final Boolean parentNonBlocking = parentNon0; - - ClassLoader loader = classLoader == null ? Thread.currentThread().getContextClassLoader() : classLoader; - String stname = serviceType.getSimpleName(); - if (stname.startsWith("Service")) { // 类似ServiceWatchService这样的类保留第一个Service字样 - stname = "Service" + stname.substring("Service".length()).replaceAll("Service.*$", ""); - } else { - stname = stname.replaceAll("Service.*$", ""); - } - String namePostfix = Utility.isBlank(serviceResourceName) ? "" : serviceResourceName; - for (char ch : namePostfix.toCharArray()) { - if ((ch == '$' - || ch == '_' - || (ch >= '0' && ch <= '9') - || (ch >= 'a' && ch <= 'z') - || (ch >= 'A' && ch <= 'Z'))) { - continue; - } - // 带特殊字符的值不能作为类名的后缀 - namePostfix = Utility.md5Hex(namePostfix); - break; - } - // String newDynName = serviceTypeInternalName.substring(0, serviceTypeInternalName.lastIndexOf('/') + 1) + - // "_Dyn" + stname + "RestServlet"; - final String newDynName = "org/redkaledyn/http/rest/" + "_Dyn" + stname + "RestServlet__" - + serviceType.getName().replace('.', '_').replace('$', '_') - + (namePostfix.isEmpty() ? "" : ("_" + namePostfix) + "DynServlet"); - - try { - Class newClazz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.')); - if (newClazz == null) { - newClazz = loader.loadClass(newDynName.replace('/', '.')); - } - T obj = (T) newClazz.getDeclaredConstructor().newInstance(); - - final String defModuleName = getWebModuleNameLowerCase(serviceType); - final String bigModuleName = getWebModuleName(serviceType); - final Map classMap = new LinkedHashMap<>(); - - final List entrys = new ArrayList<>(); - final List paramTypes = new ArrayList<>(); - final List retvalTypes = new ArrayList<>(); - - final List restConverts = new ArrayList<>(); - final Map typeRefs = new LinkedHashMap<>(); - final Map mappingUrlToMethod = new HashMap<>(); - final Map restAttributes = new LinkedHashMap<>(); - final Map bodyTypes = new HashMap<>(); - - { // entrys、paramTypes赋值 - final Method[] allMethods = serviceType.getMethods(); - Arrays.sort(allMethods, (m1, m2) -> { // 必须排序,否则paramTypes顺序容易乱 - int s = m1.getName().compareTo(m2.getName()); - if (s != 0) { - return s; - } - s = Arrays.toString(m1.getParameterTypes()).compareTo(Arrays.toString(m2.getParameterTypes())); - return s; - }); - int methodIdex = 0; - for (final Method method : allMethods) { - if (Modifier.isStatic(method.getModifiers())) { - continue; - } - if (method.isSynthetic()) { - continue; - } - if (EXCLUDERMETHODS.contains(method.getName())) { - continue; - } - if (method.getParameterCount() == 1 && method.getParameterTypes()[0] == AnyValue.class) { - if ("init".equals(method.getName())) { - continue; - } - if ("destroy".equals(method.getName())) { - continue; - } - } - if (controller == null) { - continue; - } - - RestMapping[] mappings = method.getAnnotationsByType(RestMapping.class); - if (!controller.autoMapping() && mappings.length < 1) { - continue; - } - boolean ignore = false; - for (RestMapping mapping : mappings) { - if (mapping.ignore()) { - ignore = true; - break; - } - } - if (ignore) { - continue; - } - java.lang.reflect.Type[] ptypes = - TypeToken.getGenericType(method.getGenericParameterTypes(), serviceType); - for (java.lang.reflect.Type t : ptypes) { - if (!TypeToken.isClassType(t)) { - throw new RedkaleException("param type (" + t + ") is not a class in method " + method - + ", serviceType is " + serviceType.getName()); - } - } - paramTypes.add(ptypes); - java.lang.reflect.Type rtype = formatRestReturnType(method, serviceType); - if (!TypeToken.isClassType(rtype)) { - throw new RedkaleException("return type (" + rtype + ") is not a class in method " + method - + ", serviceType is " + serviceType.getName()); - } - retvalTypes.add(rtype); - if (mappings.length == 0) { // 没有Mapping,设置一个默认值 - MappingEntry entry = new MappingEntry( - serRpcOnly, methodIdex, parentNonBlocking, null, bigModuleName, method); - entrys.add(entry); - } else { - for (RestMapping mapping : mappings) { - MappingEntry entry = new MappingEntry( - serRpcOnly, methodIdex, parentNonBlocking, mapping, defModuleName, method); - entrys.add(entry); - } - } - methodIdex++; - } - Collections.sort(entrys); - } - { // restConverts、typeRefs、mappingUrlToMethod、restAttributes、bodyTypes赋值 - final int headIndex = 10; - for (final MappingEntry entry : entrys) { - mappingUrlToMethod.put(entry.mappingurl, entry.mappingMethod); - final Method method = entry.mappingMethod; - final Class returnType = method.getReturnType(); - final Parameter[] params = method.getParameters(); - final RestConvert[] rcs = method.getAnnotationsByType(RestConvert.class); - final RestConvertCoder[] rcc = method.getAnnotationsByType(RestConvertCoder.class); - if ((rcs != null && rcs.length > 0) || (rcc != null && rcc.length > 0)) { - restConverts.add(new Object[] {rcs, rcc}); - } - // 解析方法中的每个参数 - List paramlist = new ArrayList<>(); - for (int i = 0; i < params.length; i++) { - final Parameter param = params[i]; - final Class ptype = param.getType(); - String n = null; - String comment = ""; - boolean required = true; - int radix = 10; - RestHeader annhead = param.getAnnotation(RestHeader.class); - if (annhead != null) { - n = annhead.name(); - radix = annhead.radix(); - comment = annhead.comment(); - required = annhead.required(); - } - RestCookie anncookie = param.getAnnotation(RestCookie.class); - if (anncookie != null) { - n = anncookie.name(); - radix = anncookie.radix(); - comment = anncookie.comment(); - } - RestSessionid annsid = param.getAnnotation(RestSessionid.class); - RestAddress annaddr = param.getAnnotation(RestAddress.class); - if (annaddr != null) { - comment = annaddr.comment(); - } - RestLocale annlocale = param.getAnnotation(RestLocale.class); - if (annlocale != null) { - comment = annlocale.comment(); - } - RestBody annbody = param.getAnnotation(RestBody.class); - if (annbody != null) { - comment = annbody.comment(); - } - RestUploadFile annfile = param.getAnnotation(RestUploadFile.class); - if (annfile != null) { - comment = annfile.comment(); - } - RestPath annpath = param.getAnnotation(RestPath.class); - if (annpath != null) { - comment = annpath.comment(); - } - RestUserid userid = param.getAnnotation(RestUserid.class); - - if (userid != null) { - comment = ""; - } - boolean annheaders = param.getType() == RestHeaders.class; - if (annheaders) { - comment = ""; - n = "^"; // Http头信息类型特殊处理 - } - boolean annparams = param.getType() == RestParams.class; - if (annparams) { - comment = ""; - n = "?"; // Http参数类型特殊处理 - } - RestParam annpara = param.getAnnotation(RestParam.class); - if (annpara != null) { - radix = annpara.radix(); - } - if (annpara != null) { - comment = annpara.comment(); - } - if (annpara != null) { - required = annpara.required(); - } - if (n == null) { - n = (annpara == null || annpara.name().isEmpty()) ? null : annpara.name(); - } - if (n == null && ptype == userType) { - n = "&"; // 用户类型特殊处理 - } - if (n == null) { - if (param.isNamePresent()) { - n = param.getName(); - } else if (ptype == Flipper.class) { - n = "flipper"; - } - } // n maybe is null - - java.lang.reflect.Type paramtype = - TypeToken.getGenericType(param.getParameterizedType(), serviceType); - paramlist.add(new Object[] { - param, - n, - ptype, - radix, - comment, - required, - annpara, - annsid, - annaddr, - annlocale, - annhead, - anncookie, - annbody, - annfile, - annpath, - userid, - annheaders, - annparams, - paramtype - }); - } - for (Object[] ps : - paramlist) { // {param, n, ptype, radix, comment, required, annpara, annsid, annaddr, - // annlocale, annhead, anncookie, annbody, annfile, annpath, annuserid, - // annheaders, annparams, paramtype} - final boolean isuserid = ((RestUserid) ps[headIndex + 5]) != null; // 是否取userid - if ((ps[1] != null && ps[1].toString().indexOf('&') >= 0) || isuserid) { - continue; // @RestUserid 不需要生成 @HttpParam - } - if (((RestAddress) ps[8]) != null) { - continue; // @RestAddress 不需要生成 @HttpParam - } - java.lang.reflect.Type pgtype = - TypeToken.getGenericType(((Parameter) ps[0]).getParameterizedType(), serviceType); - if (pgtype != (Class) ps[2]) { - String refid = typeRefs.get(pgtype); - if (refid == null) { - refid = "_typeref_" + typeRefs.size(); - typeRefs.put(pgtype, refid); - } - } - - final Parameter param = (Parameter) ps[0]; // 参数类型 - String pname = (String) ps[1]; // 参数名 - Class ptype = (Class) ps[2]; // 参数类型 - int radix = (Integer) ps[3]; - String comment = (String) ps[4]; - boolean required = (Boolean) ps[5]; - RestParam annpara = (RestParam) ps[6]; - RestSessionid annsid = (RestSessionid) ps[7]; - RestAddress annaddr = (RestAddress) ps[8]; - RestLocale annlocale = (RestLocale) ps[9]; - RestHeader annhead = (RestHeader) ps[headIndex]; - RestCookie anncookie = (RestCookie) ps[headIndex + 1]; - RestBody annbody = (RestBody) ps[headIndex + 2]; - RestUploadFile annfile = (RestUploadFile) ps[headIndex + 3]; - RestPath annpath = (RestPath) ps[headIndex + 4]; - RestUserid annuserid = (RestUserid) ps[headIndex + 5]; - boolean annheaders = (Boolean) ps[headIndex + 6]; - boolean annparams = (Boolean) ps[headIndex + 7]; - - if (CompletionHandler.class.isAssignableFrom( - ptype)) { // HttpResponse.createAsyncHandler() or HttpResponse.createAsyncHandler(Class) - } else if (annsid != null) { // HttpRequest.getSessionid(true|false) - } else if (annaddr != null) { // HttpRequest.getRemoteAddr - } else if (annlocale != null) { // HttpRequest.getLocale - } else if (annbody != null) { // HttpRequest.getBodyUTF8 / HttpRequest.getBody - } else if (annfile != null) { // MultiContext.partsFirstBytes / HttpRequest.partsFirstFile / - // HttpRequest.partsFiles - } else if (annpath != null) { // HttpRequest.getRequestPath - } else if (annuserid != null) { // HttpRequest.currentUserid - } else if (pname != null && pname.charAt(0) == '#') { // 从request.getPathParam 中去参数 - } else if ("#".equals(pname)) { // 从request.getRequstURI 中取参数 - } else if ("&".equals(pname) && ptype == userType) { // 当前用户对象的类名 - } else if ("^".equals(pname) && annheaders) { // HttpRequest.getHeaders Http头信息 - } else if ("?".equals(pname) && annparams) { // HttpRequest.getParameters Http参数信息 - } else if (ptype.isPrimitive()) { - // do nothing - } else if (ptype == String.class) { - // do nothing - } else if (ptype == Flipper.class) { - // do nothing - } else { // 其他Json对象 - // 构建 RestHeader、RestCookie、RestAddress 等赋值操作 - Class loop = ptype; - Set fields = new HashSet<>(); - Map attrParaNames = new LinkedHashMap<>(); - do { - if (loop == null || loop.isInterface()) { - break; // 接口时getSuperclass可能会得到null - } - for (Field field : loop.getDeclaredFields()) { - if (Modifier.isStatic(field.getModifiers())) { - continue; - } - if (Modifier.isFinal(field.getModifiers())) { - continue; - } - if (fields.contains(field.getName())) { - continue; - } - RestHeader rh = field.getAnnotation(RestHeader.class); - RestCookie rc = field.getAnnotation(RestCookie.class); - RestSessionid rs = field.getAnnotation(RestSessionid.class); - RestAddress ra = field.getAnnotation(RestAddress.class); - RestLocale rl = field.getAnnotation(RestLocale.class); - RestBody rb = field.getAnnotation(RestBody.class); - RestUploadFile ru = field.getAnnotation(RestUploadFile.class); - RestPath ri = field.getAnnotation(RestPath.class); - if (rh == null - && rc == null - && ra == null - && rl == null - && rb == null - && rs == null - && ru == null - && ri == null) { - continue; - } - - org.redkale.util.Attribute attr = org.redkale.util.Attribute.create(loop, field); - String attrFieldName; - String restname = ""; - if (rh != null) { - attrFieldName = "_redkale_attr_header_" - + (field.getType() != String.class ? "json_" : "") - + restAttributes.size(); - restname = rh.name(); - } else if (rc != null) { - attrFieldName = "_redkale_attr_cookie_" + restAttributes.size(); - restname = rc.name(); - } else if (rs != null) { - attrFieldName = "_redkale_attr_sessionid_" + restAttributes.size(); - restname = rs.create() ? "1" : ""; // 用于下面区分create值 - } else if (ra != null) { - attrFieldName = "_redkale_attr_address_" + restAttributes.size(); - // restname = ""; - } else if (rl != null) { - attrFieldName = "_redkale_attr_locale_" + restAttributes.size(); - // restname = ""; - } else if (rb != null && field.getType() == String.class) { - attrFieldName = "_redkale_attr_bodystring_" + restAttributes.size(); - // restname = ""; - } else if (rb != null && field.getType() == byte[].class) { - attrFieldName = "_redkale_attr_bodybytes_" + restAttributes.size(); - // restname = ""; - } else if (rb != null - && field.getType() != String.class - && field.getType() != byte[].class) { - attrFieldName = "_redkale_attr_bodyjson_" + restAttributes.size(); - // restname = ""; - } else if (ru != null && field.getType() == byte[].class) { - attrFieldName = "_redkale_attr_uploadbytes_" + restAttributes.size(); - // restname = ""; - } else if (ru != null && field.getType() == File.class) { - attrFieldName = "_redkale_attr_uploadfile_" + restAttributes.size(); - // restname = ""; - } else if (ru != null && field.getType() == File[].class) { - attrFieldName = "_redkale_attr_uploadfiles_" + restAttributes.size(); - // restname = ""; - } else if (ri != null && field.getType() == String.class) { - attrFieldName = "_redkale_attr_uri_" + restAttributes.size(); - // restname = ""; - } else { - continue; - } - restAttributes.put(attrFieldName, attr); - attrParaNames.put( - attrFieldName, - new Object[] {restname, field.getType(), field.getGenericType(), ru}); - fields.add(field.getName()); - } - } while ((loop = loop.getSuperclass()) != Object.class); - - if (!attrParaNames - .isEmpty()) { // 参数存在 RestHeader、RestCookie、RestSessionid、RestAddress、RestBody字段 - for (Map.Entry en : attrParaNames.entrySet()) { - if (en.getKey().contains("_header_")) { - String headerkey = en.getValue()[0].toString(); - if ("Host".equalsIgnoreCase(headerkey)) { - // do nothing - } else if ("Content-Type".equalsIgnoreCase(headerkey)) { - // do nothing - } else if ("Connection".equalsIgnoreCase(headerkey)) { - // do nothing - } else if ("Method".equalsIgnoreCase(headerkey)) { - // do nothing - } else if (en.getKey().contains("_header_json_")) { - String typefieldname = "_redkale_body_jsontype_" + bodyTypes.size(); - bodyTypes.put(typefieldname, (java.lang.reflect.Type) en.getValue()[2]); - } - } else if (en.getKey().contains("_cookie_")) { - // do nothing - } else if (en.getKey().contains("_sessionid_")) { - // do nothing - } else if (en.getKey().contains("_address_")) { - // do nothing - } else if (en.getKey().contains("_locale_")) { - // do nothing - } else if (en.getKey().contains("_uri_")) { - // do nothing - } else if (en.getKey().contains("_bodystring_")) { - // do nothing - } else if (en.getKey().contains("_bodybytes_")) { - // do nothing - } else if (en.getKey().contains("_bodyjson_")) { // JavaBean 转 Json - String typefieldname = "_redkale_body_jsontype_" + bodyTypes.size(); - bodyTypes.put(typefieldname, (java.lang.reflect.Type) en.getValue()[2]); - } else if (en.getKey().contains("_uploadbytes_")) { - // 只需mv.visitVarInsn(ALOAD, 4), 无需处理 - } else if (en.getKey().contains("_uploadfile_")) { - // 只需mv.visitVarInsn(ALOAD, 4), 无需处理 - } else if (en.getKey().contains("_uploadfiles_")) { - // 只需mv.visitVarInsn(ALOAD, 4), 无需处理 - } - } - } - } - } - java.lang.reflect.Type grt = TypeToken.getGenericType(method.getGenericReturnType(), serviceType); - Class rtc = returnType; - if (rtc == void.class) { - rtc = RetResult.class; - grt = TYPE_RETRESULT_STRING; - } else if (CompletionStage.class.isAssignableFrom(returnType)) { - ParameterizedType ptgrt = (ParameterizedType) grt; - grt = ptgrt.getActualTypeArguments()[0]; - rtc = TypeToken.typeToClass(grt); - if (rtc == null) { - rtc = Object.class; // 应该不会发生吧? - } - } else if (Flows.maybePublisherClass(returnType)) { - java.lang.reflect.Type grt0 = Flows.maybePublisherSubType(grt); - if (grt0 != null) { - grt = grt0; - } - } - if (grt != rtc) { - String refid = typeRefs.get(grt); - if (refid == null) { - refid = "_typeref_" + typeRefs.size(); - typeRefs.put(grt, refid); - } - } - } - } - for (Map.Entry en : typeRefs.entrySet()) { - Field refField = newClazz.getDeclaredField(en.getValue()); - refField.setAccessible(true); - refField.set(obj, en.getKey()); - } - for (Map.Entry en : restAttributes.entrySet()) { - Field attrField = newClazz.getDeclaredField(en.getKey()); - attrField.setAccessible(true); - attrField.set(obj, en.getValue()); - } - for (Map.Entry en : bodyTypes.entrySet()) { - Field genField = newClazz.getDeclaredField(en.getKey()); - genField.setAccessible(true); - genField.set(obj, en.getValue()); - } - for (int i = 0; i < restConverts.size(); i++) { - Field genField = newClazz.getDeclaredField(REST_CONVERT_FIELD_PREFIX + (i + 1)); - genField.setAccessible(true); - Object[] rc = restConverts.get(i); - - genField.set( - obj, - createJsonFactory((RestConvert[]) rc[0], (RestConvertCoder[]) rc[1]) - .getConvert()); - } - Field typesfield = newClazz.getDeclaredField(REST_PARAMTYPES_FIELD_NAME); - typesfield.setAccessible(true); - java.lang.reflect.Type[][] paramtypeArray = new java.lang.reflect.Type[paramTypes.size()][]; - paramtypeArray = paramTypes.toArray(paramtypeArray); - typesfield.set(obj, paramtypeArray); - - Field retfield = newClazz.getDeclaredField(REST_RETURNTYPES_FIELD_NAME); - retfield.setAccessible(true); - java.lang.reflect.Type[] rettypeArray = new java.lang.reflect.Type[retvalTypes.size()]; - rettypeArray = retvalTypes.toArray(rettypeArray); - retfield.set(obj, rettypeArray); - - Field tostringfield = newClazz.getDeclaredField(REST_TOSTRINGOBJ_FIELD_NAME); - tostringfield.setAccessible(true); - { // 注入 @WebServlet 注解 - String urlpath = ""; - final String defmodulename = getWebModuleNameLowerCase(serviceType); - final int moduleid = controller == null ? 0 : controller.moduleid(); - boolean repair = controller == null || controller.repair(); - final String catalog = controller == null ? "" : controller.catalog(); - - boolean pound = false; - for (MappingEntry entry : entrys) { - if (entry.existsPound) { - pound = true; - break; - } - } - if (defmodulename.isEmpty() || (!pound && entrys.size() <= 2)) { - Set startWiths = new HashSet<>(); - for (MappingEntry entry : entrys) { - String suburl = (catalog.isEmpty() ? "/" : ("/" + catalog + "/")) - + (defmodulename.isEmpty() ? "" : (defmodulename + "/")) - + entry.name; - if ("//".equals(suburl)) { - suburl = "/"; - } else if (suburl.length() > 2 && suburl.endsWith("/")) { - startWiths.add(suburl); - suburl += "*"; - } else { - boolean match = false; - for (String s : startWiths) { - if (suburl.startsWith(s)) { - match = true; - break; - } - } - if (match) { - continue; - } - } - urlpath += "," + suburl; - } - if (urlpath.length() > 0) { - urlpath = urlpath.substring(1); - } - } else { - urlpath = (catalog.isEmpty() ? "/" : ("/" + catalog + '/')) + defmodulename + "/*"; - } - - classMap.put("type", serviceType.getName()); - classMap.put("url", urlpath); - classMap.put("moduleid", moduleid); - classMap.put("repair", repair); - // classMap.put("comment", comment); //不显示太多信息 - } - java.util.function.Supplier sSupplier = - () -> JsonConvert.root().convertTo(classMap); - tostringfield.set(obj, sSupplier); - - Method restactMethod = newClazz.getDeclaredMethod("_createRestActionEntry"); - restactMethod.setAccessible(true); - Field tmpEntrysField = HttpServlet.class.getDeclaredField("_actionmap"); - tmpEntrysField.setAccessible(true); - HashMap innerEntryMap = (HashMap) restactMethod.invoke(obj); - for (Map.Entry en : innerEntryMap.entrySet()) { - Method m = mappingUrlToMethod.get(en.getKey()); - if (m != null) { - en.getValue().annotations = HttpServlet.ActionEntry.annotations(m); - } - } - tmpEntrysField.set(obj, innerEntryMap); - Field nonblockField = Servlet.class.getDeclaredField("_nonBlocking"); - nonblockField.setAccessible(true); - nonblockField.set(obj, parentNonBlocking == null || parentNonBlocking); - return obj; - } catch (ClassNotFoundException e) { - // do nothing - } catch (Throwable e) { - e.printStackTrace(); - } - // ------------------------------------------------------------------------------ - final String defModuleName = getWebModuleNameLowerCase(serviceType); - final String bigModuleName = getWebModuleName(serviceType); - final String catalog = controller == null ? "" : controller.catalog(); - final String httpDesc = Type.getDescriptor(HttpServlet.class); - if (!checkName(catalog)) { - throw new RestException(serviceType.getName() + " have illegal " + RestService.class.getSimpleName() - + ".catalog, only 0-9 a-z A-Z _ cannot begin 0-9"); - } - if (!checkName(defModuleName)) { - throw new RestException(serviceType.getName() + " have illegal " + RestService.class.getSimpleName() - + ".value, only 0-9 a-z A-Z _ cannot begin 0-9"); - } - ClassWriter cw = new ClassWriter(COMPUTE_FRAMES); - FieldVisitor fv; - MethodDebugVisitor mv; - AnnotationVisitor av0; - final List entrys = new ArrayList<>(); - final Map restAttributes = new LinkedHashMap<>(); - final Map classMap = new LinkedHashMap<>(); - final Map typeRefs = new LinkedHashMap<>(); - final List paramTypes = new ArrayList<>(); - final List retvalTypes = new ArrayList<>(); - final Map bodyTypes = new HashMap<>(); - final List restConverts = new ArrayList<>(); - final Map mappingurlToMethod = new HashMap<>(); - - cw.visit(V11, ACC_PUBLIC + ACC_SUPER, newDynName, null, supDynName, null); - - { // RestDynSourceType - av0 = cw.visitAnnotation(Type.getDescriptor(RestDynSourceType.class), true); - av0.visit("value", Type.getType(Type.getDescriptor(serviceType))); - av0.visitEnd(); - } - boolean dynsimple = baseServletType == HttpServlet.class; // 有自定义的BaseServlet会存在读取header的操作 - // 获取所有可以转换成HttpMapping的方法 - int methodidex = 0; - final Method[] allMethods = serviceType.getMethods(); - Arrays.sort(allMethods, (m1, m2) -> { // 必须排序,否则paramTypes顺序容易乱 - int s = m1.getName().compareTo(m2.getName()); - if (s != 0) { - return s; - } - s = Arrays.toString(m1.getParameterTypes()).compareTo(Arrays.toString(m2.getParameterTypes())); - return s; - }); - for (final Method method : allMethods) { - if (Modifier.isStatic(method.getModifiers())) { - continue; - } - if (method.isSynthetic()) { - continue; - } - if (EXCLUDERMETHODS.contains(method.getName())) { - continue; - } - if (method.getParameterCount() == 1 && method.getParameterTypes()[0] == AnyValue.class) { - if ("init".equals(method.getName())) { - continue; - } - if ("destroy".equals(method.getName())) { - continue; - } - } - if (controller == null) { - continue; - } - - RestMapping[] mappings = method.getAnnotationsByType(RestMapping.class); - if (!controller.autoMapping() && mappings.length < 1) { - continue; - } - boolean ignore = false; - for (RestMapping mapping : mappings) { - if (mapping.ignore()) { - ignore = true; - break; - } - } - if (ignore) { - continue; - } - - Class[] extypes = method.getExceptionTypes(); - if (extypes.length > 0) { - for (Class exp : extypes) { - if (!RuntimeException.class.isAssignableFrom(exp) && !IOException.class.isAssignableFrom(exp)) { - throw new RestException("@" + RestMapping.class.getSimpleName() + " only for method(" + method - + ") with throws IOException"); - } - } - } - java.lang.reflect.Type[] ptypes = TypeToken.getGenericType(method.getGenericParameterTypes(), serviceType); - for (java.lang.reflect.Type t : ptypes) { - if (!TypeToken.isClassType(t)) { - throw new RedkaleException("param type (" + t + ") is not a class in method " + method - + ", serviceType is " + serviceType.getName()); - } - } - paramTypes.add(ptypes); - java.lang.reflect.Type rtype = formatRestReturnType(method, serviceType); - if (!TypeToken.isClassType(rtype)) { - throw new RedkaleException("return type (" + rtype + ") is not a class in method " + method - + ", serviceType is " + serviceType.getName()); - } - retvalTypes.add(rtype); - if (mappings.length == 0) { // 没有Mapping,设置一个默认值 - MappingEntry entry = - new MappingEntry(serRpcOnly, methodidex, parentNonBlocking, null, bigModuleName, method); - if (entrys.contains(entry)) { - throw new RestException(serviceType.getName() + " on " + method.getName() + " 's mapping(" - + entry.name + ") is repeat"); - } - entrys.add(entry); - } else { - for (RestMapping mapping : mappings) { - MappingEntry entry = - new MappingEntry(serRpcOnly, methodidex, parentNonBlocking, mapping, defModuleName, method); - if (entrys.contains(entry)) { - throw new RestException(serviceType.getName() + " on " + method.getName() + " 's mapping(" - + entry.name + ") is repeat"); - } - entrys.add(entry); - } - } - methodidex++; - } - if (entrys.isEmpty()) { - return null; // 没有可HttpMapping的方法 - } - Collections.sort(entrys); - DynBytesClassLoader newLoader = new DynBytesClassLoader(loader); - final int moduleid = controller == null ? 0 : controller.moduleid(); - { // 注入 @WebServlet 注解 - String urlpath = ""; - boolean repair = controller == null || controller.repair(); - String comment = controller == null ? "" : controller.comment(); - av0 = cw.visitAnnotation(webServletDesc, true); - { - AnnotationVisitor av1 = av0.visitArray("value"); - boolean pound = false; - for (MappingEntry entry : entrys) { - if (entry.existsPound) { - pound = true; - break; - } - } - if (isEmpty(defModuleName) || (!pound && entrys.size() <= 2)) { - Set startWiths = new HashSet<>(); - for (MappingEntry entry : entrys) { - String suburl = (isEmpty(catalog) ? "/" : ("/" + catalog + "/")) - + (isEmpty(defModuleName) ? "" : (defModuleName + "/")) - + entry.name; - if ("//".equals(suburl)) { - suburl = "/"; - } else if (suburl.length() > 2 && suburl.endsWith("/")) { - startWiths.add(suburl); - suburl += "*"; - } else { - boolean match = false; - for (String s : startWiths) { - if (suburl.startsWith(s)) { - match = true; - break; - } - } - if (match) { - continue; - } - } - urlpath += "," + suburl; - av1.visit(null, suburl); - } - if (urlpath.length() > 0) { - urlpath = urlpath.substring(1); - } - } else { - urlpath = (catalog.isEmpty() ? "/" : ("/" + catalog + "/")) + defModuleName + "/*"; - av1.visit(null, urlpath); - } - av1.visitEnd(); - } - av0.visit("name", defModuleName); - av0.visit("moduleid", moduleid); - av0.visit("repair", repair); - av0.visit("comment", comment); - av0.visitEnd(); - classMap.put("type", serviceType.getName()); - classMap.put("url", urlpath); - classMap.put("moduleid", moduleid); - classMap.put("repair", repair); - // classMap.put("comment", comment); //不显示太多信息 - } - { // NonBlocking - av0 = cw.visitAnnotation(nonblockDesc, true); - av0.visit("value", true); - av0.visitEnd(); - } - { // 内部类 - cw.visitInnerClass( - actionEntryName, - httpServletName, - HttpServlet.ActionEntry.class.getSimpleName(), - ACC_PROTECTED + ACC_FINAL + ACC_STATIC); - - for (final MappingEntry entry : entrys) { - cw.visitInnerClass( - newDynName + "$" + entry.newActionClassName, - newDynName, - entry.newActionClassName, - ACC_PRIVATE + ACC_STATIC); - } - } - { // 注入 @Resource private XXXService _service; - fv = cw.visitField(ACC_PRIVATE, REST_SERVICE_FIELD_NAME, serviceDesc, null, null); - av0 = fv.visitAnnotation(resDesc, true); - av0.visit("name", Utility.isBlank(serviceResourceName) ? "" : serviceResourceName); - av0.visitEnd(); - fv.visitEnd(); - } - { // _serviceMap字段 Map - fv = cw.visitField( - ACC_PRIVATE, - REST_SERVICEMAP_FIELD_NAME, - "Ljava/util/Map;", - "Ljava/util/Map;", - null); - fv.visitEnd(); - } - { // _redkale_toStringSupplier字段 Supplier - fv = cw.visitField( - ACC_PRIVATE, - REST_TOSTRINGOBJ_FIELD_NAME, - "Ljava/util/function/Supplier;", - "Ljava/util/function/Supplier;", - null); - fv.visitEnd(); - } - { // 构造函数 - mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "", "()V", null, null)); - // mv.setDebug(true); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, supDynName, "", "()V", false); - mv.visitInsn(RETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - - // 将每个Service可转换的方法生成HttpServlet对应的HttpMapping方法 - boolean namePresent = false; - try { - Method m0 = null; - for (final MappingEntry entry : entrys) { - if (entry.mappingMethod.getParameterCount() > 0) { - m0 = entry.mappingMethod; - break; - } - } - namePresent = m0 == null || m0.getParameters()[0].isNamePresent(); - } catch (Exception e) { - // do nothing - } - final Map asmParamMap = namePresent ? null : AsmMethodBoost.getMethodBeans(serviceType); - - Map innerClassBytesMap = new LinkedHashMap<>(); - boolean containsMupload = false; - for (final MappingEntry entry : entrys) { - RestUploadFile mupload = null; - Class muploadType = null; - final Method method = entry.mappingMethod; - final Class returnType = method.getReturnType(); - final java.lang.reflect.Type retvalType = formatRestReturnType(method, serviceType); - final String methodDesc = Type.getMethodDescriptor(method); - final Parameter[] params = method.getParameters(); - - final RestConvert[] rcs = method.getAnnotationsByType(RestConvert.class); - final RestConvertCoder[] rcc = method.getAnnotationsByType(RestConvertCoder.class); - if ((rcs != null && rcs.length > 0) || (rcc != null && rcc.length > 0)) { - restConverts.add(new Object[] {rcs, rcc}); - } - if (dynsimple && entry.rpcOnly) { // 需要读取http header - dynsimple = false; - } - - mv = new MethodDebugVisitor(cw.visitMethod( - ACC_PUBLIC, entry.newMethodName, "(" + reqDesc + respDesc + ")V", null, new String[] { - "java/io/IOException" - })); - // mv.setDebug(true); - mv.debugLine(); - - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, REST_SERVICEMAP_FIELD_NAME, "Ljava/util/Map;"); - Label lmapif = new Label(); - mv.visitJumpInsn(IFNONNULL, lmapif); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, REST_SERVICE_FIELD_NAME, serviceDesc); - Label lserif = new Label(); - mv.visitJumpInsn(GOTO, lserif); - mv.visitLabel(lmapif); - - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, REST_SERVICEMAP_FIELD_NAME, "Ljava/util/Map;"); - mv.visitVarInsn(ALOAD, 1); - mv.visitLdcInsn(REST_HEADER_RESNAME); - mv.visitLdcInsn(""); - mv.visitMethodInsn( - INVOKEVIRTUAL, - reqInternalName, - "getHeader", - "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", - false); - mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Map", "get", "(Ljava/lang/Object;)Ljava/lang/Object;", true); - mv.visitTypeInsn(CHECKCAST, serviceTypeInternalName); - mv.visitLabel(lserif); - mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {serviceTypeInternalName}); - mv.visitVarInsn(ASTORE, 3); - - final int maxStack = 3 + params.length; - List varInsns = new ArrayList<>(); - int maxLocals = 4; - - AsmMethodBean methodBean = asmParamMap == null ? null : AsmMethodBean.get(asmParamMap, method); - List asmParamNames = methodBean == null ? null : methodBean.getParams(); - List paramlist = new ArrayList<>(); - // 解析方法中的每个参数 - for (int i = 0; i < params.length; i++) { - final Parameter param = params[i]; - final Class ptype = param.getType(); - String n = null; - String comment = ""; - boolean required = true; - int radix = 10; - - RestHeader annhead = param.getAnnotation(RestHeader.class); - if (annhead != null) { - if (ptype != String.class && ptype != InetSocketAddress.class) { - throw new RestException( - "@RestHeader must on String or InetSocketAddress Parameter in " + method); - } - n = annhead.name(); - radix = annhead.radix(); - comment = annhead.comment(); - required = false; - if (n.isEmpty()) { - throw new RestException("@RestHeader.value is illegal in " + method); - } - } - RestCookie anncookie = param.getAnnotation(RestCookie.class); - if (anncookie != null) { - if (annhead != null) { - throw new RestException( - "@RestCookie and @RestHeader cannot on the same Parameter in " + method); - } - if (ptype != String.class) { - throw new RestException("@RestCookie must on String Parameter in " + method); - } - n = anncookie.name(); - radix = anncookie.radix(); - comment = anncookie.comment(); - required = false; - if (n.isEmpty()) { - throw new RestException("@RestCookie.value is illegal in " + method); - } - } - RestSessionid annsid = param.getAnnotation(RestSessionid.class); - if (annsid != null) { - if (annhead != null) { - throw new RestException( - "@RestSessionid and @RestHeader cannot on the same Parameter in " + method); - } - if (anncookie != null) { - throw new RestException( - "@RestSessionid and @RestCookie cannot on the same Parameter in " + method); - } - if (ptype != String.class) { - throw new RestException("@RestSessionid must on String Parameter in " + method); - } - required = false; - } - RestAddress annaddr = param.getAnnotation(RestAddress.class); - if (annaddr != null) { - if (annhead != null) { - throw new RestException( - "@RestAddress and @RestHeader cannot on the same Parameter in " + method); - } - if (anncookie != null) { - throw new RestException( - "@RestAddress and @RestCookie cannot on the same Parameter in " + method); - } - if (annsid != null) { - throw new RestException( - "@RestAddress and @RestSessionid cannot on the same Parameter in " + method); - } - if (ptype != String.class) { - throw new RestException("@RestAddress must on String Parameter in " + method); - } - comment = annaddr.comment(); - required = false; - } - RestLocale annlocale = param.getAnnotation(RestLocale.class); - if (annlocale != null) { - if (annhead != null) { - throw new RestException( - "@RestLocale and @RestHeader cannot on the same Parameter in " + method); - } - if (anncookie != null) { - throw new RestException( - "@RestLocale and @RestCookie cannot on the same Parameter in " + method); - } - if (annsid != null) { - throw new RestException( - "@RestLocale and @RestSessionid cannot on the same Parameter in " + method); - } - if (annaddr != null) { - throw new RestException( - "@RestLocale and @RestAddress cannot on the same Parameter in " + method); - } - if (ptype != String.class) { - throw new RestException("@RestAddress must on String Parameter in " + method); - } - comment = annlocale.comment(); - required = false; - } - RestBody annbody = param.getAnnotation(RestBody.class); - if (annbody != null) { - if (annhead != null) { - throw new RestException("@RestBody and @RestHeader cannot on the same Parameter in " + method); - } - if (anncookie != null) { - throw new RestException("@RestBody and @RestCookie cannot on the same Parameter in " + method); - } - if (annsid != null) { - throw new RestException( - "@RestBody and @RestSessionid cannot on the same Parameter in " + method); - } - if (annaddr != null) { - throw new RestException("@RestBody and @RestAddress cannot on the same Parameter in " + method); - } - if (annlocale != null) { - throw new RestException("@RestBody and @RestLocale cannot on the same Parameter in " + method); - } - if (ptype.isPrimitive()) { - throw new RestException("@RestBody cannot on primitive type Parameter in " + method); - } - comment = annbody.comment(); - } - RestUploadFile annfile = param.getAnnotation(RestUploadFile.class); - if (annfile != null) { - if (mupload != null) { - throw new RestException("@RestUploadFile repeat in " + method); - } - mupload = annfile; - muploadType = ptype; - if (annhead != null) { - throw new RestException( - "@RestUploadFile and @RestHeader cannot on the same Parameter in " + method); - } - if (anncookie != null) { - throw new RestException( - "@RestUploadFile and @RestCookie cannot on the same Parameter in " + method); - } - if (annsid != null) { - throw new RestException( - "@RestUploadFile and @RestSessionid cannot on the same Parameter in " + method); - } - if (annaddr != null) { - throw new RestException( - "@RestUploadFile and @RestAddress cannot on the same Parameter in " + method); - } - if (annlocale != null) { - throw new RestException( - "@RestUploadFile and @RestLocale cannot on the same Parameter in " + method); - } - if (annbody != null) { - throw new RestException( - "@RestUploadFile and @RestBody cannot on the same Parameter in " + method); - } - if (ptype != byte[].class && ptype != File.class && ptype != File[].class) { - throw new RestException( - "@RestUploadFile must on byte[] or File or File[] Parameter in " + method); - } - comment = annfile.comment(); - } - - RestPath annpath = param.getAnnotation(RestPath.class); - if (annpath != null) { - if (annhead != null) { - throw new RestException("@RestPath and @RestHeader cannot on the same Parameter in " + method); - } - if (anncookie != null) { - throw new RestException("@RestPath and @RestCookie cannot on the same Parameter in " + method); - } - if (annsid != null) { - throw new RestException( - "@RestPath and @RestSessionid cannot on the same Parameter in " + method); - } - if (annaddr != null) { - throw new RestException("@RestPath and @RestAddress cannot on the same Parameter in " + method); - } - if (annlocale != null) { - throw new RestException("@RestPath and @RestLocale cannot on the same Parameter in " + method); - } - if (annbody != null) { - throw new RestException("@RestPath and @RestBody cannot on the same Parameter in " + method); - } - if (annfile != null) { - throw new RestException( - "@RestPath and @RestUploadFile cannot on the same Parameter in " + method); - } - if (ptype != String.class) { - throw new RestException("@RestPath must on String Parameter in " + method); - } - comment = annpath.comment(); - } - - RestUserid userid = param.getAnnotation(RestUserid.class); - if (userid != null) { - if (annhead != null) { - throw new RestException( - "@RestUserid and @RestHeader cannot on the same Parameter in " + method); - } - if (anncookie != null) { - throw new RestException( - "@RestUserid and @RestCookie cannot on the same Parameter in " + method); - } - if (annsid != null) { - throw new RestException( - "@RestUserid and @RestSessionid cannot on the same Parameter in " + method); - } - if (annaddr != null) { - throw new RestException( - "@RestUserid and @RestAddress cannot on the same Parameter in " + method); - } - if (annlocale != null) { - throw new RestException( - "@RestUserid and @RestLocale cannot on the same Parameter in " + method); - } - if (annbody != null) { - throw new RestException("@RestUserid and @RestBody cannot on the same Parameter in " + method); - } - if (annfile != null) { - throw new RestException( - "@RestUserid and @RestUploadFile cannot on the same Parameter in " + method); - } - if (!ptype.isPrimitive() && !java.io.Serializable.class.isAssignableFrom(ptype)) { - throw new RestException("@RestUserid must on java.io.Serializable Parameter in " + method); - } - comment = ""; - required = false; - } - - boolean annparams = param.getType() == RestParams.class; - boolean annheaders = param.getType() == RestHeaders.class; - if (annparams) { - if (annhead != null) { - throw new RestException("@RestHeader cannot on the " + RestParams.class.getSimpleName() - + " Parameter in " + method); - } - if (anncookie != null) { - throw new RestException("@RestCookie cannot on the " + RestParams.class.getSimpleName() - + " Parameter in " + method); - } - if (annsid != null) { - throw new RestException("@RestSessionid cannot on the " + RestParams.class.getSimpleName() - + " Parameter in " + method); - } - if (annaddr != null) { - throw new RestException("@RestAddress cannot on the " + RestParams.class.getSimpleName() - + " Parameter in " + method); - } - if (annlocale != null) { - throw new RestException("@RestLocale cannot on the " + RestParams.class.getSimpleName() - + " Parameter in " + method); - } - if (annbody != null) { - throw new RestException("@RestBody cannot on the " + RestParams.class.getSimpleName() - + " Parameter in " + method); - } - if (annfile != null) { - throw new RestException("@RestUploadFile cannot on the " + RestParams.class.getSimpleName() - + " Parameter in " + method); - } - if (userid != null) { - throw new RestException("@RestUserid cannot on the " + RestParams.class.getSimpleName() - + " Parameter in " + method); - } - if (annheaders) { - throw new RestException("@RestHeaders cannot on the " + RestParams.class.getSimpleName() - + " Parameter in " + method); - } - comment = ""; - } - - if (annheaders) { - if (annhead != null) { - throw new RestException("@RestHeader cannot on the " + RestHeaders.class.getSimpleName() - + " Parameter in " + method); - } - if (anncookie != null) { - throw new RestException("@RestCookie cannot on the " + RestHeaders.class.getSimpleName() - + " Parameter in " + method); - } - if (annsid != null) { - throw new RestException("@RestSessionid cannot on the " + RestHeaders.class.getSimpleName() - + " Parameter in " + method); - } - if (annaddr != null) { - throw new RestException("@RestAddress cannot on the " + RestHeaders.class.getSimpleName() - + " Parameter in " + method); - } - if (annlocale != null) { - throw new RestException("@RestLocale cannot on the " + RestHeaders.class.getSimpleName() - + " Parameter in " + method); - } - if (annbody != null) { - throw new RestException("@RestBody cannot on the " + RestHeaders.class.getSimpleName() - + " Parameter in " + method); - } - if (annfile != null) { - throw new RestException("@RestUploadFile cannot on the " + RestHeaders.class.getSimpleName() - + " Parameter in " + method); - } - if (userid != null) { - throw new RestException("@RestUserid cannot on the " + RestHeaders.class.getSimpleName() - + " Parameter in " + method); - } - if (annparams) { - throw new RestException("@RestParams cannot on the " + RestHeaders.class.getSimpleName() - + " Parameter in " + method); - } - comment = ""; - required = false; - } - - RestParam annpara = param.getAnnotation(RestParam.class); - if (annpara != null) { - radix = annpara.radix(); - } - if (annpara != null) { - comment = annpara.comment(); - } - if (annpara != null) { - required = annpara.required(); - } - if (n == null) { - n = (annpara == null || annpara.name().isEmpty()) ? null : annpara.name(); - } - if (n == null && ptype == userType) { - n = "&"; // 用户类型特殊处理 - } - if (n == null && ptype == RestHeaders.class) { - n = "^"; // Http头信息类型特殊处理 - } - if (n == null && ptype == RestParams.class) { - n = "?"; // Http参数类型特殊处理 - } - if (n == null && asmParamNames != null && asmParamNames.size() > i) { - n = asmParamNames.get(i).getName(); - } - if (n == null) { - if (param.isNamePresent()) { - n = param.getName(); - } else if (ptype == Flipper.class) { - n = "flipper"; - } else { - throw new RestException( - "Parameter " + param.getName() + " not found name by @RestParam in " + method); - } - } - if (annhead == null - && anncookie == null - && annsid == null - && annaddr == null - && annlocale == null - && annbody == null - && annfile == null - && !ptype.isPrimitive() - && ptype != String.class - && ptype != Flipper.class - && !CompletionHandler.class.isAssignableFrom(ptype) - && !ptype.getName().startsWith("java") - && n.charAt(0) != '#' - && !"&".equals(n)) { // 判断Json对象是否包含@RestUploadFile - Class loop = ptype; - do { - if (loop == null || loop.isInterface()) { - break; // 接口时getSuperclass可能会得到null - } - for (Field field : loop.getDeclaredFields()) { - if (Modifier.isStatic(field.getModifiers())) { - continue; - } - if (Modifier.isFinal(field.getModifiers())) { - continue; - } - RestUploadFile ruf = field.getAnnotation(RestUploadFile.class); - if (ruf == null) { - continue; - } - if (mupload != null) { - throw new RestException("@RestUploadFile repeat in " + method + " or field " + field); - } - mupload = ruf; - muploadType = field.getType(); - } - } while ((loop = loop.getSuperclass()) != Object.class); - } - java.lang.reflect.Type paramtype = TypeToken.getGenericType(param.getParameterizedType(), serviceType); - paramlist.add(new Object[] { - param, - n, - ptype, - radix, - comment, - required, - annpara, - annsid, - annaddr, - annlocale, - annhead, - anncookie, - annbody, - annfile, - annpath, - userid, - annheaders, - annparams, - paramtype - }); - } - - Map mappingMap = new LinkedHashMap<>(); - java.lang.reflect.Type returnGenericNoFutureType = - TypeToken.getGenericType(method.getGenericReturnType(), serviceType); - { // 设置 Annotation HttpMapping - boolean reqpath = false; - for (Object[] ps : paramlist) { - if ("#".equals((String) ps[1])) { - reqpath = true; - break; - } - } - if (method.getAnnotation(Deprecated.class) != null) { - av0 = mv.visitAnnotation(Type.getDescriptor(Deprecated.class), true); - av0.visitEnd(); - } - av0 = mv.visitAnnotation(mappingDesc, true); - String url = (catalog.isEmpty() ? "/" : ("/" + catalog + "/")) - + (defModuleName.isEmpty() ? "" : (defModuleName + "/")) - + entry.name - + (reqpath ? "/" : ""); - if ("//".equals(url)) { - url = "/"; - } - av0.visit("url", url); - av0.visit("name", (defModuleName.isEmpty() ? "" : (defModuleName + "_")) + entry.name); - av0.visit("example", entry.example); - av0.visit("rpcOnly", entry.rpcOnly); - av0.visit("auth", entry.auth); - av0.visit("cacheSeconds", entry.cacheSeconds); - av0.visit("actionid", entry.actionid); - av0.visit("comment", entry.comment); - - AnnotationVisitor av1 = av0.visitArray("methods"); - for (String m : entry.methods) { - av1.visit(null, m); - } - av1.visitEnd(); - - Class rtc = returnType; - if (rtc == void.class) { - rtc = RetResult.class; - returnGenericNoFutureType = TYPE_RETRESULT_STRING; - } else if (CompletionStage.class.isAssignableFrom(returnType)) { - ParameterizedType ptgrt = (ParameterizedType) returnGenericNoFutureType; - returnGenericNoFutureType = ptgrt.getActualTypeArguments()[0]; - rtc = TypeToken.typeToClass(returnGenericNoFutureType); - if (rtc == null) { - rtc = Object.class; // 应该不会发生吧? - } - } - av0.visit("result", Type.getType(Type.getDescriptor(rtc))); - if (returnGenericNoFutureType != rtc) { - String refid = typeRefs.get(returnGenericNoFutureType); - if (refid == null) { - refid = "_typeref_" + typeRefs.size(); - typeRefs.put(returnGenericNoFutureType, refid); - } - av0.visit("resultRef", refid); - } - - av0.visitEnd(); - mappingMap.put("url", url); - mappingMap.put("rpcOnly", entry.rpcOnly); - mappingMap.put("auth", entry.auth); - mappingMap.put("cacheSeconds", entry.cacheSeconds); - mappingMap.put("actionid", entry.actionid); - mappingMap.put("comment", entry.comment); - mappingMap.put("methods", entry.methods); - mappingMap.put( - "result", - returnGenericNoFutureType == returnType - ? returnType.getName() - : String.valueOf(returnGenericNoFutureType)); - entry.mappingurl = url; - } - { // 设置 Annotation NonBlocking - av0 = mv.visitAnnotation(nonblockDesc, true); - av0.visit("value", entry.nonBlocking); - av0.visitEnd(); - } - if (rcs != null && rcs.length > 0) { // 设置 Annotation RestConvert - av0 = mv.visitAnnotation(restConvertsDesc, true); - AnnotationVisitor av1 = av0.visitArray("value"); - // 设置 RestConvert - for (RestConvert rc : rcs) { - AnnotationVisitor av2 = av1.visitAnnotation(null, restConvertDesc); - av2.visit("features", rc.features()); - av2.visit("skipIgnore", rc.skipIgnore()); - av2.visit("type", Type.getType(Type.getDescriptor(rc.type()))); - AnnotationVisitor av3 = av2.visitArray("onlyColumns"); - for (String s : rc.onlyColumns()) { - av3.visit(null, s); - } - av3.visitEnd(); - av3 = av2.visitArray("ignoreColumns"); - for (String s : rc.ignoreColumns()) { - av3.visit(null, s); - } - av3.visitEnd(); - av3 = av2.visitArray("convertColumns"); - for (String s : rc.convertColumns()) { - av3.visit(null, s); - } - av3.visitEnd(); - av2.visitEnd(); - } - av1.visitEnd(); - av0.visitEnd(); - } - if (rcc != null && rcc.length > 0) { // 设置 Annotation RestConvertCoder - av0 = mv.visitAnnotation(restConvertCodersDesc, true); - AnnotationVisitor av1 = av0.visitArray("value"); - // 设置 RestConvertCoder - for (RestConvertCoder rc : rcc) { - AnnotationVisitor av2 = av1.visitAnnotation(null, restConvertCoderDesc); - av2.visit("type", Type.getType(Type.getDescriptor(rc.type()))); - av2.visit("field", rc.field()); - av2.visit("coder", Type.getType(Type.getDescriptor(rc.coder()))); - av2.visitEnd(); - } - av1.visitEnd(); - av0.visitEnd(); - } - final int headIndex = 10; - { // 设置 Annotation - av0 = mv.visitAnnotation(httpParamsDesc, true); - AnnotationVisitor av1 = av0.visitArray("value"); - // 设置 HttpParam - for (Object[] ps : - paramlist) { // {param, n, ptype, radix, comment, required, annpara, annsid, annaddr, annlocale, - // annhead, anncookie, annbody, annfile, annpath, annuserid, annheaders, annparams, - // paramtype} - String n = ps[1].toString(); - final boolean isuserid = ((RestUserid) ps[headIndex + 5]) != null; // 是否取userid - if (n.indexOf('&') >= 0 || isuserid) { - continue; // @RestUserid 不需要生成 @HttpParam - } - if (((RestAddress) ps[8]) != null) { - continue; // @RestAddress 不需要生成 @HttpParam - } - if (((RestLocale) ps[9]) != null) { - continue; // @RestLocale 不需要生成 @HttpParam - } - final boolean ishead = ((RestHeader) ps[headIndex]) != null; // 是否取getHeader 而不是 getParameter - final boolean iscookie = ((RestCookie) ps[headIndex + 1]) != null; // 是否取getCookie - final boolean isbody = ((RestBody) ps[headIndex + 2]) != null; // 是否取getBody - AnnotationVisitor av2 = av1.visitAnnotation(null, httpParamDesc); - av2.visit("name", (String) ps[1]); - if (((Parameter) ps[0]).getAnnotation(Deprecated.class) != null) { - av2.visit("deprecated", true); - } - av2.visit("type", Type.getType(Type.getDescriptor((Class) ps[2]))); - java.lang.reflect.Type pgtype = - TypeToken.getGenericType(((Parameter) ps[0]).getParameterizedType(), serviceType); - if (pgtype != (Class) ps[2]) { - String refid = typeRefs.get(pgtype); - if (refid == null) { - refid = "_typeref_" + typeRefs.size(); - typeRefs.put(pgtype, refid); - } - av2.visit("typeref", refid); - } - av2.visit("radix", (Integer) ps[3]); - if (ishead) { - av2.visitEnum("style", sourcetypeDesc, HttpParam.HttpParameterStyle.HEADER.name()); - av2.visit("example", ((RestHeader) ps[headIndex]).example()); - } else if (iscookie) { - av2.visitEnum("style", sourcetypeDesc, HttpParam.HttpParameterStyle.COOKIE.name()); - av2.visit("example", ((RestCookie) ps[headIndex + 1]).example()); - } else if (isbody) { - av2.visitEnum("style", sourcetypeDesc, HttpParam.HttpParameterStyle.BODY.name()); - av2.visit("example", ((RestBody) ps[headIndex + 2]).example()); - } else if (ps[6] != null) { - av2.visitEnum("style", sourcetypeDesc, HttpParam.HttpParameterStyle.QUERY.name()); - av2.visit("example", ((RestParam) ps[6]).example()); - } - av2.visit("comment", (String) ps[4]); - av2.visit("required", (Boolean) ps[5]); - av2.visitEnd(); - } - av1.visitEnd(); - av0.visitEnd(); - } - int uploadLocal = 0; - if (mupload != null) { // 存在文件上传 - containsMupload = true; - if (muploadType == byte[].class) { - mv.visitVarInsn(ALOAD, 1); - mv.visitMethodInsn( - INVOKEVIRTUAL, reqInternalName, "getMultiContext", "()" + multiContextDesc, false); - mv.visitLdcInsn(mupload.maxLength()); - mv.visitLdcInsn(mupload.fileNameRegx()); - mv.visitLdcInsn(mupload.contentTypeRegx()); - mv.visitMethodInsn( - INVOKEVIRTUAL, - multiContextName, - "partsFirstBytes", - "(JLjava/lang/String;Ljava/lang/String;)[B", - false); - mv.visitVarInsn(ASTORE, maxLocals); - uploadLocal = maxLocals; - } else if (muploadType == File.class) { - mv.visitVarInsn(ALOAD, 1); - mv.visitMethodInsn( - INVOKEVIRTUAL, reqInternalName, "getMultiContext", "()" + multiContextDesc, false); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, "_redkale_home", "Ljava/io/File;"); - mv.visitLdcInsn(mupload.maxLength()); - mv.visitLdcInsn(mupload.fileNameRegx()); - mv.visitLdcInsn(mupload.contentTypeRegx()); - mv.visitMethodInsn( - INVOKEVIRTUAL, - multiContextName, - "partsFirstFile", - "(Ljava/io/File;JLjava/lang/String;Ljava/lang/String;)Ljava/io/File;", - false); - mv.visitVarInsn(ASTORE, maxLocals); - uploadLocal = maxLocals; - } else if (muploadType == File[].class) { // File[] - mv.visitVarInsn(ALOAD, 1); - mv.visitMethodInsn( - INVOKEVIRTUAL, reqInternalName, "getMultiContext", "()" + multiContextDesc, false); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, "_redkale_home", "Ljava/io/File;"); - mv.visitLdcInsn(mupload.maxLength()); - mv.visitLdcInsn(mupload.fileNameRegx()); - mv.visitLdcInsn(mupload.contentTypeRegx()); - mv.visitMethodInsn( - INVOKEVIRTUAL, - multiContextName, - "partsFiles", - "(Ljava/io/File;JLjava/lang/String;Ljava/lang/String;)[Ljava/io/File;", - false); - mv.visitVarInsn(ASTORE, maxLocals); - uploadLocal = maxLocals; - } - maxLocals++; - } - - List> paramMaps = new ArrayList<>(); - // 获取每个参数的值 - boolean hasAsyncHandler = false; - for (Object[] ps : paramlist) { - Map paramMap = new LinkedHashMap<>(); - final Parameter param = (Parameter) ps[0]; // 参数类型 - String pname = (String) ps[1]; // 参数名 - Class ptype = (Class) ps[2]; // 参数类型 - int radix = (Integer) ps[3]; - String comment = (String) ps[4]; - boolean required = (Boolean) ps[5]; - RestParam annpara = (RestParam) ps[6]; - RestSessionid annsid = (RestSessionid) ps[7]; - RestAddress annaddr = (RestAddress) ps[8]; - RestLocale annlocale = (RestLocale) ps[9]; - RestHeader annhead = (RestHeader) ps[headIndex]; - RestCookie anncookie = (RestCookie) ps[headIndex + 1]; - RestBody annbody = (RestBody) ps[headIndex + 2]; - RestUploadFile annfile = (RestUploadFile) ps[headIndex + 3]; - RestPath annpath = (RestPath) ps[headIndex + 4]; - RestUserid userid = (RestUserid) ps[headIndex + 5]; - boolean annheaders = (Boolean) ps[headIndex + 6]; - boolean annparams = (Boolean) ps[headIndex + 7]; - java.lang.reflect.Type pgentype = (java.lang.reflect.Type) ps[headIndex + 8]; - if (dynsimple - && (annsid != null - || annaddr != null - || annlocale != null - || annhead != null - || anncookie != null - || annfile != null - || annheaders)) { - dynsimple = false; - } - - final boolean ishead = annhead != null; // 是否取getHeader 而不是 getParameter - final boolean iscookie = anncookie != null; // 是否取getCookie - - paramMap.put("name", pname); - paramMap.put("type", ptype.getName()); - if (CompletionHandler.class.isAssignableFrom( - ptype)) { // HttpResponse.createAsyncHandler() or HttpResponse.createAsyncHandler(Class) - if (ptype == CompletionHandler.class) { - mv.visitVarInsn(ALOAD, 2); - mv.visitMethodInsn( - INVOKEVIRTUAL, - respInternalName, - "createAsyncHandler", - "()Ljava/nio/channels/CompletionHandler;", - false); - mv.visitVarInsn(ASTORE, maxLocals); - varInsns.add(new int[] {ALOAD, maxLocals}); - } else { - mv.visitVarInsn(ALOAD, 3); - mv.visitVarInsn(ALOAD, 2); - mv.visitLdcInsn(Type.getType(Type.getDescriptor(ptype))); - mv.visitMethodInsn( - INVOKEVIRTUAL, - respInternalName, - "createAsyncHandler", - "(Ljava/lang/Class;)Ljava/nio/channels/CompletionHandler;", - false); - mv.visitTypeInsn(CHECKCAST, ptype.getName().replace('.', '/')); - mv.visitVarInsn(ASTORE, maxLocals); - varInsns.add(new int[] {ALOAD, maxLocals}); - } - hasAsyncHandler = true; - } else if (annsid != null) { // HttpRequest.getSessionid(true|false) - mv.visitVarInsn(ALOAD, 1); - mv.visitInsn(annsid.create() ? ICONST_1 : ICONST_0); - mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getSessionid", "(Z)Ljava/lang/String;", false); - mv.visitVarInsn(ASTORE, maxLocals); - varInsns.add(new int[] {ALOAD, maxLocals}); - } else if (annaddr != null) { // HttpRequest.getRemoteAddr - mv.visitVarInsn(ALOAD, 1); - mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getRemoteAddr", "()Ljava/lang/String;", false); - mv.visitVarInsn(ASTORE, maxLocals); - varInsns.add(new int[] {ALOAD, maxLocals}); - } else if (annlocale != null) { // HttpRequest.getLocale - mv.visitVarInsn(ALOAD, 1); - mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getLocale", "()Ljava/lang/String;", false); - mv.visitVarInsn(ASTORE, maxLocals); - varInsns.add(new int[] {ALOAD, maxLocals}); - } else if (annheaders) { // HttpRequest.getHeaders - mv.visitVarInsn(ALOAD, 1); - mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getHeaders", "()" + httpHeadersDesc, false); - mv.visitVarInsn(ASTORE, maxLocals); - varInsns.add(new int[] {ALOAD, maxLocals}); - } else if (annparams) { // HttpRequest.getParameters - mv.visitVarInsn(ALOAD, 1); - mv.visitMethodInsn( - INVOKEVIRTUAL, reqInternalName, "getParameters", "()" + httpParametersDesc, false); - mv.visitVarInsn(ASTORE, maxLocals); - varInsns.add(new int[] {ALOAD, maxLocals}); - } else if (annbody != null) { // HttpRequest.getBodyUTF8 / HttpRequest.getBody - if (ptype == String.class) { - mv.visitVarInsn(ALOAD, 1); - mv.visitMethodInsn( - INVOKEVIRTUAL, reqInternalName, "getBodyUTF8", "()Ljava/lang/String;", false); - mv.visitVarInsn(ASTORE, maxLocals); - varInsns.add(new int[] {ALOAD, maxLocals}); - } else if (ptype == byte[].class) { - mv.visitVarInsn(ALOAD, 1); - mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getBody", "()[B", false); - mv.visitVarInsn(ASTORE, maxLocals); - varInsns.add(new int[] {ALOAD, maxLocals}); - } else { // JavaBean 转 Json - String typefieldname = "_redkale_body_jsontype_" + bodyTypes.size(); - bodyTypes.put(typefieldname, pgentype); - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, typefieldname, "Ljava/lang/reflect/Type;"); - mv.visitMethodInsn( - INVOKEVIRTUAL, - reqInternalName, - "getBodyJson", - "(Ljava/lang/reflect/Type;)Ljava/lang/Object;", - false); - mv.visitTypeInsn(CHECKCAST, Type.getInternalName(ptype)); - mv.visitVarInsn(ASTORE, maxLocals); - varInsns.add(new int[] {ALOAD, maxLocals}); - } - } else if (annfile - != null) { // MultiContext.partsFirstBytes / HttpRequest.partsFirstFile / HttpRequest.partsFiles - mv.visitVarInsn(ALOAD, 4); - mv.visitVarInsn(ASTORE, maxLocals); - varInsns.add(new int[] {ALOAD, maxLocals}); - } else if (annpath != null) { // HttpRequest.getRequestPath - mv.visitVarInsn(ALOAD, 1); - mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getRequestPath", "()Ljava/lang/String;", false); - mv.visitVarInsn(ASTORE, maxLocals); - varInsns.add(new int[] {ALOAD, maxLocals}); - } else if (userid != null) { // HttpRequest.currentUserid - mv.visitVarInsn(ALOAD, 1); - if (ptype == int.class) { - mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "currentIntUserid", "()I", false); - mv.visitVarInsn(ISTORE, maxLocals); - varInsns.add(new int[] {ILOAD, maxLocals}); - } else if (ptype == long.class) { - mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "currentLongUserid", "()J", false); - mv.visitVarInsn(LSTORE, maxLocals); - varInsns.add(new int[] {LLOAD, maxLocals}); - maxLocals++; - } else if (ptype == String.class) { - mv.visitMethodInsn( - INVOKEVIRTUAL, reqInternalName, "currentStringUserid", "()Ljava/lang/String;", false); - mv.visitVarInsn(ASTORE, maxLocals); - varInsns.add(new int[] {ALOAD, maxLocals}); - } else { - mv.visitLdcInsn(Type.getType(Type.getDescriptor(ptype))); - mv.visitMethodInsn( - INVOKEVIRTUAL, - reqInternalName, - "currentUserid", - "(Ljava/lang/Class;)Ljava/io/Serializable;", - false); - mv.visitTypeInsn(CHECKCAST, Type.getInternalName(ptype)); - mv.visitVarInsn(ASTORE, maxLocals); - varInsns.add(new int[] {ALOAD, maxLocals}); - } - } else if ("#".equals(pname)) { // 从request.getRequstURI 中取参数 - if (ptype == boolean.class) { - mv.visitVarInsn(ALOAD, 1); - mv.visitMethodInsn( - INVOKEVIRTUAL, reqInternalName, "getPathLastParam", "()Ljava/lang/String;", false); - mv.visitMethodInsn( - INVOKESTATIC, "java/lang/Boolean", "parseBoolean", "(Ljava/lang/String;)Z", false); - mv.visitVarInsn(ISTORE, maxLocals); - varInsns.add(new int[] {ILOAD, maxLocals}); - } else if (ptype == byte.class) { - mv.visitVarInsn(ALOAD, 1); - mv.visitMethodInsn( - INVOKEVIRTUAL, reqInternalName, "getPathLastParam", "()Ljava/lang/String;", false); - mv.visitIntInsn(BIPUSH, radix); - mv.visitMethodInsn( - INVOKESTATIC, "java/lang/Byte", "parseByte", "(Ljava/lang/String;I)B", false); - mv.visitVarInsn(ISTORE, maxLocals); - varInsns.add(new int[] {ILOAD, maxLocals}); - } else if (ptype == short.class) { - mv.visitVarInsn(ALOAD, 1); - mv.visitMethodInsn( - INVOKEVIRTUAL, reqInternalName, "getPathLastParam", "()Ljava/lang/String;", false); - mv.visitIntInsn(BIPUSH, radix); - mv.visitMethodInsn( - INVOKESTATIC, "java/lang/Short", "parseShort", "(Ljava/lang/String;I)S", false); - mv.visitVarInsn(ISTORE, maxLocals); - varInsns.add(new int[] {ILOAD, maxLocals}); - } else if (ptype == char.class) { - mv.visitVarInsn(ALOAD, 1); - mv.visitMethodInsn( - INVOKEVIRTUAL, reqInternalName, "getPathLastParam", "()Ljava/lang/String;", false); - mv.visitInsn(ICONST_0); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "charAt", "(I)C", false); - mv.visitVarInsn(ISTORE, maxLocals); - varInsns.add(new int[] {ILOAD, maxLocals}); - } else if (ptype == int.class) { - mv.visitVarInsn(ALOAD, 1); - mv.visitMethodInsn( - INVOKEVIRTUAL, reqInternalName, "getPathLastParam", "()Ljava/lang/String;", false); - mv.visitIntInsn(BIPUSH, radix); - mv.visitMethodInsn( - INVOKESTATIC, "java/lang/Integer", "parseInt", "(Ljava/lang/String;I)I", false); - mv.visitVarInsn(ISTORE, maxLocals); - varInsns.add(new int[] {ILOAD, maxLocals}); - } else if (ptype == float.class) { - mv.visitVarInsn(ALOAD, 1); - mv.visitMethodInsn( - INVOKEVIRTUAL, reqInternalName, "getPathLastParam", "()Ljava/lang/String;", false); - mv.visitMethodInsn( - INVOKESTATIC, "java/lang/Float", "parseFloat", "(Ljava/lang/String;)F", false); - mv.visitVarInsn(FSTORE, maxLocals); - varInsns.add(new int[] {FLOAD, maxLocals}); - } else if (ptype == long.class) { - mv.visitVarInsn(ALOAD, 1); - mv.visitMethodInsn( - INVOKEVIRTUAL, reqInternalName, "getPathLastParam", "()Ljava/lang/String;", false); - mv.visitIntInsn(BIPUSH, radix); - mv.visitMethodInsn( - INVOKESTATIC, "java/lang/Long", "parseLong", "(Ljava/lang/String;I)J", false); - mv.visitVarInsn(LSTORE, maxLocals); - varInsns.add(new int[] {LLOAD, maxLocals}); - maxLocals++; - } else if (ptype == double.class) { - mv.visitVarInsn(ALOAD, 1); - mv.visitMethodInsn( - INVOKEVIRTUAL, reqInternalName, "getPathLastParam", "()Ljava/lang/String;", false); - mv.visitMethodInsn( - INVOKESTATIC, "java/lang/Double", "parseDouble", "(Ljava/lang/String;)D", false); - mv.visitVarInsn(DSTORE, maxLocals); - varInsns.add(new int[] {DLOAD, maxLocals}); - maxLocals++; - } else if (ptype == String.class) { - mv.visitVarInsn(ALOAD, 1); - mv.visitMethodInsn( - INVOKEVIRTUAL, reqInternalName, "getPathLastParam", "()Ljava/lang/String;", false); - mv.visitVarInsn(ASTORE, maxLocals); - varInsns.add(new int[] {ALOAD, maxLocals}); - } else { - throw new RestException(method + " only " + RestParam.class.getSimpleName() - + "(#) to Type(primitive class or String)"); - } - } else if (pname.charAt(0) == '#') { // 从request.getPathParam 中去参数 - if (ptype == boolean.class) { - mv.visitVarInsn(ALOAD, 1); - mv.visitLdcInsn(pname.substring(1)); - mv.visitLdcInsn("false"); - mv.visitMethodInsn( - INVOKEVIRTUAL, - reqInternalName, - "getPathParam", - "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", - false); - mv.visitMethodInsn( - INVOKESTATIC, "java/lang/Boolean", "parseBoolean", "(Ljava/lang/String;)Z", false); - mv.visitVarInsn(ISTORE, maxLocals); - varInsns.add(new int[] {ILOAD, maxLocals}); - } else if (ptype == byte.class) { - mv.visitVarInsn(ALOAD, 1); - mv.visitLdcInsn(pname.substring(1)); - mv.visitLdcInsn("0"); - mv.visitMethodInsn( - INVOKEVIRTUAL, - reqInternalName, - "getPathParam", - "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", - false); - mv.visitIntInsn(BIPUSH, radix); - mv.visitMethodInsn( - INVOKESTATIC, "java/lang/Byte", "parseByte", "(Ljava/lang/String;I)B", false); - mv.visitVarInsn(ISTORE, maxLocals); - varInsns.add(new int[] {ILOAD, maxLocals}); - } else if (ptype == short.class) { - mv.visitVarInsn(ALOAD, 1); - mv.visitLdcInsn(pname.substring(1)); - mv.visitLdcInsn("0"); - mv.visitMethodInsn( - INVOKEVIRTUAL, - reqInternalName, - "getPathParam", - "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", - false); - mv.visitIntInsn(BIPUSH, radix); - mv.visitMethodInsn( - INVOKESTATIC, "java/lang/Short", "parseShort", "(Ljava/lang/String;I)S", false); - mv.visitVarInsn(ISTORE, maxLocals); - varInsns.add(new int[] {ILOAD, maxLocals}); - } else if (ptype == char.class) { - mv.visitVarInsn(ALOAD, 1); - mv.visitLdcInsn(pname.substring(1)); - mv.visitLdcInsn("0"); - mv.visitMethodInsn( - INVOKEVIRTUAL, - reqInternalName, - "getPathParam", - "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", - false); - mv.visitInsn(ICONST_0); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "charAt", "(I)C", false); - mv.visitVarInsn(ISTORE, maxLocals); - varInsns.add(new int[] {ILOAD, maxLocals}); - } else if (ptype == int.class) { - mv.visitVarInsn(ALOAD, 1); - mv.visitLdcInsn(pname.substring(1)); - mv.visitLdcInsn("0"); - mv.visitMethodInsn( - INVOKEVIRTUAL, - reqInternalName, - "getPathParam", - "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", - false); - mv.visitIntInsn(BIPUSH, radix); - mv.visitMethodInsn( - INVOKESTATIC, "java/lang/Integer", "parseInt", "(Ljava/lang/String;I)I", false); - mv.visitVarInsn(ISTORE, maxLocals); - varInsns.add(new int[] {ILOAD, maxLocals}); - } else if (ptype == float.class) { - mv.visitVarInsn(ALOAD, 1); - mv.visitLdcInsn(pname.substring(1)); - mv.visitLdcInsn("0"); - mv.visitMethodInsn( - INVOKEVIRTUAL, - reqInternalName, - "getPathParam", - "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", - false); - mv.visitMethodInsn( - INVOKESTATIC, "java/lang/Float", "parseFloat", "(Ljava/lang/String;)F", false); - mv.visitVarInsn(FSTORE, maxLocals); - varInsns.add(new int[] {FLOAD, maxLocals}); - } else if (ptype == long.class) { - mv.visitVarInsn(ALOAD, 1); - mv.visitLdcInsn(pname.substring(1)); - mv.visitLdcInsn("0"); - mv.visitMethodInsn( - INVOKEVIRTUAL, - reqInternalName, - "getPathParam", - "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", - false); - mv.visitIntInsn(BIPUSH, radix); - mv.visitMethodInsn( - INVOKESTATIC, "java/lang/Long", "parseLong", "(Ljava/lang/String;I)J", false); - mv.visitVarInsn(LSTORE, maxLocals); - varInsns.add(new int[] {LLOAD, maxLocals}); - maxLocals++; - } else if (ptype == double.class) { - mv.visitVarInsn(ALOAD, 1); - mv.visitLdcInsn(pname.substring(1)); - mv.visitLdcInsn("0"); - mv.visitMethodInsn( - INVOKEVIRTUAL, - reqInternalName, - "getPathParam", - "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", - false); - mv.visitMethodInsn( - INVOKESTATIC, "java/lang/Double", "parseDouble", "(Ljava/lang/String;)D", false); - mv.visitVarInsn(DSTORE, maxLocals); - varInsns.add(new int[] {DLOAD, maxLocals}); - maxLocals++; - } else if (ptype == String.class) { - mv.visitVarInsn(ALOAD, 1); - mv.visitLdcInsn(pname.substring(1)); - mv.visitLdcInsn(""); - mv.visitMethodInsn( - INVOKEVIRTUAL, - reqInternalName, - "getPathParam", - "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", - false); - mv.visitVarInsn(ASTORE, maxLocals); - varInsns.add(new int[] {ALOAD, maxLocals}); - } else { - throw new RestException(method + " only " + RestParam.class.getSimpleName() - + "(#) to Type(primitive class or String)"); - } - } else if ("&".equals(pname) && ptype == userType) { // 当前用户对象的类名 - mv.visitVarInsn(ALOAD, 1); - mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "currentUser", "()Ljava/lang/Object;", false); - mv.visitTypeInsn(CHECKCAST, Type.getInternalName(ptype)); - mv.visitVarInsn(ASTORE, maxLocals); - varInsns.add(new int[] {ALOAD, maxLocals}); - } else if (ptype == boolean.class) { - mv.visitVarInsn(ALOAD, 1); - mv.visitLdcInsn(pname); - mv.visitInsn(ICONST_0); - mv.visitMethodInsn( - INVOKEVIRTUAL, - reqInternalName, - ishead ? "getBooleanHeader" : "getBooleanParameter", - "(Ljava/lang/String;Z)Z", - false); - mv.visitVarInsn(ISTORE, maxLocals); - varInsns.add(new int[] {ILOAD, maxLocals}); - } else if (ptype == byte.class) { - mv.visitVarInsn(ALOAD, 1); - mv.visitLdcInsn(pname); - mv.visitLdcInsn("0"); - mv.visitMethodInsn( - INVOKEVIRTUAL, - reqInternalName, - ishead ? "getHeader" : "getParameter", - "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", - false); - mv.visitIntInsn(BIPUSH, radix); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "parseByte", "(Ljava/lang/String;I)B", false); - mv.visitVarInsn(ISTORE, maxLocals); - varInsns.add(new int[] {ILOAD, maxLocals}); - } else if (ptype == short.class) { - mv.visitVarInsn(ALOAD, 1); - mv.visitIntInsn(BIPUSH, radix); - mv.visitLdcInsn(pname); - mv.visitInsn(ICONST_0); - mv.visitMethodInsn( - INVOKEVIRTUAL, - reqInternalName, - ishead ? "getShortHeader" : "getShortParameter", - "(ILjava/lang/String;S)S", - false); - mv.visitVarInsn(ISTORE, maxLocals); - varInsns.add(new int[] {ILOAD, maxLocals}); - } else if (ptype == char.class) { - mv.visitVarInsn(ALOAD, 1); - mv.visitLdcInsn(pname); - mv.visitLdcInsn("0"); - mv.visitMethodInsn( - INVOKEVIRTUAL, - reqInternalName, - ishead ? "getHeader" : "getParameter", - "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", - false); - mv.visitInsn(ICONST_0); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "charAt", "(I)C", false); - mv.visitVarInsn(ISTORE, maxLocals); - varInsns.add(new int[] {ILOAD, maxLocals}); - } else if (ptype == int.class) { - mv.visitVarInsn(ALOAD, 1); - mv.visitIntInsn(BIPUSH, radix); - mv.visitLdcInsn(pname); - mv.visitInsn(ICONST_0); - mv.visitMethodInsn( - INVOKEVIRTUAL, - reqInternalName, - ishead ? "getIntHeader" : "getIntParameter", - "(ILjava/lang/String;I)I", - false); - mv.visitVarInsn(ISTORE, maxLocals); - varInsns.add(new int[] {ILOAD, maxLocals}); - } else if (ptype == float.class) { - mv.visitVarInsn(ALOAD, 1); - mv.visitLdcInsn(pname); - mv.visitInsn(FCONST_0); - mv.visitMethodInsn( - INVOKEVIRTUAL, - reqInternalName, - ishead ? "getFloatHeader" : "getFloatParameter", - "(Ljava/lang/String;F)F", - false); - mv.visitVarInsn(FSTORE, maxLocals); - varInsns.add(new int[] {FLOAD, maxLocals}); - } else if (ptype == long.class) { - mv.visitVarInsn(ALOAD, 1); - mv.visitIntInsn(BIPUSH, radix); - mv.visitLdcInsn(pname); - mv.visitInsn(LCONST_0); - mv.visitMethodInsn( - INVOKEVIRTUAL, - reqInternalName, - ishead ? "getLongHeader" : "getLongParameter", - "(ILjava/lang/String;J)J", - false); - mv.visitVarInsn(LSTORE, maxLocals); - varInsns.add(new int[] {LLOAD, maxLocals}); - maxLocals++; - } else if (ptype == double.class) { - mv.visitVarInsn(ALOAD, 1); - mv.visitLdcInsn(pname); - mv.visitInsn(DCONST_0); - mv.visitMethodInsn( - INVOKEVIRTUAL, - reqInternalName, - ishead ? "getDoubleHeader" : "getDoubleParameter", - "(Ljava/lang/String;D)D", - false); - mv.visitVarInsn(DSTORE, maxLocals); - varInsns.add(new int[] {DLOAD, maxLocals}); - maxLocals++; - } else if (ptype == String.class) { - mv.visitVarInsn(ALOAD, 1); - mv.visitLdcInsn(pname); - mv.visitLdcInsn(""); - mv.visitMethodInsn( - INVOKEVIRTUAL, - reqInternalName, - iscookie ? "getCookie" : (ishead ? "getHeader" : "getParameter"), - "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", - false); - mv.visitVarInsn(ASTORE, maxLocals); - varInsns.add(new int[] {ALOAD, maxLocals}); - } else if (ptype == Flipper.class) { - mv.visitVarInsn(ALOAD, 1); - mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getFlipper", "()" + flipperDesc, false); - mv.visitVarInsn(ASTORE, maxLocals); - varInsns.add(new int[] {ALOAD, maxLocals}); - } else { // 其他Json对象 - mv.visitVarInsn(ALOAD, 1); - if (param.getType() == param.getParameterizedType()) { - mv.visitLdcInsn(Type.getType(Type.getDescriptor(ptype))); - } else { - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn( - GETFIELD, newDynName, REST_PARAMTYPES_FIELD_NAME, "[[Ljava/lang/reflect/Type;"); - Asms.visitInsn(mv, entry.methodIdx); // 方法下标 - mv.visitInsn(AALOAD); - int paramidx = -1; - for (int i = 0; i < params.length; i++) { - if (params[i] == param) { - paramidx = i; - break; - } - } - Asms.visitInsn(mv, paramidx); // 参数下标 - mv.visitInsn(AALOAD); - } - mv.visitLdcInsn(pname); - mv.visitMethodInsn( - INVOKEVIRTUAL, - reqInternalName, - ishead ? "getJsonHeader" : "getJsonParameter", - "(Ljava/lang/reflect/Type;Ljava/lang/String;)Ljava/lang/Object;", - false); - mv.visitTypeInsn(CHECKCAST, ptype.getName().replace('.', '/')); - mv.visitVarInsn(ASTORE, maxLocals); - varInsns.add(new int[] {ALOAD, maxLocals}); - JsonFactory.root().loadDecoder(pgentype); - - // 构建 RestHeader、RestCookie、RestAddress 等赋值操作 - Class loop = ptype; - Set fields = new HashSet<>(); - Map attrParaNames = new LinkedHashMap<>(); - do { - if (loop == null || loop.isInterface()) { - break; // 接口时getSuperclass可能会得到null - } - for (Field field : loop.getDeclaredFields()) { - if (Modifier.isStatic(field.getModifiers())) { - continue; - } - if (Modifier.isFinal(field.getModifiers())) { - continue; - } - if (fields.contains(field.getName())) { - continue; - } - RestHeader rh = field.getAnnotation(RestHeader.class); - RestCookie rc = field.getAnnotation(RestCookie.class); - RestSessionid rs = field.getAnnotation(RestSessionid.class); - RestAddress ra = field.getAnnotation(RestAddress.class); - RestLocale rl = field.getAnnotation(RestLocale.class); - RestBody rb = field.getAnnotation(RestBody.class); - RestUploadFile ru = field.getAnnotation(RestUploadFile.class); - RestPath ri = field.getAnnotation(RestPath.class); - if (rh == null - && rc == null - && ra == null - && rl == null - && rb == null - && rs == null - && ru == null - && ri == null) { - continue; - } - if (rh != null - && field.getType() != String.class - && field.getType() != InetSocketAddress.class) { - throw new RestException("@RestHeader must on String Field in " + field); - } - if (rc != null && field.getType() != String.class) { - throw new RestException("@RestCookie must on String Field in " + field); - } - if (rs != null && field.getType() != String.class) { - throw new RestException("@RestSessionid must on String Field in " + field); - } - if (ra != null && field.getType() != String.class) { - throw new RestException("@RestAddress must on String Field in " + field); - } - if (rl != null && field.getType() != String.class) { - throw new RestException("@RestLocale must on String Field in " + field); - } - if (rb != null && field.getType().isPrimitive()) { - throw new RestException("@RestBody must on cannot on primitive type Field in " + field); - } - if (ru != null - && field.getType() != byte[].class - && field.getType() != File.class - && field.getType() != File[].class) { - throw new RestException( - "@RestUploadFile must on byte[] or File or File[] Field in " + field); - } - - if (ri != null && field.getType() != String.class) { - throw new RestException("@RestPath must on String Field in " + field); - } - org.redkale.util.Attribute attr = org.redkale.util.Attribute.create(loop, field); - String attrFieldName; - String restname = ""; - if (rh != null) { - attrFieldName = "_redkale_attr_header_" - + (field.getType() != String.class ? "json_" : "") + restAttributes.size(); - restname = rh.name(); - } else if (rc != null) { - attrFieldName = "_redkale_attr_cookie_" + restAttributes.size(); - restname = rc.name(); - } else if (rs != null) { - attrFieldName = "_redkale_attr_sessionid_" + restAttributes.size(); - restname = rs.create() ? "1" : ""; // 用于下面区分create值 - } else if (ra != null) { - attrFieldName = "_redkale_attr_address_" + restAttributes.size(); - // restname = ""; - } else if (rl != null) { - attrFieldName = "_redkale_attr_locale_" + restAttributes.size(); - // restname = ""; - } else if (rb != null && field.getType() == String.class) { - attrFieldName = "_redkale_attr_bodystring_" + restAttributes.size(); - // restname = ""; - } else if (rb != null && field.getType() == byte[].class) { - attrFieldName = "_redkale_attr_bodybytes_" + restAttributes.size(); - // restname = ""; - } else if (rb != null - && field.getType() != String.class - && field.getType() != byte[].class) { - attrFieldName = "_redkale_attr_bodyjson_" + restAttributes.size(); - // restname = ""; - } else if (ru != null && field.getType() == byte[].class) { - attrFieldName = "_redkale_attr_uploadbytes_" + restAttributes.size(); - // restname = ""; - } else if (ru != null && field.getType() == File.class) { - attrFieldName = "_redkale_attr_uploadfile_" + restAttributes.size(); - // restname = ""; - } else if (ru != null && field.getType() == File[].class) { - attrFieldName = "_redkale_attr_uploadfiles_" + restAttributes.size(); - // restname = ""; - } else if (ri != null && field.getType() == String.class) { - attrFieldName = "_redkale_attr_uri_" + restAttributes.size(); - // restname = ""; - } else { - continue; - } - restAttributes.put(attrFieldName, attr); - attrParaNames.put( - attrFieldName, - new Object[] {restname, field.getType(), field.getGenericType(), ru}); - fields.add(field.getName()); - } - } while ((loop = loop.getSuperclass()) != Object.class); - - if (!attrParaNames - .isEmpty()) { // 参数存在 RestHeader、RestCookie、RestSessionid、RestAddress、RestLocale、RestBody字段 - mv.visitVarInsn(ALOAD, maxLocals); // 加载JsonBean - Label lif = new Label(); - mv.visitJumpInsn(IFNULL, lif); // if(bean != null) { - for (Map.Entry en : attrParaNames.entrySet()) { - RestUploadFile ru = (RestUploadFile) en.getValue()[3]; - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, en.getKey(), attrDesc); - mv.visitVarInsn(ALOAD, maxLocals); - mv.visitVarInsn(ALOAD, en.getKey().contains("_upload") ? uploadLocal : 1); - if (en.getKey().contains("_header_")) { - String headerkey = en.getValue()[0].toString(); - if ("Host".equalsIgnoreCase(headerkey)) { - mv.visitMethodInsn( - INVOKEVIRTUAL, reqInternalName, "getHost", "()Ljava/lang/String;", false); - } else if ("Content-Type".equalsIgnoreCase(headerkey)) { - mv.visitMethodInsn( - INVOKEVIRTUAL, - reqInternalName, - "getContentType", - "()Ljava/lang/String;", - false); - } else if ("Connection".equalsIgnoreCase(headerkey)) { - mv.visitMethodInsn( - INVOKEVIRTUAL, - reqInternalName, - "getConnection", - "()Ljava/lang/String;", - false); - } else if ("Method".equalsIgnoreCase(headerkey)) { - mv.visitMethodInsn( - INVOKEVIRTUAL, reqInternalName, "getMethod", "()Ljava/lang/String;", false); - } else if (en.getKey().contains("_header_json_")) { - String typefieldname = "_redkale_body_jsontype_" + bodyTypes.size(); - bodyTypes.put(typefieldname, (java.lang.reflect.Type) en.getValue()[2]); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, typefieldname, "Ljava/lang/reflect/Type;"); - mv.visitLdcInsn(headerkey); - mv.visitMethodInsn( - INVOKEVIRTUAL, - reqInternalName, - "getJsonHeader", - "(Ljava/lang/reflect/Type;Ljava/lang/String;)Ljava/lang/Object;", - false); - mv.visitTypeInsn(CHECKCAST, Type.getInternalName((Class) en.getValue()[1])); - JsonFactory.root().loadDecoder((java.lang.reflect.Type) en.getValue()[2]); - } else { - mv.visitLdcInsn(headerkey); - mv.visitLdcInsn(""); - mv.visitMethodInsn( - INVOKEVIRTUAL, - reqInternalName, - "getHeader", - "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", - false); - } - } else if (en.getKey().contains("_cookie_")) { - mv.visitLdcInsn(en.getValue()[0].toString()); - mv.visitLdcInsn(""); - mv.visitMethodInsn( - INVOKEVIRTUAL, - reqInternalName, - "getCookie", - "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", - false); - } else if (en.getKey().contains("_sessionid_")) { - mv.visitInsn(en.getValue()[0].toString().isEmpty() ? ICONST_0 : ICONST_1); - mv.visitMethodInsn( - INVOKEVIRTUAL, reqInternalName, "getSessionid", "(Z)Ljava/lang/String;", false); - } else if (en.getKey().contains("_address_")) { - mv.visitMethodInsn( - INVOKEVIRTUAL, reqInternalName, "getRemoteAddr", "()Ljava/lang/String;", false); - } else if (en.getKey().contains("_locale_")) { - mv.visitMethodInsn( - INVOKEVIRTUAL, reqInternalName, "getLocale", "()Ljava/lang/String;", false); - } else if (en.getKey().contains("_uri_")) { - mv.visitMethodInsn( - INVOKEVIRTUAL, reqInternalName, "getPath", "()Ljava/lang/String;", false); - } else if (en.getKey().contains("_bodystring_")) { - mv.visitMethodInsn( - INVOKEVIRTUAL, reqInternalName, "getBodyUTF8", "()Ljava/lang/String;", false); - } else if (en.getKey().contains("_bodybytes_")) { - mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getBody", "()[B", false); - } else if (en.getKey().contains("_bodyjson_")) { // JavaBean 转 Json - String typefieldname = "_redkale_body_jsontype_" + bodyTypes.size(); - bodyTypes.put(typefieldname, (java.lang.reflect.Type) en.getValue()[2]); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, typefieldname, "Ljava/lang/reflect/Type;"); - mv.visitMethodInsn( - INVOKEVIRTUAL, - reqInternalName, - "getBodyJson", - "(Ljava/lang/reflect/Type;)Ljava/lang/Object;", - false); - mv.visitTypeInsn(CHECKCAST, Type.getInternalName((Class) en.getValue()[1])); - JsonFactory.root().loadDecoder((java.lang.reflect.Type) en.getValue()[2]); - } else if (en.getKey().contains("_uploadbytes_")) { - // 只需mv.visitVarInsn(ALOAD, 4), 无需处理 - } else if (en.getKey().contains("_uploadfile_")) { - // 只需mv.visitVarInsn(ALOAD, 4), 无需处理 - } else if (en.getKey().contains("_uploadfiles_")) { - // 只需mv.visitVarInsn(ALOAD, 4), 无需处理 - } - mv.visitMethodInsn( - INVOKEINTERFACE, - attrInternalName, - "set", - "(Ljava/lang/Object;Ljava/lang/Object;)V", - true); - } - mv.visitLabel(lif); // end if } - mv.visitFrame( - Opcodes.F_APPEND, - 1, - new Object[] {ptype.getName().replace('.', '/')}, - 0, - null); - } - } - maxLocals++; - paramMaps.add(paramMap); - } // end params for each - - // mv.visitVarInsn(ALOAD, 0); //调用this - // mv.visitFieldInsn(GETFIELD, newDynName, REST_SERVICE_FIELD_NAME, serviceDesc); - mv.visitVarInsn(ALOAD, 3); - for (int[] ins : varInsns) { - mv.visitVarInsn(ins[0], ins[1]); - } - mv.visitMethodInsn(INVOKEVIRTUAL, serviceTypeInternalName, method.getName(), methodDesc, false); - if (hasAsyncHandler) { - mv.visitInsn(RETURN); - } else if (returnType == void.class) { - mv.visitVarInsn(ALOAD, 2); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, REST_RETURNTYPES_FIELD_NAME, "[Ljava/lang/reflect/Type;"); - Asms.visitInsn(mv, entry.methodIdx); // 方法下标 - mv.visitInsn(AALOAD); - mv.visitMethodInsn(INVOKESTATIC, retInternalName, "success", "()" + retDesc, false); - mv.visitMethodInsn( - INVOKEVIRTUAL, respInternalName, "finishJson", "(" + typeDesc + "Ljava/lang/Object;)V", false); - mv.visitInsn(RETURN); - } else if (returnType == boolean.class) { - mv.visitVarInsn(ISTORE, maxLocals); - mv.visitVarInsn(ALOAD, 2); // response - mv.visitVarInsn(ILOAD, maxLocals); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(Z)Ljava/lang/String;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false); - mv.visitInsn(RETURN); - maxLocals++; - } else if (returnType == byte.class) { - mv.visitVarInsn(ISTORE, maxLocals); - mv.visitVarInsn(ALOAD, 2); // response - mv.visitVarInsn(ILOAD, maxLocals); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(I)Ljava/lang/String;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false); - mv.visitInsn(RETURN); - maxLocals++; - } else if (returnType == short.class) { - mv.visitVarInsn(ISTORE, maxLocals); - mv.visitVarInsn(ALOAD, 2); // response - mv.visitVarInsn(ILOAD, maxLocals); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(I)Ljava/lang/String;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false); - mv.visitInsn(RETURN); - maxLocals++; - } else if (returnType == char.class) { - mv.visitVarInsn(ISTORE, maxLocals); - mv.visitVarInsn(ALOAD, 2); // response - mv.visitVarInsn(ILOAD, maxLocals); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(C)Ljava/lang/String;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false); - mv.visitInsn(RETURN); - maxLocals++; - } else if (returnType == int.class) { - mv.visitVarInsn(ISTORE, maxLocals); - mv.visitVarInsn(ALOAD, 2); // response - mv.visitVarInsn(ILOAD, maxLocals); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(I)Ljava/lang/String;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false); - mv.visitInsn(RETURN); - maxLocals++; - } else if (returnType == float.class) { - mv.visitVarInsn(FSTORE, maxLocals); - mv.visitVarInsn(ALOAD, 2); // response - mv.visitVarInsn(FLOAD, maxLocals); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(F)Ljava/lang/String;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false); - mv.visitInsn(RETURN); - maxLocals++; - } else if (returnType == long.class) { - mv.visitVarInsn(LSTORE, maxLocals); - mv.visitVarInsn(ALOAD, 2); // response - mv.visitVarInsn(LLOAD, maxLocals); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(J)Ljava/lang/String;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false); - mv.visitInsn(RETURN); - maxLocals += 2; - } else if (returnType == double.class) { - mv.visitVarInsn(DSTORE, maxLocals); - mv.visitVarInsn(ALOAD, 2); // response - mv.visitVarInsn(DLOAD, maxLocals); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(D)Ljava/lang/String;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false); - mv.visitInsn(RETURN); - maxLocals += 2; - } else if (returnType == byte[].class) { - mv.visitVarInsn(ASTORE, maxLocals); - mv.visitVarInsn(ALOAD, 2); // response - mv.visitVarInsn(ALOAD, maxLocals); - mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "([B)V", false); - mv.visitInsn(RETURN); - maxLocals++; - } else if (returnType == String.class) { - mv.visitVarInsn(ASTORE, maxLocals); - mv.visitVarInsn(ALOAD, 2); // response - mv.visitVarInsn(ALOAD, maxLocals); - mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false); - mv.visitInsn(RETURN); - maxLocals++; - } else if (returnType == File.class) { - mv.visitVarInsn(ASTORE, maxLocals); - mv.visitVarInsn(ALOAD, 2); // response - mv.visitVarInsn(ALOAD, maxLocals); - mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/io/File;)V", false); - mv.visitInsn(RETURN); - maxLocals++; - } else if (Number.class.isAssignableFrom(returnType) - || CharSequence.class.isAssignableFrom(returnType)) { // returnType == String.class 必须放在前面 - mv.visitVarInsn(ASTORE, maxLocals); - mv.visitVarInsn(ALOAD, 2); // response - mv.visitVarInsn(ALOAD, maxLocals); - mv.visitMethodInsn( - INVOKESTATIC, "java/lang/String", "valueOf", "(Ljava/lang/Object;)Ljava/lang/String;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false); - mv.visitInsn(RETURN); - maxLocals++; - } else if (RetResult.class.isAssignableFrom(returnType)) { - mv.visitVarInsn(ASTORE, maxLocals); - mv.visitVarInsn(ALOAD, 2); // response - if (rcs != null && rcs.length > 0) { - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn( - GETFIELD, newDynName, REST_CONVERT_FIELD_PREFIX + restConverts.size(), convertDesc); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, REST_RETURNTYPES_FIELD_NAME, "[Ljava/lang/reflect/Type;"); - Asms.visitInsn(mv, entry.methodIdx); // 方法下标 - mv.visitInsn(AALOAD); - mv.visitVarInsn(ALOAD, maxLocals); - mv.visitMethodInsn( - INVOKEVIRTUAL, - respInternalName, - "finish", - "(" + convertDesc + typeDesc + retDesc + ")V", - false); - } else { - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, REST_RETURNTYPES_FIELD_NAME, "[Ljava/lang/reflect/Type;"); - Asms.visitInsn(mv, entry.methodIdx); // 方法下标 - mv.visitInsn(AALOAD); - mv.visitVarInsn(ALOAD, maxLocals); - mv.visitMethodInsn( - INVOKEVIRTUAL, respInternalName, "finish", "(" + typeDesc + retDesc + ")V", false); - } - mv.visitInsn(RETURN); - maxLocals++; - } else if (HttpResult.class.isAssignableFrom(returnType)) { - mv.visitVarInsn(ASTORE, maxLocals); - mv.visitVarInsn(ALOAD, 2); // response - if (rcs != null && rcs.length > 0) { - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn( - GETFIELD, newDynName, REST_CONVERT_FIELD_PREFIX + restConverts.size(), convertDesc); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, REST_RETURNTYPES_FIELD_NAME, "[Ljava/lang/reflect/Type;"); - Asms.visitInsn(mv, entry.methodIdx); // 方法下标 - mv.visitInsn(AALOAD); - mv.visitVarInsn(ALOAD, maxLocals); - mv.visitMethodInsn( - INVOKEVIRTUAL, - respInternalName, - "finish", - "(" + convertDesc + typeDesc + httpResultDesc + ")V", - false); - } else { - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, REST_RETURNTYPES_FIELD_NAME, "[Ljava/lang/reflect/Type;"); - Asms.visitInsn(mv, entry.methodIdx); // 方法下标 - mv.visitInsn(AALOAD); - mv.visitVarInsn(ALOAD, maxLocals); - mv.visitMethodInsn( - INVOKEVIRTUAL, respInternalName, "finish", "(" + typeDesc + httpResultDesc + ")V", false); - } - mv.visitInsn(RETURN); - maxLocals++; - } else if (HttpScope.class.isAssignableFrom(returnType)) { - mv.visitVarInsn(ASTORE, maxLocals); - mv.visitVarInsn(ALOAD, 2); // response - if (rcs != null && rcs.length > 0) { - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn( - GETFIELD, newDynName, REST_CONVERT_FIELD_PREFIX + restConverts.size(), convertDesc); - mv.visitVarInsn(ALOAD, maxLocals); - mv.visitMethodInsn( - INVOKEVIRTUAL, respInternalName, "finish", "(" + convertDesc + httpScopeDesc + ")V", false); - } else { - mv.visitVarInsn(ALOAD, maxLocals); - mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(" + httpScopeDesc + ")V", false); - } - mv.visitInsn(RETURN); - maxLocals++; - } else if (CompletionStage.class.isAssignableFrom(returnType)) { - mv.visitVarInsn(ASTORE, maxLocals); - mv.visitVarInsn(ALOAD, 2); // response - Class returnNoFutureType = TypeToken.typeToClassOrElse(returnGenericNoFutureType, Object.class); - if (returnNoFutureType == HttpScope.class) { - if (rcs != null && rcs.length > 0) { - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn( - GETFIELD, newDynName, REST_CONVERT_FIELD_PREFIX + restConverts.size(), convertDesc); - mv.visitVarInsn(ALOAD, maxLocals); - mv.visitMethodInsn( - INVOKEVIRTUAL, - respInternalName, - "finishScopeFuture", - "(" + convertDesc + stageDesc + ")V", - false); - } else { - mv.visitVarInsn(ALOAD, maxLocals); - mv.visitMethodInsn( - INVOKEVIRTUAL, respInternalName, "finishScopeFuture", "(" + stageDesc + ")V", false); - } - } else if (returnNoFutureType != byte[].class - && returnNoFutureType != RetResult.class - && returnNoFutureType != HttpResult.class - && returnNoFutureType != File.class - && !((returnGenericNoFutureType instanceof Class) - && (((Class) returnGenericNoFutureType).isPrimitive() - || CharSequence.class.isAssignableFrom((Class) returnGenericNoFutureType)))) { - if (rcs != null && rcs.length > 0) { - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn( - GETFIELD, newDynName, REST_CONVERT_FIELD_PREFIX + restConverts.size(), convertDesc); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn( - GETFIELD, newDynName, REST_RETURNTYPES_FIELD_NAME, "[Ljava/lang/reflect/Type;"); - Asms.visitInsn(mv, entry.methodIdx); // 方法下标 - mv.visitInsn(AALOAD); - mv.visitVarInsn(ALOAD, maxLocals); - mv.visitMethodInsn( - INVOKEVIRTUAL, - respInternalName, - "finishJsonFuture", - "(" + convertDesc + typeDesc + stageDesc + ")V", - false); - } else { - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn( - GETFIELD, newDynName, REST_RETURNTYPES_FIELD_NAME, "[Ljava/lang/reflect/Type;"); - Asms.visitInsn(mv, entry.methodIdx); // 方法下标 - mv.visitInsn(AALOAD); - mv.visitVarInsn(ALOAD, maxLocals); - mv.visitMethodInsn( - INVOKEVIRTUAL, - respInternalName, - "finishJsonFuture", - "(" + typeDesc + stageDesc + ")V", - false); - } - } else { - if (rcs != null && rcs.length > 0) { - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn( - GETFIELD, newDynName, REST_CONVERT_FIELD_PREFIX + restConverts.size(), convertDesc); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn( - GETFIELD, newDynName, REST_RETURNTYPES_FIELD_NAME, "[Ljava/lang/reflect/Type;"); - Asms.visitInsn(mv, entry.methodIdx); // 方法下标 - mv.visitInsn(AALOAD); - mv.visitVarInsn(ALOAD, maxLocals); - mv.visitMethodInsn( - INVOKEVIRTUAL, - respInternalName, - "finishFuture", - "(" + convertDesc + typeDesc + stageDesc + ")V", - false); - } else { - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn( - GETFIELD, newDynName, REST_RETURNTYPES_FIELD_NAME, "[Ljava/lang/reflect/Type;"); - Asms.visitInsn(mv, entry.methodIdx); // 方法下标 - mv.visitInsn(AALOAD); - mv.visitVarInsn(ALOAD, maxLocals); - mv.visitMethodInsn( - INVOKEVIRTUAL, - respInternalName, - "finishFuture", - "(" + typeDesc + stageDesc + ")V", - false); - } - } - mv.visitInsn(RETURN); - maxLocals++; - } else if (Flows.maybePublisherClass(returnType)) { // Flow.Publisher - mv.visitVarInsn(ASTORE, maxLocals); - mv.visitVarInsn(ALOAD, 2); // response - if (rcs != null && rcs.length > 0) { - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn( - GETFIELD, newDynName, REST_CONVERT_FIELD_PREFIX + restConverts.size(), convertDesc); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, REST_RETURNTYPES_FIELD_NAME, "[Ljava/lang/reflect/Type;"); - Asms.visitInsn(mv, entry.methodIdx); // 方法下标 - mv.visitInsn(AALOAD); - mv.visitVarInsn(ALOAD, maxLocals); - mv.visitMethodInsn( - INVOKEVIRTUAL, - respInternalName, - "finishPublisher", - "(" + convertDesc + typeDesc + "Ljava/lang/Object;)V", - false); - } else { - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, REST_RETURNTYPES_FIELD_NAME, "[Ljava/lang/reflect/Type;"); - Asms.visitInsn(mv, entry.methodIdx); // 方法下标 - mv.visitInsn(AALOAD); - mv.visitVarInsn(ALOAD, maxLocals); - mv.visitMethodInsn( - INVOKEVIRTUAL, - respInternalName, - "finishPublisher", - "(" + typeDesc + "Ljava/lang/Object;)V", - false); - } - mv.visitInsn(RETURN); - maxLocals++; - } else if (returnType == retvalType) { // 普通JavaBean或JavaBean[] - mv.visitVarInsn(ASTORE, maxLocals); - mv.visitVarInsn(ALOAD, 2); // response - if (rcs != null && rcs.length > 0) { - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn( - GETFIELD, newDynName, REST_CONVERT_FIELD_PREFIX + restConverts.size(), convertDesc); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, REST_RETURNTYPES_FIELD_NAME, "[Ljava/lang/reflect/Type;"); - Asms.visitInsn(mv, entry.methodIdx); // 方法下标 - mv.visitInsn(AALOAD); - mv.visitVarInsn(ALOAD, maxLocals); - mv.visitMethodInsn( - INVOKEVIRTUAL, - respInternalName, - "finishJson", - "(" + convertDesc + typeDesc + "Ljava/lang/Object;)V", - false); - } else { - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, REST_RETURNTYPES_FIELD_NAME, "[Ljava/lang/reflect/Type;"); - Asms.visitInsn(mv, entry.methodIdx); // 方法下标 - mv.visitInsn(AALOAD); - mv.visitVarInsn(ALOAD, maxLocals); - mv.visitMethodInsn( - INVOKEVIRTUAL, - respInternalName, - "finishJson", - "(" + typeDesc + "Ljava/lang/Object;)V", - false); - } - mv.visitInsn(RETURN); - maxLocals++; - } else { - mv.visitVarInsn(ASTORE, maxLocals); - mv.visitVarInsn(ALOAD, 2); // response - if (rcs != null && rcs.length > 0) { - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn( - GETFIELD, newDynName, REST_CONVERT_FIELD_PREFIX + restConverts.size(), convertDesc); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, REST_RETURNTYPES_FIELD_NAME, "[Ljava/lang/reflect/Type;"); - Asms.visitInsn(mv, entry.methodIdx); // 方法下标 - mv.visitInsn(AALOAD); - mv.visitVarInsn(ALOAD, maxLocals); - mv.visitMethodInsn( - INVOKEVIRTUAL, - respInternalName, - "finish", - "(" + convertDesc + typeDesc + "Ljava/lang/Object;)V", - false); - } else { - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, REST_RETURNTYPES_FIELD_NAME, "[Ljava/lang/reflect/Type;"); - Asms.visitInsn(mv, entry.methodIdx); // 方法下标 - mv.visitInsn(AALOAD); - mv.visitVarInsn(ALOAD, maxLocals); - mv.visitMethodInsn( - INVOKEVIRTUAL, respInternalName, "finish", "(" + typeDesc + "Ljava/lang/Object;)V", false); - } - mv.visitInsn(RETURN); - maxLocals++; - } - mv.visitMaxs(maxStack, maxLocals); - mappingMap.put("params", paramMaps); - - { // _Dync_XXX__HttpServlet.class - ClassWriter cw2 = new ClassWriter(COMPUTE_FRAMES); - cw2.visit(V11, ACC_SUPER, newDynName + "$" + entry.newActionClassName, null, httpServletName, null); - - cw2.visitInnerClass( - newDynName + "$" + entry.newActionClassName, - newDynName, - entry.newActionClassName, - ACC_PRIVATE + ACC_STATIC); - { // 设置 Annotation NonBlocking - av0 = cw2.visitAnnotation(nonblockDesc, true); - av0.visit("value", entry.nonBlocking); - av0.visitEnd(); - } - { - fv = cw2.visitField(0, "_parentServlet", "L" + newDynName + ";", null, null); - fv.visitEnd(); - } - { - mv = new MethodDebugVisitor(cw2.visitMethod(0, "", "(L" + newDynName + ";)V", null, null)); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, httpServletName, "", "()V", false); - mv.visitVarInsn(ALOAD, 0); - mv.visitVarInsn(ALOAD, 1); - mv.visitFieldInsn( - PUTFIELD, - newDynName + "$" + entry.newActionClassName, - "_parentServlet", - "L" + newDynName + ";"); - mv.visitVarInsn(ALOAD, 0); - mv.visitInsn(entry.nonBlocking ? ICONST_1 : ICONST_0); - mv.visitFieldInsn(PUTFIELD, newDynName + "$" + entry.newActionClassName, "_nonBlocking", "Z"); - mv.visitInsn(RETURN); - mv.visitMaxs(2, 2); - mv.visitEnd(); - } - // if (false) { - // mv = new MethodDebugVisitor(cw2.visitMethod(ACC_SYNTHETIC, "", "(L" + - // newDynName + ";L" + newDynName + "$" + entry.newActionClassName + ";)V", null, null)); - // mv.visitVarInsn(ALOAD, 0); - // mv.visitVarInsn(ALOAD, 1); - // mv.visitCheckCast(INVOKESPECIAL, newDynName + "$" + entry.newActionClassName, - // "", "L" + newDynName + ";", false); - // mv.visitInsn(RETURN); - // mv.visitMaxs(2, 3); - // mv.visitEnd(); - // } - { - mv = new MethodDebugVisitor( - cw2.visitMethod(ACC_PUBLIC, "execute", "(" + reqDesc + respDesc + ")V", null, new String[] { - "java/io/IOException" - })); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn( - GETFIELD, - newDynName + "$" + entry.newActionClassName, - "_parentServlet", - "L" + newDynName + ";"); - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(ALOAD, 2); - mv.visitMethodInsn( - INVOKEVIRTUAL, newDynName, entry.newMethodName, "(" + reqDesc + respDesc + ")V", false); - mv.visitInsn(RETURN); - mv.visitMaxs(3, 3); - mv.visitEnd(); - } - cw2.visitEnd(); - byte[] bytes = cw2.toByteArray(); - newLoader.addClass((newDynName + "$" + entry.newActionClassName).replace('/', '.'), bytes); - innerClassBytesMap.put((newDynName + "$" + entry.newActionClassName).replace('/', '.'), bytes); - } - } // end for each - - if (containsMupload) { // 注入 @Resource(name = "APP_HOME") private File _redkale_home; - fv = cw.visitField(ACC_PRIVATE, "_redkale_home", Type.getDescriptor(File.class), null, null); - av0 = fv.visitAnnotation(resDesc, true); - av0.visit("name", "APP_HOME"); - av0.visitEnd(); - fv.visitEnd(); - } - - // HashMap _createRestActionEntry() { - // HashMap map = new HashMap<>(); - // map.put("asyncfind3", new ActionEntry(100000,200000,"asyncfind3", new - // String[]{},null,false,false,0, new _Dync_asyncfind3_HttpServlet())); - // map.put("asyncfind2", new ActionEntry(1,2,"asyncfind2", new String[]{"GET", - // "POST"},null,false,true,0, new _Dync_asyncfind2_HttpServlet())); - // return map; - // } - { // _createRestActionEntry 方法 - mv = new MethodDebugVisitor(cw.visitMethod( - 0, - "_createRestActionEntry", - "()Ljava/util/HashMap;", - "()Ljava/util/HashMap;", - null)); - // mv.setDebug(true); - mv.visitTypeInsn(NEW, "java/util/HashMap"); - mv.visitInsn(DUP); - mv.visitMethodInsn(INVOKESPECIAL, "java/util/HashMap", "", "()V", false); - mv.visitVarInsn(ASTORE, 1); - - for (final MappingEntry entry : entrys) { - mappingurlToMethod.put(entry.mappingurl, entry.mappingMethod); - mv.visitVarInsn(ALOAD, 1); - mv.visitLdcInsn(entry.mappingurl); // name - mv.visitTypeInsn(NEW, actionEntryName); // new ActionEntry - mv.visitInsn(DUP); - Asms.visitInsn(mv, moduleid); // moduleid - Asms.visitInsn(mv, entry.actionid); // actionid - mv.visitLdcInsn(entry.mappingurl); // name - Asms.visitInsn(mv, entry.methods.length); // methods - mv.visitTypeInsn(ANEWARRAY, "java/lang/String"); - for (int i = 0; i < entry.methods.length; i++) { - mv.visitInsn(DUP); - Asms.visitInsn(mv, i); - mv.visitLdcInsn(entry.methods[i]); - mv.visitInsn(AASTORE); - } - mv.visitInsn(ACONST_NULL); // method - mv.visitInsn(entry.rpcOnly ? ICONST_1 : ICONST_0); // rpcOnly - mv.visitInsn(entry.auth ? ICONST_1 : ICONST_0); // auth - Asms.visitInsn(mv, entry.cacheSeconds); // cacheSeconds - mv.visitTypeInsn(NEW, newDynName + "$" + entry.newActionClassName); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn( - INVOKESPECIAL, - newDynName + "$" + entry.newActionClassName, - "", - "(L" + newDynName + ";)V", - false); - mv.visitMethodInsn( - INVOKESPECIAL, - actionEntryName, - "", - "(IILjava/lang/String;[Ljava/lang/String;Ljava/lang/reflect/Method;ZZI" + httpDesc + ")V", - false); - mv.visitMethodInsn( - INVOKEVIRTUAL, - "java/util/HashMap", - "put", - "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", - false); - mv.visitInsn(POP); - } - mv.visitVarInsn(ALOAD, 1); - mv.visitInsn(ARETURN); - mv.visitMaxs(2, 2); - mv.visitEnd(); - } - - for (Map.Entry en : bodyTypes.entrySet()) { - fv = cw.visitField(ACC_PRIVATE, en.getKey(), "Ljava/lang/reflect/Type;", null, null); - av0 = fv.visitAnnotation(Type.getDescriptor(Comment.class), true); - av0.visit("value", en.getValue().toString()); - av0.visitEnd(); - fv.visitEnd(); - } - - for (Map.Entry en : typeRefs.entrySet()) { - fv = cw.visitField(ACC_PRIVATE, en.getValue(), "Ljava/lang/reflect/Type;", null, null); - av0 = fv.visitAnnotation(Type.getDescriptor(Comment.class), true); - av0.visit("value", en.getKey().toString()); - av0.visitEnd(); - fv.visitEnd(); - } - - for (Map.Entry en : restAttributes.entrySet()) { - fv = cw.visitField(ACC_PRIVATE, en.getKey(), attrDesc, null, null); - av0 = fv.visitAnnotation(Type.getDescriptor(Comment.class), true); - av0.visit("value", en.getValue().toString()); - av0.visitEnd(); - fv.visitEnd(); - } - - for (int i = 1; i <= restConverts.size(); i++) { - fv = cw.visitField(ACC_PRIVATE, REST_CONVERT_FIELD_PREFIX + i, convertDesc, null, null); - fv.visitEnd(); - } - - { // _paramtypes字段 java.lang.reflect.Type[][] - fv = cw.visitField(ACC_PRIVATE, REST_PARAMTYPES_FIELD_NAME, "[[Ljava/lang/reflect/Type;", null, null); - av0 = fv.visitAnnotation(Type.getDescriptor(Comment.class), true); - StringBuilder sb = new StringBuilder().append('['); - for (java.lang.reflect.Type[] rs : paramTypes) { - sb.append(Arrays.toString(rs)).append(','); - } - av0.visit("value", sb.append(']').toString()); - av0.visitEnd(); - fv.visitEnd(); - } - { // _returntypes字段 java.lang.reflect.Type[] - fv = cw.visitField(ACC_PRIVATE, REST_RETURNTYPES_FIELD_NAME, "[Ljava/lang/reflect/Type;", null, null); - av0 = fv.visitAnnotation(Type.getDescriptor(Comment.class), true); - av0.visit("value", retvalTypes.toString()); - av0.visitEnd(); - fv.visitEnd(); - } - - // classMap.put("mappings", mappingMaps); //不显示太多信息 - { // toString函数 - mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null)); - // mv.setDebug(true); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, REST_TOSTRINGOBJ_FIELD_NAME, "Ljava/util/function/Supplier;"); - mv.visitMethodInsn(INVOKEINTERFACE, "java/util/function/Supplier", "get", "()Ljava/lang/Object;", true); - mv.visitTypeInsn(CHECKCAST, "java/lang/String"); - mv.visitInsn(ARETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - - { // RestDyn - av0 = cw.visitAnnotation(Type.getDescriptor(RestDyn.class), true); - av0.visit("simple", (Boolean) dynsimple); - av0.visitEnd(); - } - - cw.visitEnd(); - byte[] bytes = cw.toByteArray(); - newLoader.addClass(newDynName.replace('/', '.'), bytes); - try { - Class newClazz = newLoader.findClass(newDynName.replace('/', '.')); - innerClassBytesMap.forEach((n, bs) -> { - try { - RedkaleClassLoader.putDynClass(n, bs, newLoader.findClass(n)); - RedkaleClassLoader.putReflectionClass(n); - } catch (Exception e) { - throw new RestException(e); - } - }); - RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, newClazz); - RedkaleClassLoader.putReflectionDeclaredConstructors(newClazz, newDynName.replace('/', '.')); - for (java.lang.reflect.Type t : retvalTypes) { - JsonFactory.root().loadEncoder(t); - } - - T obj = ((Class) newClazz).getDeclaredConstructor().newInstance(); - { - Field serviceField = newClazz.getDeclaredField(REST_SERVICE_FIELD_NAME); - RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), serviceField); - Field servicemapField = newClazz.getDeclaredField(REST_SERVICEMAP_FIELD_NAME); - RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), servicemapField); - } - for (Map.Entry en : typeRefs.entrySet()) { - Field refField = newClazz.getDeclaredField(en.getValue()); - refField.setAccessible(true); - refField.set(obj, en.getKey()); - RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), refField); - } - for (Map.Entry en : restAttributes.entrySet()) { - Field attrField = newClazz.getDeclaredField(en.getKey()); - attrField.setAccessible(true); - attrField.set(obj, en.getValue()); - RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), attrField); - } - for (Map.Entry en : bodyTypes.entrySet()) { - Field genField = newClazz.getDeclaredField(en.getKey()); - genField.setAccessible(true); - genField.set(obj, en.getValue()); - RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), genField); - } - for (int i = 0; i < restConverts.size(); i++) { - Field genField = newClazz.getDeclaredField(REST_CONVERT_FIELD_PREFIX + (i + 1)); - genField.setAccessible(true); - Object[] rc = restConverts.get(i); - genField.set( - obj, - createJsonFactory((RestConvert[]) rc[0], (RestConvertCoder[]) rc[1]) - .getConvert()); - RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), genField); - } - Field typesfield = newClazz.getDeclaredField(REST_PARAMTYPES_FIELD_NAME); - typesfield.setAccessible(true); - java.lang.reflect.Type[][] paramtypeArray = new java.lang.reflect.Type[paramTypes.size()][]; - paramtypeArray = paramTypes.toArray(paramtypeArray); - typesfield.set(obj, paramtypeArray); - RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), typesfield); - - Field retfield = newClazz.getDeclaredField(REST_RETURNTYPES_FIELD_NAME); - retfield.setAccessible(true); - java.lang.reflect.Type[] rettypeArray = new java.lang.reflect.Type[retvalTypes.size()]; - rettypeArray = retvalTypes.toArray(rettypeArray); - retfield.set(obj, rettypeArray); - RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), retfield); - - Field tostringfield = newClazz.getDeclaredField(REST_TOSTRINGOBJ_FIELD_NAME); - tostringfield.setAccessible(true); - java.util.function.Supplier sSupplier = - () -> JsonConvert.root().convertTo(classMap); - tostringfield.set(obj, sSupplier); - RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), tostringfield); - - Method restactMethod = newClazz.getDeclaredMethod("_createRestActionEntry"); - restactMethod.setAccessible(true); - RedkaleClassLoader.putReflectionMethod(newDynName.replace('/', '.'), restactMethod); - Field tmpEntrysField = HttpServlet.class.getDeclaredField("_actionmap"); - tmpEntrysField.setAccessible(true); - HashMap innerEntryMap = (HashMap) restactMethod.invoke(obj); - for (Map.Entry en : innerEntryMap.entrySet()) { - Method m = mappingurlToMethod.get(en.getKey()); - if (m != null) { - en.getValue().annotations = HttpServlet.ActionEntry.annotations(m); - } - } - tmpEntrysField.set(obj, innerEntryMap); - RedkaleClassLoader.putReflectionField(HttpServlet.class.getName(), tmpEntrysField); - - Field nonblockField = Servlet.class.getDeclaredField("_nonBlocking"); - nonblockField.setAccessible(true); - nonblockField.set(obj, parentNonBlocking == null || parentNonBlocking); - RedkaleClassLoader.putReflectionField(Servlet.class.getName(), nonblockField); - return obj; - } catch (Throwable e) { - throw new RestException(e); - } - } - - private static java.lang.reflect.Type formatRestReturnType(Method method, Class serviceType) { - final Class returnType = method.getReturnType(); - java.lang.reflect.Type t = TypeToken.getGenericType(method.getGenericReturnType(), serviceType); - if (method.getReturnType() == void.class) { - return RetResult.TYPE_RET_STRING; - } else if (HttpResult.class.isAssignableFrom(returnType)) { - if (!(t instanceof ParameterizedType)) { - return Object.class; - } - ParameterizedType pt = (ParameterizedType) t; - return pt.getActualTypeArguments()[0]; - } else if (CompletionStage.class.isAssignableFrom(returnType)) { - ParameterizedType pt = (ParameterizedType) t; - java.lang.reflect.Type grt = pt.getActualTypeArguments()[0]; - Class gct = TypeToken.typeToClass(grt); - if (HttpResult.class.isAssignableFrom(gct)) { - if (!(grt instanceof ParameterizedType)) { - return Object.class; - } - ParameterizedType pt2 = (ParameterizedType) grt; - return pt2.getActualTypeArguments()[0]; - } else if (gct == void.class || gct == Void.class) { - return RetResult.TYPE_RET_STRING; - } else { - return grt; - } - } else if (Flows.maybePublisherClass(returnType)) { - return Flows.maybePublisherSubType(t); - } - return t; - } - - private static boolean checkName(String name) { // 只能是字母、数字和下划线,且不能以数字开头 - if (name.isEmpty()) { - return true; - } - if (name.charAt(0) >= '0' && name.charAt(0) <= '9') { - return false; - } - for (char ch : name.toCharArray()) { - if (!((ch >= '0' && ch <= '9') - || ch == '_' - || (ch >= 'a' && ch <= 'z') - || (ch >= 'A' && ch <= 'Z'))) { // 不能含特殊字符 - return false; - } - } - return true; - } - - private static boolean checkName2(String name) { // 只能是字母、数字、短横、点和下划线,且不能以数字开头 - if (name.isEmpty()) { - return true; - } - if (name.charAt(0) >= '0' && name.charAt(0) <= '9') { - return false; - } - for (char ch : name.toCharArray()) { - if (!((ch >= '0' && ch <= '9') - || ch == '_' - || ch == '-' - || ch == '.' - || (ch >= 'a' && ch <= 'z') - || (ch >= 'A' && ch <= 'Z'))) { // 不能含特殊字符 - return false; - } - } - return true; - } - - private static class MappingEntry implements Comparable { - - private static final RestMapping DEFAULT__MAPPING; - - static { - try { - DEFAULT__MAPPING = - MappingEntry.class.getDeclaredMethod("mapping").getAnnotation(RestMapping.class); - } catch (Exception e) { - throw new Error(e); - } - } - - private static String formatMappingName(String name) { - if (name.isEmpty()) { - return name; - } - boolean normal = true; // 是否包含特殊字符 - for (char ch : name.toCharArray()) { - if (ch >= '0' && ch <= '9') { - continue; - } - if (ch >= 'a' && ch <= 'z') { - continue; - } - if (ch >= 'A' && ch <= 'Z') { - continue; - } - if (ch == '_' || ch == '$') { - continue; - } - normal = false; - break; - } - return normal ? name : Utility.md5Hex(name); - } - - public MappingEntry( - final boolean serRpcOnly, - int methodIndex, - Boolean typeNonBlocking, - RestMapping mapping, - final String defModuleName, - Method method) { - if (mapping == null) { - mapping = DEFAULT__MAPPING; - } - this.methodIdx = methodIndex; - this.ignore = mapping.ignore(); - String n = mapping.name(); - if (n.isEmpty()) { - n = method.getName(); - } - this.name = n.trim(); - this.example = mapping.example(); - this.mappingMethod = method; - this.methods = mapping.methods(); - this.auth = mapping.auth(); - this.rpcOnly = serRpcOnly || mapping.rpcOnly(); - this.actionid = mapping.actionid(); - this.cacheSeconds = mapping.cacheSeconds(); - this.comment = mapping.comment(); - boolean pound = false; - Parameter[] params = method.getParameters(); - for (Parameter param : params) { - RestParam rp = param.getAnnotation(RestParam.class); - String pn = null; - if (rp != null && !rp.name().isEmpty()) { - pn = rp.name(); - } else { - Param pm = param.getAnnotation(Param.class); - if (pm != null && !pm.value().isEmpty()) { - pn = pm.value(); - } - } - if (pn != null && pn.charAt(0) == '#') { - pound = true; - break; - } - } - this.existsPound = pound; - this.newMethodName = formatMappingName( - this.name.replace('/', '$').replace('.', '_').replace('-', '_')); - this.newActionClassName = "_Dyn_" + this.newMethodName + "_ActionHttpServlet"; - - NonBlocking non = method.getAnnotation(NonBlocking.class); - Boolean nonFlag = non == null ? typeNonBlocking : (Boolean) non.value(); // 显注在方法优先级大于类 - if (nonFlag == null) { - if (CompletionStage.class.isAssignableFrom(method.getReturnType())) { - nonFlag = true; - } else { - for (Parameter mp : method.getParameters()) { - if (CompletionHandler.class.isAssignableFrom(mp.getType())) { - nonFlag = true; - break; - } - } - } - } - this.nonBlocking = nonFlag != null && nonFlag; - } - - public final int methodIdx; // _paramtypes 的下标,从0开始 - - public final Method mappingMethod; - - public final boolean ignore; - - public final String newMethodName; - - public final String newActionClassName; - - public final String name; - - public final String example; - - public final String comment; - - public final String[] methods; - - public final boolean nonBlocking; - - public final boolean rpcOnly; - - public final boolean auth; - - public final int actionid; - - public final int cacheSeconds; - - public final boolean existsPound; // 是否包含#的参数 - - String mappingurl; // 在生成方法时赋值, 供 _createRestActionEntry 使用 - - @RestMapping() - void mapping() { // 用于获取Mapping 默认值 - } - - @Override - public int hashCode() { - return this.name.hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null || getClass() != obj.getClass()) { - return false; - } - return this.name.equals(((MappingEntry) obj).name); - } - - @Override - public int compareTo(MappingEntry o) { - return this.name.compareTo(o.name); - } - } -} +/* + * 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.http; + +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import static org.redkale.asm.ClassWriter.COMPUTE_FRAMES; +import static org.redkale.asm.Opcodes.*; +import static org.redkale.util.Utility.isEmpty; + +import java.io.*; +import java.lang.annotation.*; +import java.lang.reflect.*; +import java.net.InetSocketAddress; +import java.nio.channels.CompletionHandler; +import java.util.*; +import java.util.concurrent.CompletionStage; +import org.redkale.annotation.*; +import org.redkale.annotation.ClassDepends; +import org.redkale.annotation.Comment; +import org.redkale.asm.*; +import org.redkale.asm.Type; +import org.redkale.convert.*; +import org.redkale.convert.json.*; +import org.redkale.inject.ResourceFactory; +import org.redkale.mq.spi.MessageAgent; +import org.redkale.net.*; +import org.redkale.net.sncp.Sncp; +import org.redkale.service.*; +import org.redkale.source.Flipper; +import org.redkale.util.*; +import org.redkale.util.RedkaleClassLoader.DynBytesClassLoader; + +/** + * 详情见: https://redkale.org + * + * @author zhangjx + */ +@SuppressWarnings("unchecked") +public final class Rest { + + // 请求是否为rpc协议,值类型: 布尔,取值为true、false + public static final String REST_HEADER_RPC = "Rest-Rpc"; + + // traceid,值类型: 字符串 + public static final String REST_HEADER_TRACEID = "Rest-Traceid"; + + // 当前用户ID值,值类型: 字符串 + public static final String REST_HEADER_CURRUSERID = "Rest-Curruserid"; + + // 请求所需的RestService的资源名,值类型: 字符串 + public static final String REST_HEADER_RESNAME = "Rest-Resname"; + + // 请求参数的反序列化种类,值类型: 字符串,取值为ConvertType枚举值名 + public static final String REST_HEADER_REQ_CONVERT = "Rest-Req-Convert"; + + // 响应结果的序列化种类,值类型: 字符串,取值为ConvertType枚举值名 + public static final String REST_HEADER_RESP_CONVERT = "Rest-Resp-Convert"; + + // --------------------------------------------------------------------------------------------------- + static final String REST_TOSTRINGOBJ_FIELD_NAME = "_redkale_toStringSupplier"; + + static final String REST_CONVERT_FIELD_PREFIX = "_redkale_restConvert_"; + + static final String REST_SERVICE_FIELD_NAME = "_redkale_service"; + + static final String REST_SERVICEMAP_FIELD_NAME = + "_redkale_serviceMap"; // 如果只有name=""的Service资源,则实例中_servicemap必须为null + + private static final String REST_PARAMTYPES_FIELD_NAME = + "_redkale_paramTypes"; // 存在泛型的参数数组 Type[][] 第1维度是方法的下标, 第二维度是参数的下标 + + private static final String REST_RETURNTYPES_FIELD_NAME = "_redkale_returnTypes"; // 存在泛型的结果数组 + + private static final java.lang.reflect.Type TYPE_RETRESULT_STRING = new TypeToken>() {}.getType(); + + private static final Set EXCLUDERMETHODS = new HashSet<>(); + + static { + for (Method m : Object.class.getMethods()) { + EXCLUDERMETHODS.add(m.getName()); + } + } + + /** 用于标记由Rest.createRestServlet 方法创建的RestServlet */ + @Inherited + @Documented + @Target({TYPE}) + @Retention(RUNTIME) + public static @interface RestDyn { + + // 是否不需要解析HttpHeader,对应HttpContext.lazyHeaders + boolean simple() default false; + + // 动态生成的类的子类需要关联一下,否则在运行过程中可能出现NoClassDefFoundError + Class[] types() default {}; + } + + /** 用于标记由Rest.createRestServlet 方法创建的RestServlet */ + @Inherited + @Documented + @Target({TYPE}) + @Retention(RUNTIME) + public static @interface RestDynSourceType { + + Class value(); + } + + private Rest() {} + + public static JsonFactory createJsonFactory(RestConvert[] converts, RestConvertCoder[] coders) { + return createJsonFactory(-1, converts, coders); + } + + public static JsonFactory createJsonFactory(int features, RestConvert[] converts, RestConvertCoder[] coders) { + if ((converts == null || converts.length < 1) && (coders == null || coders.length < 1)) { + return JsonFactory.root(); + } + final JsonFactory childFactory = JsonFactory.create(); + if (features > -1) { + childFactory.withFeatures(features); + } + List types = new ArrayList<>(); + Set reloadTypes = new HashSet<>(); + if (coders != null) { + for (RestConvertCoder rcc : coders) { + reloadTypes.add(rcc.type()); + childFactory.register(rcc.type(), rcc.field(), (SimpledCoder) + Creator.create(rcc.coder()).create()); + } + } + if (converts != null) { + for (RestConvert rc : converts) { + if (rc.type() == void.class || rc.type() == Void.class) { + return JsonFactory.create().skipAllIgnore(true); + } + if (types.contains(rc.type())) { + throw new RestException("@RestConvert type(" + rc.type() + ") repeat"); + } + if (rc.skipIgnore()) { + childFactory.registerSkipIgnore(rc.type()); + childFactory.reloadCoder(rc.type()); + } else if (rc.onlyColumns().length > 0) { + childFactory.registerIgnoreAll(rc.type(), rc.onlyColumns()); + childFactory.reloadCoder(rc.type()); + } else { + childFactory.register(rc.type(), false, rc.convertColumns()); + childFactory.register(rc.type(), true, rc.ignoreColumns()); + childFactory.reloadCoder(rc.type()); + } + types.add(rc.type()); + if (rc.features() > -1) { + childFactory.withFeatures(rc.features()); + } + } + } + for (Class type : reloadTypes) { + childFactory.reloadCoder(type); + } + return childFactory; + } + + static String getWebModuleNameLowerCase(Class serviceType) { + final RestService controller = serviceType.getAnnotation(RestService.class); + if (controller == null) { + return serviceType.getSimpleName().replaceAll("Service.*$", "").toLowerCase(); + } + if (controller.ignore()) { + return null; + } + return (!controller.name().isEmpty()) + ? controller.name().trim() + : serviceType.getSimpleName().replaceAll("Service.*$", "").toLowerCase(); + } + + static String getWebModuleName(Class serviceType) { + final RestService controller = serviceType.getAnnotation(RestService.class); + if (controller == null) { + return serviceType.getSimpleName().replaceAll("Service.*$", ""); + } + if (controller.ignore()) { + return null; + } + return (!controller.name().isEmpty()) + ? controller.name().trim() + : serviceType.getSimpleName().replaceAll("Service.*$", ""); + } + + /** + * 判断HttpServlet是否为Rest动态生成的 + * + * @param servlet 检测的HttpServlet + * @return 是否是动态生成的RestHttpServlet + */ + public static boolean isRestDyn(HttpServlet servlet) { + return servlet.getClass().getAnnotation(RestDyn.class) != null; + } + + /** + * 判断HttpServlet是否为Rest动态生成的,且simple, 不需要读取http-header的方法视为simple=true + * + * @param servlet 检测的HttpServlet + * @return 是否是动态生成的RestHttpServlet + */ + static boolean isSimpleRestDyn(HttpServlet servlet) { + RestDyn dyn = servlet.getClass().getAnnotation(RestDyn.class); + return dyn != null && dyn.simple(); + } + + /** + * 获取Rest动态生成HttpServlet里的Service对象,若不是Rest动态生成的HttpServlet,返回null + * + * @param servlet HttpServlet + * @return Service + */ + public static Service getService(HttpServlet servlet) { + if (servlet == null) { + return null; + } + if (!isRestDyn(servlet)) { + return null; + } + try { + Field ts = servlet.getClass().getDeclaredField(REST_SERVICE_FIELD_NAME); + ts.setAccessible(true); + return (Service) ts.get(servlet); + } catch (Exception e) { + return null; + } + } + + public static Map getServiceMap(HttpServlet servlet) { + if (servlet == null) { + return null; + } + try { + Field ts = servlet.getClass().getDeclaredField(REST_SERVICEMAP_FIELD_NAME); + ts.setAccessible(true); + return (Map) ts.get(servlet); + } catch (Exception e) { + return null; + } + } + + public static void setServiceMap(HttpServlet servlet, Map map) { + if (servlet == null) { + return; + } + try { + Field ts = servlet.getClass().getDeclaredField(REST_SERVICEMAP_FIELD_NAME); + ts.setAccessible(true); + ts.set(servlet, map); + } catch (Exception e) { + throw new RestException(e); + } + } + + public static String getRestModule(Service service) { + final RestService controller = service.getClass().getAnnotation(RestService.class); + if (controller != null && !controller.name().isEmpty()) { + return controller.name(); + } + final Class serviceType = Sncp.getResourceType(service); + return serviceType.getSimpleName().replaceAll("Service.*$", "").toLowerCase(); + } + + // 格式: http.req.module.user + public static String generateHttpReqTopic(String module, String nodeid) { + return getHttpReqTopicPrefix() + "module." + module.toLowerCase(); + } + + // 格式: http.req.module.user + public static String generateHttpReqTopic(String module, String resname, String nodeid) { + return getHttpReqTopicPrefix() + "module." + module.toLowerCase() + + (resname == null || resname.isEmpty() ? "" : ("-" + resname)); + } + + public static String generateHttpReqTopic(Service service, String nodeid) { + String resname = Sncp.getResourceName(service); + String module = getRestModule(service).toLowerCase(); + return getHttpReqTopicPrefix() + "module." + module + (resname.isEmpty() ? "" : ("-" + resname)); + } + + public static String getHttpReqTopicPrefix() { + return "http.req."; + } + + public static String getHttpRespTopicPrefix() { + return "http.resp."; + } + + // 仅供Rest动态构建里 currentUserid() 使用 + @ClassDepends + public static T orElse(T t, T defValue) { + return t == null ? defValue : t; + } + + public static T createRestWebSocketServlet( + final ClassLoader classLoader, final Class webSocketType, MessageAgent messageAgent) { + if (webSocketType == null) { + throw new RestException("Rest WebSocket Class is null on createRestWebSocketServlet"); + } + if (Modifier.isAbstract(webSocketType.getModifiers())) { + throw new RestException( + "Rest WebSocket Class(" + webSocketType + ") cannot abstract on createRestWebSocketServlet"); + } + if (Modifier.isFinal(webSocketType.getModifiers())) { + throw new RestException( + "Rest WebSocket Class(" + webSocketType + ") cannot final on createRestWebSocketServlet"); + } + final RestWebSocket rws = webSocketType.getAnnotation(RestWebSocket.class); + if (rws == null || rws.ignore()) { + throw new RestException("Rest WebSocket Class(" + webSocketType + + ") have not @RestWebSocket or @RestWebSocket.ignore=true on createRestWebSocketServlet"); + } + boolean valid = false; + for (Constructor c : webSocketType.getDeclaredConstructors()) { + if (c.getParameterCount() == 0 + && (Modifier.isPublic(c.getModifiers()) || Modifier.isProtected(c.getModifiers()))) { + valid = true; + break; + } + } + if (!valid) { + throw new RestException("Rest WebSocket Class(" + webSocketType + + ") must have public or protected Constructor on createRestWebSocketServlet"); + } + final String rwsname = ResourceFactory.getResourceName(rws.name()); + if (!checkName(rws.catalog())) { + throw new RestException(webSocketType.getName() + " have illegal " + RestWebSocket.class.getSimpleName() + + ".catalog, only 0-9 a-z A-Z _ cannot begin 0-9"); + } + if (!checkName(rwsname)) { + throw new RestException(webSocketType.getName() + " have illegal " + RestWebSocket.class.getSimpleName() + + ".name, only 0-9 a-z A-Z _ cannot begin 0-9"); + } + + // ---------------------------------------------------------------------------------------- + final Set resourcesFieldSet = new LinkedHashSet<>(); + final ClassLoader loader = classLoader == null ? Thread.currentThread().getContextClassLoader() : classLoader; + final Set resourcesFieldNameSet = new HashSet<>(); + Class clzz = webSocketType; + do { + for (Field field : clzz.getDeclaredFields()) { + if (field.getAnnotation(Resource.class) == null + && field.getAnnotation(javax.annotation.Resource.class) == null) { + continue; + } + if (resourcesFieldNameSet.contains(field.getName())) { + continue; + } + if (Modifier.isStatic(field.getModifiers())) { + throw new RestException(field + " cannot static on createRestWebSocketServlet"); + } + if (Modifier.isFinal(field.getModifiers())) { + throw new RestException(field + " cannot final on createRestWebSocketServlet"); + } + if (!Modifier.isPublic(field.getModifiers()) && !Modifier.isProtected(field.getModifiers())) { + throw new RestException(field + " must be public or protected on createRestWebSocketServlet"); + } + resourcesFieldNameSet.add(field.getName()); + resourcesFieldSet.add(field); + } + } while ((clzz = clzz.getSuperclass()) != Object.class); + + // ---------------------------------------------------------------------------------------- + boolean namePresent = false; + try { + Method m0 = null; + for (Method method : webSocketType.getMethods()) { + if (method.getParameterCount() > 0) { + m0 = method; + break; + } + } + namePresent = m0 == null || m0.getParameters()[0].isNamePresent(); + } catch (Exception e) { + // do nothing + } + final Map asmParamMap = + namePresent ? null : AsmMethodBoost.getMethodBeans(webSocketType); + final Set messageNames = new HashSet<>(); + Method wildcardMethod = null; + List mmethods = new ArrayList<>(); + for (Method method : webSocketType.getMethods()) { + RestOnMessage rom = method.getAnnotation(RestOnMessage.class); + if (rom == null) { + continue; + } + String name = rom.name(); + if (!"*".equals(name) && !checkName(name)) { + throw new RestException("@RestOnMessage.name contains illegal characters on (" + method + ")"); + } + if (Modifier.isFinal(method.getModifiers())) { + throw new RestException("@RestOnMessage method can not final but (" + method + ")"); + } + if (Modifier.isStatic(method.getModifiers())) { + throw new RestException("@RestOnMessage method can not static but (" + method + ")"); + } + if (method.getReturnType() != void.class) { + throw new RestException("@RestOnMessage method must return void but (" + method + ")"); + } + if (method.getExceptionTypes().length > 0) { + throw new RestException("@RestOnMessage method can not throw exception but (" + method + ")"); + } + if (name.isEmpty()) { + throw new RestException(method + " RestOnMessage.name is empty createRestWebSocketServlet"); + } + if (messageNames.contains(name)) { + throw new RestException(method + " repeat RestOnMessage.name(" + name + ") createRestWebSocketServlet"); + } + messageNames.add(name); + if ("*".equals(name)) { + wildcardMethod = method; + } else { + mmethods.add(method); + } + } + final List messageMethods = new ArrayList<>(); + messageMethods.addAll(mmethods); + // wildcardMethod 必须放最后, _DynRestOnMessageConsumer 是按messageMethods顺序来判断的 + if (wildcardMethod != null) { + messageMethods.add(wildcardMethod); + } + // ---------------------------------------------------------------------------------------- + final String resDesc = Type.getDescriptor(Resource.class); + final String wsDesc = Type.getDescriptor(WebSocket.class); + final String wsParamDesc = Type.getDescriptor(WebSocketParam.class); + final String jsonConvertDesc = Type.getDescriptor(JsonConvert.class); + final String convertDisabledDesc = Type.getDescriptor(ConvertDisabled.class); + final String webSocketParamName = Type.getInternalName(WebSocketParam.class); + final String supDynName = WebSocketServlet.class.getName().replace('.', '/'); + final String webServletDesc = Type.getDescriptor(WebServlet.class); + final String webSocketInternalName = Type.getInternalName(webSocketType); + + final String newDynName = "org/redkaledyn/http/restws/" + "_DynWebScoketServlet__" + + webSocketType.getName().replace('.', '_').replace('$', '_'); + + final String newDynWebSokcetSimpleName = "_Dyn" + webSocketType.getSimpleName(); + final String newDynWebSokcetFullName = newDynName + "$" + newDynWebSokcetSimpleName; + + final String newDynMessageSimpleName = "_Dyn" + webSocketType.getSimpleName() + "Message"; + final String newDynMessageFullName = newDynName + "$" + newDynMessageSimpleName; + + final String newDynConsumerSimpleName = "_DynRestOnMessageConsumer"; + final String newDynConsumerFullName = newDynName + "$" + newDynConsumerSimpleName; + try { + Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.')); + if (clz == null) { + clz = loader.loadClass(newDynName.replace('/', '.')); + } + T servlet = (T) clz.getDeclaredConstructor().newInstance(); + Map msgclassToAnnotations = new HashMap<>(); + for (int i = 0; i < messageMethods.size(); i++) { // _DyncXXXWebSocketMessage 子消息List + Method method = messageMethods.get(i); + String endfix = "_" + method.getName() + "_" + (i > 9 ? i : ("0" + i)); + String newDynSuperMessageFullName = newDynMessageFullName + (method == wildcardMethod ? "" : endfix); + msgclassToAnnotations.put(newDynSuperMessageFullName, method.getAnnotations()); + } + clz.getField("_redkale_annotations").set(null, msgclassToAnnotations); + if (rws.cryptor() != Cryptor.class) { + Cryptor cryptor = rws.cryptor().getDeclaredConstructor().newInstance(); + Field cryptorField = clz.getSuperclass().getDeclaredField("cryptor"); // WebSocketServlet + cryptorField.setAccessible(true); + cryptorField.set(servlet, cryptor); + } + if (messageAgent != null) { + ((WebSocketServlet) servlet).messageAgent = messageAgent; + } + return servlet; + } catch (Throwable e) { + // do nothing + } + + final List resourcesFields = new ArrayList<>(resourcesFieldSet); + StringBuilder sb1 = new StringBuilder(); + StringBuilder sb2 = new StringBuilder(); + for (int i = 0; i < resourcesFields.size(); i++) { + Field field = resourcesFields.get(i); + sb1.append(Type.getDescriptor(field.getType())); + sb2.append(Utility.getTypeDescriptor(field.getGenericType())); + } + final String resourceDescriptor = sb1.toString(); + final String resourceGenericDescriptor = sb1.length() == sb2.length() ? null : sb2.toString(); + // ---------------------------------------------------------------------------------------- + + ClassWriter cw = new ClassWriter(COMPUTE_FRAMES); + FieldVisitor fv; + MethodDebugVisitor mv; + AnnotationVisitor av0; + cw.visit(V11, ACC_PUBLIC + ACC_SUPER, newDynName, null, supDynName, null); + { // RestDyn + av0 = cw.visitAnnotation(Type.getDescriptor(RestDyn.class), true); + av0.visit("simple", false); // WebSocketServlet必须要解析http-header + { + AnnotationVisitor av1 = av0.visitArray("types"); + av1.visit(null, Type.getType("L" + newDynConsumerFullName.replace('.', '/') + ";")); + av1.visit(null, Type.getType("L" + newDynWebSokcetFullName.replace('.', '/') + ";")); + av1.visit( + null, + Type.getType("L" + newDynMessageFullName.replace('.', '/') + + ";")); // 位置固定第三个,下面用Message类进行loadDecoder会用到 + av1.visitEnd(); + } + av0.visitEnd(); + } + { // RestDynSourceType + av0 = cw.visitAnnotation(Type.getDescriptor(RestDynSourceType.class), true); + av0.visit("value", Type.getType(Type.getDescriptor(webSocketType))); + av0.visitEnd(); + } + { // 注入 @WebServlet 注解 + String urlpath = (rws.catalog().isEmpty() ? "/" : ("/" + rws.catalog() + "/")) + rwsname; + av0 = cw.visitAnnotation(webServletDesc, true); + { + AnnotationVisitor av1 = av0.visitArray("value"); + av1.visit(null, urlpath); + av1.visitEnd(); + } + av0.visit("name", rwsname); + av0.visit("moduleid", 0); + av0.visit("repair", rws.repair()); + av0.visit("comment", rws.comment()); + av0.visitEnd(); + } + { // 内部类 + cw.visitInnerClass(newDynConsumerFullName, newDynName, newDynConsumerSimpleName, ACC_PUBLIC + ACC_STATIC); + + cw.visitInnerClass(newDynWebSokcetFullName, newDynName, newDynWebSokcetSimpleName, ACC_PUBLIC + ACC_STATIC); + + cw.visitInnerClass(newDynMessageFullName, newDynName, newDynMessageSimpleName, ACC_PUBLIC + ACC_STATIC); + + for (int i = 0; i < messageMethods.size(); i++) { + Method method = messageMethods.get(i); + String endfix = "_" + method.getName() + "_" + (i > 9 ? i : ("0" + i)); + String newDynSuperMessageFullName = newDynMessageFullName + (method == wildcardMethod ? "" : endfix); + cw.visitInnerClass( + newDynSuperMessageFullName, + newDynName, + newDynMessageSimpleName + endfix, + ACC_PUBLIC + ACC_STATIC); + } + } + { // @Resource + for (int i = 0; i < resourcesFields.size(); i++) { + Field field = resourcesFields.get(i); + Resource res = field.getAnnotation(Resource.class); + javax.annotation.Resource res2 = field.getAnnotation(javax.annotation.Resource.class); + java.lang.reflect.Type fieldType = field.getGenericType(); + fv = cw.visitField( + ACC_PRIVATE, + "_redkale_resource_" + i, + Type.getDescriptor(field.getType()), + fieldType == field.getType() ? null : Utility.getTypeDescriptor(fieldType), + null); + { + av0 = fv.visitAnnotation(resDesc, true); + av0.visit("name", res != null ? res.name() : res2.name()); + av0.visit("required", res == null || res.required()); + av0.visitEnd(); + } + fv.visitEnd(); + } + } + { // _redkale_annotations + fv = cw.visitField( + ACC_PUBLIC + ACC_STATIC, + "_redkale_annotations", + "Ljava/util/Map;", + "Ljava/util/Map;", + null); + fv.visitEnd(); + } + { // _DynWebSocketServlet构造函数 + mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "", "()V", null, null)); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, supDynName, "", "()V", false); + mv.visitVarInsn(ALOAD, 0); + mv.visitLdcInsn(Type.getObjectType(newDynName + "$" + newDynWebSokcetSimpleName + "Message")); + mv.visitFieldInsn(PUTFIELD, newDynName, "messageRestType", "Ljava/lang/reflect/Type;"); + + mv.visitVarInsn(ALOAD, 0); + Asms.visitInsn(mv, rws.liveinterval()); + mv.visitFieldInsn(PUTFIELD, newDynName, "liveinterval", "I"); + + mv.visitVarInsn(ALOAD, 0); + Asms.visitInsn(mv, rws.wsmaxconns()); + mv.visitFieldInsn(PUTFIELD, newDynName, "wsmaxconns", "I"); + + mv.visitVarInsn(ALOAD, 0); + Asms.visitInsn(mv, rws.wsmaxbody()); + mv.visitFieldInsn(PUTFIELD, newDynName, "wsmaxbody", "I"); + + mv.visitVarInsn(ALOAD, 0); + mv.visitInsn(rws.single() ? ICONST_1 : ICONST_0); + mv.visitFieldInsn(PUTFIELD, newDynName, "single", "Z"); + + mv.visitVarInsn(ALOAD, 0); + mv.visitInsn(rws.anyuser() ? ICONST_1 : ICONST_0); + mv.visitFieldInsn(PUTFIELD, newDynName, "anyuser", "Z"); + + mv.visitInsn(RETURN); + mv.visitMaxs(3, 1); + mv.visitEnd(); + } + { // createWebSocket 方法 + mv = new MethodDebugVisitor(cw.visitMethod( + ACC_PROTECTED, + "createWebSocket", + "()" + wsDesc, + "()L" + + WebSocket.class.getName().replace('.', '/') + ";", + null)); + mv.visitTypeInsn(NEW, newDynName + "$" + newDynWebSokcetSimpleName); + mv.visitInsn(DUP); + for (int i = 0; i < resourcesFields.size(); i++) { + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn( + GETFIELD, + newDynName, + "_redkale_resource_" + i, + Type.getDescriptor(resourcesFields.get(i).getType())); + } + mv.visitMethodInsn( + INVOKESPECIAL, newDynWebSokcetFullName, "", "(" + resourceDescriptor + ")V", false); + mv.visitInsn(ARETURN); + mv.visitMaxs(2 + resourcesFields.size(), 1); + mv.visitEnd(); + } + { // createRestOnMessageConsumer + mv = new MethodDebugVisitor(cw.visitMethod( + ACC_PROTECTED, + "createRestOnMessageConsumer", + "()Ljava/util/function/BiConsumer;", + "()Ljava/util/function/BiConsumer<" + wsDesc + "Ljava/lang/Object;>;", + null)); + mv.visitTypeInsn(NEW, newDynConsumerFullName); + mv.visitInsn(DUP); + mv.visitMethodInsn(INVOKESPECIAL, newDynConsumerFullName, "", "()V", false); + mv.visitInsn(ARETURN); + mv.visitMaxs(2, 1); + mv.visitEnd(); + } + { // resourceName + mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "resourceName", "()Ljava/lang/String;", null, null)); + mv.visitLdcInsn(rwsname); + mv.visitInsn(ARETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + + DynBytesClassLoader newLoader = new DynBytesClassLoader(loader); + Map msgclassToAnnotations = new HashMap<>(); + for (int i = 0; i < messageMethods.size(); i++) { // _DyncXXXWebSocketMessage 子消息List + final Method method = messageMethods.get(i); + String endfix = "_" + method.getName() + "_" + (i > 9 ? i : ("0" + i)); + String newDynSuperMessageFullName = newDynMessageFullName + (method == wildcardMethod ? "" : endfix); + msgclassToAnnotations.put(newDynSuperMessageFullName, method.getAnnotations()); + + ClassWriter cw2 = new ClassWriter(COMPUTE_FRAMES); + cw2.visit( + V11, + ACC_PUBLIC + ACC_FINAL + ACC_SUPER, + newDynSuperMessageFullName, + null, + "java/lang/Object", + new String[] {webSocketParamName, "java/lang/Runnable"}); + cw2.visitInnerClass( + newDynSuperMessageFullName, newDynName, newDynMessageSimpleName + endfix, ACC_PUBLIC + ACC_STATIC); + Set paramNames = new HashSet<>(); + AsmMethodBean methodBean = asmParamMap == null ? null : AsmMethodBean.get(asmParamMap, method); + List names = methodBean == null ? null : methodBean.getParams(); + Parameter[] params = method.getParameters(); + final LinkedHashMap paramap = new LinkedHashMap(); // 必须使用LinkedHashMap确保顺序 + for (int j = 0; j < params.length; j++) { // 字段列表 + Parameter param = params[j]; + String paramName = param.getName(); + RestParam rp = param.getAnnotation(RestParam.class); + Param pm = param.getAnnotation(Param.class); + if (rp != null && !rp.name().isEmpty()) { + paramName = rp.name(); + } else if (pm != null && !pm.value().isEmpty()) { + paramName = pm.value(); + } else if (names != null && names.size() > j) { + paramName = names.get(j).getName(); + } + if (paramNames.contains(paramName)) { + throw new RestException(method + " has same @RestParam.name"); + } + paramNames.add(paramName); + paramap.put(paramName, param); + fv = cw2.visitField( + ACC_PUBLIC, + paramName, + Type.getDescriptor(param.getType()), + param.getType() == param.getParameterizedType() + ? null + : Utility.getTypeDescriptor(param.getParameterizedType()), + null); + fv.visitEnd(); + } + if (method == wildcardMethod) { + for (int j = 0; j < messageMethods.size(); j++) { + Method method2 = messageMethods.get(j); + if (method2 == wildcardMethod) { + continue; + } + String endfix2 = "_" + method2.getName() + "_" + (j > 9 ? j : ("0" + j)); + String newDynSuperMessageFullName2 = + newDynMessageFullName + (method2 == wildcardMethod ? "" : endfix2); + cw2.visitInnerClass( + newDynSuperMessageFullName2, + newDynName, + newDynMessageSimpleName + endfix2, + ACC_PUBLIC + ACC_STATIC); + fv = cw2.visitField( + ACC_PUBLIC, + method2.getAnnotation(RestOnMessage.class).name(), + "L" + newDynSuperMessageFullName2 + ";", + null, + null); + fv.visitEnd(); + } + } + { // _redkale_websocket + fv = cw2.visitField(ACC_PUBLIC, "_redkale_websocket", "L" + newDynWebSokcetFullName + ";", null, null); + av0 = fv.visitAnnotation(convertDisabledDesc, true); + av0.visitEnd(); + fv.visitEnd(); + } + { // 空构造函数 + mv = new MethodDebugVisitor(cw2.visitMethod(ACC_PUBLIC, "", "()V", null, null)); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + { // getNames + mv = new MethodDebugVisitor( + cw2.visitMethod(ACC_PUBLIC, "getNames", "()[Ljava/lang/String;", null, null)); + av0 = mv.visitAnnotation(convertDisabledDesc, true); + av0.visitEnd(); + Asms.visitInsn(mv, paramap.size()); + mv.visitTypeInsn(ANEWARRAY, "java/lang/String"); + int index = -1; + for (Map.Entry en : paramap.entrySet()) { + mv.visitInsn(DUP); + Asms.visitInsn(mv, ++index); + mv.visitLdcInsn(en.getKey()); + mv.visitInsn(AASTORE); + } + mv.visitInsn(ARETURN); + mv.visitMaxs(paramap.size() + 2, 1); + mv.visitEnd(); + } + { // getValue + mv = new MethodDebugVisitor(cw2.visitMethod( + ACC_PUBLIC, + "getValue", + "(Ljava/lang/String;)Ljava/lang/Object;", + "(Ljava/lang/String;)TT;", + null)); + for (Map.Entry en : paramap.entrySet()) { + Class paramType = en.getValue().getType(); + mv.visitLdcInsn(en.getKey()); + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z", false); + Label l1 = new Label(); + mv.visitJumpInsn(IFEQ, l1); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynSuperMessageFullName, en.getKey(), Type.getDescriptor(paramType)); + if (paramType.isPrimitive()) { + Class bigclaz = TypeToken.primitiveToWrapper(paramType); + mv.visitMethodInsn( + INVOKESTATIC, + bigclaz.getName().replace('.', '/'), + "valueOf", + "(" + Type.getDescriptor(paramType) + ")" + Type.getDescriptor(bigclaz), + false); + } + mv.visitInsn(ARETURN); + mv.visitLabel(l1); + } + mv.visitInsn(ACONST_NULL); + mv.visitInsn(ARETURN); + mv.visitMaxs(2, 2); + mv.visitEnd(); + } + { // getAnnotations + mv = new MethodDebugVisitor(cw2.visitMethod( + ACC_PUBLIC, "getAnnotations", "()[Ljava/lang/annotation/Annotation;", null, null)); + av0 = mv.visitAnnotation(convertDisabledDesc, true); + av0.visitEnd(); + mv.visitFieldInsn(GETSTATIC, newDynName, "_redkale_annotations", "Ljava/util/Map;"); + mv.visitLdcInsn(newDynSuperMessageFullName); + mv.visitMethodInsn( + INVOKEINTERFACE, "java/util/Map", "get", "(Ljava/lang/Object;)Ljava/lang/Object;", true); + mv.visitTypeInsn(CHECKCAST, "[Ljava/lang/annotation/Annotation;"); + mv.visitVarInsn(ASTORE, 1); + mv.visitVarInsn(ALOAD, 1); + Label l2 = new Label(); + mv.visitJumpInsn(IFNONNULL, l2); + mv.visitInsn(ICONST_0); + mv.visitTypeInsn(ANEWARRAY, "java/lang/annotation/Annotation"); + mv.visitInsn(ARETURN); + mv.visitLabel(l2); + mv.visitFrame(Opcodes.F_APPEND, 1, new Object[] {"[Ljava/lang/annotation/Annotation;"}, 0, null); + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 1); + mv.visitInsn(ARRAYLENGTH); + mv.visitMethodInsn( + INVOKESTATIC, "java/util/Arrays", "copyOf", "([Ljava/lang/Object;I)[Ljava/lang/Object;", false); + mv.visitTypeInsn(CHECKCAST, "[Ljava/lang/annotation/Annotation;"); + mv.visitInsn(ARETURN); + mv.visitMaxs(2, 2); + mv.visitEnd(); + } + { // execute + mv = new MethodDebugVisitor( + cw2.visitMethod(ACC_PUBLIC, "execute", "(L" + newDynWebSokcetFullName + ";)V", null, null)); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 1); + mv.visitFieldInsn( + PUTFIELD, + newDynSuperMessageFullName, + "_redkale_websocket", + "L" + newDynWebSokcetFullName + ";"); + mv.visitVarInsn(ALOAD, 1); + mv.visitLdcInsn(method.getAnnotation(RestOnMessage.class).name()); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn( + INVOKEVIRTUAL, + newDynWebSokcetFullName, + "preOnMessage", + "(Ljava/lang/String;" + wsParamDesc + "Ljava/lang/Runnable;)V", + false); + mv.visitInsn(RETURN); + mv.visitMaxs(4, 2); + mv.visitEnd(); + } + { // run + mv = new MethodDebugVisitor(cw2.visitMethod(ACC_PUBLIC, "run", "()V", null, null)); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn( + GETFIELD, + newDynSuperMessageFullName, + "_redkale_websocket", + "L" + newDynWebSokcetFullName + ";"); + + for (Map.Entry en : paramap.entrySet()) { + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn( + GETFIELD, + (newDynSuperMessageFullName), + en.getKey(), + Type.getDescriptor(en.getValue().getType())); + } + mv.visitMethodInsn( + INVOKEVIRTUAL, + newDynWebSokcetFullName, + method.getName(), + Type.getMethodDescriptor(method), + false); + + mv.visitInsn(RETURN); + mv.visitMaxs(3, 1); + mv.visitEnd(); + } + { // toString + mv = new MethodDebugVisitor( + cw2.visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null)); + mv.visitMethodInsn( + INVOKESTATIC, + JsonConvert.class.getName().replace('.', '/'), + "root", + "()" + jsonConvertDesc, + false); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn( + INVOKEVIRTUAL, + JsonConvert.class.getName().replace('.', '/'), + "convertTo", + "(Ljava/lang/Object;)Ljava/lang/String;", + false); + mv.visitInsn(ARETURN); + mv.visitMaxs(2, 1); + mv.visitEnd(); + } + cw2.visitEnd(); + byte[] bytes = cw2.toByteArray(); + Class cz = newLoader.loadClass((newDynSuperMessageFullName).replace('/', '.'), bytes); + RedkaleClassLoader.putDynClass((newDynSuperMessageFullName).replace('/', '.'), bytes, cz); + } + + if (wildcardMethod == null) { // _DynXXXWebSocketMessage class + ClassWriter cw2 = new ClassWriter(COMPUTE_FRAMES); + cw2.visit(V11, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynMessageFullName, null, "java/lang/Object", null); + + cw2.visitInnerClass(newDynMessageFullName, newDynName, newDynMessageSimpleName, ACC_PUBLIC + ACC_STATIC); + + for (int i = 0; i < messageMethods.size(); i++) { + Method method = messageMethods.get(i); + String endfix = "_" + method.getName() + "_" + (i > 9 ? i : ("0" + i)); + String newDynSuperMessageFullName = newDynMessageFullName + (method == wildcardMethod ? "" : endfix); + cw2.visitInnerClass( + newDynSuperMessageFullName, + newDynName, + newDynMessageSimpleName + endfix, + ACC_PUBLIC + ACC_STATIC); + + fv = cw2.visitField( + ACC_PUBLIC, + method.getAnnotation(RestOnMessage.class).name(), + "L" + newDynSuperMessageFullName + ";", + null, + null); + fv.visitEnd(); + } + { // 构造函数 + mv = new MethodDebugVisitor(cw2.visitMethod(ACC_PUBLIC, "", "()V", null, null)); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + { // toString + mv = new MethodDebugVisitor( + cw2.visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null)); + mv.visitMethodInsn( + INVOKESTATIC, + JsonConvert.class.getName().replace('.', '/'), + "root", + "()" + jsonConvertDesc, + false); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn( + INVOKEVIRTUAL, + JsonConvert.class.getName().replace('.', '/'), + "convertTo", + "(Ljava/lang/Object;)Ljava/lang/String;", + false); + mv.visitInsn(ARETURN); + mv.visitMaxs(2, 1); + mv.visitEnd(); + } + cw2.visitEnd(); + byte[] bytes = cw2.toByteArray(); + Class cz = newLoader.loadClass(newDynMessageFullName.replace('/', '.'), bytes); + RedkaleClassLoader.putDynClass(newDynMessageFullName.replace('/', '.'), bytes, cz); + } + + { // _DynXXXWebSocket class + ClassWriter cw2 = new ClassWriter(COMPUTE_FRAMES); + cw2.visit( + V11, + ACC_PUBLIC + ACC_FINAL + ACC_SUPER, + newDynWebSokcetFullName, + null, + webSocketInternalName, + null); + + cw2.visitInnerClass( + newDynWebSokcetFullName, newDynName, newDynWebSokcetSimpleName, ACC_PUBLIC + ACC_STATIC); + { + mv = new MethodDebugVisitor(cw2.visitMethod( + ACC_PUBLIC, + "", + "(" + resourceDescriptor + ")V", + resourceGenericDescriptor == null ? null : ("(" + resourceGenericDescriptor + ")V"), + null)); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, webSocketInternalName, "", "()V", false); + for (int i = 0; i < resourcesFields.size(); i++) { + Field field = resourcesFields.get(i); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, i + 1); + mv.visitFieldInsn( + PUTFIELD, newDynWebSokcetFullName, field.getName(), Type.getDescriptor(field.getType())); + } + mv.visitInsn(RETURN); + mv.visitMaxs(2, 1 + resourcesFields.size()); + mv.visitEnd(); + } + { // RestDyn + av0 = cw2.visitAnnotation(Type.getDescriptor(RestDyn.class), true); + av0.visit("simple", false); + av0.visitEnd(); + } + cw2.visitEnd(); + byte[] bytes = cw2.toByteArray(); + Class cz = newLoader.loadClass(newDynWebSokcetFullName.replace('/', '.'), bytes); + RedkaleClassLoader.putDynClass(newDynWebSokcetFullName.replace('/', '.'), bytes, cz); + } + + { // _DynRestOnMessageConsumer class + ClassWriter cw2 = new ClassWriter(COMPUTE_FRAMES); + cw2.visit( + V11, + ACC_PUBLIC + ACC_FINAL + ACC_SUPER, + newDynConsumerFullName, + "Ljava/lang/Object;Ljava/util/function/BiConsumer<" + wsDesc + "Ljava/lang/Object;>;", + "java/lang/Object", + new String[] {"java/util/function/BiConsumer"}); + + cw2.visitInnerClass(newDynConsumerFullName, newDynName, newDynConsumerSimpleName, ACC_PUBLIC + ACC_STATIC); + cw2.visitInnerClass(newDynMessageFullName, newDynName, newDynMessageSimpleName, ACC_PUBLIC + ACC_STATIC); + for (int i = 0; i < messageMethods.size(); i++) { + Method method = messageMethods.get(i); + String endfix = "_" + method.getName() + "_" + (i > 9 ? i : ("0" + i)); + String newDynSuperMessageFullName = newDynMessageFullName + (method == wildcardMethod ? "" : endfix); + cw2.visitInnerClass( + newDynSuperMessageFullName, + newDynName, + newDynMessageSimpleName + endfix, + ACC_PUBLIC + ACC_STATIC); + } + + { // 构造函数 + mv = new MethodDebugVisitor(cw2.visitMethod(ACC_PUBLIC, "", "()V", null, null)); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + + { // accept函数 + mv = new MethodDebugVisitor( + cw2.visitMethod(ACC_PUBLIC, "accept", "(" + wsDesc + "Ljava/lang/Object;)V", null, null)); + mv.visitVarInsn(ALOAD, 1); + mv.visitTypeInsn(CHECKCAST, newDynWebSokcetFullName); + mv.visitVarInsn(ASTORE, 3); + + mv.visitVarInsn(ALOAD, 2); + mv.visitTypeInsn(CHECKCAST, newDynMessageFullName); + mv.visitVarInsn(ASTORE, 4); + + for (int i = 0; i < messageMethods.size(); i++) { + final Method method = messageMethods.get(i); + String endfix = "_" + method.getName() + "_" + (i > 9 ? i : ("0" + i)); + String newDynSuperMessageFullName = + newDynMessageFullName + (method == wildcardMethod ? "" : endfix); + final String messagename = + method.getAnnotation(RestOnMessage.class).name(); + if (method == wildcardMethod) { + mv.visitVarInsn(ALOAD, 4); + mv.visitVarInsn(ALOAD, 3); + mv.visitMethodInsn( + INVOKEVIRTUAL, + newDynSuperMessageFullName, + "execute", + "(L" + newDynWebSokcetFullName + ";)V", + false); + } else { + mv.visitVarInsn(ALOAD, 4); + mv.visitFieldInsn( + GETFIELD, newDynMessageFullName, messagename, "L" + newDynSuperMessageFullName + ";"); + Label ifLabel = new Label(); + mv.visitJumpInsn(IFNULL, ifLabel); + + mv.visitVarInsn(ALOAD, 4); + mv.visitFieldInsn( + GETFIELD, newDynMessageFullName, messagename, "L" + newDynSuperMessageFullName + ";"); + mv.visitVarInsn(ALOAD, 3); + mv.visitMethodInsn( + INVOKEVIRTUAL, + newDynSuperMessageFullName, + "execute", + "(L" + newDynWebSokcetFullName + ";)V", + false); + mv.visitInsn(RETURN); + mv.visitLabel(ifLabel); + } + } + mv.visitInsn(RETURN); + mv.visitMaxs(3, 3 + messageMethods.size()); + mv.visitEnd(); + } + { // 虚拟accept函数 + mv = new MethodDebugVisitor(cw2.visitMethod( + ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC, + "accept", + "(Ljava/lang/Object;Ljava/lang/Object;)V", + null, + null)); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 1); + mv.visitTypeInsn(CHECKCAST, WebSocket.class.getName().replace('.', '/')); + mv.visitVarInsn(ALOAD, 2); + mv.visitTypeInsn(CHECKCAST, "java/lang/Object"); + mv.visitMethodInsn( + INVOKEVIRTUAL, newDynConsumerFullName, "accept", "(" + wsDesc + "Ljava/lang/Object;)V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(3, 3); + mv.visitEnd(); + } + cw2.visitEnd(); + byte[] bytes = cw2.toByteArray(); + Class cz = newLoader.loadClass(newDynConsumerFullName.replace('/', '.'), bytes); + RedkaleClassLoader.putDynClass(newDynConsumerFullName.replace('/', '.'), bytes, cz); + } + cw.visitEnd(); + + byte[] bytes = cw.toByteArray(); + Class newClazz = newLoader.loadClass(newDynName.replace('/', '.'), bytes); + RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, newClazz); + RedkaleClassLoader.putReflectionDeclaredConstructors(newClazz, newDynName.replace('/', '.')); + JsonFactory.root().loadDecoder(newClazz.getAnnotation(RestDyn.class).types()[2]); // 固定Message类 + + RedkaleClassLoader.putReflectionPublicMethods(webSocketType.getName()); + Class cwt = webSocketType; + do { + RedkaleClassLoader.putReflectionDeclaredFields(cwt.getName()); + } while ((cwt = cwt.getSuperclass()) != Object.class); + RedkaleClassLoader.putReflectionDeclaredConstructors(webSocketType, webSocketType.getName()); + + try { + T servlet = (T) newClazz.getDeclaredConstructor().newInstance(); + Field field = newClazz.getField("_redkale_annotations"); + field.set(null, msgclassToAnnotations); + RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), field); + if (rws.cryptor() != Cryptor.class) { + RedkaleClassLoader.putReflectionDeclaredConstructors( + rws.cryptor(), rws.cryptor().getName()); + Cryptor cryptor = rws.cryptor().getDeclaredConstructor().newInstance(); + Field cryptorField = newClazz.getSuperclass().getDeclaredField("cryptor"); // WebSocketServlet + RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), cryptorField); + cryptorField.setAccessible(true); + cryptorField.set(servlet, cryptor); + } + if (messageAgent != null) { + ((WebSocketServlet) servlet).messageAgent = messageAgent; + } + return servlet; + } catch (Exception e) { + throw new RestException(e); + } + } + + public static T createRestServlet( + final ClassLoader classLoader, + final Class userType0, + final Class baseServletType, + final Class serviceType, + String serviceResourceName) { + + if (baseServletType == null || serviceType == null) { + throw new RestException(" Servlet or Service is null Class on createRestServlet"); + } + if (!HttpServlet.class.isAssignableFrom(baseServletType)) { + throw new RestException(baseServletType + " is not HttpServlet Class on createRestServlet"); + } + int parentMod = baseServletType.getModifiers(); + if (!java.lang.reflect.Modifier.isPublic(parentMod)) { + throw new RestException(baseServletType + " is not Public Class on createRestServlet"); + } + Boolean parentNon0 = null; + { + NonBlocking snon = serviceType.getAnnotation(NonBlocking.class); + parentNon0 = snon == null ? null : snon.value(); + if (HttpServlet.class != baseServletType) { + Boolean preNonBlocking = null; + Boolean authNonBlocking = null; + RedkaleClassLoader.putReflectionDeclaredMethods(baseServletType.getName()); + for (Method m : baseServletType.getDeclaredMethods()) { + if (java.lang.reflect.Modifier.isAbstract(parentMod) + && java.lang.reflect.Modifier.isAbstract(m.getModifiers())) { // @since 2.4.0 + throw new RestException( + baseServletType + " cannot contains a abstract Method on " + baseServletType); + } + Class[] paramTypes = m.getParameterTypes(); + if (paramTypes.length != 2 + || paramTypes[0] != HttpRequest.class + || paramTypes[1] != HttpResponse.class) { + continue; + } + // ----------------------------------------------- + Class[] exps = m.getExceptionTypes(); + if (exps.length > 0 && (exps.length != 1 || exps[0] != IOException.class)) { + continue; + } + // ----------------------------------------------- + String methodName = m.getName(); + if ("preExecute".equals(methodName)) { + if (preNonBlocking == null) { + NonBlocking non = m.getAnnotation(NonBlocking.class); + preNonBlocking = non != null && non.value(); + } + continue; + } + if ("authenticate".equals(methodName)) { + if (authNonBlocking == null) { + NonBlocking non = m.getAnnotation(NonBlocking.class); + authNonBlocking = non != null && non.value(); + } + continue; + } + } + if (preNonBlocking != null && !preNonBlocking) { + parentNon0 = false; + } else if (authNonBlocking != null && !authNonBlocking) { + parentNon0 = false; + } else { + NonBlocking bnon = baseServletType.getAnnotation(NonBlocking.class); + if (bnon != null && !bnon.value()) { + parentNon0 = false; + } + } + } + } + + final String restInternalName = Type.getInternalName(Rest.class); + final String serviceDesc = Type.getDescriptor(serviceType); + final String webServletDesc = Type.getDescriptor(WebServlet.class); + final String resDesc = Type.getDescriptor(Resource.class); + final String reqDesc = Type.getDescriptor(HttpRequest.class); + final String respDesc = Type.getDescriptor(HttpResponse.class); + final String convertDesc = Type.getDescriptor(Convert.class); + final String nonblockDesc = Type.getDescriptor(NonBlocking.class); + final String typeDesc = Type.getDescriptor(java.lang.reflect.Type.class); + final String retDesc = Type.getDescriptor(RetResult.class); + final String httpResultDesc = Type.getDescriptor(HttpResult.class); + final String httpScopeDesc = Type.getDescriptor(HttpScope.class); + final String stageDesc = Type.getDescriptor(CompletionStage.class); + final String httpHeadersDesc = Type.getDescriptor(HttpHeaders.class); + final String httpParametersDesc = Type.getDescriptor(HttpParameters.class); + final String flipperDesc = Type.getDescriptor(Flipper.class); + final String httpServletName = HttpServlet.class.getName().replace('.', '/'); + final String actionEntryName = HttpServlet.ActionEntry.class.getName().replace('.', '/'); + final String attrDesc = Type.getDescriptor(org.redkale.util.Attribute.class); + final String multiContextDesc = Type.getDescriptor(MultiContext.class); + final String multiContextName = MultiContext.class.getName().replace('.', '/'); + final String mappingDesc = Type.getDescriptor(HttpMapping.class); + final String restConvertDesc = Type.getDescriptor(RestConvert.class); + final String restConvertsDesc = Type.getDescriptor(RestConvert.RestConverts.class); + final String restConvertCoderDesc = Type.getDescriptor(RestConvertCoder.class); + final String restConvertCodersDesc = Type.getDescriptor(RestConvertCoder.RestConvertCoders.class); + final String httpParamDesc = Type.getDescriptor(HttpParam.class); + final String httpParamsDesc = Type.getDescriptor(HttpParam.HttpParams.class); + final String sourcetypeDesc = Type.getDescriptor(HttpParam.HttpParameterStyle.class); + + final String reqInternalName = Type.getInternalName(HttpRequest.class); + final String respInternalName = Type.getInternalName(HttpResponse.class); + final String attrInternalName = Type.getInternalName(org.redkale.util.Attribute.class); + final String retInternalName = Type.getInternalName(RetResult.class); + final String serviceTypeInternalName = Type.getInternalName(serviceType); + + HttpUserType hut = baseServletType.getAnnotation(HttpUserType.class); + final Class userType = + (userType0 == null || userType0 == Object.class) ? (hut == null ? null : hut.value()) : userType0; + if (userType != null + && (userType.isPrimitive() + || userType.getName().startsWith("java.") + || userType.getName().startsWith("javax."))) { + throw new RestException(HttpUserType.class.getSimpleName() + " must be a JavaBean but found " + userType); + } + + final String supDynName = baseServletType.getName().replace('.', '/'); + final RestService controller = serviceType.getAnnotation(RestService.class); + if (controller != null && controller.ignore()) { + throw new RestException(serviceType + " is ignore Rest Service Class"); // 标记为ignore=true不创建Servlet + } + final boolean serRpcOnly = controller != null && controller.rpcOnly(); + final Boolean parentNonBlocking = parentNon0; + + ClassLoader loader = classLoader == null ? Thread.currentThread().getContextClassLoader() : classLoader; + String stname = serviceType.getSimpleName(); + if (stname.startsWith("Service")) { // 类似ServiceWatchService这样的类保留第一个Service字样 + stname = "Service" + stname.substring("Service".length()).replaceAll("Service.*$", ""); + } else { + stname = stname.replaceAll("Service.*$", ""); + } + String namePostfix = Utility.isBlank(serviceResourceName) ? "" : serviceResourceName; + for (char ch : namePostfix.toCharArray()) { + if ((ch == '$' + || ch == '_' + || (ch >= '0' && ch <= '9') + || (ch >= 'a' && ch <= 'z') + || (ch >= 'A' && ch <= 'Z'))) { + continue; + } + // 带特殊字符的值不能作为类名的后缀 + namePostfix = Utility.md5Hex(namePostfix); + break; + } + // String newDynName = serviceTypeInternalName.substring(0, serviceTypeInternalName.lastIndexOf('/') + 1) + + // "_Dyn" + stname + "RestServlet"; + final String newDynName = "org/redkaledyn/http/rest/" + "_Dyn" + stname + "RestServlet__" + + serviceType.getName().replace('.', '_').replace('$', '_') + + (namePostfix.isEmpty() ? "" : ("_" + namePostfix) + "DynServlet"); + + try { + Class newClazz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.')); + if (newClazz == null) { + newClazz = loader.loadClass(newDynName.replace('/', '.')); + } + T obj = (T) newClazz.getDeclaredConstructor().newInstance(); + + final String defModuleName = getWebModuleNameLowerCase(serviceType); + final String bigModuleName = getWebModuleName(serviceType); + final Map classMap = new LinkedHashMap<>(); + + final List entrys = new ArrayList<>(); + final List paramTypes = new ArrayList<>(); + final List retvalTypes = new ArrayList<>(); + + final List restConverts = new ArrayList<>(); + final Map typeRefs = new LinkedHashMap<>(); + final Map mappingUrlToMethod = new HashMap<>(); + final Map restAttributes = new LinkedHashMap<>(); + final Map bodyTypes = new HashMap<>(); + + { // entrys、paramTypes赋值 + final Method[] allMethods = serviceType.getMethods(); + Arrays.sort(allMethods, (m1, m2) -> { // 必须排序,否则paramTypes顺序容易乱 + int s = m1.getName().compareTo(m2.getName()); + if (s != 0) { + return s; + } + s = Arrays.toString(m1.getParameterTypes()).compareTo(Arrays.toString(m2.getParameterTypes())); + return s; + }); + int methodIdex = 0; + for (final Method method : allMethods) { + if (Modifier.isStatic(method.getModifiers())) { + continue; + } + if (method.isSynthetic()) { + continue; + } + if (EXCLUDERMETHODS.contains(method.getName())) { + continue; + } + if (method.getParameterCount() == 1 && method.getParameterTypes()[0] == AnyValue.class) { + if ("init".equals(method.getName())) { + continue; + } + if ("destroy".equals(method.getName())) { + continue; + } + } + if (controller == null) { + continue; + } + + RestMapping[] mappings = method.getAnnotationsByType(RestMapping.class); + if (!controller.autoMapping() && mappings.length < 1) { + continue; + } + boolean ignore = false; + for (RestMapping mapping : mappings) { + if (mapping.ignore()) { + ignore = true; + break; + } + } + if (ignore) { + continue; + } + java.lang.reflect.Type[] ptypes = + TypeToken.getGenericType(method.getGenericParameterTypes(), serviceType); + for (java.lang.reflect.Type t : ptypes) { + if (!TypeToken.isClassType(t)) { + throw new RedkaleException("param type (" + t + ") is not a class in method " + method + + ", serviceType is " + serviceType.getName()); + } + } + paramTypes.add(ptypes); + java.lang.reflect.Type rtype = formatRestReturnType(method, serviceType); + if (!TypeToken.isClassType(rtype)) { + throw new RedkaleException("return type (" + rtype + ") is not a class in method " + method + + ", serviceType is " + serviceType.getName()); + } + retvalTypes.add(rtype); + if (mappings.length == 0) { // 没有Mapping,设置一个默认值 + MappingEntry entry = new MappingEntry( + serRpcOnly, methodIdex, parentNonBlocking, null, bigModuleName, method); + entrys.add(entry); + } else { + for (RestMapping mapping : mappings) { + MappingEntry entry = new MappingEntry( + serRpcOnly, methodIdex, parentNonBlocking, mapping, defModuleName, method); + entrys.add(entry); + } + } + methodIdex++; + } + Collections.sort(entrys); + } + { // restConverts、typeRefs、mappingUrlToMethod、restAttributes、bodyTypes赋值 + final int headIndex = 10; + for (final MappingEntry entry : entrys) { + mappingUrlToMethod.put(entry.mappingurl, entry.mappingMethod); + final Method method = entry.mappingMethod; + final Class returnType = method.getReturnType(); + final Parameter[] params = method.getParameters(); + final RestConvert[] rcs = method.getAnnotationsByType(RestConvert.class); + final RestConvertCoder[] rcc = method.getAnnotationsByType(RestConvertCoder.class); + if ((rcs != null && rcs.length > 0) || (rcc != null && rcc.length > 0)) { + restConverts.add(new Object[] {rcs, rcc}); + } + // 解析方法中的每个参数 + List paramlist = new ArrayList<>(); + for (int i = 0; i < params.length; i++) { + final Parameter param = params[i]; + final Class ptype = param.getType(); + String n = null; + String comment = ""; + boolean required = true; + int radix = 10; + RestHeader annhead = param.getAnnotation(RestHeader.class); + if (annhead != null) { + n = annhead.name(); + radix = annhead.radix(); + comment = annhead.comment(); + required = annhead.required(); + } + RestCookie anncookie = param.getAnnotation(RestCookie.class); + if (anncookie != null) { + n = anncookie.name(); + radix = anncookie.radix(); + comment = anncookie.comment(); + } + RestSessionid annsid = param.getAnnotation(RestSessionid.class); + RestAddress annaddr = param.getAnnotation(RestAddress.class); + if (annaddr != null) { + comment = annaddr.comment(); + } + RestLocale annlocale = param.getAnnotation(RestLocale.class); + if (annlocale != null) { + comment = annlocale.comment(); + } + RestBody annbody = param.getAnnotation(RestBody.class); + if (annbody != null) { + comment = annbody.comment(); + } + RestUploadFile annfile = param.getAnnotation(RestUploadFile.class); + if (annfile != null) { + comment = annfile.comment(); + } + RestPath annpath = param.getAnnotation(RestPath.class); + if (annpath != null) { + comment = annpath.comment(); + } + RestUserid userid = param.getAnnotation(RestUserid.class); + + if (userid != null) { + comment = ""; + } + boolean annheaders = param.getType() == RestHeaders.class; + if (annheaders) { + comment = ""; + n = "^"; // Http头信息类型特殊处理 + } + boolean annparams = param.getType() == RestParams.class; + if (annparams) { + comment = ""; + n = "?"; // Http参数类型特殊处理 + } + RestParam annpara = param.getAnnotation(RestParam.class); + if (annpara != null) { + radix = annpara.radix(); + } + if (annpara != null) { + comment = annpara.comment(); + } + if (annpara != null) { + required = annpara.required(); + } + if (n == null) { + n = (annpara == null || annpara.name().isEmpty()) ? null : annpara.name(); + } + if (n == null && ptype == userType) { + n = "&"; // 用户类型特殊处理 + } + if (n == null) { + if (param.isNamePresent()) { + n = param.getName(); + } else if (ptype == Flipper.class) { + n = "flipper"; + } + } // n maybe is null + + java.lang.reflect.Type paramtype = + TypeToken.getGenericType(param.getParameterizedType(), serviceType); + paramlist.add(new Object[] { + param, + n, + ptype, + radix, + comment, + required, + annpara, + annsid, + annaddr, + annlocale, + annhead, + anncookie, + annbody, + annfile, + annpath, + userid, + annheaders, + annparams, + paramtype + }); + } + for (Object[] ps : + paramlist) { // {param, n, ptype, radix, comment, required, annpara, annsid, annaddr, + // annlocale, annhead, anncookie, annbody, annfile, annpath, annuserid, + // annheaders, annparams, paramtype} + final boolean isuserid = ((RestUserid) ps[headIndex + 5]) != null; // 是否取userid + if ((ps[1] != null && ps[1].toString().indexOf('&') >= 0) || isuserid) { + continue; // @RestUserid 不需要生成 @HttpParam + } + if (((RestAddress) ps[8]) != null) { + continue; // @RestAddress 不需要生成 @HttpParam + } + java.lang.reflect.Type pgtype = + TypeToken.getGenericType(((Parameter) ps[0]).getParameterizedType(), serviceType); + if (pgtype != (Class) ps[2]) { + String refid = typeRefs.get(pgtype); + if (refid == null) { + refid = "_typeref_" + typeRefs.size(); + typeRefs.put(pgtype, refid); + } + } + + final Parameter param = (Parameter) ps[0]; // 参数类型 + String pname = (String) ps[1]; // 参数名 + Class ptype = (Class) ps[2]; // 参数类型 + int radix = (Integer) ps[3]; + String comment = (String) ps[4]; + boolean required = (Boolean) ps[5]; + RestParam annpara = (RestParam) ps[6]; + RestSessionid annsid = (RestSessionid) ps[7]; + RestAddress annaddr = (RestAddress) ps[8]; + RestLocale annlocale = (RestLocale) ps[9]; + RestHeader annhead = (RestHeader) ps[headIndex]; + RestCookie anncookie = (RestCookie) ps[headIndex + 1]; + RestBody annbody = (RestBody) ps[headIndex + 2]; + RestUploadFile annfile = (RestUploadFile) ps[headIndex + 3]; + RestPath annpath = (RestPath) ps[headIndex + 4]; + RestUserid annuserid = (RestUserid) ps[headIndex + 5]; + boolean annheaders = (Boolean) ps[headIndex + 6]; + boolean annparams = (Boolean) ps[headIndex + 7]; + + if (CompletionHandler.class.isAssignableFrom( + ptype)) { // HttpResponse.createAsyncHandler() or HttpResponse.createAsyncHandler(Class) + } else if (annsid != null) { // HttpRequest.getSessionid(true|false) + } else if (annaddr != null) { // HttpRequest.getRemoteAddr + } else if (annlocale != null) { // HttpRequest.getLocale + } else if (annbody != null) { // HttpRequest.getBodyUTF8 / HttpRequest.getBody + } else if (annfile != null) { // MultiContext.partsFirstBytes / HttpRequest.partsFirstFile / + // HttpRequest.partsFiles + } else if (annpath != null) { // HttpRequest.getRequestPath + } else if (annuserid != null) { // HttpRequest.currentUserid + } else if (pname != null && pname.charAt(0) == '#') { // 从request.getPathParam 中去参数 + } else if ("#".equals(pname)) { // 从request.getRequstURI 中取参数 + } else if ("&".equals(pname) && ptype == userType) { // 当前用户对象的类名 + } else if ("^".equals(pname) && annheaders) { // HttpRequest.getHeaders Http头信息 + } else if ("?".equals(pname) && annparams) { // HttpRequest.getParameters Http参数信息 + } else if (ptype.isPrimitive()) { + // do nothing + } else if (ptype == String.class) { + // do nothing + } else if (ptype == Flipper.class) { + // do nothing + } else { // 其他Json对象 + // 构建 RestHeader、RestCookie、RestAddress 等赋值操作 + Class loop = ptype; + Set fields = new HashSet<>(); + Map attrParaNames = new LinkedHashMap<>(); + do { + if (loop == null || loop.isInterface()) { + break; // 接口时getSuperclass可能会得到null + } + for (Field field : loop.getDeclaredFields()) { + if (Modifier.isStatic(field.getModifiers())) { + continue; + } + if (Modifier.isFinal(field.getModifiers())) { + continue; + } + if (fields.contains(field.getName())) { + continue; + } + RestHeader rh = field.getAnnotation(RestHeader.class); + RestCookie rc = field.getAnnotation(RestCookie.class); + RestSessionid rs = field.getAnnotation(RestSessionid.class); + RestAddress ra = field.getAnnotation(RestAddress.class); + RestLocale rl = field.getAnnotation(RestLocale.class); + RestBody rb = field.getAnnotation(RestBody.class); + RestUploadFile ru = field.getAnnotation(RestUploadFile.class); + RestPath ri = field.getAnnotation(RestPath.class); + if (rh == null + && rc == null + && ra == null + && rl == null + && rb == null + && rs == null + && ru == null + && ri == null) { + continue; + } + + org.redkale.util.Attribute attr = org.redkale.util.Attribute.create(loop, field); + String attrFieldName; + String restname = ""; + if (rh != null) { + attrFieldName = "_redkale_attr_header_" + + (field.getType() != String.class ? "json_" : "") + + restAttributes.size(); + restname = rh.name(); + } else if (rc != null) { + attrFieldName = "_redkale_attr_cookie_" + restAttributes.size(); + restname = rc.name(); + } else if (rs != null) { + attrFieldName = "_redkale_attr_sessionid_" + restAttributes.size(); + restname = rs.create() ? "1" : ""; // 用于下面区分create值 + } else if (ra != null) { + attrFieldName = "_redkale_attr_address_" + restAttributes.size(); + // restname = ""; + } else if (rl != null) { + attrFieldName = "_redkale_attr_locale_" + restAttributes.size(); + // restname = ""; + } else if (rb != null && field.getType() == String.class) { + attrFieldName = "_redkale_attr_bodystring_" + restAttributes.size(); + // restname = ""; + } else if (rb != null && field.getType() == byte[].class) { + attrFieldName = "_redkale_attr_bodybytes_" + restAttributes.size(); + // restname = ""; + } else if (rb != null + && field.getType() != String.class + && field.getType() != byte[].class) { + attrFieldName = "_redkale_attr_bodyjson_" + restAttributes.size(); + // restname = ""; + } else if (ru != null && field.getType() == byte[].class) { + attrFieldName = "_redkale_attr_uploadbytes_" + restAttributes.size(); + // restname = ""; + } else if (ru != null && field.getType() == File.class) { + attrFieldName = "_redkale_attr_uploadfile_" + restAttributes.size(); + // restname = ""; + } else if (ru != null && field.getType() == File[].class) { + attrFieldName = "_redkale_attr_uploadfiles_" + restAttributes.size(); + // restname = ""; + } else if (ri != null && field.getType() == String.class) { + attrFieldName = "_redkale_attr_uri_" + restAttributes.size(); + // restname = ""; + } else { + continue; + } + restAttributes.put(attrFieldName, attr); + attrParaNames.put( + attrFieldName, + new Object[] {restname, field.getType(), field.getGenericType(), ru}); + fields.add(field.getName()); + } + } while ((loop = loop.getSuperclass()) != Object.class); + + if (!attrParaNames + .isEmpty()) { // 参数存在 RestHeader、RestCookie、RestSessionid、RestAddress、RestBody字段 + for (Map.Entry en : attrParaNames.entrySet()) { + if (en.getKey().contains("_header_")) { + String headerkey = en.getValue()[0].toString(); + if ("Host".equalsIgnoreCase(headerkey)) { + // do nothing + } else if ("Content-Type".equalsIgnoreCase(headerkey)) { + // do nothing + } else if ("Connection".equalsIgnoreCase(headerkey)) { + // do nothing + } else if ("Method".equalsIgnoreCase(headerkey)) { + // do nothing + } else if (en.getKey().contains("_header_json_")) { + String typefieldname = "_redkale_body_jsontype_" + bodyTypes.size(); + bodyTypes.put(typefieldname, (java.lang.reflect.Type) en.getValue()[2]); + } + } else if (en.getKey().contains("_cookie_")) { + // do nothing + } else if (en.getKey().contains("_sessionid_")) { + // do nothing + } else if (en.getKey().contains("_address_")) { + // do nothing + } else if (en.getKey().contains("_locale_")) { + // do nothing + } else if (en.getKey().contains("_uri_")) { + // do nothing + } else if (en.getKey().contains("_bodystring_")) { + // do nothing + } else if (en.getKey().contains("_bodybytes_")) { + // do nothing + } else if (en.getKey().contains("_bodyjson_")) { // JavaBean 转 Json + String typefieldname = "_redkale_body_jsontype_" + bodyTypes.size(); + bodyTypes.put(typefieldname, (java.lang.reflect.Type) en.getValue()[2]); + } else if (en.getKey().contains("_uploadbytes_")) { + // 只需mv.visitVarInsn(ALOAD, 4), 无需处理 + } else if (en.getKey().contains("_uploadfile_")) { + // 只需mv.visitVarInsn(ALOAD, 4), 无需处理 + } else if (en.getKey().contains("_uploadfiles_")) { + // 只需mv.visitVarInsn(ALOAD, 4), 无需处理 + } + } + } + } + } + java.lang.reflect.Type grt = TypeToken.getGenericType(method.getGenericReturnType(), serviceType); + Class rtc = returnType; + if (rtc == void.class) { + rtc = RetResult.class; + grt = TYPE_RETRESULT_STRING; + } else if (CompletionStage.class.isAssignableFrom(returnType)) { + ParameterizedType ptgrt = (ParameterizedType) grt; + grt = ptgrt.getActualTypeArguments()[0]; + rtc = TypeToken.typeToClass(grt); + if (rtc == null) { + rtc = Object.class; // 应该不会发生吧? + } + } else if (Flows.maybePublisherClass(returnType)) { + java.lang.reflect.Type grt0 = Flows.maybePublisherSubType(grt); + if (grt0 != null) { + grt = grt0; + } + } + if (grt != rtc) { + String refid = typeRefs.get(grt); + if (refid == null) { + refid = "_typeref_" + typeRefs.size(); + typeRefs.put(grt, refid); + } + } + } + } + for (Map.Entry en : typeRefs.entrySet()) { + Field refField = newClazz.getDeclaredField(en.getValue()); + refField.setAccessible(true); + refField.set(obj, en.getKey()); + } + for (Map.Entry en : restAttributes.entrySet()) { + Field attrField = newClazz.getDeclaredField(en.getKey()); + attrField.setAccessible(true); + attrField.set(obj, en.getValue()); + } + for (Map.Entry en : bodyTypes.entrySet()) { + Field genField = newClazz.getDeclaredField(en.getKey()); + genField.setAccessible(true); + genField.set(obj, en.getValue()); + } + for (int i = 0; i < restConverts.size(); i++) { + Field genField = newClazz.getDeclaredField(REST_CONVERT_FIELD_PREFIX + (i + 1)); + genField.setAccessible(true); + Object[] rc = restConverts.get(i); + + genField.set( + obj, + createJsonFactory((RestConvert[]) rc[0], (RestConvertCoder[]) rc[1]) + .getConvert()); + } + Field typesfield = newClazz.getDeclaredField(REST_PARAMTYPES_FIELD_NAME); + typesfield.setAccessible(true); + java.lang.reflect.Type[][] paramtypeArray = new java.lang.reflect.Type[paramTypes.size()][]; + paramtypeArray = paramTypes.toArray(paramtypeArray); + typesfield.set(obj, paramtypeArray); + + Field retfield = newClazz.getDeclaredField(REST_RETURNTYPES_FIELD_NAME); + retfield.setAccessible(true); + java.lang.reflect.Type[] rettypeArray = new java.lang.reflect.Type[retvalTypes.size()]; + rettypeArray = retvalTypes.toArray(rettypeArray); + retfield.set(obj, rettypeArray); + + Field tostringfield = newClazz.getDeclaredField(REST_TOSTRINGOBJ_FIELD_NAME); + tostringfield.setAccessible(true); + { // 注入 @WebServlet 注解 + String urlpath = ""; + final String defmodulename = getWebModuleNameLowerCase(serviceType); + final int moduleid = controller == null ? 0 : controller.moduleid(); + boolean repair = controller == null || controller.repair(); + final String catalog = controller == null ? "" : controller.catalog(); + + boolean pound = false; + for (MappingEntry entry : entrys) { + if (entry.existsPound) { + pound = true; + break; + } + } + if (defmodulename.isEmpty() || (!pound && entrys.size() <= 2)) { + Set startWiths = new HashSet<>(); + for (MappingEntry entry : entrys) { + String suburl = (catalog.isEmpty() ? "/" : ("/" + catalog + "/")) + + (defmodulename.isEmpty() ? "" : (defmodulename + "/")) + + entry.name; + if ("//".equals(suburl)) { + suburl = "/"; + } else if (suburl.length() > 2 && suburl.endsWith("/")) { + startWiths.add(suburl); + suburl += "*"; + } else { + boolean match = false; + for (String s : startWiths) { + if (suburl.startsWith(s)) { + match = true; + break; + } + } + if (match) { + continue; + } + } + urlpath += "," + suburl; + } + if (urlpath.length() > 0) { + urlpath = urlpath.substring(1); + } + } else { + urlpath = (catalog.isEmpty() ? "/" : ("/" + catalog + '/')) + defmodulename + "/*"; + } + + classMap.put("type", serviceType.getName()); + classMap.put("url", urlpath); + classMap.put("moduleid", moduleid); + classMap.put("repair", repair); + // classMap.put("comment", comment); //不显示太多信息 + } + java.util.function.Supplier sSupplier = + () -> JsonConvert.root().convertTo(classMap); + tostringfield.set(obj, sSupplier); + + Method restactMethod = newClazz.getDeclaredMethod("_createRestActionEntry"); + restactMethod.setAccessible(true); + Field tmpEntrysField = HttpServlet.class.getDeclaredField("_actionmap"); + tmpEntrysField.setAccessible(true); + HashMap innerEntryMap = (HashMap) restactMethod.invoke(obj); + for (Map.Entry en : innerEntryMap.entrySet()) { + Method m = mappingUrlToMethod.get(en.getKey()); + if (m != null) { + en.getValue().annotations = HttpServlet.ActionEntry.annotations(m); + } + } + tmpEntrysField.set(obj, innerEntryMap); + Field nonblockField = Servlet.class.getDeclaredField("_nonBlocking"); + nonblockField.setAccessible(true); + nonblockField.set(obj, parentNonBlocking == null || parentNonBlocking); + return obj; + } catch (ClassNotFoundException e) { + // do nothing + } catch (Throwable e) { + e.printStackTrace(); + } + // ------------------------------------------------------------------------------ + final String defModuleName = getWebModuleNameLowerCase(serviceType); + final String bigModuleName = getWebModuleName(serviceType); + final String catalog = controller == null ? "" : controller.catalog(); + final String httpDesc = Type.getDescriptor(HttpServlet.class); + if (!checkName(catalog)) { + throw new RestException(serviceType.getName() + " have illegal " + RestService.class.getSimpleName() + + ".catalog, only 0-9 a-z A-Z _ cannot begin 0-9"); + } + if (!checkName(defModuleName)) { + throw new RestException(serviceType.getName() + " have illegal " + RestService.class.getSimpleName() + + ".value, only 0-9 a-z A-Z _ cannot begin 0-9"); + } + ClassWriter cw = new ClassWriter(COMPUTE_FRAMES); + FieldVisitor fv; + MethodDebugVisitor mv; + AnnotationVisitor av0; + final List entrys = new ArrayList<>(); + final Map restAttributes = new LinkedHashMap<>(); + final Map classMap = new LinkedHashMap<>(); + final Map typeRefs = new LinkedHashMap<>(); + final List paramTypes = new ArrayList<>(); + final List retvalTypes = new ArrayList<>(); + final Map bodyTypes = new HashMap<>(); + final List restConverts = new ArrayList<>(); + final Map mappingurlToMethod = new HashMap<>(); + + cw.visit(V11, ACC_PUBLIC + ACC_SUPER, newDynName, null, supDynName, null); + + { // RestDynSourceType + av0 = cw.visitAnnotation(Type.getDescriptor(RestDynSourceType.class), true); + av0.visit("value", Type.getType(Type.getDescriptor(serviceType))); + av0.visitEnd(); + } + boolean dynsimple = baseServletType == HttpServlet.class; // 有自定义的BaseServlet会存在读取header的操作 + // 获取所有可以转换成HttpMapping的方法 + int methodidex = 0; + final Method[] allMethods = serviceType.getMethods(); + Arrays.sort(allMethods, (m1, m2) -> { // 必须排序,否则paramTypes顺序容易乱 + int s = m1.getName().compareTo(m2.getName()); + if (s != 0) { + return s; + } + s = Arrays.toString(m1.getParameterTypes()).compareTo(Arrays.toString(m2.getParameterTypes())); + return s; + }); + for (final Method method : allMethods) { + if (Modifier.isStatic(method.getModifiers())) { + continue; + } + if (method.isSynthetic()) { + continue; + } + if (EXCLUDERMETHODS.contains(method.getName())) { + continue; + } + if (method.getParameterCount() == 1 && method.getParameterTypes()[0] == AnyValue.class) { + if ("init".equals(method.getName())) { + continue; + } + if ("destroy".equals(method.getName())) { + continue; + } + } + if (controller == null) { + continue; + } + + RestMapping[] mappings = method.getAnnotationsByType(RestMapping.class); + if (!controller.autoMapping() && mappings.length < 1) { + continue; + } + boolean ignore = false; + for (RestMapping mapping : mappings) { + if (mapping.ignore()) { + ignore = true; + break; + } + } + if (ignore) { + continue; + } + + Class[] extypes = method.getExceptionTypes(); + if (extypes.length > 0) { + for (Class exp : extypes) { + if (!RuntimeException.class.isAssignableFrom(exp) && !IOException.class.isAssignableFrom(exp)) { + throw new RestException("@" + RestMapping.class.getSimpleName() + " only for method(" + method + + ") with throws IOException"); + } + } + } + java.lang.reflect.Type[] ptypes = TypeToken.getGenericType(method.getGenericParameterTypes(), serviceType); + for (java.lang.reflect.Type t : ptypes) { + if (!TypeToken.isClassType(t)) { + throw new RedkaleException("param type (" + t + ") is not a class in method " + method + + ", serviceType is " + serviceType.getName()); + } + } + paramTypes.add(ptypes); + java.lang.reflect.Type rtype = formatRestReturnType(method, serviceType); + if (!TypeToken.isClassType(rtype)) { + throw new RedkaleException("return type (" + rtype + ") is not a class in method " + method + + ", serviceType is " + serviceType.getName()); + } + retvalTypes.add(rtype); + if (mappings.length == 0) { // 没有Mapping,设置一个默认值 + MappingEntry entry = + new MappingEntry(serRpcOnly, methodidex, parentNonBlocking, null, bigModuleName, method); + if (entrys.contains(entry)) { + throw new RestException(serviceType.getName() + " on " + method.getName() + " 's mapping(" + + entry.name + ") is repeat"); + } + entrys.add(entry); + } else { + for (RestMapping mapping : mappings) { + MappingEntry entry = + new MappingEntry(serRpcOnly, methodidex, parentNonBlocking, mapping, defModuleName, method); + if (entrys.contains(entry)) { + throw new RestException(serviceType.getName() + " on " + method.getName() + " 's mapping(" + + entry.name + ") is repeat"); + } + entrys.add(entry); + } + } + methodidex++; + } + if (entrys.isEmpty()) { + return null; // 没有可HttpMapping的方法 + } + Collections.sort(entrys); + DynBytesClassLoader newLoader = new DynBytesClassLoader(loader); + final int moduleid = controller == null ? 0 : controller.moduleid(); + { // 注入 @WebServlet 注解 + String urlpath = ""; + boolean repair = controller == null || controller.repair(); + String comment = controller == null ? "" : controller.comment(); + av0 = cw.visitAnnotation(webServletDesc, true); + { + AnnotationVisitor av1 = av0.visitArray("value"); + boolean pound = false; + for (MappingEntry entry : entrys) { + if (entry.existsPound) { + pound = true; + break; + } + } + if (isEmpty(defModuleName) || (!pound && entrys.size() <= 2)) { + Set startWiths = new HashSet<>(); + for (MappingEntry entry : entrys) { + String suburl = (isEmpty(catalog) ? "/" : ("/" + catalog + "/")) + + (isEmpty(defModuleName) ? "" : (defModuleName + "/")) + + entry.name; + if ("//".equals(suburl)) { + suburl = "/"; + } else if (suburl.length() > 2 && suburl.endsWith("/")) { + startWiths.add(suburl); + suburl += "*"; + } else { + boolean match = false; + for (String s : startWiths) { + if (suburl.startsWith(s)) { + match = true; + break; + } + } + if (match) { + continue; + } + } + urlpath += "," + suburl; + av1.visit(null, suburl); + } + if (urlpath.length() > 0) { + urlpath = urlpath.substring(1); + } + } else { + urlpath = (catalog.isEmpty() ? "/" : ("/" + catalog + "/")) + defModuleName + "/*"; + av1.visit(null, urlpath); + } + av1.visitEnd(); + } + av0.visit("name", defModuleName); + av0.visit("moduleid", moduleid); + av0.visit("repair", repair); + av0.visit("comment", comment); + av0.visitEnd(); + classMap.put("type", serviceType.getName()); + classMap.put("url", urlpath); + classMap.put("moduleid", moduleid); + classMap.put("repair", repair); + // classMap.put("comment", comment); //不显示太多信息 + } + { // NonBlocking + av0 = cw.visitAnnotation(nonblockDesc, true); + av0.visit("value", true); + av0.visitEnd(); + } + { // 内部类 + cw.visitInnerClass( + actionEntryName, + httpServletName, + HttpServlet.ActionEntry.class.getSimpleName(), + ACC_PROTECTED + ACC_FINAL + ACC_STATIC); + + for (final MappingEntry entry : entrys) { + cw.visitInnerClass( + newDynName + "$" + entry.newActionClassName, + newDynName, + entry.newActionClassName, + ACC_PRIVATE + ACC_STATIC); + } + } + { // 注入 @Resource private XXXService _service; + fv = cw.visitField(ACC_PRIVATE, REST_SERVICE_FIELD_NAME, serviceDesc, null, null); + av0 = fv.visitAnnotation(resDesc, true); + av0.visit("name", Utility.isBlank(serviceResourceName) ? "" : serviceResourceName); + av0.visitEnd(); + fv.visitEnd(); + } + { // _serviceMap字段 Map + fv = cw.visitField( + ACC_PRIVATE, + REST_SERVICEMAP_FIELD_NAME, + "Ljava/util/Map;", + "Ljava/util/Map;", + null); + fv.visitEnd(); + } + { // _redkale_toStringSupplier字段 Supplier + fv = cw.visitField( + ACC_PRIVATE, + REST_TOSTRINGOBJ_FIELD_NAME, + "Ljava/util/function/Supplier;", + "Ljava/util/function/Supplier;", + null); + fv.visitEnd(); + } + { // 构造函数 + mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "", "()V", null, null)); + // mv.setDebug(true); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, supDynName, "", "()V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + + // 将每个Service可转换的方法生成HttpServlet对应的HttpMapping方法 + boolean namePresent = false; + try { + Method m0 = null; + for (final MappingEntry entry : entrys) { + if (entry.mappingMethod.getParameterCount() > 0) { + m0 = entry.mappingMethod; + break; + } + } + namePresent = m0 == null || m0.getParameters()[0].isNamePresent(); + } catch (Exception e) { + // do nothing + } + final Map asmParamMap = namePresent ? null : AsmMethodBoost.getMethodBeans(serviceType); + + Map innerClassBytesMap = new LinkedHashMap<>(); + boolean containsMupload = false; + for (final MappingEntry entry : entrys) { + RestUploadFile mupload = null; + Class muploadType = null; + final Method method = entry.mappingMethod; + final Class returnType = method.getReturnType(); + final java.lang.reflect.Type retvalType = formatRestReturnType(method, serviceType); + final String methodDesc = Type.getMethodDescriptor(method); + final Parameter[] params = method.getParameters(); + + final RestConvert[] rcs = method.getAnnotationsByType(RestConvert.class); + final RestConvertCoder[] rcc = method.getAnnotationsByType(RestConvertCoder.class); + if ((rcs != null && rcs.length > 0) || (rcc != null && rcc.length > 0)) { + restConverts.add(new Object[] {rcs, rcc}); + } + if (dynsimple && entry.rpcOnly) { // 需要读取http header + dynsimple = false; + } + + mv = new MethodDebugVisitor(cw.visitMethod( + ACC_PUBLIC, entry.newMethodName, "(" + reqDesc + respDesc + ")V", null, new String[] { + "java/io/IOException" + })); + // mv.setDebug(true); + mv.debugLine(); + + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, REST_SERVICEMAP_FIELD_NAME, "Ljava/util/Map;"); + Label lmapif = new Label(); + mv.visitJumpInsn(IFNONNULL, lmapif); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, REST_SERVICE_FIELD_NAME, serviceDesc); + Label lserif = new Label(); + mv.visitJumpInsn(GOTO, lserif); + mv.visitLabel(lmapif); + + mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); + + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, REST_SERVICEMAP_FIELD_NAME, "Ljava/util/Map;"); + mv.visitVarInsn(ALOAD, 1); + mv.visitLdcInsn(REST_HEADER_RESNAME); + mv.visitLdcInsn(""); + mv.visitMethodInsn( + INVOKEVIRTUAL, + reqInternalName, + "getHeader", + "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", + false); + mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Map", "get", "(Ljava/lang/Object;)Ljava/lang/Object;", true); + mv.visitTypeInsn(CHECKCAST, serviceTypeInternalName); + mv.visitLabel(lserif); + mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {serviceTypeInternalName}); + mv.visitVarInsn(ASTORE, 3); + + final int maxStack = 3 + params.length; + List varInsns = new ArrayList<>(); + int maxLocals = 4; + + AsmMethodBean methodBean = asmParamMap == null ? null : AsmMethodBean.get(asmParamMap, method); + List asmParamNames = methodBean == null ? null : methodBean.getParams(); + List paramlist = new ArrayList<>(); + // 解析方法中的每个参数 + for (int i = 0; i < params.length; i++) { + final Parameter param = params[i]; + final Class ptype = param.getType(); + String n = null; + String comment = ""; + boolean required = true; + int radix = 10; + + RestHeader annhead = param.getAnnotation(RestHeader.class); + if (annhead != null) { + if (ptype != String.class && ptype != InetSocketAddress.class) { + throw new RestException( + "@RestHeader must on String or InetSocketAddress Parameter in " + method); + } + n = annhead.name(); + radix = annhead.radix(); + comment = annhead.comment(); + required = false; + if (n.isEmpty()) { + throw new RestException("@RestHeader.value is illegal in " + method); + } + } + RestCookie anncookie = param.getAnnotation(RestCookie.class); + if (anncookie != null) { + if (annhead != null) { + throw new RestException( + "@RestCookie and @RestHeader cannot on the same Parameter in " + method); + } + if (ptype != String.class) { + throw new RestException("@RestCookie must on String Parameter in " + method); + } + n = anncookie.name(); + radix = anncookie.radix(); + comment = anncookie.comment(); + required = false; + if (n.isEmpty()) { + throw new RestException("@RestCookie.value is illegal in " + method); + } + } + RestSessionid annsid = param.getAnnotation(RestSessionid.class); + if (annsid != null) { + if (annhead != null) { + throw new RestException( + "@RestSessionid and @RestHeader cannot on the same Parameter in " + method); + } + if (anncookie != null) { + throw new RestException( + "@RestSessionid and @RestCookie cannot on the same Parameter in " + method); + } + if (ptype != String.class) { + throw new RestException("@RestSessionid must on String Parameter in " + method); + } + required = false; + } + RestAddress annaddr = param.getAnnotation(RestAddress.class); + if (annaddr != null) { + if (annhead != null) { + throw new RestException( + "@RestAddress and @RestHeader cannot on the same Parameter in " + method); + } + if (anncookie != null) { + throw new RestException( + "@RestAddress and @RestCookie cannot on the same Parameter in " + method); + } + if (annsid != null) { + throw new RestException( + "@RestAddress and @RestSessionid cannot on the same Parameter in " + method); + } + if (ptype != String.class) { + throw new RestException("@RestAddress must on String Parameter in " + method); + } + comment = annaddr.comment(); + required = false; + } + RestLocale annlocale = param.getAnnotation(RestLocale.class); + if (annlocale != null) { + if (annhead != null) { + throw new RestException( + "@RestLocale and @RestHeader cannot on the same Parameter in " + method); + } + if (anncookie != null) { + throw new RestException( + "@RestLocale and @RestCookie cannot on the same Parameter in " + method); + } + if (annsid != null) { + throw new RestException( + "@RestLocale and @RestSessionid cannot on the same Parameter in " + method); + } + if (annaddr != null) { + throw new RestException( + "@RestLocale and @RestAddress cannot on the same Parameter in " + method); + } + if (ptype != String.class) { + throw new RestException("@RestAddress must on String Parameter in " + method); + } + comment = annlocale.comment(); + required = false; + } + RestBody annbody = param.getAnnotation(RestBody.class); + if (annbody != null) { + if (annhead != null) { + throw new RestException("@RestBody and @RestHeader cannot on the same Parameter in " + method); + } + if (anncookie != null) { + throw new RestException("@RestBody and @RestCookie cannot on the same Parameter in " + method); + } + if (annsid != null) { + throw new RestException( + "@RestBody and @RestSessionid cannot on the same Parameter in " + method); + } + if (annaddr != null) { + throw new RestException("@RestBody and @RestAddress cannot on the same Parameter in " + method); + } + if (annlocale != null) { + throw new RestException("@RestBody and @RestLocale cannot on the same Parameter in " + method); + } + if (ptype.isPrimitive()) { + throw new RestException("@RestBody cannot on primitive type Parameter in " + method); + } + comment = annbody.comment(); + } + RestUploadFile annfile = param.getAnnotation(RestUploadFile.class); + if (annfile != null) { + if (mupload != null) { + throw new RestException("@RestUploadFile repeat in " + method); + } + mupload = annfile; + muploadType = ptype; + if (annhead != null) { + throw new RestException( + "@RestUploadFile and @RestHeader cannot on the same Parameter in " + method); + } + if (anncookie != null) { + throw new RestException( + "@RestUploadFile and @RestCookie cannot on the same Parameter in " + method); + } + if (annsid != null) { + throw new RestException( + "@RestUploadFile and @RestSessionid cannot on the same Parameter in " + method); + } + if (annaddr != null) { + throw new RestException( + "@RestUploadFile and @RestAddress cannot on the same Parameter in " + method); + } + if (annlocale != null) { + throw new RestException( + "@RestUploadFile and @RestLocale cannot on the same Parameter in " + method); + } + if (annbody != null) { + throw new RestException( + "@RestUploadFile and @RestBody cannot on the same Parameter in " + method); + } + if (ptype != byte[].class && ptype != File.class && ptype != File[].class) { + throw new RestException( + "@RestUploadFile must on byte[] or File or File[] Parameter in " + method); + } + comment = annfile.comment(); + } + + RestPath annpath = param.getAnnotation(RestPath.class); + if (annpath != null) { + if (annhead != null) { + throw new RestException("@RestPath and @RestHeader cannot on the same Parameter in " + method); + } + if (anncookie != null) { + throw new RestException("@RestPath and @RestCookie cannot on the same Parameter in " + method); + } + if (annsid != null) { + throw new RestException( + "@RestPath and @RestSessionid cannot on the same Parameter in " + method); + } + if (annaddr != null) { + throw new RestException("@RestPath and @RestAddress cannot on the same Parameter in " + method); + } + if (annlocale != null) { + throw new RestException("@RestPath and @RestLocale cannot on the same Parameter in " + method); + } + if (annbody != null) { + throw new RestException("@RestPath and @RestBody cannot on the same Parameter in " + method); + } + if (annfile != null) { + throw new RestException( + "@RestPath and @RestUploadFile cannot on the same Parameter in " + method); + } + if (ptype != String.class) { + throw new RestException("@RestPath must on String Parameter in " + method); + } + comment = annpath.comment(); + } + + RestUserid userid = param.getAnnotation(RestUserid.class); + if (userid != null) { + if (annhead != null) { + throw new RestException( + "@RestUserid and @RestHeader cannot on the same Parameter in " + method); + } + if (anncookie != null) { + throw new RestException( + "@RestUserid and @RestCookie cannot on the same Parameter in " + method); + } + if (annsid != null) { + throw new RestException( + "@RestUserid and @RestSessionid cannot on the same Parameter in " + method); + } + if (annaddr != null) { + throw new RestException( + "@RestUserid and @RestAddress cannot on the same Parameter in " + method); + } + if (annlocale != null) { + throw new RestException( + "@RestUserid and @RestLocale cannot on the same Parameter in " + method); + } + if (annbody != null) { + throw new RestException("@RestUserid and @RestBody cannot on the same Parameter in " + method); + } + if (annfile != null) { + throw new RestException( + "@RestUserid and @RestUploadFile cannot on the same Parameter in " + method); + } + if (!ptype.isPrimitive() && !java.io.Serializable.class.isAssignableFrom(ptype)) { + throw new RestException("@RestUserid must on java.io.Serializable Parameter in " + method); + } + comment = ""; + required = false; + } + + boolean annparams = param.getType() == RestParams.class; + boolean annheaders = param.getType() == RestHeaders.class; + if (annparams) { + if (annhead != null) { + throw new RestException("@RestHeader cannot on the " + RestParams.class.getSimpleName() + + " Parameter in " + method); + } + if (anncookie != null) { + throw new RestException("@RestCookie cannot on the " + RestParams.class.getSimpleName() + + " Parameter in " + method); + } + if (annsid != null) { + throw new RestException("@RestSessionid cannot on the " + RestParams.class.getSimpleName() + + " Parameter in " + method); + } + if (annaddr != null) { + throw new RestException("@RestAddress cannot on the " + RestParams.class.getSimpleName() + + " Parameter in " + method); + } + if (annlocale != null) { + throw new RestException("@RestLocale cannot on the " + RestParams.class.getSimpleName() + + " Parameter in " + method); + } + if (annbody != null) { + throw new RestException("@RestBody cannot on the " + RestParams.class.getSimpleName() + + " Parameter in " + method); + } + if (annfile != null) { + throw new RestException("@RestUploadFile cannot on the " + RestParams.class.getSimpleName() + + " Parameter in " + method); + } + if (userid != null) { + throw new RestException("@RestUserid cannot on the " + RestParams.class.getSimpleName() + + " Parameter in " + method); + } + if (annheaders) { + throw new RestException("@RestHeaders cannot on the " + RestParams.class.getSimpleName() + + " Parameter in " + method); + } + comment = ""; + } + + if (annheaders) { + if (annhead != null) { + throw new RestException("@RestHeader cannot on the " + RestHeaders.class.getSimpleName() + + " Parameter in " + method); + } + if (anncookie != null) { + throw new RestException("@RestCookie cannot on the " + RestHeaders.class.getSimpleName() + + " Parameter in " + method); + } + if (annsid != null) { + throw new RestException("@RestSessionid cannot on the " + RestHeaders.class.getSimpleName() + + " Parameter in " + method); + } + if (annaddr != null) { + throw new RestException("@RestAddress cannot on the " + RestHeaders.class.getSimpleName() + + " Parameter in " + method); + } + if (annlocale != null) { + throw new RestException("@RestLocale cannot on the " + RestHeaders.class.getSimpleName() + + " Parameter in " + method); + } + if (annbody != null) { + throw new RestException("@RestBody cannot on the " + RestHeaders.class.getSimpleName() + + " Parameter in " + method); + } + if (annfile != null) { + throw new RestException("@RestUploadFile cannot on the " + RestHeaders.class.getSimpleName() + + " Parameter in " + method); + } + if (userid != null) { + throw new RestException("@RestUserid cannot on the " + RestHeaders.class.getSimpleName() + + " Parameter in " + method); + } + if (annparams) { + throw new RestException("@RestParams cannot on the " + RestHeaders.class.getSimpleName() + + " Parameter in " + method); + } + comment = ""; + required = false; + } + + RestParam annpara = param.getAnnotation(RestParam.class); + if (annpara != null) { + radix = annpara.radix(); + } + if (annpara != null) { + comment = annpara.comment(); + } + if (annpara != null) { + required = annpara.required(); + } + if (n == null) { + n = (annpara == null || annpara.name().isEmpty()) ? null : annpara.name(); + } + if (n == null && ptype == userType) { + n = "&"; // 用户类型特殊处理 + } + if (n == null && ptype == RestHeaders.class) { + n = "^"; // Http头信息类型特殊处理 + } + if (n == null && ptype == RestParams.class) { + n = "?"; // Http参数类型特殊处理 + } + if (n == null && asmParamNames != null && asmParamNames.size() > i) { + n = asmParamNames.get(i).getName(); + } + if (n == null) { + if (param.isNamePresent()) { + n = param.getName(); + } else if (ptype == Flipper.class) { + n = "flipper"; + } else { + throw new RestException( + "Parameter " + param.getName() + " not found name by @RestParam in " + method); + } + } + if (annhead == null + && anncookie == null + && annsid == null + && annaddr == null + && annlocale == null + && annbody == null + && annfile == null + && !ptype.isPrimitive() + && ptype != String.class + && ptype != Flipper.class + && !CompletionHandler.class.isAssignableFrom(ptype) + && !ptype.getName().startsWith("java") + && n.charAt(0) != '#' + && !"&".equals(n)) { // 判断Json对象是否包含@RestUploadFile + Class loop = ptype; + do { + if (loop == null || loop.isInterface()) { + break; // 接口时getSuperclass可能会得到null + } + for (Field field : loop.getDeclaredFields()) { + if (Modifier.isStatic(field.getModifiers())) { + continue; + } + if (Modifier.isFinal(field.getModifiers())) { + continue; + } + RestUploadFile ruf = field.getAnnotation(RestUploadFile.class); + if (ruf == null) { + continue; + } + if (mupload != null) { + throw new RestException("@RestUploadFile repeat in " + method + " or field " + field); + } + mupload = ruf; + muploadType = field.getType(); + } + } while ((loop = loop.getSuperclass()) != Object.class); + } + java.lang.reflect.Type paramtype = TypeToken.getGenericType(param.getParameterizedType(), serviceType); + paramlist.add(new Object[] { + param, + n, + ptype, + radix, + comment, + required, + annpara, + annsid, + annaddr, + annlocale, + annhead, + anncookie, + annbody, + annfile, + annpath, + userid, + annheaders, + annparams, + paramtype + }); + } + + Map mappingMap = new LinkedHashMap<>(); + java.lang.reflect.Type returnGenericNoFutureType = + TypeToken.getGenericType(method.getGenericReturnType(), serviceType); + { // 设置 Annotation HttpMapping + boolean reqpath = false; + for (Object[] ps : paramlist) { + if ("#".equals((String) ps[1])) { + reqpath = true; + break; + } + } + if (method.getAnnotation(Deprecated.class) != null) { + av0 = mv.visitAnnotation(Type.getDescriptor(Deprecated.class), true); + av0.visitEnd(); + } + av0 = mv.visitAnnotation(mappingDesc, true); + String url = (catalog.isEmpty() ? "/" : ("/" + catalog + "/")) + + (defModuleName.isEmpty() ? "" : (defModuleName + "/")) + + entry.name + + (reqpath ? "/" : ""); + if ("//".equals(url)) { + url = "/"; + } + av0.visit("url", url); + av0.visit("name", (defModuleName.isEmpty() ? "" : (defModuleName + "_")) + entry.name); + av0.visit("example", entry.example); + av0.visit("rpcOnly", entry.rpcOnly); + av0.visit("auth", entry.auth); + av0.visit("cacheSeconds", entry.cacheSeconds); + av0.visit("actionid", entry.actionid); + av0.visit("comment", entry.comment); + + AnnotationVisitor av1 = av0.visitArray("methods"); + for (String m : entry.methods) { + av1.visit(null, m); + } + av1.visitEnd(); + + Class rtc = returnType; + if (rtc == void.class) { + rtc = RetResult.class; + returnGenericNoFutureType = TYPE_RETRESULT_STRING; + } else if (CompletionStage.class.isAssignableFrom(returnType)) { + ParameterizedType ptgrt = (ParameterizedType) returnGenericNoFutureType; + returnGenericNoFutureType = ptgrt.getActualTypeArguments()[0]; + rtc = TypeToken.typeToClass(returnGenericNoFutureType); + if (rtc == null) { + rtc = Object.class; // 应该不会发生吧? + } + } + av0.visit("result", Type.getType(Type.getDescriptor(rtc))); + if (returnGenericNoFutureType != rtc) { + String refid = typeRefs.get(returnGenericNoFutureType); + if (refid == null) { + refid = "_typeref_" + typeRefs.size(); + typeRefs.put(returnGenericNoFutureType, refid); + } + av0.visit("resultRef", refid); + } + + av0.visitEnd(); + mappingMap.put("url", url); + mappingMap.put("rpcOnly", entry.rpcOnly); + mappingMap.put("auth", entry.auth); + mappingMap.put("cacheSeconds", entry.cacheSeconds); + mappingMap.put("actionid", entry.actionid); + mappingMap.put("comment", entry.comment); + mappingMap.put("methods", entry.methods); + mappingMap.put( + "result", + returnGenericNoFutureType == returnType + ? returnType.getName() + : String.valueOf(returnGenericNoFutureType)); + entry.mappingurl = url; + } + { // 设置 Annotation NonBlocking + av0 = mv.visitAnnotation(nonblockDesc, true); + av0.visit("value", entry.nonBlocking); + av0.visitEnd(); + } + if (rcs != null && rcs.length > 0) { // 设置 Annotation RestConvert + av0 = mv.visitAnnotation(restConvertsDesc, true); + AnnotationVisitor av1 = av0.visitArray("value"); + // 设置 RestConvert + for (RestConvert rc : rcs) { + AnnotationVisitor av2 = av1.visitAnnotation(null, restConvertDesc); + av2.visit("features", rc.features()); + av2.visit("skipIgnore", rc.skipIgnore()); + av2.visit("type", Type.getType(Type.getDescriptor(rc.type()))); + AnnotationVisitor av3 = av2.visitArray("onlyColumns"); + for (String s : rc.onlyColumns()) { + av3.visit(null, s); + } + av3.visitEnd(); + av3 = av2.visitArray("ignoreColumns"); + for (String s : rc.ignoreColumns()) { + av3.visit(null, s); + } + av3.visitEnd(); + av3 = av2.visitArray("convertColumns"); + for (String s : rc.convertColumns()) { + av3.visit(null, s); + } + av3.visitEnd(); + av2.visitEnd(); + } + av1.visitEnd(); + av0.visitEnd(); + } + if (rcc != null && rcc.length > 0) { // 设置 Annotation RestConvertCoder + av0 = mv.visitAnnotation(restConvertCodersDesc, true); + AnnotationVisitor av1 = av0.visitArray("value"); + // 设置 RestConvertCoder + for (RestConvertCoder rc : rcc) { + AnnotationVisitor av2 = av1.visitAnnotation(null, restConvertCoderDesc); + av2.visit("type", Type.getType(Type.getDescriptor(rc.type()))); + av2.visit("field", rc.field()); + av2.visit("coder", Type.getType(Type.getDescriptor(rc.coder()))); + av2.visitEnd(); + } + av1.visitEnd(); + av0.visitEnd(); + } + final int headIndex = 10; + { // 设置 Annotation + av0 = mv.visitAnnotation(httpParamsDesc, true); + AnnotationVisitor av1 = av0.visitArray("value"); + // 设置 HttpParam + for (Object[] ps : + paramlist) { // {param, n, ptype, radix, comment, required, annpara, annsid, annaddr, annlocale, + // annhead, anncookie, annbody, annfile, annpath, annuserid, annheaders, annparams, + // paramtype} + String n = ps[1].toString(); + final boolean isuserid = ((RestUserid) ps[headIndex + 5]) != null; // 是否取userid + if (n.indexOf('&') >= 0 || isuserid) { + continue; // @RestUserid 不需要生成 @HttpParam + } + if (((RestAddress) ps[8]) != null) { + continue; // @RestAddress 不需要生成 @HttpParam + } + if (((RestLocale) ps[9]) != null) { + continue; // @RestLocale 不需要生成 @HttpParam + } + final boolean ishead = ((RestHeader) ps[headIndex]) != null; // 是否取getHeader 而不是 getParameter + final boolean iscookie = ((RestCookie) ps[headIndex + 1]) != null; // 是否取getCookie + final boolean isbody = ((RestBody) ps[headIndex + 2]) != null; // 是否取getBody + AnnotationVisitor av2 = av1.visitAnnotation(null, httpParamDesc); + av2.visit("name", (String) ps[1]); + if (((Parameter) ps[0]).getAnnotation(Deprecated.class) != null) { + av2.visit("deprecated", true); + } + av2.visit("type", Type.getType(Type.getDescriptor((Class) ps[2]))); + java.lang.reflect.Type pgtype = + TypeToken.getGenericType(((Parameter) ps[0]).getParameterizedType(), serviceType); + if (pgtype != (Class) ps[2]) { + String refid = typeRefs.get(pgtype); + if (refid == null) { + refid = "_typeref_" + typeRefs.size(); + typeRefs.put(pgtype, refid); + } + av2.visit("typeref", refid); + } + av2.visit("radix", (Integer) ps[3]); + if (ishead) { + av2.visitEnum("style", sourcetypeDesc, HttpParam.HttpParameterStyle.HEADER.name()); + av2.visit("example", ((RestHeader) ps[headIndex]).example()); + } else if (iscookie) { + av2.visitEnum("style", sourcetypeDesc, HttpParam.HttpParameterStyle.COOKIE.name()); + av2.visit("example", ((RestCookie) ps[headIndex + 1]).example()); + } else if (isbody) { + av2.visitEnum("style", sourcetypeDesc, HttpParam.HttpParameterStyle.BODY.name()); + av2.visit("example", ((RestBody) ps[headIndex + 2]).example()); + } else if (ps[6] != null) { + av2.visitEnum("style", sourcetypeDesc, HttpParam.HttpParameterStyle.QUERY.name()); + av2.visit("example", ((RestParam) ps[6]).example()); + } + av2.visit("comment", (String) ps[4]); + av2.visit("required", (Boolean) ps[5]); + av2.visitEnd(); + } + av1.visitEnd(); + av0.visitEnd(); + } + int uploadLocal = 0; + if (mupload != null) { // 存在文件上传 + containsMupload = true; + if (muploadType == byte[].class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn( + INVOKEVIRTUAL, reqInternalName, "getMultiContext", "()" + multiContextDesc, false); + mv.visitLdcInsn(mupload.maxLength()); + mv.visitLdcInsn(mupload.fileNameRegx()); + mv.visitLdcInsn(mupload.contentTypeRegx()); + mv.visitMethodInsn( + INVOKEVIRTUAL, + multiContextName, + "partsFirstBytes", + "(JLjava/lang/String;Ljava/lang/String;)[B", + false); + mv.visitVarInsn(ASTORE, maxLocals); + uploadLocal = maxLocals; + } else if (muploadType == File.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn( + INVOKEVIRTUAL, reqInternalName, "getMultiContext", "()" + multiContextDesc, false); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, "_redkale_home", "Ljava/io/File;"); + mv.visitLdcInsn(mupload.maxLength()); + mv.visitLdcInsn(mupload.fileNameRegx()); + mv.visitLdcInsn(mupload.contentTypeRegx()); + mv.visitMethodInsn( + INVOKEVIRTUAL, + multiContextName, + "partsFirstFile", + "(Ljava/io/File;JLjava/lang/String;Ljava/lang/String;)Ljava/io/File;", + false); + mv.visitVarInsn(ASTORE, maxLocals); + uploadLocal = maxLocals; + } else if (muploadType == File[].class) { // File[] + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn( + INVOKEVIRTUAL, reqInternalName, "getMultiContext", "()" + multiContextDesc, false); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, "_redkale_home", "Ljava/io/File;"); + mv.visitLdcInsn(mupload.maxLength()); + mv.visitLdcInsn(mupload.fileNameRegx()); + mv.visitLdcInsn(mupload.contentTypeRegx()); + mv.visitMethodInsn( + INVOKEVIRTUAL, + multiContextName, + "partsFiles", + "(Ljava/io/File;JLjava/lang/String;Ljava/lang/String;)[Ljava/io/File;", + false); + mv.visitVarInsn(ASTORE, maxLocals); + uploadLocal = maxLocals; + } + maxLocals++; + } + + List> paramMaps = new ArrayList<>(); + // 获取每个参数的值 + boolean hasAsyncHandler = false; + for (Object[] ps : paramlist) { + Map paramMap = new LinkedHashMap<>(); + final Parameter param = (Parameter) ps[0]; // 参数类型 + String pname = (String) ps[1]; // 参数名 + Class ptype = (Class) ps[2]; // 参数类型 + int radix = (Integer) ps[3]; + String comment = (String) ps[4]; + boolean required = (Boolean) ps[5]; + RestParam annpara = (RestParam) ps[6]; + RestSessionid annsid = (RestSessionid) ps[7]; + RestAddress annaddr = (RestAddress) ps[8]; + RestLocale annlocale = (RestLocale) ps[9]; + RestHeader annhead = (RestHeader) ps[headIndex]; + RestCookie anncookie = (RestCookie) ps[headIndex + 1]; + RestBody annbody = (RestBody) ps[headIndex + 2]; + RestUploadFile annfile = (RestUploadFile) ps[headIndex + 3]; + RestPath annpath = (RestPath) ps[headIndex + 4]; + RestUserid userid = (RestUserid) ps[headIndex + 5]; + boolean annheaders = (Boolean) ps[headIndex + 6]; + boolean annparams = (Boolean) ps[headIndex + 7]; + java.lang.reflect.Type pgentype = (java.lang.reflect.Type) ps[headIndex + 8]; + if (dynsimple + && (annsid != null + || annaddr != null + || annlocale != null + || annhead != null + || anncookie != null + || annfile != null + || annheaders)) { + dynsimple = false; + } + + final boolean ishead = annhead != null; // 是否取getHeader 而不是 getParameter + final boolean iscookie = anncookie != null; // 是否取getCookie + + paramMap.put("name", pname); + paramMap.put("type", ptype.getName()); + if (CompletionHandler.class.isAssignableFrom( + ptype)) { // HttpResponse.createAsyncHandler() or HttpResponse.createAsyncHandler(Class) + if (ptype == CompletionHandler.class) { + mv.visitVarInsn(ALOAD, 2); + mv.visitMethodInsn( + INVOKEVIRTUAL, + respInternalName, + "createAsyncHandler", + "()Ljava/nio/channels/CompletionHandler;", + false); + mv.visitVarInsn(ASTORE, maxLocals); + varInsns.add(new int[] {ALOAD, maxLocals}); + } else { + mv.visitVarInsn(ALOAD, 3); + mv.visitVarInsn(ALOAD, 2); + mv.visitLdcInsn(Type.getType(Type.getDescriptor(ptype))); + mv.visitMethodInsn( + INVOKEVIRTUAL, + respInternalName, + "createAsyncHandler", + "(Ljava/lang/Class;)Ljava/nio/channels/CompletionHandler;", + false); + mv.visitTypeInsn(CHECKCAST, ptype.getName().replace('.', '/')); + mv.visitVarInsn(ASTORE, maxLocals); + varInsns.add(new int[] {ALOAD, maxLocals}); + } + hasAsyncHandler = true; + } else if (annsid != null) { // HttpRequest.getSessionid(true|false) + mv.visitVarInsn(ALOAD, 1); + mv.visitInsn(annsid.create() ? ICONST_1 : ICONST_0); + mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getSessionid", "(Z)Ljava/lang/String;", false); + mv.visitVarInsn(ASTORE, maxLocals); + varInsns.add(new int[] {ALOAD, maxLocals}); + } else if (annaddr != null) { // HttpRequest.getRemoteAddr + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getRemoteAddr", "()Ljava/lang/String;", false); + mv.visitVarInsn(ASTORE, maxLocals); + varInsns.add(new int[] {ALOAD, maxLocals}); + } else if (annlocale != null) { // HttpRequest.getLocale + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getLocale", "()Ljava/lang/String;", false); + mv.visitVarInsn(ASTORE, maxLocals); + varInsns.add(new int[] {ALOAD, maxLocals}); + } else if (annheaders) { // HttpRequest.getHeaders + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getHeaders", "()" + httpHeadersDesc, false); + mv.visitVarInsn(ASTORE, maxLocals); + varInsns.add(new int[] {ALOAD, maxLocals}); + } else if (annparams) { // HttpRequest.getParameters + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn( + INVOKEVIRTUAL, reqInternalName, "getParameters", "()" + httpParametersDesc, false); + mv.visitVarInsn(ASTORE, maxLocals); + varInsns.add(new int[] {ALOAD, maxLocals}); + } else if (annbody != null) { // HttpRequest.getBodyUTF8 / HttpRequest.getBody + if (ptype == String.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn( + INVOKEVIRTUAL, reqInternalName, "getBodyUTF8", "()Ljava/lang/String;", false); + mv.visitVarInsn(ASTORE, maxLocals); + varInsns.add(new int[] {ALOAD, maxLocals}); + } else if (ptype == byte[].class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getBody", "()[B", false); + mv.visitVarInsn(ASTORE, maxLocals); + varInsns.add(new int[] {ALOAD, maxLocals}); + } else { // JavaBean 转 Json + String typefieldname = "_redkale_body_jsontype_" + bodyTypes.size(); + bodyTypes.put(typefieldname, pgentype); + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, typefieldname, "Ljava/lang/reflect/Type;"); + mv.visitMethodInsn( + INVOKEVIRTUAL, + reqInternalName, + "getBodyJson", + "(Ljava/lang/reflect/Type;)Ljava/lang/Object;", + false); + mv.visitTypeInsn(CHECKCAST, Type.getInternalName(ptype)); + mv.visitVarInsn(ASTORE, maxLocals); + varInsns.add(new int[] {ALOAD, maxLocals}); + } + } else if (annfile + != null) { // MultiContext.partsFirstBytes / HttpRequest.partsFirstFile / HttpRequest.partsFiles + mv.visitVarInsn(ALOAD, 4); + mv.visitVarInsn(ASTORE, maxLocals); + varInsns.add(new int[] {ALOAD, maxLocals}); + } else if (annpath != null) { // HttpRequest.getRequestPath + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getRequestPath", "()Ljava/lang/String;", false); + mv.visitVarInsn(ASTORE, maxLocals); + varInsns.add(new int[] {ALOAD, maxLocals}); + } else if (userid != null) { // HttpRequest.currentUserid + mv.visitVarInsn(ALOAD, 1); + if (ptype == int.class) { + mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "currentIntUserid", "()I", false); + mv.visitVarInsn(ISTORE, maxLocals); + varInsns.add(new int[] {ILOAD, maxLocals}); + } else if (ptype == long.class) { + mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "currentLongUserid", "()J", false); + mv.visitVarInsn(LSTORE, maxLocals); + varInsns.add(new int[] {LLOAD, maxLocals}); + maxLocals++; + } else if (ptype == String.class) { + mv.visitMethodInsn( + INVOKEVIRTUAL, reqInternalName, "currentStringUserid", "()Ljava/lang/String;", false); + mv.visitVarInsn(ASTORE, maxLocals); + varInsns.add(new int[] {ALOAD, maxLocals}); + } else { + mv.visitLdcInsn(Type.getType(Type.getDescriptor(ptype))); + mv.visitMethodInsn( + INVOKEVIRTUAL, + reqInternalName, + "currentUserid", + "(Ljava/lang/Class;)Ljava/io/Serializable;", + false); + mv.visitTypeInsn(CHECKCAST, Type.getInternalName(ptype)); + mv.visitVarInsn(ASTORE, maxLocals); + varInsns.add(new int[] {ALOAD, maxLocals}); + } + } else if ("#".equals(pname)) { // 从request.getRequstURI 中取参数 + if (ptype == boolean.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn( + INVOKEVIRTUAL, reqInternalName, "getPathLastParam", "()Ljava/lang/String;", false); + mv.visitMethodInsn( + INVOKESTATIC, "java/lang/Boolean", "parseBoolean", "(Ljava/lang/String;)Z", false); + mv.visitVarInsn(ISTORE, maxLocals); + varInsns.add(new int[] {ILOAD, maxLocals}); + } else if (ptype == byte.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn( + INVOKEVIRTUAL, reqInternalName, "getPathLastParam", "()Ljava/lang/String;", false); + mv.visitIntInsn(BIPUSH, radix); + mv.visitMethodInsn( + INVOKESTATIC, "java/lang/Byte", "parseByte", "(Ljava/lang/String;I)B", false); + mv.visitVarInsn(ISTORE, maxLocals); + varInsns.add(new int[] {ILOAD, maxLocals}); + } else if (ptype == short.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn( + INVOKEVIRTUAL, reqInternalName, "getPathLastParam", "()Ljava/lang/String;", false); + mv.visitIntInsn(BIPUSH, radix); + mv.visitMethodInsn( + INVOKESTATIC, "java/lang/Short", "parseShort", "(Ljava/lang/String;I)S", false); + mv.visitVarInsn(ISTORE, maxLocals); + varInsns.add(new int[] {ILOAD, maxLocals}); + } else if (ptype == char.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn( + INVOKEVIRTUAL, reqInternalName, "getPathLastParam", "()Ljava/lang/String;", false); + mv.visitInsn(ICONST_0); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "charAt", "(I)C", false); + mv.visitVarInsn(ISTORE, maxLocals); + varInsns.add(new int[] {ILOAD, maxLocals}); + } else if (ptype == int.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn( + INVOKEVIRTUAL, reqInternalName, "getPathLastParam", "()Ljava/lang/String;", false); + mv.visitIntInsn(BIPUSH, radix); + mv.visitMethodInsn( + INVOKESTATIC, "java/lang/Integer", "parseInt", "(Ljava/lang/String;I)I", false); + mv.visitVarInsn(ISTORE, maxLocals); + varInsns.add(new int[] {ILOAD, maxLocals}); + } else if (ptype == float.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn( + INVOKEVIRTUAL, reqInternalName, "getPathLastParam", "()Ljava/lang/String;", false); + mv.visitMethodInsn( + INVOKESTATIC, "java/lang/Float", "parseFloat", "(Ljava/lang/String;)F", false); + mv.visitVarInsn(FSTORE, maxLocals); + varInsns.add(new int[] {FLOAD, maxLocals}); + } else if (ptype == long.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn( + INVOKEVIRTUAL, reqInternalName, "getPathLastParam", "()Ljava/lang/String;", false); + mv.visitIntInsn(BIPUSH, radix); + mv.visitMethodInsn( + INVOKESTATIC, "java/lang/Long", "parseLong", "(Ljava/lang/String;I)J", false); + mv.visitVarInsn(LSTORE, maxLocals); + varInsns.add(new int[] {LLOAD, maxLocals}); + maxLocals++; + } else if (ptype == double.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn( + INVOKEVIRTUAL, reqInternalName, "getPathLastParam", "()Ljava/lang/String;", false); + mv.visitMethodInsn( + INVOKESTATIC, "java/lang/Double", "parseDouble", "(Ljava/lang/String;)D", false); + mv.visitVarInsn(DSTORE, maxLocals); + varInsns.add(new int[] {DLOAD, maxLocals}); + maxLocals++; + } else if (ptype == String.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn( + INVOKEVIRTUAL, reqInternalName, "getPathLastParam", "()Ljava/lang/String;", false); + mv.visitVarInsn(ASTORE, maxLocals); + varInsns.add(new int[] {ALOAD, maxLocals}); + } else { + throw new RestException(method + " only " + RestParam.class.getSimpleName() + + "(#) to Type(primitive class or String)"); + } + } else if (pname.charAt(0) == '#') { // 从request.getPathParam 中去参数 + if (ptype == boolean.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitLdcInsn(pname.substring(1)); + mv.visitLdcInsn("false"); + mv.visitMethodInsn( + INVOKEVIRTUAL, + reqInternalName, + "getPathParam", + "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", + false); + mv.visitMethodInsn( + INVOKESTATIC, "java/lang/Boolean", "parseBoolean", "(Ljava/lang/String;)Z", false); + mv.visitVarInsn(ISTORE, maxLocals); + varInsns.add(new int[] {ILOAD, maxLocals}); + } else if (ptype == byte.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitLdcInsn(pname.substring(1)); + mv.visitLdcInsn("0"); + mv.visitMethodInsn( + INVOKEVIRTUAL, + reqInternalName, + "getPathParam", + "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", + false); + mv.visitIntInsn(BIPUSH, radix); + mv.visitMethodInsn( + INVOKESTATIC, "java/lang/Byte", "parseByte", "(Ljava/lang/String;I)B", false); + mv.visitVarInsn(ISTORE, maxLocals); + varInsns.add(new int[] {ILOAD, maxLocals}); + } else if (ptype == short.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitLdcInsn(pname.substring(1)); + mv.visitLdcInsn("0"); + mv.visitMethodInsn( + INVOKEVIRTUAL, + reqInternalName, + "getPathParam", + "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", + false); + mv.visitIntInsn(BIPUSH, radix); + mv.visitMethodInsn( + INVOKESTATIC, "java/lang/Short", "parseShort", "(Ljava/lang/String;I)S", false); + mv.visitVarInsn(ISTORE, maxLocals); + varInsns.add(new int[] {ILOAD, maxLocals}); + } else if (ptype == char.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitLdcInsn(pname.substring(1)); + mv.visitLdcInsn("0"); + mv.visitMethodInsn( + INVOKEVIRTUAL, + reqInternalName, + "getPathParam", + "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", + false); + mv.visitInsn(ICONST_0); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "charAt", "(I)C", false); + mv.visitVarInsn(ISTORE, maxLocals); + varInsns.add(new int[] {ILOAD, maxLocals}); + } else if (ptype == int.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitLdcInsn(pname.substring(1)); + mv.visitLdcInsn("0"); + mv.visitMethodInsn( + INVOKEVIRTUAL, + reqInternalName, + "getPathParam", + "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", + false); + mv.visitIntInsn(BIPUSH, radix); + mv.visitMethodInsn( + INVOKESTATIC, "java/lang/Integer", "parseInt", "(Ljava/lang/String;I)I", false); + mv.visitVarInsn(ISTORE, maxLocals); + varInsns.add(new int[] {ILOAD, maxLocals}); + } else if (ptype == float.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitLdcInsn(pname.substring(1)); + mv.visitLdcInsn("0"); + mv.visitMethodInsn( + INVOKEVIRTUAL, + reqInternalName, + "getPathParam", + "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", + false); + mv.visitMethodInsn( + INVOKESTATIC, "java/lang/Float", "parseFloat", "(Ljava/lang/String;)F", false); + mv.visitVarInsn(FSTORE, maxLocals); + varInsns.add(new int[] {FLOAD, maxLocals}); + } else if (ptype == long.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitLdcInsn(pname.substring(1)); + mv.visitLdcInsn("0"); + mv.visitMethodInsn( + INVOKEVIRTUAL, + reqInternalName, + "getPathParam", + "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", + false); + mv.visitIntInsn(BIPUSH, radix); + mv.visitMethodInsn( + INVOKESTATIC, "java/lang/Long", "parseLong", "(Ljava/lang/String;I)J", false); + mv.visitVarInsn(LSTORE, maxLocals); + varInsns.add(new int[] {LLOAD, maxLocals}); + maxLocals++; + } else if (ptype == double.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitLdcInsn(pname.substring(1)); + mv.visitLdcInsn("0"); + mv.visitMethodInsn( + INVOKEVIRTUAL, + reqInternalName, + "getPathParam", + "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", + false); + mv.visitMethodInsn( + INVOKESTATIC, "java/lang/Double", "parseDouble", "(Ljava/lang/String;)D", false); + mv.visitVarInsn(DSTORE, maxLocals); + varInsns.add(new int[] {DLOAD, maxLocals}); + maxLocals++; + } else if (ptype == String.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitLdcInsn(pname.substring(1)); + mv.visitLdcInsn(""); + mv.visitMethodInsn( + INVOKEVIRTUAL, + reqInternalName, + "getPathParam", + "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", + false); + mv.visitVarInsn(ASTORE, maxLocals); + varInsns.add(new int[] {ALOAD, maxLocals}); + } else { + throw new RestException(method + " only " + RestParam.class.getSimpleName() + + "(#) to Type(primitive class or String)"); + } + } else if ("&".equals(pname) && ptype == userType) { // 当前用户对象的类名 + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "currentUser", "()Ljava/lang/Object;", false); + mv.visitTypeInsn(CHECKCAST, Type.getInternalName(ptype)); + mv.visitVarInsn(ASTORE, maxLocals); + varInsns.add(new int[] {ALOAD, maxLocals}); + } else if (ptype == boolean.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitLdcInsn(pname); + mv.visitInsn(ICONST_0); + mv.visitMethodInsn( + INVOKEVIRTUAL, + reqInternalName, + ishead ? "getBooleanHeader" : "getBooleanParameter", + "(Ljava/lang/String;Z)Z", + false); + mv.visitVarInsn(ISTORE, maxLocals); + varInsns.add(new int[] {ILOAD, maxLocals}); + } else if (ptype == byte.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitLdcInsn(pname); + mv.visitLdcInsn("0"); + mv.visitMethodInsn( + INVOKEVIRTUAL, + reqInternalName, + ishead ? "getHeader" : "getParameter", + "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", + false); + mv.visitIntInsn(BIPUSH, radix); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "parseByte", "(Ljava/lang/String;I)B", false); + mv.visitVarInsn(ISTORE, maxLocals); + varInsns.add(new int[] {ILOAD, maxLocals}); + } else if (ptype == short.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitIntInsn(BIPUSH, radix); + mv.visitLdcInsn(pname); + mv.visitInsn(ICONST_0); + mv.visitMethodInsn( + INVOKEVIRTUAL, + reqInternalName, + ishead ? "getShortHeader" : "getShortParameter", + "(ILjava/lang/String;S)S", + false); + mv.visitVarInsn(ISTORE, maxLocals); + varInsns.add(new int[] {ILOAD, maxLocals}); + } else if (ptype == char.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitLdcInsn(pname); + mv.visitLdcInsn("0"); + mv.visitMethodInsn( + INVOKEVIRTUAL, + reqInternalName, + ishead ? "getHeader" : "getParameter", + "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", + false); + mv.visitInsn(ICONST_0); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "charAt", "(I)C", false); + mv.visitVarInsn(ISTORE, maxLocals); + varInsns.add(new int[] {ILOAD, maxLocals}); + } else if (ptype == int.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitIntInsn(BIPUSH, radix); + mv.visitLdcInsn(pname); + mv.visitInsn(ICONST_0); + mv.visitMethodInsn( + INVOKEVIRTUAL, + reqInternalName, + ishead ? "getIntHeader" : "getIntParameter", + "(ILjava/lang/String;I)I", + false); + mv.visitVarInsn(ISTORE, maxLocals); + varInsns.add(new int[] {ILOAD, maxLocals}); + } else if (ptype == float.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitLdcInsn(pname); + mv.visitInsn(FCONST_0); + mv.visitMethodInsn( + INVOKEVIRTUAL, + reqInternalName, + ishead ? "getFloatHeader" : "getFloatParameter", + "(Ljava/lang/String;F)F", + false); + mv.visitVarInsn(FSTORE, maxLocals); + varInsns.add(new int[] {FLOAD, maxLocals}); + } else if (ptype == long.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitIntInsn(BIPUSH, radix); + mv.visitLdcInsn(pname); + mv.visitInsn(LCONST_0); + mv.visitMethodInsn( + INVOKEVIRTUAL, + reqInternalName, + ishead ? "getLongHeader" : "getLongParameter", + "(ILjava/lang/String;J)J", + false); + mv.visitVarInsn(LSTORE, maxLocals); + varInsns.add(new int[] {LLOAD, maxLocals}); + maxLocals++; + } else if (ptype == double.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitLdcInsn(pname); + mv.visitInsn(DCONST_0); + mv.visitMethodInsn( + INVOKEVIRTUAL, + reqInternalName, + ishead ? "getDoubleHeader" : "getDoubleParameter", + "(Ljava/lang/String;D)D", + false); + mv.visitVarInsn(DSTORE, maxLocals); + varInsns.add(new int[] {DLOAD, maxLocals}); + maxLocals++; + } else if (ptype == String.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitLdcInsn(pname); + mv.visitLdcInsn(""); + mv.visitMethodInsn( + INVOKEVIRTUAL, + reqInternalName, + iscookie ? "getCookie" : (ishead ? "getHeader" : "getParameter"), + "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", + false); + mv.visitVarInsn(ASTORE, maxLocals); + varInsns.add(new int[] {ALOAD, maxLocals}); + } else if (ptype == Flipper.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getFlipper", "()" + flipperDesc, false); + mv.visitVarInsn(ASTORE, maxLocals); + varInsns.add(new int[] {ALOAD, maxLocals}); + } else { // 其他Json对象 + mv.visitVarInsn(ALOAD, 1); + if (param.getType() == param.getParameterizedType()) { + mv.visitLdcInsn(Type.getType(Type.getDescriptor(ptype))); + } else { + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn( + GETFIELD, newDynName, REST_PARAMTYPES_FIELD_NAME, "[[Ljava/lang/reflect/Type;"); + Asms.visitInsn(mv, entry.methodIdx); // 方法下标 + mv.visitInsn(AALOAD); + int paramidx = -1; + for (int i = 0; i < params.length; i++) { + if (params[i] == param) { + paramidx = i; + break; + } + } + Asms.visitInsn(mv, paramidx); // 参数下标 + mv.visitInsn(AALOAD); + } + mv.visitLdcInsn(pname); + mv.visitMethodInsn( + INVOKEVIRTUAL, + reqInternalName, + ishead ? "getJsonHeader" : "getJsonParameter", + "(Ljava/lang/reflect/Type;Ljava/lang/String;)Ljava/lang/Object;", + false); + mv.visitTypeInsn(CHECKCAST, ptype.getName().replace('.', '/')); + mv.visitVarInsn(ASTORE, maxLocals); + varInsns.add(new int[] {ALOAD, maxLocals}); + JsonFactory.root().loadDecoder(pgentype); + + // 构建 RestHeader、RestCookie、RestAddress 等赋值操作 + Class loop = ptype; + Set fields = new HashSet<>(); + Map attrParaNames = new LinkedHashMap<>(); + do { + if (loop == null || loop.isInterface()) { + break; // 接口时getSuperclass可能会得到null + } + for (Field field : loop.getDeclaredFields()) { + if (Modifier.isStatic(field.getModifiers())) { + continue; + } + if (Modifier.isFinal(field.getModifiers())) { + continue; + } + if (fields.contains(field.getName())) { + continue; + } + RestHeader rh = field.getAnnotation(RestHeader.class); + RestCookie rc = field.getAnnotation(RestCookie.class); + RestSessionid rs = field.getAnnotation(RestSessionid.class); + RestAddress ra = field.getAnnotation(RestAddress.class); + RestLocale rl = field.getAnnotation(RestLocale.class); + RestBody rb = field.getAnnotation(RestBody.class); + RestUploadFile ru = field.getAnnotation(RestUploadFile.class); + RestPath ri = field.getAnnotation(RestPath.class); + if (rh == null + && rc == null + && ra == null + && rl == null + && rb == null + && rs == null + && ru == null + && ri == null) { + continue; + } + if (rh != null + && field.getType() != String.class + && field.getType() != InetSocketAddress.class) { + throw new RestException("@RestHeader must on String Field in " + field); + } + if (rc != null && field.getType() != String.class) { + throw new RestException("@RestCookie must on String Field in " + field); + } + if (rs != null && field.getType() != String.class) { + throw new RestException("@RestSessionid must on String Field in " + field); + } + if (ra != null && field.getType() != String.class) { + throw new RestException("@RestAddress must on String Field in " + field); + } + if (rl != null && field.getType() != String.class) { + throw new RestException("@RestLocale must on String Field in " + field); + } + if (rb != null && field.getType().isPrimitive()) { + throw new RestException("@RestBody must on cannot on primitive type Field in " + field); + } + if (ru != null + && field.getType() != byte[].class + && field.getType() != File.class + && field.getType() != File[].class) { + throw new RestException( + "@RestUploadFile must on byte[] or File or File[] Field in " + field); + } + + if (ri != null && field.getType() != String.class) { + throw new RestException("@RestPath must on String Field in " + field); + } + org.redkale.util.Attribute attr = org.redkale.util.Attribute.create(loop, field); + String attrFieldName; + String restname = ""; + if (rh != null) { + attrFieldName = "_redkale_attr_header_" + + (field.getType() != String.class ? "json_" : "") + restAttributes.size(); + restname = rh.name(); + } else if (rc != null) { + attrFieldName = "_redkale_attr_cookie_" + restAttributes.size(); + restname = rc.name(); + } else if (rs != null) { + attrFieldName = "_redkale_attr_sessionid_" + restAttributes.size(); + restname = rs.create() ? "1" : ""; // 用于下面区分create值 + } else if (ra != null) { + attrFieldName = "_redkale_attr_address_" + restAttributes.size(); + // restname = ""; + } else if (rl != null) { + attrFieldName = "_redkale_attr_locale_" + restAttributes.size(); + // restname = ""; + } else if (rb != null && field.getType() == String.class) { + attrFieldName = "_redkale_attr_bodystring_" + restAttributes.size(); + // restname = ""; + } else if (rb != null && field.getType() == byte[].class) { + attrFieldName = "_redkale_attr_bodybytes_" + restAttributes.size(); + // restname = ""; + } else if (rb != null + && field.getType() != String.class + && field.getType() != byte[].class) { + attrFieldName = "_redkale_attr_bodyjson_" + restAttributes.size(); + // restname = ""; + } else if (ru != null && field.getType() == byte[].class) { + attrFieldName = "_redkale_attr_uploadbytes_" + restAttributes.size(); + // restname = ""; + } else if (ru != null && field.getType() == File.class) { + attrFieldName = "_redkale_attr_uploadfile_" + restAttributes.size(); + // restname = ""; + } else if (ru != null && field.getType() == File[].class) { + attrFieldName = "_redkale_attr_uploadfiles_" + restAttributes.size(); + // restname = ""; + } else if (ri != null && field.getType() == String.class) { + attrFieldName = "_redkale_attr_uri_" + restAttributes.size(); + // restname = ""; + } else { + continue; + } + restAttributes.put(attrFieldName, attr); + attrParaNames.put( + attrFieldName, + new Object[] {restname, field.getType(), field.getGenericType(), ru}); + fields.add(field.getName()); + } + } while ((loop = loop.getSuperclass()) != Object.class); + + if (!attrParaNames + .isEmpty()) { // 参数存在 RestHeader、RestCookie、RestSessionid、RestAddress、RestLocale、RestBody字段 + mv.visitVarInsn(ALOAD, maxLocals); // 加载JsonBean + Label lif = new Label(); + mv.visitJumpInsn(IFNULL, lif); // if(bean != null) { + for (Map.Entry en : attrParaNames.entrySet()) { + RestUploadFile ru = (RestUploadFile) en.getValue()[3]; + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, en.getKey(), attrDesc); + mv.visitVarInsn(ALOAD, maxLocals); + mv.visitVarInsn(ALOAD, en.getKey().contains("_upload") ? uploadLocal : 1); + if (en.getKey().contains("_header_")) { + String headerkey = en.getValue()[0].toString(); + if ("Host".equalsIgnoreCase(headerkey)) { + mv.visitMethodInsn( + INVOKEVIRTUAL, reqInternalName, "getHost", "()Ljava/lang/String;", false); + } else if ("Content-Type".equalsIgnoreCase(headerkey)) { + mv.visitMethodInsn( + INVOKEVIRTUAL, + reqInternalName, + "getContentType", + "()Ljava/lang/String;", + false); + } else if ("Connection".equalsIgnoreCase(headerkey)) { + mv.visitMethodInsn( + INVOKEVIRTUAL, + reqInternalName, + "getConnection", + "()Ljava/lang/String;", + false); + } else if ("Method".equalsIgnoreCase(headerkey)) { + mv.visitMethodInsn( + INVOKEVIRTUAL, reqInternalName, "getMethod", "()Ljava/lang/String;", false); + } else if (en.getKey().contains("_header_json_")) { + String typefieldname = "_redkale_body_jsontype_" + bodyTypes.size(); + bodyTypes.put(typefieldname, (java.lang.reflect.Type) en.getValue()[2]); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, typefieldname, "Ljava/lang/reflect/Type;"); + mv.visitLdcInsn(headerkey); + mv.visitMethodInsn( + INVOKEVIRTUAL, + reqInternalName, + "getJsonHeader", + "(Ljava/lang/reflect/Type;Ljava/lang/String;)Ljava/lang/Object;", + false); + mv.visitTypeInsn(CHECKCAST, Type.getInternalName((Class) en.getValue()[1])); + JsonFactory.root().loadDecoder((java.lang.reflect.Type) en.getValue()[2]); + } else { + mv.visitLdcInsn(headerkey); + mv.visitLdcInsn(""); + mv.visitMethodInsn( + INVOKEVIRTUAL, + reqInternalName, + "getHeader", + "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", + false); + } + } else if (en.getKey().contains("_cookie_")) { + mv.visitLdcInsn(en.getValue()[0].toString()); + mv.visitLdcInsn(""); + mv.visitMethodInsn( + INVOKEVIRTUAL, + reqInternalName, + "getCookie", + "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", + false); + } else if (en.getKey().contains("_sessionid_")) { + mv.visitInsn(en.getValue()[0].toString().isEmpty() ? ICONST_0 : ICONST_1); + mv.visitMethodInsn( + INVOKEVIRTUAL, reqInternalName, "getSessionid", "(Z)Ljava/lang/String;", false); + } else if (en.getKey().contains("_address_")) { + mv.visitMethodInsn( + INVOKEVIRTUAL, reqInternalName, "getRemoteAddr", "()Ljava/lang/String;", false); + } else if (en.getKey().contains("_locale_")) { + mv.visitMethodInsn( + INVOKEVIRTUAL, reqInternalName, "getLocale", "()Ljava/lang/String;", false); + } else if (en.getKey().contains("_uri_")) { + mv.visitMethodInsn( + INVOKEVIRTUAL, reqInternalName, "getPath", "()Ljava/lang/String;", false); + } else if (en.getKey().contains("_bodystring_")) { + mv.visitMethodInsn( + INVOKEVIRTUAL, reqInternalName, "getBodyUTF8", "()Ljava/lang/String;", false); + } else if (en.getKey().contains("_bodybytes_")) { + mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getBody", "()[B", false); + } else if (en.getKey().contains("_bodyjson_")) { // JavaBean 转 Json + String typefieldname = "_redkale_body_jsontype_" + bodyTypes.size(); + bodyTypes.put(typefieldname, (java.lang.reflect.Type) en.getValue()[2]); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, typefieldname, "Ljava/lang/reflect/Type;"); + mv.visitMethodInsn( + INVOKEVIRTUAL, + reqInternalName, + "getBodyJson", + "(Ljava/lang/reflect/Type;)Ljava/lang/Object;", + false); + mv.visitTypeInsn(CHECKCAST, Type.getInternalName((Class) en.getValue()[1])); + JsonFactory.root().loadDecoder((java.lang.reflect.Type) en.getValue()[2]); + } else if (en.getKey().contains("_uploadbytes_")) { + // 只需mv.visitVarInsn(ALOAD, 4), 无需处理 + } else if (en.getKey().contains("_uploadfile_")) { + // 只需mv.visitVarInsn(ALOAD, 4), 无需处理 + } else if (en.getKey().contains("_uploadfiles_")) { + // 只需mv.visitVarInsn(ALOAD, 4), 无需处理 + } + mv.visitMethodInsn( + INVOKEINTERFACE, + attrInternalName, + "set", + "(Ljava/lang/Object;Ljava/lang/Object;)V", + true); + } + mv.visitLabel(lif); // end if } + mv.visitFrame( + Opcodes.F_APPEND, + 1, + new Object[] {ptype.getName().replace('.', '/')}, + 0, + null); + } + } + maxLocals++; + paramMaps.add(paramMap); + } // end params for each + + // mv.visitVarInsn(ALOAD, 0); //调用this + // mv.visitFieldInsn(GETFIELD, newDynName, REST_SERVICE_FIELD_NAME, serviceDesc); + mv.visitVarInsn(ALOAD, 3); + for (int[] ins : varInsns) { + mv.visitVarInsn(ins[0], ins[1]); + } + mv.visitMethodInsn(INVOKEVIRTUAL, serviceTypeInternalName, method.getName(), methodDesc, false); + if (hasAsyncHandler) { + mv.visitInsn(RETURN); + } else if (returnType == void.class) { + mv.visitVarInsn(ALOAD, 2); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, REST_RETURNTYPES_FIELD_NAME, "[Ljava/lang/reflect/Type;"); + Asms.visitInsn(mv, entry.methodIdx); // 方法下标 + mv.visitInsn(AALOAD); + mv.visitMethodInsn(INVOKESTATIC, retInternalName, "success", "()" + retDesc, false); + mv.visitMethodInsn( + INVOKEVIRTUAL, respInternalName, "finishJson", "(" + typeDesc + "Ljava/lang/Object;)V", false); + mv.visitInsn(RETURN); + } else if (returnType == boolean.class) { + mv.visitVarInsn(ISTORE, maxLocals); + mv.visitVarInsn(ALOAD, 2); // response + mv.visitVarInsn(ILOAD, maxLocals); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(Z)Ljava/lang/String;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false); + mv.visitInsn(RETURN); + maxLocals++; + } else if (returnType == byte.class) { + mv.visitVarInsn(ISTORE, maxLocals); + mv.visitVarInsn(ALOAD, 2); // response + mv.visitVarInsn(ILOAD, maxLocals); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(I)Ljava/lang/String;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false); + mv.visitInsn(RETURN); + maxLocals++; + } else if (returnType == short.class) { + mv.visitVarInsn(ISTORE, maxLocals); + mv.visitVarInsn(ALOAD, 2); // response + mv.visitVarInsn(ILOAD, maxLocals); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(I)Ljava/lang/String;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false); + mv.visitInsn(RETURN); + maxLocals++; + } else if (returnType == char.class) { + mv.visitVarInsn(ISTORE, maxLocals); + mv.visitVarInsn(ALOAD, 2); // response + mv.visitVarInsn(ILOAD, maxLocals); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(C)Ljava/lang/String;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false); + mv.visitInsn(RETURN); + maxLocals++; + } else if (returnType == int.class) { + mv.visitVarInsn(ISTORE, maxLocals); + mv.visitVarInsn(ALOAD, 2); // response + mv.visitVarInsn(ILOAD, maxLocals); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(I)Ljava/lang/String;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false); + mv.visitInsn(RETURN); + maxLocals++; + } else if (returnType == float.class) { + mv.visitVarInsn(FSTORE, maxLocals); + mv.visitVarInsn(ALOAD, 2); // response + mv.visitVarInsn(FLOAD, maxLocals); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(F)Ljava/lang/String;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false); + mv.visitInsn(RETURN); + maxLocals++; + } else if (returnType == long.class) { + mv.visitVarInsn(LSTORE, maxLocals); + mv.visitVarInsn(ALOAD, 2); // response + mv.visitVarInsn(LLOAD, maxLocals); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(J)Ljava/lang/String;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false); + mv.visitInsn(RETURN); + maxLocals += 2; + } else if (returnType == double.class) { + mv.visitVarInsn(DSTORE, maxLocals); + mv.visitVarInsn(ALOAD, 2); // response + mv.visitVarInsn(DLOAD, maxLocals); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(D)Ljava/lang/String;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false); + mv.visitInsn(RETURN); + maxLocals += 2; + } else if (returnType == byte[].class) { + mv.visitVarInsn(ASTORE, maxLocals); + mv.visitVarInsn(ALOAD, 2); // response + mv.visitVarInsn(ALOAD, maxLocals); + mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "([B)V", false); + mv.visitInsn(RETURN); + maxLocals++; + } else if (returnType == String.class) { + mv.visitVarInsn(ASTORE, maxLocals); + mv.visitVarInsn(ALOAD, 2); // response + mv.visitVarInsn(ALOAD, maxLocals); + mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false); + mv.visitInsn(RETURN); + maxLocals++; + } else if (returnType == File.class) { + mv.visitVarInsn(ASTORE, maxLocals); + mv.visitVarInsn(ALOAD, 2); // response + mv.visitVarInsn(ALOAD, maxLocals); + mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/io/File;)V", false); + mv.visitInsn(RETURN); + maxLocals++; + } else if (Number.class.isAssignableFrom(returnType) + || CharSequence.class.isAssignableFrom(returnType)) { // returnType == String.class 必须放在前面 + mv.visitVarInsn(ASTORE, maxLocals); + mv.visitVarInsn(ALOAD, 2); // response + mv.visitVarInsn(ALOAD, maxLocals); + mv.visitMethodInsn( + INVOKESTATIC, "java/lang/String", "valueOf", "(Ljava/lang/Object;)Ljava/lang/String;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false); + mv.visitInsn(RETURN); + maxLocals++; + } else if (RetResult.class.isAssignableFrom(returnType)) { + mv.visitVarInsn(ASTORE, maxLocals); + mv.visitVarInsn(ALOAD, 2); // response + if (rcs != null && rcs.length > 0) { + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn( + GETFIELD, newDynName, REST_CONVERT_FIELD_PREFIX + restConverts.size(), convertDesc); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, REST_RETURNTYPES_FIELD_NAME, "[Ljava/lang/reflect/Type;"); + Asms.visitInsn(mv, entry.methodIdx); // 方法下标 + mv.visitInsn(AALOAD); + mv.visitVarInsn(ALOAD, maxLocals); + mv.visitMethodInsn( + INVOKEVIRTUAL, + respInternalName, + "finish", + "(" + convertDesc + typeDesc + retDesc + ")V", + false); + } else { + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, REST_RETURNTYPES_FIELD_NAME, "[Ljava/lang/reflect/Type;"); + Asms.visitInsn(mv, entry.methodIdx); // 方法下标 + mv.visitInsn(AALOAD); + mv.visitVarInsn(ALOAD, maxLocals); + mv.visitMethodInsn( + INVOKEVIRTUAL, respInternalName, "finish", "(" + typeDesc + retDesc + ")V", false); + } + mv.visitInsn(RETURN); + maxLocals++; + } else if (HttpResult.class.isAssignableFrom(returnType)) { + mv.visitVarInsn(ASTORE, maxLocals); + mv.visitVarInsn(ALOAD, 2); // response + if (rcs != null && rcs.length > 0) { + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn( + GETFIELD, newDynName, REST_CONVERT_FIELD_PREFIX + restConverts.size(), convertDesc); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, REST_RETURNTYPES_FIELD_NAME, "[Ljava/lang/reflect/Type;"); + Asms.visitInsn(mv, entry.methodIdx); // 方法下标 + mv.visitInsn(AALOAD); + mv.visitVarInsn(ALOAD, maxLocals); + mv.visitMethodInsn( + INVOKEVIRTUAL, + respInternalName, + "finish", + "(" + convertDesc + typeDesc + httpResultDesc + ")V", + false); + } else { + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, REST_RETURNTYPES_FIELD_NAME, "[Ljava/lang/reflect/Type;"); + Asms.visitInsn(mv, entry.methodIdx); // 方法下标 + mv.visitInsn(AALOAD); + mv.visitVarInsn(ALOAD, maxLocals); + mv.visitMethodInsn( + INVOKEVIRTUAL, respInternalName, "finish", "(" + typeDesc + httpResultDesc + ")V", false); + } + mv.visitInsn(RETURN); + maxLocals++; + } else if (HttpScope.class.isAssignableFrom(returnType)) { + mv.visitVarInsn(ASTORE, maxLocals); + mv.visitVarInsn(ALOAD, 2); // response + if (rcs != null && rcs.length > 0) { + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn( + GETFIELD, newDynName, REST_CONVERT_FIELD_PREFIX + restConverts.size(), convertDesc); + mv.visitVarInsn(ALOAD, maxLocals); + mv.visitMethodInsn( + INVOKEVIRTUAL, respInternalName, "finish", "(" + convertDesc + httpScopeDesc + ")V", false); + } else { + mv.visitVarInsn(ALOAD, maxLocals); + mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(" + httpScopeDesc + ")V", false); + } + mv.visitInsn(RETURN); + maxLocals++; + } else if (CompletionStage.class.isAssignableFrom(returnType)) { + mv.visitVarInsn(ASTORE, maxLocals); + mv.visitVarInsn(ALOAD, 2); // response + Class returnNoFutureType = TypeToken.typeToClassOrElse(returnGenericNoFutureType, Object.class); + if (returnNoFutureType == HttpScope.class) { + if (rcs != null && rcs.length > 0) { + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn( + GETFIELD, newDynName, REST_CONVERT_FIELD_PREFIX + restConverts.size(), convertDesc); + mv.visitVarInsn(ALOAD, maxLocals); + mv.visitMethodInsn( + INVOKEVIRTUAL, + respInternalName, + "finishScopeFuture", + "(" + convertDesc + stageDesc + ")V", + false); + } else { + mv.visitVarInsn(ALOAD, maxLocals); + mv.visitMethodInsn( + INVOKEVIRTUAL, respInternalName, "finishScopeFuture", "(" + stageDesc + ")V", false); + } + } else if (returnNoFutureType != byte[].class + && returnNoFutureType != RetResult.class + && returnNoFutureType != HttpResult.class + && returnNoFutureType != File.class + && !((returnGenericNoFutureType instanceof Class) + && (((Class) returnGenericNoFutureType).isPrimitive() + || CharSequence.class.isAssignableFrom((Class) returnGenericNoFutureType)))) { + if (rcs != null && rcs.length > 0) { + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn( + GETFIELD, newDynName, REST_CONVERT_FIELD_PREFIX + restConverts.size(), convertDesc); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn( + GETFIELD, newDynName, REST_RETURNTYPES_FIELD_NAME, "[Ljava/lang/reflect/Type;"); + Asms.visitInsn(mv, entry.methodIdx); // 方法下标 + mv.visitInsn(AALOAD); + mv.visitVarInsn(ALOAD, maxLocals); + mv.visitMethodInsn( + INVOKEVIRTUAL, + respInternalName, + "finishJsonFuture", + "(" + convertDesc + typeDesc + stageDesc + ")V", + false); + } else { + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn( + GETFIELD, newDynName, REST_RETURNTYPES_FIELD_NAME, "[Ljava/lang/reflect/Type;"); + Asms.visitInsn(mv, entry.methodIdx); // 方法下标 + mv.visitInsn(AALOAD); + mv.visitVarInsn(ALOAD, maxLocals); + mv.visitMethodInsn( + INVOKEVIRTUAL, + respInternalName, + "finishJsonFuture", + "(" + typeDesc + stageDesc + ")V", + false); + } + } else { + if (rcs != null && rcs.length > 0) { + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn( + GETFIELD, newDynName, REST_CONVERT_FIELD_PREFIX + restConverts.size(), convertDesc); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn( + GETFIELD, newDynName, REST_RETURNTYPES_FIELD_NAME, "[Ljava/lang/reflect/Type;"); + Asms.visitInsn(mv, entry.methodIdx); // 方法下标 + mv.visitInsn(AALOAD); + mv.visitVarInsn(ALOAD, maxLocals); + mv.visitMethodInsn( + INVOKEVIRTUAL, + respInternalName, + "finishFuture", + "(" + convertDesc + typeDesc + stageDesc + ")V", + false); + } else { + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn( + GETFIELD, newDynName, REST_RETURNTYPES_FIELD_NAME, "[Ljava/lang/reflect/Type;"); + Asms.visitInsn(mv, entry.methodIdx); // 方法下标 + mv.visitInsn(AALOAD); + mv.visitVarInsn(ALOAD, maxLocals); + mv.visitMethodInsn( + INVOKEVIRTUAL, + respInternalName, + "finishFuture", + "(" + typeDesc + stageDesc + ")V", + false); + } + } + mv.visitInsn(RETURN); + maxLocals++; + } else if (Flows.maybePublisherClass(returnType)) { // Flow.Publisher + mv.visitVarInsn(ASTORE, maxLocals); + mv.visitVarInsn(ALOAD, 2); // response + if (rcs != null && rcs.length > 0) { + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn( + GETFIELD, newDynName, REST_CONVERT_FIELD_PREFIX + restConverts.size(), convertDesc); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, REST_RETURNTYPES_FIELD_NAME, "[Ljava/lang/reflect/Type;"); + Asms.visitInsn(mv, entry.methodIdx); // 方法下标 + mv.visitInsn(AALOAD); + mv.visitVarInsn(ALOAD, maxLocals); + mv.visitMethodInsn( + INVOKEVIRTUAL, + respInternalName, + "finishPublisher", + "(" + convertDesc + typeDesc + "Ljava/lang/Object;)V", + false); + } else { + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, REST_RETURNTYPES_FIELD_NAME, "[Ljava/lang/reflect/Type;"); + Asms.visitInsn(mv, entry.methodIdx); // 方法下标 + mv.visitInsn(AALOAD); + mv.visitVarInsn(ALOAD, maxLocals); + mv.visitMethodInsn( + INVOKEVIRTUAL, + respInternalName, + "finishPublisher", + "(" + typeDesc + "Ljava/lang/Object;)V", + false); + } + mv.visitInsn(RETURN); + maxLocals++; + } else if (returnType == retvalType) { // 普通JavaBean或JavaBean[] + mv.visitVarInsn(ASTORE, maxLocals); + mv.visitVarInsn(ALOAD, 2); // response + if (rcs != null && rcs.length > 0) { + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn( + GETFIELD, newDynName, REST_CONVERT_FIELD_PREFIX + restConverts.size(), convertDesc); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, REST_RETURNTYPES_FIELD_NAME, "[Ljava/lang/reflect/Type;"); + Asms.visitInsn(mv, entry.methodIdx); // 方法下标 + mv.visitInsn(AALOAD); + mv.visitVarInsn(ALOAD, maxLocals); + mv.visitMethodInsn( + INVOKEVIRTUAL, + respInternalName, + "finishJson", + "(" + convertDesc + typeDesc + "Ljava/lang/Object;)V", + false); + } else { + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, REST_RETURNTYPES_FIELD_NAME, "[Ljava/lang/reflect/Type;"); + Asms.visitInsn(mv, entry.methodIdx); // 方法下标 + mv.visitInsn(AALOAD); + mv.visitVarInsn(ALOAD, maxLocals); + mv.visitMethodInsn( + INVOKEVIRTUAL, + respInternalName, + "finishJson", + "(" + typeDesc + "Ljava/lang/Object;)V", + false); + } + mv.visitInsn(RETURN); + maxLocals++; + } else { + mv.visitVarInsn(ASTORE, maxLocals); + mv.visitVarInsn(ALOAD, 2); // response + if (rcs != null && rcs.length > 0) { + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn( + GETFIELD, newDynName, REST_CONVERT_FIELD_PREFIX + restConverts.size(), convertDesc); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, REST_RETURNTYPES_FIELD_NAME, "[Ljava/lang/reflect/Type;"); + Asms.visitInsn(mv, entry.methodIdx); // 方法下标 + mv.visitInsn(AALOAD); + mv.visitVarInsn(ALOAD, maxLocals); + mv.visitMethodInsn( + INVOKEVIRTUAL, + respInternalName, + "finish", + "(" + convertDesc + typeDesc + "Ljava/lang/Object;)V", + false); + } else { + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, REST_RETURNTYPES_FIELD_NAME, "[Ljava/lang/reflect/Type;"); + Asms.visitInsn(mv, entry.methodIdx); // 方法下标 + mv.visitInsn(AALOAD); + mv.visitVarInsn(ALOAD, maxLocals); + mv.visitMethodInsn( + INVOKEVIRTUAL, respInternalName, "finish", "(" + typeDesc + "Ljava/lang/Object;)V", false); + } + mv.visitInsn(RETURN); + maxLocals++; + } + mv.visitMaxs(maxStack, maxLocals); + mappingMap.put("params", paramMaps); + + { // _Dync_XXX__HttpServlet.class + ClassWriter cw2 = new ClassWriter(COMPUTE_FRAMES); + cw2.visit(V11, ACC_SUPER, newDynName + "$" + entry.newActionClassName, null, httpServletName, null); + + cw2.visitInnerClass( + newDynName + "$" + entry.newActionClassName, + newDynName, + entry.newActionClassName, + ACC_PRIVATE + ACC_STATIC); + { // 设置 Annotation NonBlocking + av0 = cw2.visitAnnotation(nonblockDesc, true); + av0.visit("value", entry.nonBlocking); + av0.visitEnd(); + } + { + fv = cw2.visitField(0, "_parentServlet", "L" + newDynName + ";", null, null); + fv.visitEnd(); + } + { + mv = new MethodDebugVisitor(cw2.visitMethod(0, "", "(L" + newDynName + ";)V", null, null)); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, httpServletName, "", "()V", false); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 1); + mv.visitFieldInsn( + PUTFIELD, + newDynName + "$" + entry.newActionClassName, + "_parentServlet", + "L" + newDynName + ";"); + mv.visitVarInsn(ALOAD, 0); + mv.visitInsn(entry.nonBlocking ? ICONST_1 : ICONST_0); + mv.visitFieldInsn(PUTFIELD, newDynName + "$" + entry.newActionClassName, "_nonBlocking", "Z"); + mv.visitInsn(RETURN); + mv.visitMaxs(2, 2); + mv.visitEnd(); + } + // if (false) { + // mv = new MethodDebugVisitor(cw2.visitMethod(ACC_SYNTHETIC, "", "(L" + + // newDynName + ";L" + newDynName + "$" + entry.newActionClassName + ";)V", null, null)); + // mv.visitVarInsn(ALOAD, 0); + // mv.visitVarInsn(ALOAD, 1); + // mv.visitCheckCast(INVOKESPECIAL, newDynName + "$" + entry.newActionClassName, + // "", "L" + newDynName + ";", false); + // mv.visitInsn(RETURN); + // mv.visitMaxs(2, 3); + // mv.visitEnd(); + // } + { + mv = new MethodDebugVisitor( + cw2.visitMethod(ACC_PUBLIC, "execute", "(" + reqDesc + respDesc + ")V", null, new String[] { + "java/io/IOException" + })); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn( + GETFIELD, + newDynName + "$" + entry.newActionClassName, + "_parentServlet", + "L" + newDynName + ";"); + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 2); + mv.visitMethodInsn( + INVOKEVIRTUAL, newDynName, entry.newMethodName, "(" + reqDesc + respDesc + ")V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(3, 3); + mv.visitEnd(); + } + cw2.visitEnd(); + byte[] bytes = cw2.toByteArray(); + newLoader.addClass((newDynName + "$" + entry.newActionClassName).replace('/', '.'), bytes); + innerClassBytesMap.put((newDynName + "$" + entry.newActionClassName).replace('/', '.'), bytes); + } + } // end for each + + if (containsMupload) { // 注入 @Resource(name = "APP_HOME") private File _redkale_home; + fv = cw.visitField(ACC_PRIVATE, "_redkale_home", Type.getDescriptor(File.class), null, null); + av0 = fv.visitAnnotation(resDesc, true); + av0.visit("name", "APP_HOME"); + av0.visitEnd(); + fv.visitEnd(); + } + + // HashMap _createRestActionEntry() { + // HashMap map = new HashMap<>(); + // map.put("asyncfind3", new ActionEntry(100000,200000,"asyncfind3", new + // String[]{},null,false,false,0, new _Dync_asyncfind3_HttpServlet())); + // map.put("asyncfind2", new ActionEntry(1,2,"asyncfind2", new String[]{"GET", + // "POST"},null,false,true,0, new _Dync_asyncfind2_HttpServlet())); + // return map; + // } + { // _createRestActionEntry 方法 + mv = new MethodDebugVisitor(cw.visitMethod( + 0, + "_createRestActionEntry", + "()Ljava/util/HashMap;", + "()Ljava/util/HashMap;", + null)); + // mv.setDebug(true); + mv.visitTypeInsn(NEW, "java/util/HashMap"); + mv.visitInsn(DUP); + mv.visitMethodInsn(INVOKESPECIAL, "java/util/HashMap", "", "()V", false); + mv.visitVarInsn(ASTORE, 1); + + for (final MappingEntry entry : entrys) { + mappingurlToMethod.put(entry.mappingurl, entry.mappingMethod); + mv.visitVarInsn(ALOAD, 1); + mv.visitLdcInsn(entry.mappingurl); // name + mv.visitTypeInsn(NEW, actionEntryName); // new ActionEntry + mv.visitInsn(DUP); + Asms.visitInsn(mv, moduleid); // moduleid + Asms.visitInsn(mv, entry.actionid); // actionid + mv.visitLdcInsn(entry.mappingurl); // name + Asms.visitInsn(mv, entry.methods.length); // methods + mv.visitTypeInsn(ANEWARRAY, "java/lang/String"); + for (int i = 0; i < entry.methods.length; i++) { + mv.visitInsn(DUP); + Asms.visitInsn(mv, i); + mv.visitLdcInsn(entry.methods[i]); + mv.visitInsn(AASTORE); + } + mv.visitInsn(ACONST_NULL); // method + mv.visitInsn(entry.rpcOnly ? ICONST_1 : ICONST_0); // rpcOnly + mv.visitInsn(entry.auth ? ICONST_1 : ICONST_0); // auth + Asms.visitInsn(mv, entry.cacheSeconds); // cacheSeconds + mv.visitTypeInsn(NEW, newDynName + "$" + entry.newActionClassName); + mv.visitInsn(DUP); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn( + INVOKESPECIAL, + newDynName + "$" + entry.newActionClassName, + "", + "(L" + newDynName + ";)V", + false); + mv.visitMethodInsn( + INVOKESPECIAL, + actionEntryName, + "", + "(IILjava/lang/String;[Ljava/lang/String;Ljava/lang/reflect/Method;ZZI" + httpDesc + ")V", + false); + mv.visitMethodInsn( + INVOKEVIRTUAL, + "java/util/HashMap", + "put", + "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", + false); + mv.visitInsn(POP); + } + mv.visitVarInsn(ALOAD, 1); + mv.visitInsn(ARETURN); + mv.visitMaxs(2, 2); + mv.visitEnd(); + } + + for (Map.Entry en : bodyTypes.entrySet()) { + fv = cw.visitField(ACC_PRIVATE, en.getKey(), "Ljava/lang/reflect/Type;", null, null); + av0 = fv.visitAnnotation(Type.getDescriptor(Comment.class), true); + av0.visit("value", en.getValue().toString()); + av0.visitEnd(); + fv.visitEnd(); + } + + for (Map.Entry en : typeRefs.entrySet()) { + fv = cw.visitField(ACC_PRIVATE, en.getValue(), "Ljava/lang/reflect/Type;", null, null); + av0 = fv.visitAnnotation(Type.getDescriptor(Comment.class), true); + av0.visit("value", en.getKey().toString()); + av0.visitEnd(); + fv.visitEnd(); + } + + for (Map.Entry en : restAttributes.entrySet()) { + fv = cw.visitField(ACC_PRIVATE, en.getKey(), attrDesc, null, null); + av0 = fv.visitAnnotation(Type.getDescriptor(Comment.class), true); + av0.visit("value", en.getValue().toString()); + av0.visitEnd(); + fv.visitEnd(); + } + + for (int i = 1; i <= restConverts.size(); i++) { + fv = cw.visitField(ACC_PRIVATE, REST_CONVERT_FIELD_PREFIX + i, convertDesc, null, null); + fv.visitEnd(); + } + + { // _paramtypes字段 java.lang.reflect.Type[][] + fv = cw.visitField(ACC_PRIVATE, REST_PARAMTYPES_FIELD_NAME, "[[Ljava/lang/reflect/Type;", null, null); + av0 = fv.visitAnnotation(Type.getDescriptor(Comment.class), true); + StringBuilder sb = new StringBuilder().append('['); + for (java.lang.reflect.Type[] rs : paramTypes) { + sb.append(Arrays.toString(rs)).append(','); + } + av0.visit("value", sb.append(']').toString()); + av0.visitEnd(); + fv.visitEnd(); + } + { // _returntypes字段 java.lang.reflect.Type[] + fv = cw.visitField(ACC_PRIVATE, REST_RETURNTYPES_FIELD_NAME, "[Ljava/lang/reflect/Type;", null, null); + av0 = fv.visitAnnotation(Type.getDescriptor(Comment.class), true); + av0.visit("value", retvalTypes.toString()); + av0.visitEnd(); + fv.visitEnd(); + } + + // classMap.put("mappings", mappingMaps); //不显示太多信息 + { // toString函数 + mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null)); + // mv.setDebug(true); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, REST_TOSTRINGOBJ_FIELD_NAME, "Ljava/util/function/Supplier;"); + mv.visitMethodInsn(INVOKEINTERFACE, "java/util/function/Supplier", "get", "()Ljava/lang/Object;", true); + mv.visitTypeInsn(CHECKCAST, "java/lang/String"); + mv.visitInsn(ARETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + + { // RestDyn + av0 = cw.visitAnnotation(Type.getDescriptor(RestDyn.class), true); + av0.visit("simple", (Boolean) dynsimple); + av0.visitEnd(); + } + + cw.visitEnd(); + byte[] bytes = cw.toByteArray(); + newLoader.addClass(newDynName.replace('/', '.'), bytes); + try { + Class newClazz = newLoader.findClass(newDynName.replace('/', '.')); + innerClassBytesMap.forEach((n, bs) -> { + try { + RedkaleClassLoader.putDynClass(n, bs, newLoader.findClass(n)); + RedkaleClassLoader.putReflectionClass(n); + } catch (Exception e) { + throw new RestException(e); + } + }); + RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, newClazz); + RedkaleClassLoader.putReflectionDeclaredConstructors(newClazz, newDynName.replace('/', '.')); + for (java.lang.reflect.Type t : retvalTypes) { + JsonFactory.root().loadEncoder(t); + } + + T obj = ((Class) newClazz).getDeclaredConstructor().newInstance(); + { + Field serviceField = newClazz.getDeclaredField(REST_SERVICE_FIELD_NAME); + RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), serviceField); + Field servicemapField = newClazz.getDeclaredField(REST_SERVICEMAP_FIELD_NAME); + RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), servicemapField); + } + for (Map.Entry en : typeRefs.entrySet()) { + Field refField = newClazz.getDeclaredField(en.getValue()); + refField.setAccessible(true); + refField.set(obj, en.getKey()); + RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), refField); + } + for (Map.Entry en : restAttributes.entrySet()) { + Field attrField = newClazz.getDeclaredField(en.getKey()); + attrField.setAccessible(true); + attrField.set(obj, en.getValue()); + RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), attrField); + } + for (Map.Entry en : bodyTypes.entrySet()) { + Field genField = newClazz.getDeclaredField(en.getKey()); + genField.setAccessible(true); + genField.set(obj, en.getValue()); + RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), genField); + } + for (int i = 0; i < restConverts.size(); i++) { + Field genField = newClazz.getDeclaredField(REST_CONVERT_FIELD_PREFIX + (i + 1)); + genField.setAccessible(true); + Object[] rc = restConverts.get(i); + genField.set( + obj, + createJsonFactory((RestConvert[]) rc[0], (RestConvertCoder[]) rc[1]) + .getConvert()); + RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), genField); + } + Field typesfield = newClazz.getDeclaredField(REST_PARAMTYPES_FIELD_NAME); + typesfield.setAccessible(true); + java.lang.reflect.Type[][] paramtypeArray = new java.lang.reflect.Type[paramTypes.size()][]; + paramtypeArray = paramTypes.toArray(paramtypeArray); + typesfield.set(obj, paramtypeArray); + RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), typesfield); + + Field retfield = newClazz.getDeclaredField(REST_RETURNTYPES_FIELD_NAME); + retfield.setAccessible(true); + java.lang.reflect.Type[] rettypeArray = new java.lang.reflect.Type[retvalTypes.size()]; + rettypeArray = retvalTypes.toArray(rettypeArray); + retfield.set(obj, rettypeArray); + RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), retfield); + + Field tostringfield = newClazz.getDeclaredField(REST_TOSTRINGOBJ_FIELD_NAME); + tostringfield.setAccessible(true); + java.util.function.Supplier sSupplier = + () -> JsonConvert.root().convertTo(classMap); + tostringfield.set(obj, sSupplier); + RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), tostringfield); + + Method restactMethod = newClazz.getDeclaredMethod("_createRestActionEntry"); + restactMethod.setAccessible(true); + RedkaleClassLoader.putReflectionMethod(newDynName.replace('/', '.'), restactMethod); + Field tmpEntrysField = HttpServlet.class.getDeclaredField("_actionmap"); + tmpEntrysField.setAccessible(true); + HashMap innerEntryMap = (HashMap) restactMethod.invoke(obj); + for (Map.Entry en : innerEntryMap.entrySet()) { + Method m = mappingurlToMethod.get(en.getKey()); + if (m != null) { + en.getValue().annotations = HttpServlet.ActionEntry.annotations(m); + } + } + tmpEntrysField.set(obj, innerEntryMap); + RedkaleClassLoader.putReflectionField(HttpServlet.class.getName(), tmpEntrysField); + + Field nonblockField = Servlet.class.getDeclaredField("_nonBlocking"); + nonblockField.setAccessible(true); + nonblockField.set(obj, parentNonBlocking == null || parentNonBlocking); + RedkaleClassLoader.putReflectionField(Servlet.class.getName(), nonblockField); + return obj; + } catch (Throwable e) { + throw new RestException(e); + } + } + + private static java.lang.reflect.Type formatRestReturnType(Method method, Class serviceType) { + final Class returnType = method.getReturnType(); + java.lang.reflect.Type t = TypeToken.getGenericType(method.getGenericReturnType(), serviceType); + if (method.getReturnType() == void.class) { + return RetResult.TYPE_RET_STRING; + } else if (HttpResult.class.isAssignableFrom(returnType)) { + if (!(t instanceof ParameterizedType)) { + return Object.class; + } + ParameterizedType pt = (ParameterizedType) t; + return pt.getActualTypeArguments()[0]; + } else if (CompletionStage.class.isAssignableFrom(returnType)) { + ParameterizedType pt = (ParameterizedType) t; + java.lang.reflect.Type grt = pt.getActualTypeArguments()[0]; + Class gct = TypeToken.typeToClass(grt); + if (HttpResult.class.isAssignableFrom(gct)) { + if (!(grt instanceof ParameterizedType)) { + return Object.class; + } + ParameterizedType pt2 = (ParameterizedType) grt; + return pt2.getActualTypeArguments()[0]; + } else if (gct == void.class || gct == Void.class) { + return RetResult.TYPE_RET_STRING; + } else { + return grt; + } + } else if (Flows.maybePublisherClass(returnType)) { + return Flows.maybePublisherSubType(t); + } + return t; + } + + private static boolean checkName(String name) { // 只能是字母、数字和下划线,且不能以数字开头 + if (name.isEmpty()) { + return true; + } + if (name.charAt(0) >= '0' && name.charAt(0) <= '9') { + return false; + } + for (char ch : name.toCharArray()) { + if (!((ch >= '0' && ch <= '9') + || ch == '_' + || (ch >= 'a' && ch <= 'z') + || (ch >= 'A' && ch <= 'Z'))) { // 不能含特殊字符 + return false; + } + } + return true; + } + + private static boolean checkName2(String name) { // 只能是字母、数字、短横、点和下划线,且不能以数字开头 + if (name.isEmpty()) { + return true; + } + if (name.charAt(0) >= '0' && name.charAt(0) <= '9') { + return false; + } + for (char ch : name.toCharArray()) { + if (!((ch >= '0' && ch <= '9') + || ch == '_' + || ch == '-' + || ch == '.' + || (ch >= 'a' && ch <= 'z') + || (ch >= 'A' && ch <= 'Z'))) { // 不能含特殊字符 + return false; + } + } + return true; + } + + private static class MappingEntry implements Comparable { + + private static final RestMapping DEFAULT__MAPPING; + + static { + try { + DEFAULT__MAPPING = + MappingEntry.class.getDeclaredMethod("mapping").getAnnotation(RestMapping.class); + } catch (Exception e) { + throw new Error(e); + } + } + + private static String formatMappingName(String name) { + if (name.isEmpty()) { + return name; + } + boolean normal = true; // 是否包含特殊字符 + for (char ch : name.toCharArray()) { + if (ch >= '0' && ch <= '9') { + continue; + } + if (ch >= 'a' && ch <= 'z') { + continue; + } + if (ch >= 'A' && ch <= 'Z') { + continue; + } + if (ch == '_' || ch == '$') { + continue; + } + normal = false; + break; + } + return normal ? name : Utility.md5Hex(name); + } + + public MappingEntry( + final boolean serRpcOnly, + int methodIndex, + Boolean typeNonBlocking, + RestMapping mapping, + final String defModuleName, + Method method) { + if (mapping == null) { + mapping = DEFAULT__MAPPING; + } + this.methodIdx = methodIndex; + this.ignore = mapping.ignore(); + String n = mapping.name(); + if (n.isEmpty()) { + n = method.getName(); + } + this.name = n.trim(); + this.example = mapping.example(); + this.mappingMethod = method; + this.methods = mapping.methods(); + this.auth = mapping.auth(); + this.rpcOnly = serRpcOnly || mapping.rpcOnly(); + this.actionid = mapping.actionid(); + this.cacheSeconds = mapping.cacheSeconds(); + this.comment = mapping.comment(); + boolean pound = false; + Parameter[] params = method.getParameters(); + for (Parameter param : params) { + RestParam rp = param.getAnnotation(RestParam.class); + String pn = null; + if (rp != null && !rp.name().isEmpty()) { + pn = rp.name(); + } else { + Param pm = param.getAnnotation(Param.class); + if (pm != null && !pm.value().isEmpty()) { + pn = pm.value(); + } + } + if (pn != null && pn.charAt(0) == '#') { + pound = true; + break; + } + } + this.existsPound = pound; + this.newMethodName = formatMappingName( + this.name.replace('/', '$').replace('.', '_').replace('-', '_')); + this.newActionClassName = "_Dyn_" + this.newMethodName + "_ActionHttpServlet"; + + NonBlocking non = method.getAnnotation(NonBlocking.class); + Boolean nonFlag = non == null ? typeNonBlocking : (Boolean) non.value(); // 显注在方法优先级大于类 + if (nonFlag == null) { + if (CompletionStage.class.isAssignableFrom(method.getReturnType())) { + nonFlag = true; + } else { + for (Parameter mp : method.getParameters()) { + if (CompletionHandler.class.isAssignableFrom(mp.getType())) { + nonFlag = true; + break; + } + } + } + } + this.nonBlocking = nonFlag != null && nonFlag; + } + + public final int methodIdx; // _paramtypes 的下标,从0开始 + + public final Method mappingMethod; + + public final boolean ignore; + + public final String newMethodName; + + public final String newActionClassName; + + public final String name; + + public final String example; + + public final String comment; + + public final String[] methods; + + public final boolean nonBlocking; + + public final boolean rpcOnly; + + public final boolean auth; + + public final int actionid; + + public final int cacheSeconds; + + public final boolean existsPound; // 是否包含#的参数 + + String mappingurl; // 在生成方法时赋值, 供 _createRestActionEntry 使用 + + @RestMapping() + void mapping() { // 用于获取Mapping 默认值 + } + + @Override + public int hashCode() { + return this.name.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + return this.name.equals(((MappingEntry) obj).name); + } + + @Override + public int compareTo(MappingEntry o) { + return this.name.compareTo(o.name); + } + } +} diff --git a/src/main/java/org/redkale/net/http/RestException.java b/src/main/java/org/redkale/net/http/RestException.java index 2177c4949..72df40884 100644 --- a/src/main/java/org/redkale/net/http/RestException.java +++ b/src/main/java/org/redkale/net/http/RestException.java @@ -1,31 +1,31 @@ -/* - * - */ -package org.redkale.net.http; - -/** - * Rest自定义异常类 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public class RestException extends HttpException { - - public RestException() { - super(); - } - - public RestException(String s) { - super(s); - } - - public RestException(String message, Throwable cause) { - super(message, cause); - } - - public RestException(Throwable cause) { - super(cause); - } -} +/* + * + */ +package org.redkale.net.http; + +/** + * Rest自定义异常类 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public class RestException extends HttpException { + + public RestException() { + super(); + } + + public RestException(String s) { + super(s); + } + + public RestException(String message, Throwable cause) { + super(message, cause); + } + + public RestException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/org/redkale/net/http/WebCodec.java b/src/main/java/org/redkale/net/http/WebCodec.java index fd9ef0c19..b56315378 100644 --- a/src/main/java/org/redkale/net/http/WebCodec.java +++ b/src/main/java/org/redkale/net/http/WebCodec.java @@ -1,179 +1,179 @@ -/* - * - */ -package org.redkale.net.http; - -import static org.redkale.net.http.HttpRequest.*; - -import java.nio.ByteBuffer; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.util.logging.Logger; -import org.redkale.net.client.ClientCodec; -import org.redkale.util.ByteArray; - -/** @author zhangjx */ -class WebCodec extends ClientCodec { - - protected static final Logger logger = Logger.getLogger(WebCodec.class.getSimpleName()); - - private ByteArray recyclableArray; - - private ByteArray halfBytes; - - private WebResult lastResult = null; - - public WebCodec(WebConnection connection) { - super(connection); - } - - private ByteArray pollArray(ByteArray array) { - if (recyclableArray == null) { - recyclableArray = new ByteArray(); - } - recyclableArray.clear(); - if (array != null) { - recyclableArray.put(array); - } - return recyclableArray; - } - - @Override - public void decodeMessages(final ByteBuffer realBuf, final ByteArray array) { - int rs; - final ByteBuffer buffer = realBuf; - while (buffer.hasRemaining()) { - WebResult result = this.lastResult; - if (result == null) { - result = new WebResult(); - result.readState = READ_STATE_ROUTE; - this.lastResult = result; - } - array.clear(); - if (this.halfBytes != null) { - array.put(this.halfBytes); - this.halfBytes = null; - } - if (result.readState == READ_STATE_ROUTE) { - rs = readStatusLine(result, buffer, array); - if (rs > 0) { // 数据不全 - this.halfBytes = pollArray(array); - return; - } else if (rs < 0) { // 数据异常 - occurError(null, new HttpException("http status not valid")); - return; - } - result.readState = READ_STATE_HEADER; - } - if (result.readState == READ_STATE_HEADER) { - rs = readHeaderBytes(result, buffer, array); - if (rs > 0) { // 数据不全 - this.halfBytes = pollArray(array); - return; - } else if (rs < 0) { // 数据异常 - occurError(null, new HttpException("http header not valid")); - return; - } - result.readState = READ_STATE_BODY; - } - if (result.readState == READ_STATE_BODY) { - rs = readBody(result, buffer, array); - if (rs > 0) { // 数据不全 - this.halfBytes = pollArray(array); - return; - } else if (rs < 0) { // 数据异常 - occurError(null, new HttpException("http data not valid")); - return; - } - result.readState = READ_STATE_END; - } - addMessage(nextRequest(), result); - lastResult = null; - } - } - - // 解析 HTTP/1.1 200 OK - private int readStatusLine(final WebResult result, final ByteBuffer buffer, final ByteArray array) { - int remain = buffer.remaining(); - if (array.length() > 0 && array.getLastByte() == '\r') { // array存在半截数据 - if (buffer.get() != '\n') { - return -1; - } - } else { - for (; ; ) { - if (remain-- < 1) { - return 1; - } - byte b = buffer.get(); - if (b == '\r') { - if (remain-- < 1) { - array.put((byte) '\r'); - return 1; - } - if (buffer.get() != '\n') { - return -1; - } - break; - } - array.put(b); - } - } - String value = array.toString(null); - int pos = value.indexOf(' '); - result.setStatus(Integer.decode(value.substring(pos + 1, value.indexOf(" ", pos + 2)))); - array.clear(); - return 0; - } - - // 解析Header Connection: keep-alive - // 返回0表示解析完整,非0表示还需继续读数据 - private int readHeaderBytes(final WebResult result, final ByteBuffer buffer, final ByteArray array) { - byte b; - while (buffer.hasRemaining()) { - b = buffer.get(); - if (b == '\n') { - int len = array.length(); - if (len >= 3 - && array.get(len - 1) == '\r' - && array.get(len - 2) == '\n' - && array.get(len - 3) == '\r') { - // 最后一个\r\n不写入 - readHeaderLines(result, array.removeLastByte()); // 移除最后一个\r - array.clear(); - return 0; - } - } - array.put(b); - } - return 1; - } - - private int readBody(final WebResult result, final ByteBuffer buffer, final ByteArray array) { - if (result.contentLength >= 0) { - array.put(buffer, Math.min((int) result.contentLength, buffer.remaining())); - int lr = (int) result.contentLength - array.length(); - if (lr == 0) { - result.result(array.getBytes()); - } - return lr > 0 ? lr : 0; - } - return -1; - } - - private void readHeaderLines(final WebResult result, ByteArray bytes) { - int start = 0; - int posC, posR; - Charset charset = StandardCharsets.UTF_8; - while (start < bytes.length()) { - posC = bytes.indexOf(start, ':'); - String name = bytes.toString(start, posC - start, charset).trim(); - posR = bytes.indexOf(posC + 1, '\r'); - String value = bytes.toString(posC + 1, posR - posC - 1, charset).trim(); - result.header(name, value); - if ("Content-Length".equalsIgnoreCase(name)) { - result.contentLength = Integer.parseInt(value); - } - start = posR + 2; // 跳过\r\n - } - } -} +/* + * + */ +package org.redkale.net.http; + +import static org.redkale.net.http.HttpRequest.*; + +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.logging.Logger; +import org.redkale.net.client.ClientCodec; +import org.redkale.util.ByteArray; + +/** @author zhangjx */ +class WebCodec extends ClientCodec { + + protected static final Logger logger = Logger.getLogger(WebCodec.class.getSimpleName()); + + private ByteArray recyclableArray; + + private ByteArray halfBytes; + + private WebResult lastResult = null; + + public WebCodec(WebConnection connection) { + super(connection); + } + + private ByteArray pollArray(ByteArray array) { + if (recyclableArray == null) { + recyclableArray = new ByteArray(); + } + recyclableArray.clear(); + if (array != null) { + recyclableArray.put(array); + } + return recyclableArray; + } + + @Override + public void decodeMessages(final ByteBuffer realBuf, final ByteArray array) { + int rs; + final ByteBuffer buffer = realBuf; + while (buffer.hasRemaining()) { + WebResult result = this.lastResult; + if (result == null) { + result = new WebResult(); + result.readState = READ_STATE_ROUTE; + this.lastResult = result; + } + array.clear(); + if (this.halfBytes != null) { + array.put(this.halfBytes); + this.halfBytes = null; + } + if (result.readState == READ_STATE_ROUTE) { + rs = readStatusLine(result, buffer, array); + if (rs > 0) { // 数据不全 + this.halfBytes = pollArray(array); + return; + } else if (rs < 0) { // 数据异常 + occurError(null, new HttpException("http status not valid")); + return; + } + result.readState = READ_STATE_HEADER; + } + if (result.readState == READ_STATE_HEADER) { + rs = readHeaderBytes(result, buffer, array); + if (rs > 0) { // 数据不全 + this.halfBytes = pollArray(array); + return; + } else if (rs < 0) { // 数据异常 + occurError(null, new HttpException("http header not valid")); + return; + } + result.readState = READ_STATE_BODY; + } + if (result.readState == READ_STATE_BODY) { + rs = readBody(result, buffer, array); + if (rs > 0) { // 数据不全 + this.halfBytes = pollArray(array); + return; + } else if (rs < 0) { // 数据异常 + occurError(null, new HttpException("http data not valid")); + return; + } + result.readState = READ_STATE_END; + } + addMessage(nextRequest(), result); + lastResult = null; + } + } + + // 解析 HTTP/1.1 200 OK + private int readStatusLine(final WebResult result, final ByteBuffer buffer, final ByteArray array) { + int remain = buffer.remaining(); + if (array.length() > 0 && array.getLastByte() == '\r') { // array存在半截数据 + if (buffer.get() != '\n') { + return -1; + } + } else { + for (; ; ) { + if (remain-- < 1) { + return 1; + } + byte b = buffer.get(); + if (b == '\r') { + if (remain-- < 1) { + array.put((byte) '\r'); + return 1; + } + if (buffer.get() != '\n') { + return -1; + } + break; + } + array.put(b); + } + } + String value = array.toString(null); + int pos = value.indexOf(' '); + result.setStatus(Integer.decode(value.substring(pos + 1, value.indexOf(" ", pos + 2)))); + array.clear(); + return 0; + } + + // 解析Header Connection: keep-alive + // 返回0表示解析完整,非0表示还需继续读数据 + private int readHeaderBytes(final WebResult result, final ByteBuffer buffer, final ByteArray array) { + byte b; + while (buffer.hasRemaining()) { + b = buffer.get(); + if (b == '\n') { + int len = array.length(); + if (len >= 3 + && array.get(len - 1) == '\r' + && array.get(len - 2) == '\n' + && array.get(len - 3) == '\r') { + // 最后一个\r\n不写入 + readHeaderLines(result, array.removeLastByte()); // 移除最后一个\r + array.clear(); + return 0; + } + } + array.put(b); + } + return 1; + } + + private int readBody(final WebResult result, final ByteBuffer buffer, final ByteArray array) { + if (result.contentLength >= 0) { + array.put(buffer, Math.min((int) result.contentLength, buffer.remaining())); + int lr = (int) result.contentLength - array.length(); + if (lr == 0) { + result.result(array.getBytes()); + } + return lr > 0 ? lr : 0; + } + return -1; + } + + private void readHeaderLines(final WebResult result, ByteArray bytes) { + int start = 0; + int posC, posR; + Charset charset = StandardCharsets.UTF_8; + while (start < bytes.length()) { + posC = bytes.indexOf(start, ':'); + String name = bytes.toString(start, posC - start, charset).trim(); + posR = bytes.indexOf(posC + 1, '\r'); + String value = bytes.toString(posC + 1, posR - posC - 1, charset).trim(); + result.header(name, value); + if ("Content-Length".equalsIgnoreCase(name)) { + result.contentLength = Integer.parseInt(value); + } + start = posR + 2; // 跳过\r\n + } + } +} diff --git a/src/main/java/org/redkale/net/http/WebConnection.java b/src/main/java/org/redkale/net/http/WebConnection.java index c29a691a4..499400d03 100644 --- a/src/main/java/org/redkale/net/http/WebConnection.java +++ b/src/main/java/org/redkale/net/http/WebConnection.java @@ -1,26 +1,26 @@ -/* - * - */ -package org.redkale.net.http; - -import org.redkale.net.AsyncConnection; -import org.redkale.net.client.ClientCodec; -import org.redkale.net.client.ClientConnection; - -/** - * 详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -class WebConnection extends ClientConnection { - - public WebConnection(WebClient client, AsyncConnection channel) { - super(client, channel); - } - - @Override - protected ClientCodec createCodec() { - return new WebCodec(this); - } -} +/* + * + */ +package org.redkale.net.http; + +import org.redkale.net.AsyncConnection; +import org.redkale.net.client.ClientCodec; +import org.redkale.net.client.ClientConnection; + +/** + * 详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +class WebConnection extends ClientConnection { + + public WebConnection(WebClient client, AsyncConnection channel) { + super(client, channel); + } + + @Override + protected ClientCodec createCodec() { + return new WebCodec(this); + } +} diff --git a/src/main/java/org/redkale/net/http/WebResult.java b/src/main/java/org/redkale/net/http/WebResult.java index 142551892..f7bab2935 100644 --- a/src/main/java/org/redkale/net/http/WebResult.java +++ b/src/main/java/org/redkale/net/http/WebResult.java @@ -1,33 +1,33 @@ -/* - * - */ -package org.redkale.net.http; - -import org.redkale.convert.ConvertDisabled; -import org.redkale.convert.json.JsonConvert; -import org.redkale.net.client.ClientResult; - -/** - * 详情见: https://redkale.org - * - * @author zhangjx - * @param T - * @since 2.8.0 - */ -public class WebResult extends HttpResult implements ClientResult { - - int readState; - - int contentLength = -1; - - @Override - @ConvertDisabled - public boolean isKeepAlive() { - return true; - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(HttpResult.class, this); - } -} +/* + * + */ +package org.redkale.net.http; + +import org.redkale.convert.ConvertDisabled; +import org.redkale.convert.json.JsonConvert; +import org.redkale.net.client.ClientResult; + +/** + * 详情见: https://redkale.org + * + * @author zhangjx + * @param T + * @since 2.8.0 + */ +public class WebResult extends HttpResult implements ClientResult { + + int readState; + + int contentLength = -1; + + @Override + @ConvertDisabled + public boolean isKeepAlive() { + return true; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(HttpResult.class, this); + } +} diff --git a/src/main/java/org/redkale/net/http/WebSocketFuture.java b/src/main/java/org/redkale/net/http/WebSocketFuture.java index d340f4842..4d2f2dc8b 100644 --- a/src/main/java/org/redkale/net/http/WebSocketFuture.java +++ b/src/main/java/org/redkale/net/http/WebSocketFuture.java @@ -1,59 +1,59 @@ -/* - * - */ -package org.redkale.net.http; - -import java.util.*; -import java.util.concurrent.*; -import org.redkale.net.WorkThread; - -/** - * WebSocket连接的IO写线程 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public class WebSocketFuture extends CompletableFuture implements Runnable { - - WebSocketPacket[] packets; - - WebSocket websocket; - - WorkThread workThread; - - ScheduledFuture timeout; - - WebSocketFuture(WorkThread workThread, WebSocket websocket, WebSocketPacket... packets) { - super(); - this.workThread = workThread; - this.websocket = websocket; - this.packets = packets; - } - - void cancelTimeout() { - if (timeout != null) { - timeout.cancel(true); - } - } - - @Override // JDK9+ - public WebSocketFuture newIncompleteFuture() { - WebSocketFuture future = new WebSocketFuture(workThread, websocket, packets); - future.timeout = timeout; - return future; - } - - @Override - public void run() { - TimeoutException ex = new TimeoutException("packets: " + Arrays.toString(packets)); - workThread.runWork(() -> completeExceptionally(ex)); - } - - @Override - public String toString() { - return getClass().getSimpleName() + "_" + Objects.hash(this) + "{websocket = " + websocket + ", packets = " - + Arrays.toString(packets) + "}"; - } -} +/* + * + */ +package org.redkale.net.http; + +import java.util.*; +import java.util.concurrent.*; +import org.redkale.net.WorkThread; + +/** + * WebSocket连接的IO写线程 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public class WebSocketFuture extends CompletableFuture implements Runnable { + + WebSocketPacket[] packets; + + WebSocket websocket; + + WorkThread workThread; + + ScheduledFuture timeout; + + WebSocketFuture(WorkThread workThread, WebSocket websocket, WebSocketPacket... packets) { + super(); + this.workThread = workThread; + this.websocket = websocket; + this.packets = packets; + } + + void cancelTimeout() { + if (timeout != null) { + timeout.cancel(true); + } + } + + @Override // JDK9+ + public WebSocketFuture newIncompleteFuture() { + WebSocketFuture future = new WebSocketFuture(workThread, websocket, packets); + future.timeout = timeout; + return future; + } + + @Override + public void run() { + TimeoutException ex = new TimeoutException("packets: " + Arrays.toString(packets)); + workThread.runWork(() -> completeExceptionally(ex)); + } + + @Override + public String toString() { + return getClass().getSimpleName() + "_" + Objects.hash(this) + "{websocket = " + websocket + ", packets = " + + Arrays.toString(packets) + "}"; + } +} diff --git a/src/main/java/org/redkale/net/http/WebSocketNodeService.java b/src/main/java/org/redkale/net/http/WebSocketNodeService.java index 2dca3e1a2..e98ae061d 100644 --- a/src/main/java/org/redkale/net/http/WebSocketNodeService.java +++ b/src/main/java/org/redkale/net/http/WebSocketNodeService.java @@ -1,225 +1,225 @@ -package org.redkale.net.http; - -import static org.redkale.net.http.WebSocket.RETCODE_GROUP_EMPTY; - -import java.io.Serializable; -import java.net.InetSocketAddress; -import java.util.*; -import java.util.concurrent.CompletableFuture; -import java.util.logging.Level; -import org.redkale.annotation.*; -import org.redkale.service.RpcTargetAddress; -import org.redkale.service.RpcTargetTopic; -import org.redkale.service.Service; -import org.redkale.util.AnyValue; - -/** - * 详情见: https://redkale.org - * - * @author zhangjx - */ -@AutoLoad(false) -@ResourceType(WebSocketNode.class) -public class WebSocketNodeService extends WebSocketNode implements Service { - - @Override - public void init(AnyValue conf) { - super.init(conf); - } - - @Override - public void destroy(AnyValue conf) { - super.destroy(conf); - } - - public final void setName(String name) { - this.name = name; - } - - @Override - public CompletableFuture> getWebSocketAddresses( - @RpcTargetTopic String topic, - final @RpcTargetAddress InetSocketAddress targetAddress, - final Serializable groupid) { - if ((topic == null || !topic.equals(this.wsNodeAddress.getTopic())) - && (localSncpAddress == null || !localSncpAddress.equals(targetAddress))) { - return remoteWebSocketAddresses(topic, targetAddress, groupid); - } - if (this.localEngine == null) { - return CompletableFuture.completedFuture(new ArrayList<>()); - } - final List rs = new ArrayList<>(); - this.localEngine.getLocalWebSockets(groupid).forEach(x -> rs.add(x.getRemoteAddr())); - return CompletableFuture.completedFuture(rs); - } - - @Override - public CompletableFuture sendMessage( - @RpcTargetTopic String topic, - @RpcTargetAddress InetSocketAddress targetAddress, - Object message, - boolean last, - Serializable... userids) { - if (this.localEngine == null) { - return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY); - } - return this.localEngine.sendLocalMessage(message, last, userids); - } - - @Override - public CompletableFuture broadcastMessage( - @RpcTargetTopic String topic, - @RpcTargetAddress InetSocketAddress targetAddress, - final WebSocketRange wsrange, - Object message, - boolean last) { - if (this.localEngine == null) { - return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY); - } - return this.localEngine.broadcastLocalMessage(wsrange, message, last); - } - - @Override - public CompletableFuture sendAction( - @RpcTargetTopic String topic, - @RpcTargetAddress InetSocketAddress targetAddress, - final WebSocketAction action, - Serializable... userids) { - if (this.localEngine == null) { - return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY); - } - return this.localEngine.sendLocalAction(action, userids); - } - - @Override - public CompletableFuture broadcastAction( - @RpcTargetTopic String topic, - @RpcTargetAddress InetSocketAddress targetAddress, - final WebSocketAction action) { - if (this.localEngine == null) { - return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY); - } - return this.localEngine.broadcastLocalAction(action); - } - - @Override - public CompletableFuture getUserSize( - @RpcTargetTopic String topic, @RpcTargetAddress InetSocketAddress targetAddress) { - if (this.localEngine == null) { - return CompletableFuture.completedFuture(0); - } - return CompletableFuture.completedFuture(this.localEngine.getLocalUserSize()); - } - - /** - * 当用户连接到节点,需要更新到CacheSource - * - * @param userid Serializable - * @param wsaddr WebSocketAddress - * @return 无返回值 - */ - @Override - public CompletableFuture connect(Serializable userid, WebSocketAddress wsaddr) { - tryAcquireSemaphore(); - CompletableFuture future = - source.saddAsync(WS_SOURCE_KEY_USERID_PREFIX + userid, WebSocketAddress.class, wsaddr); - if (semaphore != null) { - future.whenComplete((r, e) -> releaseSemaphore()); - } - if (logger.isLoggable(Level.FINEST)) { - logger.finest(WebSocketNodeService.class.getSimpleName() + ".event: " + userid + " connect from " + wsaddr); - } - return future; - } - - /** - * 当用户从一个节点断掉了所有的连接,需要从CacheSource中删除 - * - * @param userid Serializable - * @param wsaddr WebSocketAddress - * @return 无返回值 - */ - @Override - public CompletableFuture disconnect(Serializable userid, WebSocketAddress wsaddr) { - tryAcquireSemaphore(); - CompletableFuture future = - source.sremAsync(WS_SOURCE_KEY_USERID_PREFIX + userid, WebSocketAddress.class, wsaddr); - if (semaphore != null) { - future.whenComplete((r, e) -> releaseSemaphore()); - } - if (logger.isLoggable(Level.FINEST)) { - logger.finest( - WebSocketNodeService.class.getSimpleName() + ".event: " + userid + " disconnect from " + wsaddr); - } - return future.thenApply(v -> null); - } - - /** - * 更改用户ID,需要更新到CacheSource - * - * @param olduserid Serializable - * @param newuserid Serializable - * @param wsaddr WebSocketAddress - * @return 无返回值 - */ - @Override - public CompletableFuture changeUserid( - Serializable olduserid, Serializable newuserid, WebSocketAddress wsaddr) { - tryAcquireSemaphore(); - CompletableFuture future = - source.saddAsync(WS_SOURCE_KEY_USERID_PREFIX + newuserid, WebSocketAddress.class, wsaddr); - future = future.thenAccept( - (a) -> source.sremAsync(WS_SOURCE_KEY_USERID_PREFIX + olduserid, WebSocketAddress.class, wsaddr)); - if (semaphore != null) { - future.whenComplete((r, e) -> releaseSemaphore()); - } - if (logger.isLoggable(Level.FINEST)) { - logger.finest(WebSocketNodeService.class.getSimpleName() + ".event: " + olduserid + " changeUserid to " - + newuserid + " from " + wsaddr); - } - return future; - } - - /** - * 判断用户是否有WebSocket - * - * @param userid Serializable - * @param topic RpcTargetTopic - * @param targetAddress InetSocketAddress - * @return 无返回值 - */ - @Override - public CompletableFuture existsWebSocket( - Serializable userid, @RpcTargetTopic String topic, @RpcTargetAddress InetSocketAddress targetAddress) { - if (logger.isLoggable(Level.FINEST)) { - logger.finest(WebSocketNodeService.class.getSimpleName() + ".event: " + userid + " existsWebSocket from " - + targetAddress); - } - if (localEngine == null) { - return CompletableFuture.completedFuture(false); - } - return CompletableFuture.completedFuture(localEngine.existsLocalWebSocket(userid)); - } - - /** - * 强制关闭用户的WebSocket - * - * @param userid Serializable - * @param topic RpcTargetTopic - * @param targetAddress InetSocketAddress - * @return 无返回值 - */ - @Override - public CompletableFuture forceCloseWebSocket( - Serializable userid, @RpcTargetTopic String topic, @RpcTargetAddress InetSocketAddress targetAddress) { - // 不能从sncpNodeAddresses中移除,因为engine.forceCloseWebSocket 会调用到disconnect - if (logger.isLoggable(Level.FINEST)) { - logger.finest(WebSocketNodeService.class.getSimpleName() + ".event: " + userid - + " forceCloseWebSocket from " + targetAddress); - } - if (localEngine == null) { - return CompletableFuture.completedFuture(0); - } - return CompletableFuture.completedFuture(localEngine.forceCloseLocalWebSocket(userid)); - } -} +package org.redkale.net.http; + +import static org.redkale.net.http.WebSocket.RETCODE_GROUP_EMPTY; + +import java.io.Serializable; +import java.net.InetSocketAddress; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.logging.Level; +import org.redkale.annotation.*; +import org.redkale.service.RpcTargetAddress; +import org.redkale.service.RpcTargetTopic; +import org.redkale.service.Service; +import org.redkale.util.AnyValue; + +/** + * 详情见: https://redkale.org + * + * @author zhangjx + */ +@AutoLoad(false) +@ResourceType(WebSocketNode.class) +public class WebSocketNodeService extends WebSocketNode implements Service { + + @Override + public void init(AnyValue conf) { + super.init(conf); + } + + @Override + public void destroy(AnyValue conf) { + super.destroy(conf); + } + + public final void setName(String name) { + this.name = name; + } + + @Override + public CompletableFuture> getWebSocketAddresses( + @RpcTargetTopic String topic, + final @RpcTargetAddress InetSocketAddress targetAddress, + final Serializable groupid) { + if ((topic == null || !topic.equals(this.wsNodeAddress.getTopic())) + && (localSncpAddress == null || !localSncpAddress.equals(targetAddress))) { + return remoteWebSocketAddresses(topic, targetAddress, groupid); + } + if (this.localEngine == null) { + return CompletableFuture.completedFuture(new ArrayList<>()); + } + final List rs = new ArrayList<>(); + this.localEngine.getLocalWebSockets(groupid).forEach(x -> rs.add(x.getRemoteAddr())); + return CompletableFuture.completedFuture(rs); + } + + @Override + public CompletableFuture sendMessage( + @RpcTargetTopic String topic, + @RpcTargetAddress InetSocketAddress targetAddress, + Object message, + boolean last, + Serializable... userids) { + if (this.localEngine == null) { + return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY); + } + return this.localEngine.sendLocalMessage(message, last, userids); + } + + @Override + public CompletableFuture broadcastMessage( + @RpcTargetTopic String topic, + @RpcTargetAddress InetSocketAddress targetAddress, + final WebSocketRange wsrange, + Object message, + boolean last) { + if (this.localEngine == null) { + return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY); + } + return this.localEngine.broadcastLocalMessage(wsrange, message, last); + } + + @Override + public CompletableFuture sendAction( + @RpcTargetTopic String topic, + @RpcTargetAddress InetSocketAddress targetAddress, + final WebSocketAction action, + Serializable... userids) { + if (this.localEngine == null) { + return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY); + } + return this.localEngine.sendLocalAction(action, userids); + } + + @Override + public CompletableFuture broadcastAction( + @RpcTargetTopic String topic, + @RpcTargetAddress InetSocketAddress targetAddress, + final WebSocketAction action) { + if (this.localEngine == null) { + return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY); + } + return this.localEngine.broadcastLocalAction(action); + } + + @Override + public CompletableFuture getUserSize( + @RpcTargetTopic String topic, @RpcTargetAddress InetSocketAddress targetAddress) { + if (this.localEngine == null) { + return CompletableFuture.completedFuture(0); + } + return CompletableFuture.completedFuture(this.localEngine.getLocalUserSize()); + } + + /** + * 当用户连接到节点,需要更新到CacheSource + * + * @param userid Serializable + * @param wsaddr WebSocketAddress + * @return 无返回值 + */ + @Override + public CompletableFuture connect(Serializable userid, WebSocketAddress wsaddr) { + tryAcquireSemaphore(); + CompletableFuture future = + source.saddAsync(WS_SOURCE_KEY_USERID_PREFIX + userid, WebSocketAddress.class, wsaddr); + if (semaphore != null) { + future.whenComplete((r, e) -> releaseSemaphore()); + } + if (logger.isLoggable(Level.FINEST)) { + logger.finest(WebSocketNodeService.class.getSimpleName() + ".event: " + userid + " connect from " + wsaddr); + } + return future; + } + + /** + * 当用户从一个节点断掉了所有的连接,需要从CacheSource中删除 + * + * @param userid Serializable + * @param wsaddr WebSocketAddress + * @return 无返回值 + */ + @Override + public CompletableFuture disconnect(Serializable userid, WebSocketAddress wsaddr) { + tryAcquireSemaphore(); + CompletableFuture future = + source.sremAsync(WS_SOURCE_KEY_USERID_PREFIX + userid, WebSocketAddress.class, wsaddr); + if (semaphore != null) { + future.whenComplete((r, e) -> releaseSemaphore()); + } + if (logger.isLoggable(Level.FINEST)) { + logger.finest( + WebSocketNodeService.class.getSimpleName() + ".event: " + userid + " disconnect from " + wsaddr); + } + return future.thenApply(v -> null); + } + + /** + * 更改用户ID,需要更新到CacheSource + * + * @param olduserid Serializable + * @param newuserid Serializable + * @param wsaddr WebSocketAddress + * @return 无返回值 + */ + @Override + public CompletableFuture changeUserid( + Serializable olduserid, Serializable newuserid, WebSocketAddress wsaddr) { + tryAcquireSemaphore(); + CompletableFuture future = + source.saddAsync(WS_SOURCE_KEY_USERID_PREFIX + newuserid, WebSocketAddress.class, wsaddr); + future = future.thenAccept( + (a) -> source.sremAsync(WS_SOURCE_KEY_USERID_PREFIX + olduserid, WebSocketAddress.class, wsaddr)); + if (semaphore != null) { + future.whenComplete((r, e) -> releaseSemaphore()); + } + if (logger.isLoggable(Level.FINEST)) { + logger.finest(WebSocketNodeService.class.getSimpleName() + ".event: " + olduserid + " changeUserid to " + + newuserid + " from " + wsaddr); + } + return future; + } + + /** + * 判断用户是否有WebSocket + * + * @param userid Serializable + * @param topic RpcTargetTopic + * @param targetAddress InetSocketAddress + * @return 无返回值 + */ + @Override + public CompletableFuture existsWebSocket( + Serializable userid, @RpcTargetTopic String topic, @RpcTargetAddress InetSocketAddress targetAddress) { + if (logger.isLoggable(Level.FINEST)) { + logger.finest(WebSocketNodeService.class.getSimpleName() + ".event: " + userid + " existsWebSocket from " + + targetAddress); + } + if (localEngine == null) { + return CompletableFuture.completedFuture(false); + } + return CompletableFuture.completedFuture(localEngine.existsLocalWebSocket(userid)); + } + + /** + * 强制关闭用户的WebSocket + * + * @param userid Serializable + * @param topic RpcTargetTopic + * @param targetAddress InetSocketAddress + * @return 无返回值 + */ + @Override + public CompletableFuture forceCloseWebSocket( + Serializable userid, @RpcTargetTopic String topic, @RpcTargetAddress InetSocketAddress targetAddress) { + // 不能从sncpNodeAddresses中移除,因为engine.forceCloseWebSocket 会调用到disconnect + if (logger.isLoggable(Level.FINEST)) { + logger.finest(WebSocketNodeService.class.getSimpleName() + ".event: " + userid + + " forceCloseWebSocket from " + targetAddress); + } + if (localEngine == null) { + return CompletableFuture.completedFuture(0); + } + return CompletableFuture.completedFuture(localEngine.forceCloseLocalWebSocket(userid)); + } +} diff --git a/src/main/java/org/redkale/net/sncp/Sncp.java b/src/main/java/org/redkale/net/sncp/Sncp.java index 5115ea4ec..ad3385320 100644 --- a/src/main/java/org/redkale/net/sncp/Sncp.java +++ b/src/main/java/org/redkale/net/sncp/Sncp.java @@ -1,1262 +1,1262 @@ -/* - * 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.sncp; - -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; -import static org.redkale.asm.ClassWriter.COMPUTE_FRAMES; -import static org.redkale.asm.Opcodes.*; -import static org.redkale.util.Utility.isEmpty; - -import java.lang.annotation.*; -import java.lang.reflect.*; -import java.nio.channels.CompletionHandler; -import java.util.*; -import org.redkale.annotation.*; -import org.redkale.asm.*; -import org.redkale.asm.Type; -import org.redkale.convert.Convert; -import org.redkale.convert.bson.BsonConvert; -import org.redkale.inject.Resourcable; -import org.redkale.inject.ResourceFactory; -import org.redkale.mq.spi.MessageAgent; -import org.redkale.net.http.WebSocketNode; -import org.redkale.net.sncp.SncpRemoteInfo.SncpRemoteAction; -import org.redkale.schedule.Scheduled; -import org.redkale.service.*; -import org.redkale.util.AnyValue; -import org.redkale.util.RedkaleClassLoader; -import org.redkale.util.TypeToken; -import org.redkale.util.Uint128; -import org.redkale.util.Utility; - -/** - * Service Node Communicate Protocol 生成Service的本地模式或远程模式Service-Class的工具类 - * - *

详情见: https://redkale.org - * - * @author zhangjx - */ -public abstract class Sncp { - - static final String FIELDPREFIX = "_redkale"; - - /** - * 修饰由SNCP协议动态生成的class、和method 本地模式:动态生成的_DynLocalXXXXService类会打上@SncpDyn(remote = false) 的注解 - * 远程模式:动态生成的_DynRemoteXXXService类会打上@SncpDyn(remote = true) 的注解 - * - *

详情见: https://redkale.org - * - * @author zhangjx - */ - @Documented - @Target({METHOD, TYPE}) - @Retention(RUNTIME) - public static @interface SncpDyn { - - boolean remote(); - - Class type(); // serviceType - - int index() default 0; // 排列顺序, 主要用于Method - } - - private Sncp() { - // do nothing - } - - // key: actionid - public static LinkedHashMap loadRemoteMethodActions(final Class serviceTypeOrImplClass) { - final List list = new ArrayList<>(); - final List multis = new ArrayList<>(); - final Map actionids = new LinkedHashMap<>(); - RedkaleClassLoader.putReflectionPublicMethods(serviceTypeOrImplClass.getName()); - for (final java.lang.reflect.Method method : serviceTypeOrImplClass.getMethods()) { - if (method.isSynthetic()) { - continue; - } - if (method.getAnnotation(Scheduled.class) != null) { - continue; - } - if (Modifier.isStatic(method.getModifiers())) { - continue; - } - if (Modifier.isFinal(method.getModifiers())) { - continue; - } - if (method.getAnnotation(Local.class) != null) { - continue; - } - if (method.getAnnotation(ResourceChanged.class) != null) { - continue; - } - if (method.getName().equals("getClass") || method.getName().equals("toString")) { - continue; - } - if (method.getName().equals("equals") || method.getName().equals("hashCode")) { - continue; - } - if (method.getName().equals("notify") - || method.getName().equals("notifyAll") - || method.getName().equals("wait")) { - continue; - } - if (method.getParameterCount() == 1 && method.getParameterTypes()[0] == AnyValue.class) { - if (method.getName().equals("init") || method.getName().equals("destroy")) { - continue; - } - } - - Uint128 actionid = Sncp.actionid(method); - Method old = actionids.get(actionid); - if (old != null) { - if (old.getDeclaringClass().equals(method.getDeclaringClass())) { - throw new SncpException(serviceTypeOrImplClass.getName() + " have one more same action(Method=" - + method + ", " + old + ", actionid=" + actionid + ")"); - } - continue; - } - actionids.put(actionid, method); - if (method.getAnnotation(Sncp.SncpDyn.class) != null) { - multis.add(method); - } else { - list.add(method); - } - } - multis.sort((m1, m2) -> m1.getAnnotation(Sncp.SncpDyn.class).index() - - m2.getAnnotation(Sncp.SncpDyn.class).index()); - list.sort((Method o1, Method o2) -> { - if (!o1.getName().equals(o2.getName())) { - return o1.getName().compareTo(o2.getName()); - } - if (o1.getParameterCount() != o2.getParameterCount()) { - return o1.getParameterCount() - o2.getParameterCount(); - } - return 0; - }); - // 带SncpDyn必须排在前面 - multis.addAll(list); - final LinkedHashMap rs = new LinkedHashMap<>(); - for (Method method : multis) { - for (Map.Entry en : actionids.entrySet()) { - if (en.getValue() == method) { - rs.put(en.getKey(), en.getValue()); - break; - } - } - } - return rs; - } - - public static SncpRemoteInfo createSncpRemoteInfo( - String resourceName, - Class resourceServiceType, - Class serviceImplClass, - Convert convert, - SncpRpcGroups sncpRpcGroups, - SncpClient sncpClient, - MessageAgent messageAgent, - String remoteGroup) { - return new SncpRemoteInfo( - resourceName, - resourceServiceType, - serviceImplClass, - convert, - sncpRpcGroups, - sncpClient, - messageAgent, - remoteGroup); - } - - /** - * 格式:资源类型:资源名 - * - * @param resourceName 资源名 - * @param resourceType 资源类型 - * @return resourceid - */ - public static String resourceid(String resourceName, Class resourceType) { - return resourceType.getName() + ':' + (resourceName == null ? "" : resourceName); - } - - public static Uint128 serviceid(String serviceResourceName, Class serviceResourceType) { - return hash(resourceid(serviceResourceName, serviceResourceType)); - } - - public static Uint128 actionid(final RpcAction action) { - return hash(action.name()); - } - - public static Uint128 actionid(final java.lang.reflect.Method method) { - if (method == null) { - return Uint128.ZERO; - } - RpcAction action = method.getAnnotation(RpcAction.class); - if (action != null) { - return hash(action.name()); - } - StringBuilder sb = new StringBuilder(); // 不能使用method.toString() 因为包含declaringClass信息导致接口与实现类的方法hash不一致 - sb.append(method.getReturnType().getName()).append(' '); - sb.append(method.getName()); - sb.append('('); - boolean first = true; - for (Class pt : method.getParameterTypes()) { - if (!first) { - sb.append(','); - } - sb.append(pt.getName()); - first = false; - } - sb.append(')'); - return hash(sb.toString()); - } - - /** - * 对类名或者name字符串进行hash。 - * - * @param name String - * @return hash值 - */ - private static Uint128 hash(final String name) { - if (name == null || name.isEmpty()) { - return Uint128.ZERO; - } - return Uint128.create(Utility.md5(name.trim().getBytes())); - } - - public static boolean isRemote(Service service) { - SncpDyn dyn = service.getClass().getAnnotation(SncpDyn.class); - return dyn != null && dyn.remote(); - } - - public static boolean isSncpDyn(Service service) { - return service.getClass().getAnnotation(SncpDyn.class) != null; - } - - public static boolean isSncpDyn(Class serviceType) { - return serviceType.getAnnotation(SncpDyn.class) != null; - } - - public static boolean isComponent(Service service) { - return service.getClass().getAnnotation(Component.class) != null; - } - - public static boolean isComponent(Class serviceType) { - return serviceType.getAnnotation(Component.class) != null; - } - - public static int getVersion(Service service) { - return -1; // 预留功能,暂不实现 - } - - public static String getResourceName(Service service) { - Resource res = service.getClass().getAnnotation(Resource.class); - return res != null - ? res.name() - : (service instanceof Resourcable ? ((Resourcable) service).resourceName() : null); - } - - public static Class getResourceType(Service service) { - ResourceType type = service.getClass().getAnnotation(ResourceType.class); - return type != null ? type.value() : service.getClass(); - } - - public static Class getResourceType(Class serviceImplClass) { - ResourceType type = serviceImplClass.getAnnotation(ResourceType.class); - return type != null ? type.value() : serviceImplClass; - } - - public static Class getServiceType(Service service) { - SncpDyn dyn = service.getClass().getAnnotation(SncpDyn.class); - return dyn != null ? dyn.type() : service.getClass(); - } - - public static Class getServiceType(Class serviceImplClass) { - SncpDyn dyn = serviceImplClass.getAnnotation(SncpDyn.class); - return dyn != null ? dyn.type() : serviceImplClass; - } - - // 格式: sncp.req.module.user - public static String generateSncpReqTopic(Service service, String nodeid) { - return generateSncpReqTopic(getResourceName(service), getResourceType(service), nodeid); - } - - // 格式: sncp.req.module.user - public static String generateSncpReqTopic(String resourceName, Class resourceType, String nodeid) { - if (WebSocketNode.class.isAssignableFrom(resourceType)) { - return getSncpReqTopicPrefix() + "module.wsnode" + nodeid - + (isEmpty(resourceName) ? "" : ("-" + resourceName)); - } - return getSncpReqTopicPrefix() + "module." - + resourceType.getSimpleName().replaceAll("Service.*$", "").toLowerCase() - + (isEmpty(resourceName) ? "" : ("-" + resourceName)); - } - - public static String getSncpReqTopicPrefix() { - return "sncp.req."; - } - - public static String getSncpRespTopicPrefix() { - return "sncp.resp."; - } - - public static AnyValue getResourceConf(Service service) { - if (service == null || !isSncpDyn(service)) { - return null; - } - try { - Field ts = service.getClass().getDeclaredField(FIELDPREFIX + "_conf"); - ts.setAccessible(true); - return (AnyValue) ts.get(service); - } catch (Exception e) { - throw new SncpException(service + " not found " + FIELDPREFIX + "_conf"); - } - } - - public static String getResourceMQ(Service service) { - if (service == null || !isSncpDyn(service)) { - return null; - } - try { - Field ts = service.getClass().getDeclaredField(FIELDPREFIX + "_mq"); - ts.setAccessible(true); - return (String) ts.get(service); - } catch (Exception e) { - throw new SncpException(service + " not found " + FIELDPREFIX + "_mq"); - } - } - - static void checkAsyncModifier(Class param, Method method) { - if (param == CompletionHandler.class) { - return; - } - if (Modifier.isFinal(param.getModifiers())) { - throw new SncpException("CompletionHandler Type Parameter on {" + method + "} cannot final modifier"); - } - if (!Modifier.isPublic(param.getModifiers())) { - throw new SncpException("CompletionHandler Type Parameter on {" + method + "} must be public modifier"); - } - if (param.isInterface()) { - return; - } - boolean constructorflag = false; - RedkaleClassLoader.putReflectionDeclaredConstructors(param, param.getName()); - for (Constructor c : param.getDeclaredConstructors()) { - if (c.getParameterCount() == 0) { - int mod = c.getModifiers(); - if (Modifier.isPublic(mod) || Modifier.isProtected(mod)) { - constructorflag = true; - break; - } - } - } - if (param.getDeclaredConstructors().length == 0) { - constructorflag = true; - } - if (!constructorflag) { - throw new SncpException(param + " must have a empty parameter Constructor"); - } - for (Method m : param.getMethods()) { - if (m.getName().equals("completed") && m.getParameterCount() == 2 && Modifier.isFinal(m.getModifiers())) { - throw new SncpException(param + "'s completed method cannot final modifier"); - } else if (m.getName().equals("failed") - && m.getParameterCount() == 2 - && Modifier.isFinal(m.getModifiers())) { - throw new SncpException(param + "'s failed method cannot final modifier"); - } - } - } - - public static String toSimpleString(final Service service, int maxNameLength, int maxTypeLength) { - StringBuilder sb = new StringBuilder(); - sb.append(isRemote(service) ? "RemoteService" : "LocalService "); - int len; - Class type = getResourceType(service); - String name = getResourceName(service); - if (name == null) { - name = ""; - } - sb.append("(type= ").append(type.getName()); - len = maxTypeLength - type.getName().length(); - for (int i = 0; i < len; i++) { - sb.append(' '); - } - sb.append(", name='").append(name).append("'"); - for (int i = 0; i < maxNameLength - name.length(); i++) { - sb.append(' '); - } - sb.append(")"); - return sb.toString(); - } - - // 获取一个clazz内所有未被实现的方法 - public static List loadNotImplMethods(Class clazz) { - LinkedHashSet types = new LinkedHashSet<>(); - loadAllSubClasses(clazz, types); - List methods = new ArrayList<>(); - Set ms = new HashSet<>(); - for (Class c : types) { - for (Method m : c.getDeclaredMethods()) { - if (c.isInterface() || Modifier.isAbstract(m.getModifiers())) { - StringBuilder sb = - new StringBuilder(); // 不能使用method.toString() 因为包含declaringClass信息导致接口与实现类的方法hash不一致 - sb.append(m.getName()); - sb.append('('); - boolean first = true; - for (Class pt : m.getParameterTypes()) { - if (!first) { - sb.append(','); - } - sb.append(pt.getName()); - first = false; - } - sb.append(')'); - String key = sb.toString(); - Uint128 a = actionid(m); - if (!ms.contains(key)) { - methods.add(m); - ms.add(key); - } - } - } - } - return methods; - } - - private static void loadAllSubClasses(Class clazz, LinkedHashSet types) { - if (clazz == null || clazz == Object.class) { - return; - } - types.add(clazz); - if (clazz.getSuperclass() != null) { - loadAllSubClasses(clazz.getSuperclass(), types); - } - if (clazz.getInterfaces() != null) { - for (Class sub : clazz.getInterfaces()) { - loadAllSubClasses(sub, types); - } - } - } - - /** - * - * - *

- * - *
-     * public class TestService implements Service {
-     *
-     *      public String findSomeThing(){
-     *          return "hello";
-     *      }
-     *
-     *      @RpcMultiRun(selfrun = false)
-     *      public void createSomeThing(TestBean bean){
-     *          //do something
-     *      }
-     *
-     *      @RpcMultiRun
-     *      public String updateSomeThing(String id){
-     *          return "hello" + id;
-     *      }
-     * }
-     * 
- * - *
- * - *
- * - *
-     * @Resource(name = "")
-     * @SncpDyn(remote = false)
-     * @ResourceType(TestService.class)
-     * public final class _DynLocalTestService extends TestService {
-     *
-     *      private AnyValue _redkale_conf;
-     *
-     * }
-     * 
- * - *
- * - * 创建Service的本地模式Class - * - * @param Service子类 - * @param classLoader ClassLoader - * @param name 资源名 - * @param serviceImplClass Service类 - * @param methodBoost 方法扩展 - * @return Service实例 - */ - @SuppressWarnings("unchecked") - protected static Class createLocalServiceClass( - ClassLoader classLoader, - final String name, - final Class serviceImplClass, - final AsmMethodBoost methodBoost) { - Objects.requireNonNull(serviceImplClass); - if (!Service.class.isAssignableFrom(serviceImplClass)) { - throw new SncpException(serviceImplClass + " is not Service type"); - } - ResourceFactory.checkResourceName(name); - int mod = serviceImplClass.getModifiers(); - if (!java.lang.reflect.Modifier.isPublic(mod)) { - throw new SncpException(serviceImplClass + " is not public"); - } - if (java.lang.reflect.Modifier.isAbstract(mod)) { - throw new SncpException(serviceImplClass + " is abstract"); - } - final String supDynName = serviceImplClass.getName().replace('.', '/'); - final String resDesc = Type.getDescriptor(Resource.class); - final String anyValueDesc = Type.getDescriptor(AnyValue.class); - final String sncpDynDesc = Type.getDescriptor(SncpDyn.class); - ClassLoader loader = classLoader == null ? Thread.currentThread().getContextClassLoader() : classLoader; - // String newDynName = supDynName.substring(0, supDynName.lastIndexOf('/') + 1) + LOCALPREFIX + - // serviceImplClass.getSimpleName(); - String newDynName = "org/redkaledyn/service/local/_DynLocalService__" - + serviceImplClass.getName().replace('.', '_').replace('$', '_'); - if (!name.isEmpty()) { - boolean normal = true; - for (char ch : name.toCharArray()) { - if (!((ch >= '0' && ch <= '9') || ch == '_' || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))) { - normal = false; - } - } - if (!normal) { - throw new SncpException(serviceImplClass + "'s resource name is illegal, must be 0-9 _ a-z A-Z"); - } - newDynName += "_" + (normal ? name : hash(name)); - } - try { - Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.')); - return (Class) (clz == null ? loader.loadClass(newDynName.replace('/', '.')) : clz); - } catch (ClassNotFoundException e) { - // do nothing - } catch (Throwable t) { - t.printStackTrace(); - } - // ------------------------------------------------------------------------------ - ClassWriter cw = new ClassWriter(COMPUTE_FRAMES); - FieldVisitor fv; - MethodDebugVisitor mv; - AnnotationVisitor av0; - - cw.visit(V11, ACC_PUBLIC + ACC_SUPER, newDynName, null, supDynName, null); - { // 给动态生成的Service类标记上Resource - av0 = cw.visitAnnotation(resDesc, true); - av0.visit("name", name); - av0.visitEnd(); - } - { - av0 = cw.visitAnnotation(sncpDynDesc, true); - av0.visit("remote", Boolean.FALSE); - av0.visit("type", Type.getType(Type.getDescriptor(serviceImplClass))); - av0.visitEnd(); - } - { // 给新类加上原有的Annotation - for (Annotation ann : serviceImplClass.getAnnotations()) { - if (ann instanceof Resource || ann instanceof SncpDyn || ann instanceof ResourceType) { - continue; - } - Asms.visitAnnotation(cw.visitAnnotation(Type.getDescriptor(ann.annotationType()), true), ann); - } - } - { - av0 = cw.visitAnnotation(Type.getDescriptor(ResourceType.class), true); - ResourceType rty = serviceImplClass.getAnnotation(ResourceType.class); - org.redkale.util.ResourceType rty2 = serviceImplClass.getAnnotation(org.redkale.util.ResourceType.class); - av0.visit( - "value", - Type.getType(Type.getDescriptor( - rty != null ? rty.value() : (rty2 != null ? rty2.value() : serviceImplClass)))); - av0.visitEnd(); - } - { - fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_conf", anyValueDesc, null, null); - fv.visitEnd(); - } - { - fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_mq", Type.getDescriptor(String.class), null, null); - fv.visitEnd(); - } - { // 构造函数 - mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "", "()V", null, null)); - // mv.setDebug(true); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, supDynName, "", "()V", false); - mv.visitInsn(RETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - if (methodBoost != null) { - createNewMethods(classLoader, serviceImplClass, methodBoost, new HashSet<>(), cw, newDynName, supDynName); - methodBoost.doAfterMethods(classLoader, cw, newDynName, FIELDPREFIX); - } - cw.visitEnd(); - byte[] bytes = cw.toByteArray(); - Class newClazz = new ClassLoader(loader) { - public final Class loadClass(String name, byte[] b) { - return defineClass(name, b, 0, b.length); - } - }.loadClass(newDynName.replace('/', '.'), bytes); - RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, newClazz); - RedkaleClassLoader.putReflectionPublicClasses(newDynName.replace('/', '.')); - RedkaleClassLoader.putReflectionDeclaredConstructors(newClazz, newDynName.replace('/', '.')); - try { - Field c = newClazz.getDeclaredField(FIELDPREFIX + "_conf"); - RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), c); - - c = newClazz.getDeclaredField(FIELDPREFIX + "_mq"); - RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), c); - } catch (Exception e) { - // do nothing - } - return (Class) newClazz; - } - - public static T createSimpleLocalService( - Class serviceImplClass, ResourceFactory resourceFactory) { - return createLocalService(null, "", serviceImplClass, null, resourceFactory, null, null, null, null, null); - } - - private static void createNewMethods( - ClassLoader classLoader, - Class clazz, - final AsmMethodBoost methodBoost, - Set methodKeys, - ClassWriter cw, - String newDynName, - String supDynName) { - if (methodBoost == null) { - return; - } - MethodDebugVisitor mv = null; - do { - Map methodBeans = AsmMethodBoost.getMethodBeans(clazz); - for (final Method method : clazz.getDeclaredMethods()) { - String mk = Utility.methodKey(method); - if (methodKeys.contains(mk)) { - // 跳过已处理的继承方法 - continue; - } - methodKeys.add(mk); - List> filterAnns = methodBoost.filterMethodAnnotations(method); - String newMethodName = - methodBoost.doMethod(classLoader, cw, newDynName, FIELDPREFIX, filterAnns, method, null); - if (newMethodName != null) { - String desc = Type.getMethodDescriptor(method); - AsmMethodBean methodBean = AsmMethodBean.get(methodBeans, method); - String signature = null; - String[] exceptions = null; - if (methodBean == null) { - Class[] expTypes = method.getExceptionTypes(); - if (expTypes.length > 0) { - exceptions = new String[expTypes.length]; - for (int i = 0; i < expTypes.length; i++) { - exceptions[i] = expTypes[i].getName().replace('.', '/'); - } - } - } else { - signature = methodBean.getSignature(); - exceptions = methodBean.getExceptions(); - } - // 需要定义一个新方法调用 super.method - mv = new MethodDebugVisitor( - cw.visitMethod(ACC_PRIVATE, newMethodName, desc, signature, exceptions)); - Label l0 = new Label(); - mv.visitLabel(l0); - // mv.setDebug(true); - mv.visitVarInsn(ALOAD, 0); - // 传参数 - Class[] paramTypes = method.getParameterTypes(); - List insns = new ArrayList<>(); - int insn = 0; - for (Class pt : paramTypes) { - insn++; - if (pt.isPrimitive()) { - if (pt == long.class) { - mv.visitVarInsn(LLOAD, insn++); - } else if (pt == float.class) { - mv.visitVarInsn(FLOAD, insn++); - } else if (pt == double.class) { - mv.visitVarInsn(DLOAD, insn++); - } else { - mv.visitVarInsn(ILOAD, insn); - } - } else { - mv.visitVarInsn(ALOAD, insn); - } - insns.add(insn); - } - mv.visitMethodInsn( - INVOKESPECIAL, supDynName, method.getName(), Type.getMethodDescriptor(method), false); - if (method.getGenericReturnType() == void.class) { - mv.visitInsn(RETURN); - } else { - Class returnclz = method.getReturnType(); - if (returnclz.isPrimitive()) { - if (returnclz == long.class) { - mv.visitInsn(LRETURN); - } else if (returnclz == float.class) { - mv.visitInsn(FRETURN); - } else if (returnclz == double.class) { - mv.visitInsn(DRETURN); - } else { - mv.visitInsn(IRETURN); - } - } else { - mv.visitInsn(ARETURN); - } - } - if (methodBean != null && paramTypes.length > 0) { - Label l2 = new Label(); - mv.visitLabel(l2); - // mv.visitLocalVariable("this", thisClassDesc, null, l0, l2, 0); - List params = methodBean.getParams(); - for (int i = 0; i < paramTypes.length; i++) { - AsmMethodParam param = params.get(i); - mv.visitLocalVariable( - param.getName(), - param.description(paramTypes[i]), - param.signature(paramTypes[i]), - l0, - l2, - insns.get(i)); - } - } - mv.visitMaxs(20, 20); - mv.visitEnd(); - } - } - } while ((clazz = clazz.getSuperclass()) != Object.class); - } - - /** - * 创建本地模式Service实例 - * - * @param Service泛型 - * @param classLoader ClassLoader - * @param name 资源名 - * @param serviceImplClass Service类 - * @param methodBoost 方法扩展 - * @param resourceFactory ResourceFactory - * @param sncpRpcGroups SncpRpcGroups - * @param client SncpClient - * @param agent MessageAgent - * @param remoteGroup 所有的组节点 - * @param conf 启动配置项 - * @return Service的本地模式实例 - */ - @SuppressWarnings("unchecked") - public static T createLocalService( - final RedkaleClassLoader classLoader, - final String name, - final Class serviceImplClass, - final AsmMethodBoost methodBoost, - final ResourceFactory resourceFactory, - final SncpRpcGroups sncpRpcGroups, - final SncpClient client, - final MessageAgent agent, - final String remoteGroup, - final AnyValue conf) { - try { - final Class newClazz = createLocalServiceClass(classLoader, name, serviceImplClass, methodBoost); - T service = (T) newClazz.getDeclaredConstructor().newInstance(); - // -------------------------------------- - Service remoteService = null; - { - Class loop = newClazz; - do { - RedkaleClassLoader.putReflectionDeclaredFields(loop.getName()); - for (Field field : loop.getDeclaredFields()) { - int mod = field.getModifiers(); - if (Modifier.isFinal(mod) || Modifier.isStatic(mod)) { - continue; - } - if (field.getAnnotation(RpcRemote.class) == null) { - continue; - } - if (!field.getType().isAssignableFrom(newClazz)) { - continue; - } - field.setAccessible(true); - RedkaleClassLoader.putReflectionField(loop.getName(), field); - if (remoteService == null && sncpRpcGroups != null && client != null) { - remoteService = createRemoteService( - classLoader, - name, - serviceImplClass, - methodBoost, - resourceFactory, - sncpRpcGroups, - client, - agent, - remoteGroup, - conf); - } - if (remoteService != null) { - field.set(service, remoteService); - } - } - } while ((loop = loop.getSuperclass()) != Object.class); - } - { - Field c = newClazz.getDeclaredField(FIELDPREFIX + "_conf"); - c.setAccessible(true); - c.set(service, conf); - } - { - Field c = newClazz.getDeclaredField(FIELDPREFIX + "_mq"); - c.setAccessible(true); - c.set(service, agent == null ? null : agent.getName()); - } - if (methodBoost != null) { - methodBoost.doInstance(resourceFactory, service); - } - return service; - } catch (RuntimeException rex) { - throw rex; - } catch (Exception ex) { - throw new SncpException(ex); - } - } - - public static T createSimpleRemoteService( - Class serviceImplClass, - ResourceFactory resourceFactory, - SncpRpcGroups sncpRpcGroups, - SncpClient client, - String group) { - if (sncpRpcGroups == null) { - throw new SncpException(SncpRpcGroups.class.getSimpleName() + " is null"); - } - if (client == null) { - throw new SncpException(SncpClient.class.getSimpleName() + " is null"); - } - return createRemoteService( - null, "", serviceImplClass, null, resourceFactory, sncpRpcGroups, client, null, group, null); - } - - /** - * - * - *
- * - *
-     * @Resource(name = "")
-     * @SncpDyn(remote = true)
-     * @ResourceType(TestService.class)
-     * public final class _DynRemoteTestService extends TestService {
-     *
-     *      private AnyValue _redkale_conf;
-     *
-     *      private SncpClient _redkale_client;
-     *
-     *      private SncpRemoteInfo _redkale_sncp;
-     *
-     *      @Override
-     *      public void createSomeThing(TestBean bean){
-     *          _redkale_client.remote(_redkale_sncp, 0, bean);
-     *      }
-     *
-     *      @Override
-     *      public String findSomeThing(){
-     *          return (String)_redkale_client.remote(_redkale_sncp, 1);
-     *      }
-     *
-     *      @Override
-     *      public String updateSomeThing(String id){
-     *          return (String)_redkale_client.remote(_redkale_sncp, 2, id);
-     *      }
-     * }
-     * 
- * - *
- * - * 创建远程模式的Service实例 - * - * @param Service泛型 - * @param classLoader ClassLoader - * @param name 资源名 - * @param serviceTypeOrImplClass Service类 - * @param methodBoost 方法扩展 - * @param resourceFactory ResourceFactory - * @param sncpRpcGroups SncpRpcGroups - * @param client SncpClient - * @param agent MessageAgent - * @param remoteGroup 所有的组节点 - * @param conf 启动配置项 - * @return Service的远程模式实例 - */ - @SuppressWarnings("unchecked") - public static T createRemoteService( - final ClassLoader classLoader, - final String name, - final Class serviceTypeOrImplClass, - final AsmMethodBoost methodBoost, - final ResourceFactory resourceFactory, - final SncpRpcGroups sncpRpcGroups, - final SncpClient client, - final MessageAgent agent, - final String remoteGroup, - final AnyValue conf) { - if (serviceTypeOrImplClass == null) { - throw new SncpException("Service implement class is null"); - } - if (!Service.class.isAssignableFrom(serviceTypeOrImplClass)) { - throw new SncpException(serviceTypeOrImplClass + " is not Service type"); - } - if ((sncpRpcGroups == null || client == null) && agent == null) { - throw new SncpException(SncpRpcGroups.class.getSimpleName() + "/" + SncpClient.class.getSimpleName() - + " and " + MessageAgent.class.getSimpleName() + " are both null"); - } - ResourceFactory.checkResourceName(name); - final int mod = serviceTypeOrImplClass.getModifiers(); - boolean realed = !(java.lang.reflect.Modifier.isAbstract(mod) || serviceTypeOrImplClass.isInterface()); - if (!java.lang.reflect.Modifier.isPublic(mod)) { - return null; - } - final SncpRemoteInfo info = createSncpRemoteInfo( - name, - getResourceType(serviceTypeOrImplClass), - serviceTypeOrImplClass, - BsonConvert.root(), - sncpRpcGroups, - client, - agent, - remoteGroup); - final String supDynName = serviceTypeOrImplClass.getName().replace('.', '/'); - final String sncpInfoName = SncpRemoteInfo.class.getName().replace('.', '/'); - final String resDesc = Type.getDescriptor(Resource.class); - final String sncpInfoDesc = Type.getDescriptor(SncpRemoteInfo.class); - final String sncpDynDesc = Type.getDescriptor(SncpDyn.class); - final String anyValueDesc = Type.getDescriptor(AnyValue.class); - final ClassLoader loader = classLoader == null ? Thread.currentThread().getContextClassLoader() : classLoader; - String newDynName = "org/redkaledyn/service/remote/_DynRemoteService__" - + serviceTypeOrImplClass.getName().replace('.', '_').replace('$', '_'); - if (!name.isEmpty()) { - boolean normal = true; - for (char ch : name.toCharArray()) { - if (!((ch >= '0' && ch <= '9') || ch == '_' || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))) { - normal = false; - } - } - if (!normal) { - throw new SncpException(serviceTypeOrImplClass + "'s resource name is illegal, must be 0-9 _ a-z A-Z"); - } - newDynName += "_" + (normal ? name : hash(name)); - } - try { - Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.')); - Class newClazz = clz == null ? loader.loadClass(newDynName.replace('/', '.')) : clz; - T service = (T) newClazz.getDeclaredConstructor().newInstance(); - { - Field c = newClazz.getDeclaredField(FIELDPREFIX + "_conf"); - c.setAccessible(true); - c.set(service, conf); - } - { - Field c = newClazz.getDeclaredField(FIELDPREFIX + "_mq"); - c.setAccessible(true); - c.set(service, agent == null ? null : agent.getName()); - } - { - Field c = newClazz.getDeclaredField(FIELDPREFIX + "_sncp"); - c.setAccessible(true); - c.set(service, info); - } - if (methodBoost != null) { - methodBoost.doInstance(resourceFactory, service); - } - return service; - } catch (Throwable ex) { - // do nothing - } - // ------------------------------------------------------------------------------ - ClassWriter cw = new ClassWriter(COMPUTE_FRAMES); - FieldVisitor fv; - MethodDebugVisitor mv; - AnnotationVisitor av0; - - cw.visit( - V11, - ACC_PUBLIC + ACC_SUPER, - newDynName, - null, - serviceTypeOrImplClass.isInterface() ? "java/lang/Object" : supDynName, - serviceTypeOrImplClass.isInterface() ? new String[] {supDynName} : null); - { // 给动态生成的Service类标记上Resource - av0 = cw.visitAnnotation(resDesc, true); - av0.visit("name", name); - av0.visitEnd(); - } - { - av0 = cw.visitAnnotation(Type.getDescriptor(ResourceType.class), true); - ResourceType rty = serviceTypeOrImplClass.getAnnotation(ResourceType.class); - org.redkale.util.ResourceType rty2 = - serviceTypeOrImplClass.getAnnotation(org.redkale.util.ResourceType.class); - av0.visit( - "value", - Type.getType(Type.getDescriptor( - rty != null ? rty.value() : (rty2 != null ? rty2.value() : serviceTypeOrImplClass)))); - av0.visitEnd(); - } - { - av0 = cw.visitAnnotation(sncpDynDesc, true); - av0.visit("remote", Boolean.TRUE); - av0.visit("type", Type.getType(Type.getDescriptor(serviceTypeOrImplClass))); - av0.visitEnd(); - } - { // 给新类加上原有的Annotation - for (Annotation ann : serviceTypeOrImplClass.getAnnotations()) { - if (ann instanceof Resource || ann instanceof SncpDyn || ann instanceof ResourceType) { - continue; - } - Asms.visitAnnotation(cw.visitAnnotation(Type.getDescriptor(ann.annotationType()), true), ann); - } - } - { - fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_conf", anyValueDesc, null, null); - fv.visitEnd(); - } - { - fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_mq", Type.getDescriptor(String.class), null, null); - fv.visitEnd(); - } - { - fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_sncp", sncpInfoDesc, null, null); - fv.visitEnd(); - } - { // 构造函数 - mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "", "()V", null, null)); - // mv.setDebug(true); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn( - INVOKESPECIAL, - serviceTypeOrImplClass.isInterface() ? "java/lang/Object" : supDynName, - "", - "()V", - false); - mv.visitInsn(RETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - { // init - mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "init", "(" + anyValueDesc + ")V", null, null)); - mv.visitInsn(RETURN); - mv.visitMaxs(0, 2); - mv.visitEnd(); - } - { // destroy - mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "destroy", "(" + anyValueDesc + ")V", null, null)); - mv.visitInsn(RETURN); - mv.visitMaxs(0, 2); - mv.visitEnd(); - } - // { // toString() - // mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, - // null)); - // mv.visitVarInsn(ALOAD, 0); - // mv.visitFieldInsn(GETFIELD, newDynName, FIELDPREFIX + "_sncp", sncpInfoDesc); - // Label l1 = new Label(); - // mv.visitJumpInsn(IFNONNULL, l1); - // mv.visitVarInsn(ALOAD, 0); - // mv.visitCheckCast(INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false); - // mv.visitCheckCast(INVOKEVIRTUAL, "java/lang/Class", "getName", "()Ljava/lang/String;", false); - // Label l2 = new Label(); - // mv.visitJumpInsn(GOTO, l2); - // mv.visitLabel(l1); - // mv.visitVarInsn(ALOAD, 0); - // mv.visitFieldInsn(GETFIELD, newDynName, FIELDPREFIX + "_sncp", sncpInfoDesc); - // mv.visitCheckCast(INVOKEVIRTUAL, sncpInfoName, "toSimpleString", "()Ljava/lang/String;", false); - // mv.visitLabel(l2); - // mv.visitInsn(ARETURN); - // mv.visitMaxs(1, 1); - // mv.visitEnd(); - // } - Set methodKeys = new HashSet<>(); - Map methodBeans = AsmMethodBoost.getMethodBeans(serviceTypeOrImplClass); - for (final SncpRemoteAction entry : info.getActions()) { - final java.lang.reflect.Method method = entry.method; - String mk = Utility.methodKey(method); - if (methodKeys.contains(mk)) { - // 跳过已处理的继承方法 - continue; - } - methodKeys.add(mk); - - int acc = ACC_PUBLIC; - String newMethodName = null; - if (methodBoost != null) { - List> filterAnns = methodBoost.filterMethodAnnotations(method); - newMethodName = - methodBoost.doMethod(classLoader, cw, newDynName, FIELDPREFIX, filterAnns, method, null); - } - if (newMethodName != null) { - acc = ACC_PRIVATE; - } else { - newMethodName = method.getName(); - } - mv = new MethodDebugVisitor( - cw.visitMethod(acc, newMethodName, Type.getMethodDescriptor(method), null, null)); - Label l0 = new Label(); - mv.visitLabel(l0); - // mv.setDebug(true); - { // 给参数加上 Annotation - final Annotation[][] anns = method.getParameterAnnotations(); - for (int k = 0; k < anns.length; k++) { - for (Annotation ann : anns[k]) { - Asms.visitAnnotation( - mv.visitParameterAnnotation(k, Type.getDescriptor(ann.annotationType()), true), ann); - } - } - } - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, FIELDPREFIX + "_sncp", sncpInfoDesc); - - mv.visitLdcInsn(entry.actionid.toString()); - - AsmMethodBean methodBean = AsmMethodBean.get(methodBeans, method); - List insns = new ArrayList<>(); - java.lang.reflect.Type[] paramTypes = entry.paramTypes; - { // 传参数 - int paramlen = entry.paramTypes.length; - Asms.visitInsn(mv, paramlen); - mv.visitTypeInsn(ANEWARRAY, "java/lang/Object"); - int insn = 0; - for (int j = 0; j < paramTypes.length; j++) { - final java.lang.reflect.Type pt = paramTypes[j]; - mv.visitInsn(DUP); - insn++; - Asms.visitInsn(mv, j); - if (pt instanceof Class && ((Class) pt).isPrimitive()) { - if (pt == long.class) { - mv.visitVarInsn(LLOAD, insn++); - } else if (pt == float.class) { - mv.visitVarInsn(FLOAD, insn++); - } else if (pt == double.class) { - mv.visitVarInsn(DLOAD, insn++); - } else { - mv.visitVarInsn(ILOAD, insn); - } - Class bigclaz = TypeToken.primitiveToWrapper((Class) pt); - mv.visitMethodInsn( - INVOKESTATIC, - bigclaz.getName().replace('.', '/'), - "valueOf", - "(" + Type.getDescriptor((Class) pt) + ")" + Type.getDescriptor(bigclaz), - false); - } else { - mv.visitVarInsn(ALOAD, insn); - } - mv.visitInsn(AASTORE); - insns.add(insn); - } - } - - mv.visitMethodInsn( - INVOKEVIRTUAL, - sncpInfoName, - "remote", - "(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/Object;", - false); - // mv.visitCheckCast(INVOKEVIRTUAL, convertName, "convertFrom", convertFromDesc, false); - if (method.getGenericReturnType() == void.class) { - mv.visitInsn(POP); - mv.visitInsn(RETURN); - } else { - Class returnclz = method.getReturnType(); - Class bigPrimitiveClass = returnclz.isPrimitive() ? TypeToken.primitiveToWrapper(returnclz) : returnclz; - mv.visitTypeInsn( - CHECKCAST, - (returnclz.isPrimitive() ? bigPrimitiveClass : returnclz) - .getName() - .replace('.', '/')); - if (returnclz.isPrimitive()) { - String bigPrimitiveName = bigPrimitiveClass.getName().replace('.', '/'); - try { - java.lang.reflect.Method pm = bigPrimitiveClass.getMethod(returnclz.getSimpleName() + "Value"); - mv.visitMethodInsn( - INVOKEVIRTUAL, bigPrimitiveName, pm.getName(), Type.getMethodDescriptor(pm), false); - } catch (Exception ex) { - throw new SncpException(ex); // 不可能会发生 - } - if (returnclz == long.class) { - mv.visitInsn(LRETURN); - } else if (returnclz == float.class) { - mv.visitInsn(FRETURN); - } else if (returnclz == double.class) { - mv.visitInsn(DRETURN); - } else { - mv.visitInsn(IRETURN); - } - } else { - mv.visitInsn(ARETURN); - } - } - if (methodBean != null && paramTypes.length > 0) { - Label l2 = new Label(); - mv.visitLabel(l2); - // mv.visitLocalVariable("this", thisClassDesc, null, l0, l2, 0); - List params = methodBean.getParams(); - for (int i = 0; i < paramTypes.length; i++) { - AsmMethodParam param = params.get(i); - mv.visitLocalVariable( - param.getName(), - param.description(paramTypes[i]), - param.signature(paramTypes[i]), - l0, - l2, - insns.get(i)); - } - } - mv.visitMaxs(20, 20); - mv.visitEnd(); - } - if (methodBoost != null) { - createNewMethods(classLoader, serviceTypeOrImplClass, methodBoost, methodKeys, cw, newDynName, supDynName); - methodBoost.doAfterMethods(classLoader, cw, newDynName, FIELDPREFIX); - } - cw.visitEnd(); - byte[] bytes = cw.toByteArray(); - Class newClazz = new ClassLoader(loader) { - public final Class loadClass(String name, byte[] b) { - return defineClass(name, b, 0, b.length); - } - }.loadClass(newDynName.replace('/', '.'), bytes); - RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, newClazz); - RedkaleClassLoader.putReflectionPublicConstructors(newClazz, newDynName.replace('/', '.')); - RedkaleClassLoader.putReflectionDeclaredConstructors(newClazz, newDynName.replace('/', '.')); - try { - T service = (T) newClazz.getDeclaredConstructor().newInstance(); - { - Field c = newClazz.getDeclaredField(FIELDPREFIX + "_conf"); - c.setAccessible(true); - c.set(service, conf); - RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), c); - } - { - Field c = newClazz.getDeclaredField(FIELDPREFIX + "_mq"); - c.setAccessible(true); - c.set(service, agent == null ? null : agent.getName()); - RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), c); - } - { - Field c = newClazz.getDeclaredField(FIELDPREFIX + "_sncp"); - c.setAccessible(true); - c.set(service, info); - RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), c); - } - if (methodBoost != null) { - methodBoost.doInstance(resourceFactory, service); - } - return service; - } catch (Exception ex) { - throw new SncpException(ex); - } - } -} +/* + * 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.sncp; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import static org.redkale.asm.ClassWriter.COMPUTE_FRAMES; +import static org.redkale.asm.Opcodes.*; +import static org.redkale.util.Utility.isEmpty; + +import java.lang.annotation.*; +import java.lang.reflect.*; +import java.nio.channels.CompletionHandler; +import java.util.*; +import org.redkale.annotation.*; +import org.redkale.asm.*; +import org.redkale.asm.Type; +import org.redkale.convert.Convert; +import org.redkale.convert.bson.BsonConvert; +import org.redkale.inject.Resourcable; +import org.redkale.inject.ResourceFactory; +import org.redkale.mq.spi.MessageAgent; +import org.redkale.net.http.WebSocketNode; +import org.redkale.net.sncp.SncpRemoteInfo.SncpRemoteAction; +import org.redkale.schedule.Scheduled; +import org.redkale.service.*; +import org.redkale.util.AnyValue; +import org.redkale.util.RedkaleClassLoader; +import org.redkale.util.TypeToken; +import org.redkale.util.Uint128; +import org.redkale.util.Utility; + +/** + * Service Node Communicate Protocol 生成Service的本地模式或远程模式Service-Class的工具类 + * + *

详情见: https://redkale.org + * + * @author zhangjx + */ +public abstract class Sncp { + + static final String FIELDPREFIX = "_redkale"; + + /** + * 修饰由SNCP协议动态生成的class、和method 本地模式:动态生成的_DynLocalXXXXService类会打上@SncpDyn(remote = false) 的注解 + * 远程模式:动态生成的_DynRemoteXXXService类会打上@SncpDyn(remote = true) 的注解 + * + *

详情见: https://redkale.org + * + * @author zhangjx + */ + @Documented + @Target({METHOD, TYPE}) + @Retention(RUNTIME) + public static @interface SncpDyn { + + boolean remote(); + + Class type(); // serviceType + + int index() default 0; // 排列顺序, 主要用于Method + } + + private Sncp() { + // do nothing + } + + // key: actionid + public static LinkedHashMap loadRemoteMethodActions(final Class serviceTypeOrImplClass) { + final List list = new ArrayList<>(); + final List multis = new ArrayList<>(); + final Map actionids = new LinkedHashMap<>(); + RedkaleClassLoader.putReflectionPublicMethods(serviceTypeOrImplClass.getName()); + for (final java.lang.reflect.Method method : serviceTypeOrImplClass.getMethods()) { + if (method.isSynthetic()) { + continue; + } + if (method.getAnnotation(Scheduled.class) != null) { + continue; + } + if (Modifier.isStatic(method.getModifiers())) { + continue; + } + if (Modifier.isFinal(method.getModifiers())) { + continue; + } + if (method.getAnnotation(Local.class) != null) { + continue; + } + if (method.getAnnotation(ResourceChanged.class) != null) { + continue; + } + if (method.getName().equals("getClass") || method.getName().equals("toString")) { + continue; + } + if (method.getName().equals("equals") || method.getName().equals("hashCode")) { + continue; + } + if (method.getName().equals("notify") + || method.getName().equals("notifyAll") + || method.getName().equals("wait")) { + continue; + } + if (method.getParameterCount() == 1 && method.getParameterTypes()[0] == AnyValue.class) { + if (method.getName().equals("init") || method.getName().equals("destroy")) { + continue; + } + } + + Uint128 actionid = Sncp.actionid(method); + Method old = actionids.get(actionid); + if (old != null) { + if (old.getDeclaringClass().equals(method.getDeclaringClass())) { + throw new SncpException(serviceTypeOrImplClass.getName() + " have one more same action(Method=" + + method + ", " + old + ", actionid=" + actionid + ")"); + } + continue; + } + actionids.put(actionid, method); + if (method.getAnnotation(Sncp.SncpDyn.class) != null) { + multis.add(method); + } else { + list.add(method); + } + } + multis.sort((m1, m2) -> m1.getAnnotation(Sncp.SncpDyn.class).index() + - m2.getAnnotation(Sncp.SncpDyn.class).index()); + list.sort((Method o1, Method o2) -> { + if (!o1.getName().equals(o2.getName())) { + return o1.getName().compareTo(o2.getName()); + } + if (o1.getParameterCount() != o2.getParameterCount()) { + return o1.getParameterCount() - o2.getParameterCount(); + } + return 0; + }); + // 带SncpDyn必须排在前面 + multis.addAll(list); + final LinkedHashMap rs = new LinkedHashMap<>(); + for (Method method : multis) { + for (Map.Entry en : actionids.entrySet()) { + if (en.getValue() == method) { + rs.put(en.getKey(), en.getValue()); + break; + } + } + } + return rs; + } + + public static SncpRemoteInfo createSncpRemoteInfo( + String resourceName, + Class resourceServiceType, + Class serviceImplClass, + Convert convert, + SncpRpcGroups sncpRpcGroups, + SncpClient sncpClient, + MessageAgent messageAgent, + String remoteGroup) { + return new SncpRemoteInfo( + resourceName, + resourceServiceType, + serviceImplClass, + convert, + sncpRpcGroups, + sncpClient, + messageAgent, + remoteGroup); + } + + /** + * 格式:资源类型:资源名 + * + * @param resourceName 资源名 + * @param resourceType 资源类型 + * @return resourceid + */ + public static String resourceid(String resourceName, Class resourceType) { + return resourceType.getName() + ':' + (resourceName == null ? "" : resourceName); + } + + public static Uint128 serviceid(String serviceResourceName, Class serviceResourceType) { + return hash(resourceid(serviceResourceName, serviceResourceType)); + } + + public static Uint128 actionid(final RpcAction action) { + return hash(action.name()); + } + + public static Uint128 actionid(final java.lang.reflect.Method method) { + if (method == null) { + return Uint128.ZERO; + } + RpcAction action = method.getAnnotation(RpcAction.class); + if (action != null) { + return hash(action.name()); + } + StringBuilder sb = new StringBuilder(); // 不能使用method.toString() 因为包含declaringClass信息导致接口与实现类的方法hash不一致 + sb.append(method.getReturnType().getName()).append(' '); + sb.append(method.getName()); + sb.append('('); + boolean first = true; + for (Class pt : method.getParameterTypes()) { + if (!first) { + sb.append(','); + } + sb.append(pt.getName()); + first = false; + } + sb.append(')'); + return hash(sb.toString()); + } + + /** + * 对类名或者name字符串进行hash。 + * + * @param name String + * @return hash值 + */ + private static Uint128 hash(final String name) { + if (name == null || name.isEmpty()) { + return Uint128.ZERO; + } + return Uint128.create(Utility.md5(name.trim().getBytes())); + } + + public static boolean isRemote(Service service) { + SncpDyn dyn = service.getClass().getAnnotation(SncpDyn.class); + return dyn != null && dyn.remote(); + } + + public static boolean isSncpDyn(Service service) { + return service.getClass().getAnnotation(SncpDyn.class) != null; + } + + public static boolean isSncpDyn(Class serviceType) { + return serviceType.getAnnotation(SncpDyn.class) != null; + } + + public static boolean isComponent(Service service) { + return service.getClass().getAnnotation(Component.class) != null; + } + + public static boolean isComponent(Class serviceType) { + return serviceType.getAnnotation(Component.class) != null; + } + + public static int getVersion(Service service) { + return -1; // 预留功能,暂不实现 + } + + public static String getResourceName(Service service) { + Resource res = service.getClass().getAnnotation(Resource.class); + return res != null + ? res.name() + : (service instanceof Resourcable ? ((Resourcable) service).resourceName() : null); + } + + public static Class getResourceType(Service service) { + ResourceType type = service.getClass().getAnnotation(ResourceType.class); + return type != null ? type.value() : service.getClass(); + } + + public static Class getResourceType(Class serviceImplClass) { + ResourceType type = serviceImplClass.getAnnotation(ResourceType.class); + return type != null ? type.value() : serviceImplClass; + } + + public static Class getServiceType(Service service) { + SncpDyn dyn = service.getClass().getAnnotation(SncpDyn.class); + return dyn != null ? dyn.type() : service.getClass(); + } + + public static Class getServiceType(Class serviceImplClass) { + SncpDyn dyn = serviceImplClass.getAnnotation(SncpDyn.class); + return dyn != null ? dyn.type() : serviceImplClass; + } + + // 格式: sncp.req.module.user + public static String generateSncpReqTopic(Service service, String nodeid) { + return generateSncpReqTopic(getResourceName(service), getResourceType(service), nodeid); + } + + // 格式: sncp.req.module.user + public static String generateSncpReqTopic(String resourceName, Class resourceType, String nodeid) { + if (WebSocketNode.class.isAssignableFrom(resourceType)) { + return getSncpReqTopicPrefix() + "module.wsnode" + nodeid + + (isEmpty(resourceName) ? "" : ("-" + resourceName)); + } + return getSncpReqTopicPrefix() + "module." + + resourceType.getSimpleName().replaceAll("Service.*$", "").toLowerCase() + + (isEmpty(resourceName) ? "" : ("-" + resourceName)); + } + + public static String getSncpReqTopicPrefix() { + return "sncp.req."; + } + + public static String getSncpRespTopicPrefix() { + return "sncp.resp."; + } + + public static AnyValue getResourceConf(Service service) { + if (service == null || !isSncpDyn(service)) { + return null; + } + try { + Field ts = service.getClass().getDeclaredField(FIELDPREFIX + "_conf"); + ts.setAccessible(true); + return (AnyValue) ts.get(service); + } catch (Exception e) { + throw new SncpException(service + " not found " + FIELDPREFIX + "_conf"); + } + } + + public static String getResourceMQ(Service service) { + if (service == null || !isSncpDyn(service)) { + return null; + } + try { + Field ts = service.getClass().getDeclaredField(FIELDPREFIX + "_mq"); + ts.setAccessible(true); + return (String) ts.get(service); + } catch (Exception e) { + throw new SncpException(service + " not found " + FIELDPREFIX + "_mq"); + } + } + + static void checkAsyncModifier(Class param, Method method) { + if (param == CompletionHandler.class) { + return; + } + if (Modifier.isFinal(param.getModifiers())) { + throw new SncpException("CompletionHandler Type Parameter on {" + method + "} cannot final modifier"); + } + if (!Modifier.isPublic(param.getModifiers())) { + throw new SncpException("CompletionHandler Type Parameter on {" + method + "} must be public modifier"); + } + if (param.isInterface()) { + return; + } + boolean constructorflag = false; + RedkaleClassLoader.putReflectionDeclaredConstructors(param, param.getName()); + for (Constructor c : param.getDeclaredConstructors()) { + if (c.getParameterCount() == 0) { + int mod = c.getModifiers(); + if (Modifier.isPublic(mod) || Modifier.isProtected(mod)) { + constructorflag = true; + break; + } + } + } + if (param.getDeclaredConstructors().length == 0) { + constructorflag = true; + } + if (!constructorflag) { + throw new SncpException(param + " must have a empty parameter Constructor"); + } + for (Method m : param.getMethods()) { + if (m.getName().equals("completed") && m.getParameterCount() == 2 && Modifier.isFinal(m.getModifiers())) { + throw new SncpException(param + "'s completed method cannot final modifier"); + } else if (m.getName().equals("failed") + && m.getParameterCount() == 2 + && Modifier.isFinal(m.getModifiers())) { + throw new SncpException(param + "'s failed method cannot final modifier"); + } + } + } + + public static String toSimpleString(final Service service, int maxNameLength, int maxTypeLength) { + StringBuilder sb = new StringBuilder(); + sb.append(isRemote(service) ? "RemoteService" : "LocalService "); + int len; + Class type = getResourceType(service); + String name = getResourceName(service); + if (name == null) { + name = ""; + } + sb.append("(type= ").append(type.getName()); + len = maxTypeLength - type.getName().length(); + for (int i = 0; i < len; i++) { + sb.append(' '); + } + sb.append(", name='").append(name).append("'"); + for (int i = 0; i < maxNameLength - name.length(); i++) { + sb.append(' '); + } + sb.append(")"); + return sb.toString(); + } + + // 获取一个clazz内所有未被实现的方法 + public static List loadNotImplMethods(Class clazz) { + LinkedHashSet types = new LinkedHashSet<>(); + loadAllSubClasses(clazz, types); + List methods = new ArrayList<>(); + Set ms = new HashSet<>(); + for (Class c : types) { + for (Method m : c.getDeclaredMethods()) { + if (c.isInterface() || Modifier.isAbstract(m.getModifiers())) { + StringBuilder sb = + new StringBuilder(); // 不能使用method.toString() 因为包含declaringClass信息导致接口与实现类的方法hash不一致 + sb.append(m.getName()); + sb.append('('); + boolean first = true; + for (Class pt : m.getParameterTypes()) { + if (!first) { + sb.append(','); + } + sb.append(pt.getName()); + first = false; + } + sb.append(')'); + String key = sb.toString(); + Uint128 a = actionid(m); + if (!ms.contains(key)) { + methods.add(m); + ms.add(key); + } + } + } + } + return methods; + } + + private static void loadAllSubClasses(Class clazz, LinkedHashSet types) { + if (clazz == null || clazz == Object.class) { + return; + } + types.add(clazz); + if (clazz.getSuperclass() != null) { + loadAllSubClasses(clazz.getSuperclass(), types); + } + if (clazz.getInterfaces() != null) { + for (Class sub : clazz.getInterfaces()) { + loadAllSubClasses(sub, types); + } + } + } + + /** + * + * + *

+ * + *
+     * public class TestService implements Service {
+     *
+     *      public String findSomeThing(){
+     *          return "hello";
+     *      }
+     *
+     *      @RpcMultiRun(selfrun = false)
+     *      public void createSomeThing(TestBean bean){
+     *          //do something
+     *      }
+     *
+     *      @RpcMultiRun
+     *      public String updateSomeThing(String id){
+     *          return "hello" + id;
+     *      }
+     * }
+     * 
+ * + *
+ * + *
+ * + *
+     * @Resource(name = "")
+     * @SncpDyn(remote = false)
+     * @ResourceType(TestService.class)
+     * public final class _DynLocalTestService extends TestService {
+     *
+     *      private AnyValue _redkale_conf;
+     *
+     * }
+     * 
+ * + *
+ * + * 创建Service的本地模式Class + * + * @param Service子类 + * @param classLoader ClassLoader + * @param name 资源名 + * @param serviceImplClass Service类 + * @param methodBoost 方法扩展 + * @return Service实例 + */ + @SuppressWarnings("unchecked") + protected static Class createLocalServiceClass( + ClassLoader classLoader, + final String name, + final Class serviceImplClass, + final AsmMethodBoost methodBoost) { + Objects.requireNonNull(serviceImplClass); + if (!Service.class.isAssignableFrom(serviceImplClass)) { + throw new SncpException(serviceImplClass + " is not Service type"); + } + ResourceFactory.checkResourceName(name); + int mod = serviceImplClass.getModifiers(); + if (!java.lang.reflect.Modifier.isPublic(mod)) { + throw new SncpException(serviceImplClass + " is not public"); + } + if (java.lang.reflect.Modifier.isAbstract(mod)) { + throw new SncpException(serviceImplClass + " is abstract"); + } + final String supDynName = serviceImplClass.getName().replace('.', '/'); + final String resDesc = Type.getDescriptor(Resource.class); + final String anyValueDesc = Type.getDescriptor(AnyValue.class); + final String sncpDynDesc = Type.getDescriptor(SncpDyn.class); + ClassLoader loader = classLoader == null ? Thread.currentThread().getContextClassLoader() : classLoader; + // String newDynName = supDynName.substring(0, supDynName.lastIndexOf('/') + 1) + LOCALPREFIX + + // serviceImplClass.getSimpleName(); + String newDynName = "org/redkaledyn/service/local/_DynLocalService__" + + serviceImplClass.getName().replace('.', '_').replace('$', '_'); + if (!name.isEmpty()) { + boolean normal = true; + for (char ch : name.toCharArray()) { + if (!((ch >= '0' && ch <= '9') || ch == '_' || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))) { + normal = false; + } + } + if (!normal) { + throw new SncpException(serviceImplClass + "'s resource name is illegal, must be 0-9 _ a-z A-Z"); + } + newDynName += "_" + (normal ? name : hash(name)); + } + try { + Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.')); + return (Class) (clz == null ? loader.loadClass(newDynName.replace('/', '.')) : clz); + } catch (ClassNotFoundException e) { + // do nothing + } catch (Throwable t) { + t.printStackTrace(); + } + // ------------------------------------------------------------------------------ + ClassWriter cw = new ClassWriter(COMPUTE_FRAMES); + FieldVisitor fv; + MethodDebugVisitor mv; + AnnotationVisitor av0; + + cw.visit(V11, ACC_PUBLIC + ACC_SUPER, newDynName, null, supDynName, null); + { // 给动态生成的Service类标记上Resource + av0 = cw.visitAnnotation(resDesc, true); + av0.visit("name", name); + av0.visitEnd(); + } + { + av0 = cw.visitAnnotation(sncpDynDesc, true); + av0.visit("remote", Boolean.FALSE); + av0.visit("type", Type.getType(Type.getDescriptor(serviceImplClass))); + av0.visitEnd(); + } + { // 给新类加上原有的Annotation + for (Annotation ann : serviceImplClass.getAnnotations()) { + if (ann instanceof Resource || ann instanceof SncpDyn || ann instanceof ResourceType) { + continue; + } + Asms.visitAnnotation(cw.visitAnnotation(Type.getDescriptor(ann.annotationType()), true), ann); + } + } + { + av0 = cw.visitAnnotation(Type.getDescriptor(ResourceType.class), true); + ResourceType rty = serviceImplClass.getAnnotation(ResourceType.class); + org.redkale.util.ResourceType rty2 = serviceImplClass.getAnnotation(org.redkale.util.ResourceType.class); + av0.visit( + "value", + Type.getType(Type.getDescriptor( + rty != null ? rty.value() : (rty2 != null ? rty2.value() : serviceImplClass)))); + av0.visitEnd(); + } + { + fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_conf", anyValueDesc, null, null); + fv.visitEnd(); + } + { + fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_mq", Type.getDescriptor(String.class), null, null); + fv.visitEnd(); + } + { // 构造函数 + mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "", "()V", null, null)); + // mv.setDebug(true); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, supDynName, "", "()V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + if (methodBoost != null) { + createNewMethods(classLoader, serviceImplClass, methodBoost, new HashSet<>(), cw, newDynName, supDynName); + methodBoost.doAfterMethods(classLoader, cw, newDynName, FIELDPREFIX); + } + cw.visitEnd(); + byte[] bytes = cw.toByteArray(); + Class newClazz = new ClassLoader(loader) { + public final Class loadClass(String name, byte[] b) { + return defineClass(name, b, 0, b.length); + } + }.loadClass(newDynName.replace('/', '.'), bytes); + RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, newClazz); + RedkaleClassLoader.putReflectionPublicClasses(newDynName.replace('/', '.')); + RedkaleClassLoader.putReflectionDeclaredConstructors(newClazz, newDynName.replace('/', '.')); + try { + Field c = newClazz.getDeclaredField(FIELDPREFIX + "_conf"); + RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), c); + + c = newClazz.getDeclaredField(FIELDPREFIX + "_mq"); + RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), c); + } catch (Exception e) { + // do nothing + } + return (Class) newClazz; + } + + public static T createSimpleLocalService( + Class serviceImplClass, ResourceFactory resourceFactory) { + return createLocalService(null, "", serviceImplClass, null, resourceFactory, null, null, null, null, null); + } + + private static void createNewMethods( + ClassLoader classLoader, + Class clazz, + final AsmMethodBoost methodBoost, + Set methodKeys, + ClassWriter cw, + String newDynName, + String supDynName) { + if (methodBoost == null) { + return; + } + MethodDebugVisitor mv = null; + do { + Map methodBeans = AsmMethodBoost.getMethodBeans(clazz); + for (final Method method : clazz.getDeclaredMethods()) { + String mk = Utility.methodKey(method); + if (methodKeys.contains(mk)) { + // 跳过已处理的继承方法 + continue; + } + methodKeys.add(mk); + List> filterAnns = methodBoost.filterMethodAnnotations(method); + String newMethodName = + methodBoost.doMethod(classLoader, cw, newDynName, FIELDPREFIX, filterAnns, method, null); + if (newMethodName != null) { + String desc = Type.getMethodDescriptor(method); + AsmMethodBean methodBean = AsmMethodBean.get(methodBeans, method); + String signature = null; + String[] exceptions = null; + if (methodBean == null) { + Class[] expTypes = method.getExceptionTypes(); + if (expTypes.length > 0) { + exceptions = new String[expTypes.length]; + for (int i = 0; i < expTypes.length; i++) { + exceptions[i] = expTypes[i].getName().replace('.', '/'); + } + } + } else { + signature = methodBean.getSignature(); + exceptions = methodBean.getExceptions(); + } + // 需要定义一个新方法调用 super.method + mv = new MethodDebugVisitor( + cw.visitMethod(ACC_PRIVATE, newMethodName, desc, signature, exceptions)); + Label l0 = new Label(); + mv.visitLabel(l0); + // mv.setDebug(true); + mv.visitVarInsn(ALOAD, 0); + // 传参数 + Class[] paramTypes = method.getParameterTypes(); + List insns = new ArrayList<>(); + int insn = 0; + for (Class pt : paramTypes) { + insn++; + if (pt.isPrimitive()) { + if (pt == long.class) { + mv.visitVarInsn(LLOAD, insn++); + } else if (pt == float.class) { + mv.visitVarInsn(FLOAD, insn++); + } else if (pt == double.class) { + mv.visitVarInsn(DLOAD, insn++); + } else { + mv.visitVarInsn(ILOAD, insn); + } + } else { + mv.visitVarInsn(ALOAD, insn); + } + insns.add(insn); + } + mv.visitMethodInsn( + INVOKESPECIAL, supDynName, method.getName(), Type.getMethodDescriptor(method), false); + if (method.getGenericReturnType() == void.class) { + mv.visitInsn(RETURN); + } else { + Class returnclz = method.getReturnType(); + if (returnclz.isPrimitive()) { + if (returnclz == long.class) { + mv.visitInsn(LRETURN); + } else if (returnclz == float.class) { + mv.visitInsn(FRETURN); + } else if (returnclz == double.class) { + mv.visitInsn(DRETURN); + } else { + mv.visitInsn(IRETURN); + } + } else { + mv.visitInsn(ARETURN); + } + } + if (methodBean != null && paramTypes.length > 0) { + Label l2 = new Label(); + mv.visitLabel(l2); + // mv.visitLocalVariable("this", thisClassDesc, null, l0, l2, 0); + List params = methodBean.getParams(); + for (int i = 0; i < paramTypes.length; i++) { + AsmMethodParam param = params.get(i); + mv.visitLocalVariable( + param.getName(), + param.description(paramTypes[i]), + param.signature(paramTypes[i]), + l0, + l2, + insns.get(i)); + } + } + mv.visitMaxs(20, 20); + mv.visitEnd(); + } + } + } while ((clazz = clazz.getSuperclass()) != Object.class); + } + + /** + * 创建本地模式Service实例 + * + * @param Service泛型 + * @param classLoader ClassLoader + * @param name 资源名 + * @param serviceImplClass Service类 + * @param methodBoost 方法扩展 + * @param resourceFactory ResourceFactory + * @param sncpRpcGroups SncpRpcGroups + * @param client SncpClient + * @param agent MessageAgent + * @param remoteGroup 所有的组节点 + * @param conf 启动配置项 + * @return Service的本地模式实例 + */ + @SuppressWarnings("unchecked") + public static T createLocalService( + final RedkaleClassLoader classLoader, + final String name, + final Class serviceImplClass, + final AsmMethodBoost methodBoost, + final ResourceFactory resourceFactory, + final SncpRpcGroups sncpRpcGroups, + final SncpClient client, + final MessageAgent agent, + final String remoteGroup, + final AnyValue conf) { + try { + final Class newClazz = createLocalServiceClass(classLoader, name, serviceImplClass, methodBoost); + T service = (T) newClazz.getDeclaredConstructor().newInstance(); + // -------------------------------------- + Service remoteService = null; + { + Class loop = newClazz; + do { + RedkaleClassLoader.putReflectionDeclaredFields(loop.getName()); + for (Field field : loop.getDeclaredFields()) { + int mod = field.getModifiers(); + if (Modifier.isFinal(mod) || Modifier.isStatic(mod)) { + continue; + } + if (field.getAnnotation(RpcRemote.class) == null) { + continue; + } + if (!field.getType().isAssignableFrom(newClazz)) { + continue; + } + field.setAccessible(true); + RedkaleClassLoader.putReflectionField(loop.getName(), field); + if (remoteService == null && sncpRpcGroups != null && client != null) { + remoteService = createRemoteService( + classLoader, + name, + serviceImplClass, + methodBoost, + resourceFactory, + sncpRpcGroups, + client, + agent, + remoteGroup, + conf); + } + if (remoteService != null) { + field.set(service, remoteService); + } + } + } while ((loop = loop.getSuperclass()) != Object.class); + } + { + Field c = newClazz.getDeclaredField(FIELDPREFIX + "_conf"); + c.setAccessible(true); + c.set(service, conf); + } + { + Field c = newClazz.getDeclaredField(FIELDPREFIX + "_mq"); + c.setAccessible(true); + c.set(service, agent == null ? null : agent.getName()); + } + if (methodBoost != null) { + methodBoost.doInstance(resourceFactory, service); + } + return service; + } catch (RuntimeException rex) { + throw rex; + } catch (Exception ex) { + throw new SncpException(ex); + } + } + + public static T createSimpleRemoteService( + Class serviceImplClass, + ResourceFactory resourceFactory, + SncpRpcGroups sncpRpcGroups, + SncpClient client, + String group) { + if (sncpRpcGroups == null) { + throw new SncpException(SncpRpcGroups.class.getSimpleName() + " is null"); + } + if (client == null) { + throw new SncpException(SncpClient.class.getSimpleName() + " is null"); + } + return createRemoteService( + null, "", serviceImplClass, null, resourceFactory, sncpRpcGroups, client, null, group, null); + } + + /** + * + * + *
+ * + *
+     * @Resource(name = "")
+     * @SncpDyn(remote = true)
+     * @ResourceType(TestService.class)
+     * public final class _DynRemoteTestService extends TestService {
+     *
+     *      private AnyValue _redkale_conf;
+     *
+     *      private SncpClient _redkale_client;
+     *
+     *      private SncpRemoteInfo _redkale_sncp;
+     *
+     *      @Override
+     *      public void createSomeThing(TestBean bean){
+     *          _redkale_client.remote(_redkale_sncp, 0, bean);
+     *      }
+     *
+     *      @Override
+     *      public String findSomeThing(){
+     *          return (String)_redkale_client.remote(_redkale_sncp, 1);
+     *      }
+     *
+     *      @Override
+     *      public String updateSomeThing(String id){
+     *          return (String)_redkale_client.remote(_redkale_sncp, 2, id);
+     *      }
+     * }
+     * 
+ * + *
+ * + * 创建远程模式的Service实例 + * + * @param Service泛型 + * @param classLoader ClassLoader + * @param name 资源名 + * @param serviceTypeOrImplClass Service类 + * @param methodBoost 方法扩展 + * @param resourceFactory ResourceFactory + * @param sncpRpcGroups SncpRpcGroups + * @param client SncpClient + * @param agent MessageAgent + * @param remoteGroup 所有的组节点 + * @param conf 启动配置项 + * @return Service的远程模式实例 + */ + @SuppressWarnings("unchecked") + public static T createRemoteService( + final ClassLoader classLoader, + final String name, + final Class serviceTypeOrImplClass, + final AsmMethodBoost methodBoost, + final ResourceFactory resourceFactory, + final SncpRpcGroups sncpRpcGroups, + final SncpClient client, + final MessageAgent agent, + final String remoteGroup, + final AnyValue conf) { + if (serviceTypeOrImplClass == null) { + throw new SncpException("Service implement class is null"); + } + if (!Service.class.isAssignableFrom(serviceTypeOrImplClass)) { + throw new SncpException(serviceTypeOrImplClass + " is not Service type"); + } + if ((sncpRpcGroups == null || client == null) && agent == null) { + throw new SncpException(SncpRpcGroups.class.getSimpleName() + "/" + SncpClient.class.getSimpleName() + + " and " + MessageAgent.class.getSimpleName() + " are both null"); + } + ResourceFactory.checkResourceName(name); + final int mod = serviceTypeOrImplClass.getModifiers(); + boolean realed = !(java.lang.reflect.Modifier.isAbstract(mod) || serviceTypeOrImplClass.isInterface()); + if (!java.lang.reflect.Modifier.isPublic(mod)) { + return null; + } + final SncpRemoteInfo info = createSncpRemoteInfo( + name, + getResourceType(serviceTypeOrImplClass), + serviceTypeOrImplClass, + BsonConvert.root(), + sncpRpcGroups, + client, + agent, + remoteGroup); + final String supDynName = serviceTypeOrImplClass.getName().replace('.', '/'); + final String sncpInfoName = SncpRemoteInfo.class.getName().replace('.', '/'); + final String resDesc = Type.getDescriptor(Resource.class); + final String sncpInfoDesc = Type.getDescriptor(SncpRemoteInfo.class); + final String sncpDynDesc = Type.getDescriptor(SncpDyn.class); + final String anyValueDesc = Type.getDescriptor(AnyValue.class); + final ClassLoader loader = classLoader == null ? Thread.currentThread().getContextClassLoader() : classLoader; + String newDynName = "org/redkaledyn/service/remote/_DynRemoteService__" + + serviceTypeOrImplClass.getName().replace('.', '_').replace('$', '_'); + if (!name.isEmpty()) { + boolean normal = true; + for (char ch : name.toCharArray()) { + if (!((ch >= '0' && ch <= '9') || ch == '_' || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))) { + normal = false; + } + } + if (!normal) { + throw new SncpException(serviceTypeOrImplClass + "'s resource name is illegal, must be 0-9 _ a-z A-Z"); + } + newDynName += "_" + (normal ? name : hash(name)); + } + try { + Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.')); + Class newClazz = clz == null ? loader.loadClass(newDynName.replace('/', '.')) : clz; + T service = (T) newClazz.getDeclaredConstructor().newInstance(); + { + Field c = newClazz.getDeclaredField(FIELDPREFIX + "_conf"); + c.setAccessible(true); + c.set(service, conf); + } + { + Field c = newClazz.getDeclaredField(FIELDPREFIX + "_mq"); + c.setAccessible(true); + c.set(service, agent == null ? null : agent.getName()); + } + { + Field c = newClazz.getDeclaredField(FIELDPREFIX + "_sncp"); + c.setAccessible(true); + c.set(service, info); + } + if (methodBoost != null) { + methodBoost.doInstance(resourceFactory, service); + } + return service; + } catch (Throwable ex) { + // do nothing + } + // ------------------------------------------------------------------------------ + ClassWriter cw = new ClassWriter(COMPUTE_FRAMES); + FieldVisitor fv; + MethodDebugVisitor mv; + AnnotationVisitor av0; + + cw.visit( + V11, + ACC_PUBLIC + ACC_SUPER, + newDynName, + null, + serviceTypeOrImplClass.isInterface() ? "java/lang/Object" : supDynName, + serviceTypeOrImplClass.isInterface() ? new String[] {supDynName} : null); + { // 给动态生成的Service类标记上Resource + av0 = cw.visitAnnotation(resDesc, true); + av0.visit("name", name); + av0.visitEnd(); + } + { + av0 = cw.visitAnnotation(Type.getDescriptor(ResourceType.class), true); + ResourceType rty = serviceTypeOrImplClass.getAnnotation(ResourceType.class); + org.redkale.util.ResourceType rty2 = + serviceTypeOrImplClass.getAnnotation(org.redkale.util.ResourceType.class); + av0.visit( + "value", + Type.getType(Type.getDescriptor( + rty != null ? rty.value() : (rty2 != null ? rty2.value() : serviceTypeOrImplClass)))); + av0.visitEnd(); + } + { + av0 = cw.visitAnnotation(sncpDynDesc, true); + av0.visit("remote", Boolean.TRUE); + av0.visit("type", Type.getType(Type.getDescriptor(serviceTypeOrImplClass))); + av0.visitEnd(); + } + { // 给新类加上原有的Annotation + for (Annotation ann : serviceTypeOrImplClass.getAnnotations()) { + if (ann instanceof Resource || ann instanceof SncpDyn || ann instanceof ResourceType) { + continue; + } + Asms.visitAnnotation(cw.visitAnnotation(Type.getDescriptor(ann.annotationType()), true), ann); + } + } + { + fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_conf", anyValueDesc, null, null); + fv.visitEnd(); + } + { + fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_mq", Type.getDescriptor(String.class), null, null); + fv.visitEnd(); + } + { + fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_sncp", sncpInfoDesc, null, null); + fv.visitEnd(); + } + { // 构造函数 + mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "", "()V", null, null)); + // mv.setDebug(true); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn( + INVOKESPECIAL, + serviceTypeOrImplClass.isInterface() ? "java/lang/Object" : supDynName, + "", + "()V", + false); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + { // init + mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "init", "(" + anyValueDesc + ")V", null, null)); + mv.visitInsn(RETURN); + mv.visitMaxs(0, 2); + mv.visitEnd(); + } + { // destroy + mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "destroy", "(" + anyValueDesc + ")V", null, null)); + mv.visitInsn(RETURN); + mv.visitMaxs(0, 2); + mv.visitEnd(); + } + // { // toString() + // mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, + // null)); + // mv.visitVarInsn(ALOAD, 0); + // mv.visitFieldInsn(GETFIELD, newDynName, FIELDPREFIX + "_sncp", sncpInfoDesc); + // Label l1 = new Label(); + // mv.visitJumpInsn(IFNONNULL, l1); + // mv.visitVarInsn(ALOAD, 0); + // mv.visitCheckCast(INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false); + // mv.visitCheckCast(INVOKEVIRTUAL, "java/lang/Class", "getName", "()Ljava/lang/String;", false); + // Label l2 = new Label(); + // mv.visitJumpInsn(GOTO, l2); + // mv.visitLabel(l1); + // mv.visitVarInsn(ALOAD, 0); + // mv.visitFieldInsn(GETFIELD, newDynName, FIELDPREFIX + "_sncp", sncpInfoDesc); + // mv.visitCheckCast(INVOKEVIRTUAL, sncpInfoName, "toSimpleString", "()Ljava/lang/String;", false); + // mv.visitLabel(l2); + // mv.visitInsn(ARETURN); + // mv.visitMaxs(1, 1); + // mv.visitEnd(); + // } + Set methodKeys = new HashSet<>(); + Map methodBeans = AsmMethodBoost.getMethodBeans(serviceTypeOrImplClass); + for (final SncpRemoteAction entry : info.getActions()) { + final java.lang.reflect.Method method = entry.method; + String mk = Utility.methodKey(method); + if (methodKeys.contains(mk)) { + // 跳过已处理的继承方法 + continue; + } + methodKeys.add(mk); + + int acc = ACC_PUBLIC; + String newMethodName = null; + if (methodBoost != null) { + List> filterAnns = methodBoost.filterMethodAnnotations(method); + newMethodName = + methodBoost.doMethod(classLoader, cw, newDynName, FIELDPREFIX, filterAnns, method, null); + } + if (newMethodName != null) { + acc = ACC_PRIVATE; + } else { + newMethodName = method.getName(); + } + mv = new MethodDebugVisitor( + cw.visitMethod(acc, newMethodName, Type.getMethodDescriptor(method), null, null)); + Label l0 = new Label(); + mv.visitLabel(l0); + // mv.setDebug(true); + { // 给参数加上 Annotation + final Annotation[][] anns = method.getParameterAnnotations(); + for (int k = 0; k < anns.length; k++) { + for (Annotation ann : anns[k]) { + Asms.visitAnnotation( + mv.visitParameterAnnotation(k, Type.getDescriptor(ann.annotationType()), true), ann); + } + } + } + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, FIELDPREFIX + "_sncp", sncpInfoDesc); + + mv.visitLdcInsn(entry.actionid.toString()); + + AsmMethodBean methodBean = AsmMethodBean.get(methodBeans, method); + List insns = new ArrayList<>(); + java.lang.reflect.Type[] paramTypes = entry.paramTypes; + { // 传参数 + int paramlen = entry.paramTypes.length; + Asms.visitInsn(mv, paramlen); + mv.visitTypeInsn(ANEWARRAY, "java/lang/Object"); + int insn = 0; + for (int j = 0; j < paramTypes.length; j++) { + final java.lang.reflect.Type pt = paramTypes[j]; + mv.visitInsn(DUP); + insn++; + Asms.visitInsn(mv, j); + if (pt instanceof Class && ((Class) pt).isPrimitive()) { + if (pt == long.class) { + mv.visitVarInsn(LLOAD, insn++); + } else if (pt == float.class) { + mv.visitVarInsn(FLOAD, insn++); + } else if (pt == double.class) { + mv.visitVarInsn(DLOAD, insn++); + } else { + mv.visitVarInsn(ILOAD, insn); + } + Class bigclaz = TypeToken.primitiveToWrapper((Class) pt); + mv.visitMethodInsn( + INVOKESTATIC, + bigclaz.getName().replace('.', '/'), + "valueOf", + "(" + Type.getDescriptor((Class) pt) + ")" + Type.getDescriptor(bigclaz), + false); + } else { + mv.visitVarInsn(ALOAD, insn); + } + mv.visitInsn(AASTORE); + insns.add(insn); + } + } + + mv.visitMethodInsn( + INVOKEVIRTUAL, + sncpInfoName, + "remote", + "(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/Object;", + false); + // mv.visitCheckCast(INVOKEVIRTUAL, convertName, "convertFrom", convertFromDesc, false); + if (method.getGenericReturnType() == void.class) { + mv.visitInsn(POP); + mv.visitInsn(RETURN); + } else { + Class returnclz = method.getReturnType(); + Class bigPrimitiveClass = returnclz.isPrimitive() ? TypeToken.primitiveToWrapper(returnclz) : returnclz; + mv.visitTypeInsn( + CHECKCAST, + (returnclz.isPrimitive() ? bigPrimitiveClass : returnclz) + .getName() + .replace('.', '/')); + if (returnclz.isPrimitive()) { + String bigPrimitiveName = bigPrimitiveClass.getName().replace('.', '/'); + try { + java.lang.reflect.Method pm = bigPrimitiveClass.getMethod(returnclz.getSimpleName() + "Value"); + mv.visitMethodInsn( + INVOKEVIRTUAL, bigPrimitiveName, pm.getName(), Type.getMethodDescriptor(pm), false); + } catch (Exception ex) { + throw new SncpException(ex); // 不可能会发生 + } + if (returnclz == long.class) { + mv.visitInsn(LRETURN); + } else if (returnclz == float.class) { + mv.visitInsn(FRETURN); + } else if (returnclz == double.class) { + mv.visitInsn(DRETURN); + } else { + mv.visitInsn(IRETURN); + } + } else { + mv.visitInsn(ARETURN); + } + } + if (methodBean != null && paramTypes.length > 0) { + Label l2 = new Label(); + mv.visitLabel(l2); + // mv.visitLocalVariable("this", thisClassDesc, null, l0, l2, 0); + List params = methodBean.getParams(); + for (int i = 0; i < paramTypes.length; i++) { + AsmMethodParam param = params.get(i); + mv.visitLocalVariable( + param.getName(), + param.description(paramTypes[i]), + param.signature(paramTypes[i]), + l0, + l2, + insns.get(i)); + } + } + mv.visitMaxs(20, 20); + mv.visitEnd(); + } + if (methodBoost != null) { + createNewMethods(classLoader, serviceTypeOrImplClass, methodBoost, methodKeys, cw, newDynName, supDynName); + methodBoost.doAfterMethods(classLoader, cw, newDynName, FIELDPREFIX); + } + cw.visitEnd(); + byte[] bytes = cw.toByteArray(); + Class newClazz = new ClassLoader(loader) { + public final Class loadClass(String name, byte[] b) { + return defineClass(name, b, 0, b.length); + } + }.loadClass(newDynName.replace('/', '.'), bytes); + RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, newClazz); + RedkaleClassLoader.putReflectionPublicConstructors(newClazz, newDynName.replace('/', '.')); + RedkaleClassLoader.putReflectionDeclaredConstructors(newClazz, newDynName.replace('/', '.')); + try { + T service = (T) newClazz.getDeclaredConstructor().newInstance(); + { + Field c = newClazz.getDeclaredField(FIELDPREFIX + "_conf"); + c.setAccessible(true); + c.set(service, conf); + RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), c); + } + { + Field c = newClazz.getDeclaredField(FIELDPREFIX + "_mq"); + c.setAccessible(true); + c.set(service, agent == null ? null : agent.getName()); + RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), c); + } + { + Field c = newClazz.getDeclaredField(FIELDPREFIX + "_sncp"); + c.setAccessible(true); + c.set(service, info); + RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), c); + } + if (methodBoost != null) { + methodBoost.doInstance(resourceFactory, service); + } + return service; + } catch (Exception ex) { + throw new SncpException(ex); + } + } +} diff --git a/src/main/java/org/redkale/net/sncp/SncpAsyncHandler.java b/src/main/java/org/redkale/net/sncp/SncpAsyncHandler.java index 9c06ff1ca..9b70199f1 100644 --- a/src/main/java/org/redkale/net/sncp/SncpAsyncHandler.java +++ b/src/main/java/org/redkale/net/sncp/SncpAsyncHandler.java @@ -1,232 +1,232 @@ -/* - * - */ -package org.redkale.net.sncp; - -import static org.redkale.asm.Opcodes.*; - -import java.lang.reflect.*; -import java.nio.channels.CompletionHandler; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import org.redkale.asm.*; -import org.redkale.asm.Type; -import org.redkale.util.*; - -/** - * 异步回调函数 - * - *

详情见: https://redkale.org + * + * @author zhangjx + * @param 结果对象的泛型 + * @param 附件对象的泛型 + * @since 2.8.0 + */ +public interface SncpAsyncHandler extends CompletionHandler { + + public static SncpAsyncHandler createHandler( + Class handlerClazz, CompletionHandler factHandler) { + Objects.requireNonNull(handlerClazz); + Objects.requireNonNull(factHandler); + if (handlerClazz == CompletionHandler.class) { + return new SncpAsyncHandler() { + @Override + public void completed(Object result, Object attachment) { + factHandler.completed(result, attachment); + } + + @Override + public void failed(Throwable exc, Object attachment) { + factHandler.failed(exc, attachment); + } + }; + } + return HandlerInner.creatorMap + .computeIfAbsent(handlerClazz, handlerClass -> { + // ------------------------------------------------------------- + final boolean handlerInterface = handlerClass.isInterface(); + final Class sncpHandlerClass = SncpAsyncHandler.class; + final String handlerClassName = handlerClass.getName().replace('.', '/'); + final String sncpHandlerName = sncpHandlerClass.getName().replace('.', '/'); + final String cpDesc = Type.getDescriptor(org.redkale.annotation.ConstructorParameters.class); + final String realHandlerName = + CompletionHandler.class.getName().replace('.', '/'); + final String realHandlerDesc = Type.getDescriptor(CompletionHandler.class); + final String newDynName = "org/redkaledyn/sncp/handler/_Dyn" + sncpHandlerClass.getSimpleName() + + "__" + handlerClass.getName().replace('.', '/').replace('$', '_'); + try { + Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.')); + Class newHandlerClazz = clz == null + ? Thread.currentThread().getContextClassLoader().loadClass(newDynName.replace('/', '.')) + : clz; + return (Creator) Creator.create(newHandlerClazz); + } catch (Throwable ex) { + // do nothing + } + // ------------------------------------------------------------------------------ + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); + FieldVisitor fv; + MethodDebugVisitor mv; + AnnotationVisitor av0; + cw.visit( + V11, + ACC_PUBLIC + ACC_FINAL + ACC_SUPER, + newDynName, + null, + handlerInterface ? "java/lang/Object" : handlerClassName, + handlerInterface && handlerClass != sncpHandlerClass + ? new String[] {handlerClassName, sncpHandlerName} + : new String[] {sncpHandlerName}); + + { // handler 属性 + fv = cw.visitField(ACC_PRIVATE, "factHandler", realHandlerDesc, null, null); + fv.visitEnd(); + } + { // 构造方法 + mv = new MethodDebugVisitor( + cw.visitMethod(ACC_PUBLIC, "", "(" + realHandlerDesc + ")V", null, null)); + // mv.setDebug(true); + { + av0 = mv.visitAnnotation(cpDesc, true); + { + AnnotationVisitor av1 = av0.visitArray("value"); + av1.visit(null, "factHandler"); + av1.visitEnd(); + } + av0.visitEnd(); + } + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn( + INVOKESPECIAL, + handlerInterface ? "java/lang/Object" : handlerClassName, + "", + "()V", + false); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 1); + mv.visitFieldInsn(PUTFIELD, newDynName, "factHandler", realHandlerDesc); + mv.visitInsn(RETURN); + mv.visitMaxs(2, 2); + mv.visitEnd(); + } + for (Method method : Sncp.loadNotImplMethods(handlerClass)) { // + int mod = method.getModifiers(); + String methodDesc = Type.getMethodDescriptor(method); + if (Modifier.isPublic(mod) + && "completed".equals(method.getName()) + && method.getParameterCount() == 2) { + mv = new MethodDebugVisitor( + cw.visitMethod(ACC_PUBLIC, "completed", methodDesc, null, null)); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, "factHandler", realHandlerDesc); + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 2); + mv.visitMethodInsn( + INVOKEINTERFACE, + realHandlerName, + "completed", + "(Ljava/lang/Object;Ljava/lang/Object;)V", + true); + mv.visitInsn(RETURN); + mv.visitMaxs(3, 3); + mv.visitEnd(); + // if (!"(Ljava/lang/Object;Ljava/lang/Object;)V".equals(methodDesc)) { + // mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC + ACC_BRIDGE + // + ACC_SYNTHETIC, "completed", "(Ljava/lang/Object;Ljava/lang/Object;)V", null, null)); + // mv.visitVarInsn(ALOAD, 0); + // mv.visitVarInsn(ALOAD, 1); + // mv.visitTypeInsn(CHECKCAST, "java/lang/Object"); + // mv.visitVarInsn(ALOAD, 2); + // mv.visitTypeInsn(CHECKCAST, "java/lang/Object"); + // mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "completed", + // methodDesc, false); + // mv.visitInsn(RETURN); + // mv.visitMaxs(3, 3); + // mv.visitEnd(); + // } + } else if (Modifier.isPublic(mod) + && "failed".equals(method.getName()) + && method.getParameterCount() == 2) { + mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "failed", methodDesc, null, null)); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, "factHandler", realHandlerDesc); + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 2); + mv.visitMethodInsn( + INVOKEINTERFACE, + realHandlerName, + "failed", + "(Ljava/lang/Throwable;Ljava/lang/Object;)V", + true); + mv.visitInsn(RETURN); + mv.visitMaxs(3, 3); + mv.visitEnd(); + // if (!"(Ljava/lang/Throwable;Ljava/lang/Object;)V".equals(methodDesc)) + // { + // mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC + ACC_BRIDGE + // + ACC_SYNTHETIC, "failed", "(Ljava/lang/Throwable;Ljava/lang/Object;)V", null, null)); + // mv.visitVarInsn(ALOAD, 0); + // mv.visitVarInsn(ALOAD, 1); + // mv.visitVarInsn(ALOAD, 2); + // mv.visitTypeInsn(CHECKCAST, "java/lang/Object"); + // mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "failed", + // methodDesc, false); + // mv.visitInsn(RETURN); + // mv.visitMaxs(3, 3); + // mv.visitEnd(); + // } + } else if (handlerInterface || Modifier.isAbstract(mod)) { + mv = new MethodDebugVisitor(cw.visitMethod( + ACC_PUBLIC, method.getName(), Type.getMethodDescriptor(method), null, null)); + Class returnType = method.getReturnType(); + if (returnType == void.class) { + mv.visitInsn(RETURN); + mv.visitMaxs(0, 1); + } else if (returnType.isPrimitive()) { + mv.visitInsn(ICONST_0); + if (returnType == long.class) { + mv.visitInsn(LRETURN); + mv.visitMaxs(2, 1); + } else if (returnType == float.class) { + mv.visitInsn(FRETURN); + mv.visitMaxs(2, 1); + } else if (returnType == double.class) { + mv.visitInsn(DRETURN); + mv.visitMaxs(2, 1); + } else { + mv.visitInsn(IRETURN); + mv.visitMaxs(1, 1); + } + } else { + mv.visitInsn(ACONST_NULL); + mv.visitInsn(ARETURN); + mv.visitMaxs(1, 1); + } + mv.visitEnd(); + } + } + cw.visitEnd(); + byte[] bytes = cw.toByteArray(); + Class newClazz = + new ClassLoader((handlerClass != CompletionHandler.class ? handlerClass : sncpHandlerClass) + .getClassLoader()) { + public final Class loadClass(String name, byte[] b) { + return defineClass(name, b, 0, b.length); + } + }.loadClass(newDynName.replace('/', '.'), bytes); + RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, newClazz); + return (Creator) Creator.create(newClazz); + }) + .create(factHandler); + } + + static class HandlerInner { + + static final Map> creatorMap = new ConcurrentHashMap<>(); + + private HandlerInner() { + // do nothing + } + } +} diff --git a/src/main/java/org/redkale/net/sncp/SncpClient.java b/src/main/java/org/redkale/net/sncp/SncpClient.java index 2aec649f7..08e4cdfeb 100644 --- a/src/main/java/org/redkale/net/sncp/SncpClient.java +++ b/src/main/java/org/redkale/net/sncp/SncpClient.java @@ -1,76 +1,76 @@ -/* - * - */ -package org.redkale.net.sncp; - -import java.net.InetSocketAddress; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.atomic.AtomicLong; -import org.redkale.net.*; -import org.redkale.net.client.*; - -/** - * SNCP版Client, 一个SncpServer只能对应一个SncpClient - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public class SncpClient extends Client { - - private final AtomicLong seqno = new AtomicLong(); - - final String nodeid; - - final InetSocketAddress clientSncpAddress; - - public SncpClient( - String name, - AsyncGroup group, - String nodeid, - InetSocketAddress clientSncpAddress, - ClientAddress address, - String netprotocol, - int maxConns, - int maxPipelines) { - super( - name, - group, - "TCP".equalsIgnoreCase(netprotocol), - address, - maxConns, - maxPipelines, - null, - null, - null); // maxConns - this.clientSncpAddress = clientSncpAddress; - this.nodeid = nodeid; - this.connectTimeoutSeconds = 10; - this.readTimeoutSeconds = 10; - this.writeTimeoutSeconds = 10; - } - - @Override - public SncpClientConnection createClientConnection(AsyncConnection channel) { - return new SncpClientConnection(this, channel); - } - - public InetSocketAddress getClientSncpAddress() { - return clientSncpAddress; - } - - public String getNodeid() { - return nodeid; - } - - protected long nextSeqno() { - // System.nanoTime()值并发下会出现重复,windows11 jdk17出现过 - return seqno.incrementAndGet(); - } - - @Override - protected CompletableFuture writeChannel(ClientConnection conn, SncpClientRequest request) { - return super.writeChannel(conn, request); - } -} +/* + * + */ +package org.redkale.net.sncp; + +import java.net.InetSocketAddress; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicLong; +import org.redkale.net.*; +import org.redkale.net.client.*; + +/** + * SNCP版Client, 一个SncpServer只能对应一个SncpClient + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public class SncpClient extends Client { + + private final AtomicLong seqno = new AtomicLong(); + + final String nodeid; + + final InetSocketAddress clientSncpAddress; + + public SncpClient( + String name, + AsyncGroup group, + String nodeid, + InetSocketAddress clientSncpAddress, + ClientAddress address, + String netprotocol, + int maxConns, + int maxPipelines) { + super( + name, + group, + "TCP".equalsIgnoreCase(netprotocol), + address, + maxConns, + maxPipelines, + null, + null, + null); // maxConns + this.clientSncpAddress = clientSncpAddress; + this.nodeid = nodeid; + this.connectTimeoutSeconds = 10; + this.readTimeoutSeconds = 10; + this.writeTimeoutSeconds = 10; + } + + @Override + public SncpClientConnection createClientConnection(AsyncConnection channel) { + return new SncpClientConnection(this, channel); + } + + public InetSocketAddress getClientSncpAddress() { + return clientSncpAddress; + } + + public String getNodeid() { + return nodeid; + } + + protected long nextSeqno() { + // System.nanoTime()值并发下会出现重复,windows11 jdk17出现过 + return seqno.incrementAndGet(); + } + + @Override + protected CompletableFuture writeChannel(ClientConnection conn, SncpClientRequest request) { + return super.writeChannel(conn, request); + } +} diff --git a/src/main/java/org/redkale/net/sncp/SncpClientCodec.java b/src/main/java/org/redkale/net/sncp/SncpClientCodec.java index 90132081f..2e838ffd1 100644 --- a/src/main/java/org/redkale/net/sncp/SncpClientCodec.java +++ b/src/main/java/org/redkale/net/sncp/SncpClientCodec.java @@ -1,159 +1,159 @@ -/* - * - */ -package org.redkale.net.sncp; - -import java.nio.ByteBuffer; -import java.util.logging.Logger; -import org.redkale.net.client.ClientCodec; -import org.redkale.util.*; - -/** - * SncpClient编解码器 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public class SncpClientCodec extends ClientCodec { - - protected static final Logger logger = Logger.getLogger(SncpClientCodec.class.getSimpleName()); - - private ByteArray recyclableArray; - - private ByteArray halfBodyBytes; - - private ByteArray halfHeaderBytes; - - private int halfHeaderSize; - - private Byte halfHeaderSizeFirstByte; - - SncpClientResult lastResult = null; - - public SncpClientCodec(SncpClientConnection connection) { - super(connection); - } - - protected SncpClientResult pollResult(SncpClientRequest request) { - return new SncpClientResult(); - } - - protected void offerResult(SncpClientResult rs) { - // do nothing - } - - protected ByteArray pollArray() { - if (recyclableArray == null) { - recyclableArray = new ByteArray(); - return recyclableArray; - } - recyclableArray.clear(); - return recyclableArray; - } - - @Override - public void decodeMessages(ByteBuffer realBuf, ByteArray array) { - ByteBuffer buffer = realBuf; - while (buffer.hasRemaining()) { - if (this.halfHeaderBytes != null) { - if (buffer.remaining() + halfHeaderBytes.length() < halfHeaderSize - 2) { // buffer不足以读取完整header - halfHeaderBytes.put(buffer); - return; - } - halfHeaderBytes.put(buffer, halfHeaderSize - 2 - halfHeaderBytes.length()); - // 读取完整header - SncpClientResult result = new SncpClientResult(); - result.readHeader(halfHeaderBytes, halfHeaderSize); - halfHeaderSize = 0; - if (!result.getHeader().isValid()) { - occurError(null, new SncpException("sncp header not valid")); - return; - } - halfHeaderBytes = null; - if (result.getBodyLength() < 1) { - addMessage(findRequest(result.getRequestid()), result); - lastResult = null; - continue; - } - // 还需要读body - lastResult = result; - } - if (lastResult != null) { // lastResult的body没有读完 - if (halfBodyBytes != null) { - if (buffer.remaining() + halfBodyBytes.length() < lastResult.getBodyLength()) { // buffer不足以读取完整body - halfBodyBytes.put(buffer); - return; - } - halfBodyBytes.put(buffer, lastResult.getBodyLength() - halfBodyBytes.length()); - // 读取完整body - lastResult.setBodyContent(halfBodyBytes.getBytes()); - // if (halfBodyBytes.length() != lastResult.getBodyLength()) { - // logger.log(Level.SEVERE, "halfBodyBytes.length must be " + lastResult.getBodyLength() + ", but - // " + halfBodyBytes.length()); - // } - halfBodyBytes = null; - addMessage(findRequest(lastResult.getRequestid()), lastResult); - lastResult = null; - continue; - } - if (buffer.remaining() < lastResult.getBodyLength()) { // buffer不足以读取完整body - halfBodyBytes = pollArray(); - halfBodyBytes.put(buffer); - return; - } - // 有足够的数据读取完整body - lastResult.readBody(buffer); - halfBodyBytes = null; - // if (lastResult.getBodyContent().length != lastResult.getBodyLength()) { - // logger.log(Level.SEVERE, "lastResult.length must be " + lastResult.getBodyLength() + ", but " + - // lastResult.getBodyContent().length); - // } - addMessage(findRequest(lastResult.getRequestid()), lastResult); - lastResult = null; - continue; - } - if (this.halfHeaderSize < 1) { - if (buffer.remaining() < 2) { // 只有一个字节 - this.halfHeaderSizeFirstByte = buffer.get(); - return; - } else { - if (this.halfHeaderSizeFirstByte != null) { - byte secondByte = buffer.get(); - this.halfHeaderSize = (0xff00 & (this.halfHeaderSizeFirstByte << 8)) | (0xff & secondByte); - } else { - this.halfHeaderSize = buffer.getChar(); - } - this.halfHeaderSizeFirstByte = null; - if (buffer.remaining() < this.halfHeaderSize - 2) { // buffer不足以读取完整header - this.halfHeaderBytes = pollArray(); - this.halfHeaderBytes.put(buffer); - return; - } - } - } - SncpClientResult result = new SncpClientResult(); - result.readHeader(buffer, halfHeaderSize); - halfHeaderSize = 0; - if (!result.getHeader().isValid()) { - occurError(null, new SncpException("sncp header not valid")); - return; - } - if (result.getBodyLength() < 1) { - addMessage(findRequest(result.getRequestid()), result); - lastResult = null; - continue; - } - if (buffer.remaining() < result.getBodyLength()) { // buffer不足以读取完整body - lastResult = result; - halfBodyBytes = pollArray(); - halfBodyBytes.put(buffer); - return; - } - result.readBody(buffer); - addMessage(findRequest(result.getRequestid()), result); - lastResult = null; - } - } -} +/* + * + */ +package org.redkale.net.sncp; + +import java.nio.ByteBuffer; +import java.util.logging.Logger; +import org.redkale.net.client.ClientCodec; +import org.redkale.util.*; + +/** + * SncpClient编解码器 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public class SncpClientCodec extends ClientCodec { + + protected static final Logger logger = Logger.getLogger(SncpClientCodec.class.getSimpleName()); + + private ByteArray recyclableArray; + + private ByteArray halfBodyBytes; + + private ByteArray halfHeaderBytes; + + private int halfHeaderSize; + + private Byte halfHeaderSizeFirstByte; + + SncpClientResult lastResult = null; + + public SncpClientCodec(SncpClientConnection connection) { + super(connection); + } + + protected SncpClientResult pollResult(SncpClientRequest request) { + return new SncpClientResult(); + } + + protected void offerResult(SncpClientResult rs) { + // do nothing + } + + protected ByteArray pollArray() { + if (recyclableArray == null) { + recyclableArray = new ByteArray(); + return recyclableArray; + } + recyclableArray.clear(); + return recyclableArray; + } + + @Override + public void decodeMessages(ByteBuffer realBuf, ByteArray array) { + ByteBuffer buffer = realBuf; + while (buffer.hasRemaining()) { + if (this.halfHeaderBytes != null) { + if (buffer.remaining() + halfHeaderBytes.length() < halfHeaderSize - 2) { // buffer不足以读取完整header + halfHeaderBytes.put(buffer); + return; + } + halfHeaderBytes.put(buffer, halfHeaderSize - 2 - halfHeaderBytes.length()); + // 读取完整header + SncpClientResult result = new SncpClientResult(); + result.readHeader(halfHeaderBytes, halfHeaderSize); + halfHeaderSize = 0; + if (!result.getHeader().isValid()) { + occurError(null, new SncpException("sncp header not valid")); + return; + } + halfHeaderBytes = null; + if (result.getBodyLength() < 1) { + addMessage(findRequest(result.getRequestid()), result); + lastResult = null; + continue; + } + // 还需要读body + lastResult = result; + } + if (lastResult != null) { // lastResult的body没有读完 + if (halfBodyBytes != null) { + if (buffer.remaining() + halfBodyBytes.length() < lastResult.getBodyLength()) { // buffer不足以读取完整body + halfBodyBytes.put(buffer); + return; + } + halfBodyBytes.put(buffer, lastResult.getBodyLength() - halfBodyBytes.length()); + // 读取完整body + lastResult.setBodyContent(halfBodyBytes.getBytes()); + // if (halfBodyBytes.length() != lastResult.getBodyLength()) { + // logger.log(Level.SEVERE, "halfBodyBytes.length must be " + lastResult.getBodyLength() + ", but + // " + halfBodyBytes.length()); + // } + halfBodyBytes = null; + addMessage(findRequest(lastResult.getRequestid()), lastResult); + lastResult = null; + continue; + } + if (buffer.remaining() < lastResult.getBodyLength()) { // buffer不足以读取完整body + halfBodyBytes = pollArray(); + halfBodyBytes.put(buffer); + return; + } + // 有足够的数据读取完整body + lastResult.readBody(buffer); + halfBodyBytes = null; + // if (lastResult.getBodyContent().length != lastResult.getBodyLength()) { + // logger.log(Level.SEVERE, "lastResult.length must be " + lastResult.getBodyLength() + ", but " + + // lastResult.getBodyContent().length); + // } + addMessage(findRequest(lastResult.getRequestid()), lastResult); + lastResult = null; + continue; + } + if (this.halfHeaderSize < 1) { + if (buffer.remaining() < 2) { // 只有一个字节 + this.halfHeaderSizeFirstByte = buffer.get(); + return; + } else { + if (this.halfHeaderSizeFirstByte != null) { + byte secondByte = buffer.get(); + this.halfHeaderSize = (0xff00 & (this.halfHeaderSizeFirstByte << 8)) | (0xff & secondByte); + } else { + this.halfHeaderSize = buffer.getChar(); + } + this.halfHeaderSizeFirstByte = null; + if (buffer.remaining() < this.halfHeaderSize - 2) { // buffer不足以读取完整header + this.halfHeaderBytes = pollArray(); + this.halfHeaderBytes.put(buffer); + return; + } + } + } + SncpClientResult result = new SncpClientResult(); + result.readHeader(buffer, halfHeaderSize); + halfHeaderSize = 0; + if (!result.getHeader().isValid()) { + occurError(null, new SncpException("sncp header not valid")); + return; + } + if (result.getBodyLength() < 1) { + addMessage(findRequest(result.getRequestid()), result); + lastResult = null; + continue; + } + if (buffer.remaining() < result.getBodyLength()) { // buffer不足以读取完整body + lastResult = result; + halfBodyBytes = pollArray(); + halfBodyBytes.put(buffer); + return; + } + result.readBody(buffer); + addMessage(findRequest(result.getRequestid()), result); + lastResult = null; + } + } +} diff --git a/src/main/java/org/redkale/net/sncp/SncpClientConnection.java b/src/main/java/org/redkale/net/sncp/SncpClientConnection.java index 7671311d8..62562c80c 100644 --- a/src/main/java/org/redkale/net/sncp/SncpClientConnection.java +++ b/src/main/java/org/redkale/net/sncp/SncpClientConnection.java @@ -1,41 +1,41 @@ -/* - * - */ -package org.redkale.net.sncp; - -import org.redkale.net.AsyncConnection; -import org.redkale.net.client.*; -import org.redkale.util.ObjectPool; - -/** - * client版连接 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public class SncpClientConnection extends ClientConnection { - - private final ObjectPool requestPool; - - public SncpClientConnection(SncpClient client, AsyncConnection channel) { - super(client, channel); - requestPool = ObjectPool.createUnsafePool( - Thread.currentThread(), - 256, - ObjectPool.createSafePool( - 256, t -> new SncpClientRequest(), SncpClientRequest::prepare, SncpClientRequest::recycle)); - } - - @Override - protected ClientCodec createCodec() { - return new SncpClientCodec(this); - } - - protected void offerResult(SncpClientRequest req, SncpClientResult rs) { - SncpClientCodec c = getCodec(); - c.offerResult(rs); - requestPool.accept(req); - } -} +/* + * + */ +package org.redkale.net.sncp; + +import org.redkale.net.AsyncConnection; +import org.redkale.net.client.*; +import org.redkale.util.ObjectPool; + +/** + * client版连接 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public class SncpClientConnection extends ClientConnection { + + private final ObjectPool requestPool; + + public SncpClientConnection(SncpClient client, AsyncConnection channel) { + super(client, channel); + requestPool = ObjectPool.createUnsafePool( + Thread.currentThread(), + 256, + ObjectPool.createSafePool( + 256, t -> new SncpClientRequest(), SncpClientRequest::prepare, SncpClientRequest::recycle)); + } + + @Override + protected ClientCodec createCodec() { + return new SncpClientCodec(this); + } + + protected void offerResult(SncpClientRequest req, SncpClientResult rs) { + SncpClientCodec c = getCodec(); + c.offerResult(rs); + requestPool.accept(req); + } +} diff --git a/src/main/java/org/redkale/net/sncp/SncpClientRequest.java b/src/main/java/org/redkale/net/sncp/SncpClientRequest.java index 3f10cdb2f..46b018ebc 100644 --- a/src/main/java/org/redkale/net/sncp/SncpClientRequest.java +++ b/src/main/java/org/redkale/net/sncp/SncpClientRequest.java @@ -1,90 +1,90 @@ -/* - * - */ -package org.redkale.net.sncp; - -import java.io.Serializable; -import java.util.Objects; -import org.redkale.net.client.*; -import org.redkale.util.ByteArray; - -/** - * client版请求 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public class SncpClientRequest extends ClientRequest { - - private SncpHeader header; - - private long seqid; - - private byte[] bodyContent; - - public SncpClientRequest() { - // do nothing - } - - public SncpClientRequest prepare(SncpHeader header, long seqid, String traceid, byte[] bodyContent) { - super.prepare(); - this.header = header; - this.seqid = seqid; - this.traceid = traceid; - this.bodyContent = bodyContent; - return this; - } - - @Override - protected void prepare() { - // do nothing - } - - @Override - protected boolean recycle() { - boolean rs = super.recycle(); - this.header = null; - this.seqid = 0; - this.traceid = null; - this.bodyContent = null; - return rs; - } - - @Override - public Serializable getRequestid() { - return seqid; - } - - @Override - public void writeTo(ClientConnection conn, ByteArray array) { - array.putPlaceholder(SncpHeader.calcHeaderSize(this)); - if (bodyContent == null) { - header.writeTo(array, this, SncpHeader.KEEPALIVE_ON, 0, 0); - } else { - header.writeTo(array, this, SncpHeader.KEEPALIVE_ON, bodyContent.length, 0); - array.put(bodyContent); - } - } - - @Override - public String toString() { - return getClass().getSimpleName() + "_" + Objects.hashCode(this) + "{" - + "header=" + header + ", seqid =" + seqid + ", traceid =" + traceid - + ", body=[" + (bodyContent == null ? -1 : bodyContent.length) + "]" - + "}"; - } - - public SncpHeader getHeader() { - return header; - } - - public long getSeqid() { - return seqid; - } - - public byte[] getBodyContent() { - return bodyContent; - } -} +/* + * + */ +package org.redkale.net.sncp; + +import java.io.Serializable; +import java.util.Objects; +import org.redkale.net.client.*; +import org.redkale.util.ByteArray; + +/** + * client版请求 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public class SncpClientRequest extends ClientRequest { + + private SncpHeader header; + + private long seqid; + + private byte[] bodyContent; + + public SncpClientRequest() { + // do nothing + } + + public SncpClientRequest prepare(SncpHeader header, long seqid, String traceid, byte[] bodyContent) { + super.prepare(); + this.header = header; + this.seqid = seqid; + this.traceid = traceid; + this.bodyContent = bodyContent; + return this; + } + + @Override + protected void prepare() { + // do nothing + } + + @Override + protected boolean recycle() { + boolean rs = super.recycle(); + this.header = null; + this.seqid = 0; + this.traceid = null; + this.bodyContent = null; + return rs; + } + + @Override + public Serializable getRequestid() { + return seqid; + } + + @Override + public void writeTo(ClientConnection conn, ByteArray array) { + array.putPlaceholder(SncpHeader.calcHeaderSize(this)); + if (bodyContent == null) { + header.writeTo(array, this, SncpHeader.KEEPALIVE_ON, 0, 0); + } else { + header.writeTo(array, this, SncpHeader.KEEPALIVE_ON, bodyContent.length, 0); + array.put(bodyContent); + } + } + + @Override + public String toString() { + return getClass().getSimpleName() + "_" + Objects.hashCode(this) + "{" + + "header=" + header + ", seqid =" + seqid + ", traceid =" + traceid + + ", body=[" + (bodyContent == null ? -1 : bodyContent.length) + "]" + + "}"; + } + + public SncpHeader getHeader() { + return header; + } + + public long getSeqid() { + return seqid; + } + + public byte[] getBodyContent() { + return bodyContent; + } +} diff --git a/src/main/java/org/redkale/net/sncp/SncpClientResult.java b/src/main/java/org/redkale/net/sncp/SncpClientResult.java index dd04f00d9..2d603b26c 100644 --- a/src/main/java/org/redkale/net/sncp/SncpClientResult.java +++ b/src/main/java/org/redkale/net/sncp/SncpClientResult.java @@ -1,85 +1,85 @@ -/* - * - */ -package org.redkale.net.sncp; - -import java.io.Serializable; -import java.nio.ByteBuffer; -import java.util.Objects; -import org.redkale.net.client.ClientResult; -import org.redkale.util.ByteArray; - -/** - * client版响应结果 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public class SncpClientResult implements ClientResult { - - private SncpHeader header; - - private byte[] bodyContent; - - // protected void prepare() { - // //do nothing - // } - - protected boolean recycle() { - this.header = null; - this.bodyContent = null; - return true; - } - - protected boolean readHeader(ByteBuffer buffer, int headerSize) { - this.header = SncpHeader.read(buffer, headerSize); - return this.header.isValid(); - } - - protected boolean readHeader(ByteArray array, int headerSize) { - this.header = SncpHeader.read(array, headerSize); - return this.header.isValid(); - } - - protected boolean readBody(ByteBuffer buffer) { - byte[] body = new byte[header.getBodyLength()]; - buffer.get(body); - this.bodyContent = body; - return true; - } - - public Serializable getRequestid() { - return header == null ? null : header.getSeqid(); - } - - @Override - public boolean isKeepAlive() { - return header != null && header.isKeepAlive(); - } - - @Override - public String toString() { - return getClass().getSimpleName() + "_" + Objects.hashCode(this) + "{" - + "header=" + header - + ", body=[" + (bodyContent == null ? -1 : bodyContent.length) + "]" - + "}"; - } - - public int getBodyLength() { - return header.getBodyLength(); - } - - public SncpHeader getHeader() { - return header; - } - - public byte[] getBodyContent() { - return bodyContent; - } - - public void setBodyContent(byte[] bodyContent) { - this.bodyContent = bodyContent; - } -} +/* + * + */ +package org.redkale.net.sncp; + +import java.io.Serializable; +import java.nio.ByteBuffer; +import java.util.Objects; +import org.redkale.net.client.ClientResult; +import org.redkale.util.ByteArray; + +/** + * client版响应结果 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public class SncpClientResult implements ClientResult { + + private SncpHeader header; + + private byte[] bodyContent; + + // protected void prepare() { + // //do nothing + // } + + protected boolean recycle() { + this.header = null; + this.bodyContent = null; + return true; + } + + protected boolean readHeader(ByteBuffer buffer, int headerSize) { + this.header = SncpHeader.read(buffer, headerSize); + return this.header.isValid(); + } + + protected boolean readHeader(ByteArray array, int headerSize) { + this.header = SncpHeader.read(array, headerSize); + return this.header.isValid(); + } + + protected boolean readBody(ByteBuffer buffer) { + byte[] body = new byte[header.getBodyLength()]; + buffer.get(body); + this.bodyContent = body; + return true; + } + + public Serializable getRequestid() { + return header == null ? null : header.getSeqid(); + } + + @Override + public boolean isKeepAlive() { + return header != null && header.isKeepAlive(); + } + + @Override + public String toString() { + return getClass().getSimpleName() + "_" + Objects.hashCode(this) + "{" + + "header=" + header + + ", body=[" + (bodyContent == null ? -1 : bodyContent.length) + "]" + + "}"; + } + + public int getBodyLength() { + return header.getBodyLength(); + } + + public SncpHeader getHeader() { + return header; + } + + public byte[] getBodyContent() { + return bodyContent; + } + + public void setBodyContent(byte[] bodyContent) { + this.bodyContent = bodyContent; + } +} diff --git a/src/main/java/org/redkale/net/sncp/SncpException.java b/src/main/java/org/redkale/net/sncp/SncpException.java index b3a51e686..8d226bdc0 100644 --- a/src/main/java/org/redkale/net/sncp/SncpException.java +++ b/src/main/java/org/redkale/net/sncp/SncpException.java @@ -1,33 +1,33 @@ -/* - * - */ -package org.redkale.net.sncp; - -import org.redkale.util.RedkaleException; - -/** - * Sncp自定义异常类 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public class SncpException extends RedkaleException { - - public SncpException() { - super(); - } - - public SncpException(String s) { - super(s); - } - - public SncpException(String message, Throwable cause) { - super(message, cause); - } - - public SncpException(Throwable cause) { - super(cause); - } -} +/* + * + */ +package org.redkale.net.sncp; + +import org.redkale.util.RedkaleException; + +/** + * Sncp自定义异常类 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public class SncpException extends RedkaleException { + + public SncpException() { + super(); + } + + public SncpException(String s) { + super(s); + } + + public SncpException(String message, Throwable cause) { + super(message, cause); + } + + public SncpException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/org/redkale/net/sncp/SncpHeader.java b/src/main/java/org/redkale/net/sncp/SncpHeader.java index b31bc93aa..84db5aabb 100644 --- a/src/main/java/org/redkale/net/sncp/SncpHeader.java +++ b/src/main/java/org/redkale/net/sncp/SncpHeader.java @@ -1,304 +1,304 @@ -/* - * - */ -package org.redkale.net.sncp; - -import java.net.InetSocketAddress; -import java.nio.ByteBuffer; -import java.nio.charset.StandardCharsets; -import java.util.Objects; -import org.redkale.util.*; - -/** @author zhangjx */ -public class SncpHeader { - - public static final int HEADER_SUBSIZE = 69; - - public static final byte KEEPALIVE_ON = 0; - - public static final byte KEEPALIVE_OFF = -1; - - private Long seqid; - - private Uint128 serviceid; - - String serviceName; - - // sncp协议版本 - private int sncpVersion; - - private Uint128 actionid; - - String methodName; - - // SncpRequest的值是clientSncpAddress,SncpResponse的值是serverSncpAddress - private byte[] addrBytes; - - // 响应方地址端口 - private int addrPort; - - // 保持连接,0:keepAlive; -1:关闭连接 - private byte keepAlive; - - // 时间戳 - private long timestamp; - - // 日志ID - private String traceid; - - // 结果码,非0表示错误 - private int retcode; - - // body长度 - private int bodyLength; - - private boolean valid; - - private SncpHeader() {} - - public static SncpHeader create( - InetSocketAddress clientSncpAddress, - Uint128 serviceid, - String serviceName, - Uint128 actionid, - String methodName) { - SncpHeader header = new SncpHeader(); - header.addrBytes = clientSncpAddress == null - ? new byte[4] - : clientSncpAddress.getAddress().getAddress(); - header.addrPort = clientSncpAddress == null ? 0 : clientSncpAddress.getPort(); - header.serviceid = serviceid; - header.serviceName = serviceName; - header.actionid = actionid; - header.methodName = methodName; - if (header.addrBytes.length != 4) { - throw new SncpException("address bytes length must be 4, but " + header.addrBytes.length); - } - return header; - } - - // 此处的buffer不包含开头headerSize的两字节,返回Header Size - public static SncpHeader read(ByteBuffer buffer, final int headerSize) { - SncpHeader header = new SncpHeader(); - header.valid = headerSize > HEADER_SUBSIZE; // 2 - header.sncpVersion = buffer.getInt(); // 4 - header.seqid = buffer.getLong(); // 8 - header.serviceid = Uint128.read(buffer); // 16 - header.actionid = Uint128.read(buffer); // 16 - if (header.addrBytes == null) { - header.addrBytes = new byte[4]; - } - buffer.get(header.addrBytes); // addr 4 - header.addrPort = buffer.getChar(); // port 2 - header.keepAlive = buffer.get(); // 1 - header.timestamp = buffer.getLong(); // 8 - int traceSize = buffer.getChar(); // 2 - if (traceSize > 0) { - byte[] traces = new byte[traceSize]; - buffer.get(traces); - header.traceid = new String(traces, StandardCharsets.UTF_8); - } - header.retcode = buffer.getInt(); // 4 - header.bodyLength = buffer.getInt(); // 4 - return header; - } - - // 此处的array不包含开头headerSize的两字节,返回Header Size - public static SncpHeader read(ByteArray array, final int headerSize) { - SncpHeader header = new SncpHeader(); - header.valid = headerSize > HEADER_SUBSIZE; // 2 - int offset = 0; - header.sncpVersion = array.getInt(offset); // 4 - offset += 4; - header.seqid = array.getLong(offset); // 8 - offset += 8; - header.serviceid = array.getUint128(offset); // 16 - offset += 16; - header.actionid = array.getUint128(offset); // 16 - offset += 16; - header.addrBytes = array.getBytes(offset, 4); // addr 4 - offset += 4; - header.addrPort = array.getChar(offset); // port 2 - offset += 2; - header.keepAlive = array.get(offset); // 1 - offset += 1; - header.timestamp = array.getLong(offset); // 8 - offset += 8; - int traceSize = array.getChar(offset); // 2 - offset += 2; - if (traceSize > 0) { - byte[] traces = array.getBytes(offset, traceSize); - header.traceid = new String(traces, StandardCharsets.UTF_8); - offset += traceSize; - } - header.retcode = array.getInt(offset); // 4 - offset += 4; - header.bodyLength = array.getInt(offset); // 4 - return header; - } - - public ByteArray writeTo( - ByteArray array, SncpClientRequest clientRequest, byte keepAlive, int bodyLength, int retcode) { - return writeTo( - array, - this.addrBytes, - this.addrPort, - (Long) clientRequest.getRequestid(), - clientRequest.traceBytes(), - keepAlive, - bodyLength, - retcode); - } - - public ByteArray writeTo(ByteArray array, SncpResponse response, byte keepAlive, int bodyLength, int retcode) { - SncpRequest request = response.request(); - return writeTo( - array, - response.addrBytes, - response.addrPort, - (Long) request.getRequestid(), - request.traceBytes(), - keepAlive, - bodyLength, - retcode); - } - - private ByteArray writeTo( - ByteArray array, - byte[] newAddrBytes, - int newAddrPort, - long newSeqid, - byte[] traces, - byte keepAlive, - int bodyLength, - int retcode) { - if (newAddrBytes.length != 4) { - throw new SncpException("address bytes length must be 4, but " + newAddrBytes.length); - } - if (traces == null) { - traces = SncpClientRequest.EMPTY_TRACEID; - } - int size = HEADER_SUBSIZE + 2 + traces.length; - if (array.length() < size) { - throw new SncpException("ByteArray length must more " + size); - } - int offset = 0; - array.putChar(offset, (char) size); // 2 - offset += 2; - array.putInt(offset, sncpVersion); // 4 - offset += 4; - array.putLong(offset, newSeqid); // 8 - offset += 8; - array.putUint128(offset, serviceid); // 16 - offset += 16; - array.putUint128(offset, actionid); // 16 - offset += 16; - array.put(offset, newAddrBytes); // 4 - offset += 4; - array.putChar(offset, (char) newAddrPort); // 2 - offset += 2; - array.put(offset, keepAlive); // 1 - offset += 1; - array.putLong(offset, System.currentTimeMillis()); // 8 - offset += 8; - array.putChar(offset, (char) traces.length); // 2 - offset += 2; - if (traces.length > 0) { - array.put(offset, traces); // traces.length - offset += traces.length; - } - array.putInt(offset, retcode); // 4 - offset += 4; - array.putInt(offset, bodyLength); // 4 - return array; - } - - @Override - public String toString() { - return getClass().getSimpleName() - + (this.seqid == null - ? ("{serviceid=" + this.serviceid + ",serviceName=" + this.serviceName) - : ("{seqid=" + this.seqid + ",serviceid=" + this.serviceid + ",serviceName=" - + this.serviceName)) - + ",sncpVersion=" + this.sncpVersion - + ",actionid=" + this.actionid - + ",methodName=" + this.methodName - + ",address=" + getAddress() - + ",keepAlive=" + isKeepAlive() - + ",timestamp=" + this.timestamp - + ",traceid=" + getTraceid() - + ",retcode=" + this.retcode - + ",bodyLength=" + this.bodyLength - + "}"; - } - - public InetSocketAddress getAddress() { - return addrBytes == null - ? null - : new InetSocketAddress( - (0xff & addrBytes[0]) + "." + (0xff & addrBytes[1]) + "." + (0xff & addrBytes[2]) + "." - + (0xff & addrBytes[3]), - addrPort); - } - - public boolean isValid() { - return valid; - } - - public boolean isKeepAlive() { - return keepAlive != -1; - } - - // 供client端request和response的header判断 - public boolean checkValid(SncpHeader other) { - return Objects.equals(this.serviceid, other.serviceid) && Objects.equals(this.actionid, other.actionid); - } - - public static int calcHeaderSize(SncpClientRequest request) { - return HEADER_SUBSIZE + 2 + request.traceBytes().length; - } - - public static int calcHeaderSize(SncpRequest request) { - return HEADER_SUBSIZE + 2 + request.traceBytes().length; - } - - public Long getSeqid() { - return seqid; - } - - public Uint128 getServiceid() { - return serviceid; - } - - public int getSncpVersion() { - return sncpVersion; - } - - public Uint128 getActionid() { - return actionid; - } - - public byte[] getAddrBytes() { - return addrBytes; - } - - public int getAddrPort() { - return addrPort; - } - - public long getTimestamp() { - return timestamp; - } - - public String getTraceid() { - return traceid; - } - - public int getRetcode() { - return retcode; - } - - public int getBodyLength() { - return bodyLength; - } -} +/* + * + */ +package org.redkale.net.sncp; + +import java.net.InetSocketAddress; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.Objects; +import org.redkale.util.*; + +/** @author zhangjx */ +public class SncpHeader { + + public static final int HEADER_SUBSIZE = 69; + + public static final byte KEEPALIVE_ON = 0; + + public static final byte KEEPALIVE_OFF = -1; + + private Long seqid; + + private Uint128 serviceid; + + String serviceName; + + // sncp协议版本 + private int sncpVersion; + + private Uint128 actionid; + + String methodName; + + // SncpRequest的值是clientSncpAddress,SncpResponse的值是serverSncpAddress + private byte[] addrBytes; + + // 响应方地址端口 + private int addrPort; + + // 保持连接,0:keepAlive; -1:关闭连接 + private byte keepAlive; + + // 时间戳 + private long timestamp; + + // 日志ID + private String traceid; + + // 结果码,非0表示错误 + private int retcode; + + // body长度 + private int bodyLength; + + private boolean valid; + + private SncpHeader() {} + + public static SncpHeader create( + InetSocketAddress clientSncpAddress, + Uint128 serviceid, + String serviceName, + Uint128 actionid, + String methodName) { + SncpHeader header = new SncpHeader(); + header.addrBytes = clientSncpAddress == null + ? new byte[4] + : clientSncpAddress.getAddress().getAddress(); + header.addrPort = clientSncpAddress == null ? 0 : clientSncpAddress.getPort(); + header.serviceid = serviceid; + header.serviceName = serviceName; + header.actionid = actionid; + header.methodName = methodName; + if (header.addrBytes.length != 4) { + throw new SncpException("address bytes length must be 4, but " + header.addrBytes.length); + } + return header; + } + + // 此处的buffer不包含开头headerSize的两字节,返回Header Size + public static SncpHeader read(ByteBuffer buffer, final int headerSize) { + SncpHeader header = new SncpHeader(); + header.valid = headerSize > HEADER_SUBSIZE; // 2 + header.sncpVersion = buffer.getInt(); // 4 + header.seqid = buffer.getLong(); // 8 + header.serviceid = Uint128.read(buffer); // 16 + header.actionid = Uint128.read(buffer); // 16 + if (header.addrBytes == null) { + header.addrBytes = new byte[4]; + } + buffer.get(header.addrBytes); // addr 4 + header.addrPort = buffer.getChar(); // port 2 + header.keepAlive = buffer.get(); // 1 + header.timestamp = buffer.getLong(); // 8 + int traceSize = buffer.getChar(); // 2 + if (traceSize > 0) { + byte[] traces = new byte[traceSize]; + buffer.get(traces); + header.traceid = new String(traces, StandardCharsets.UTF_8); + } + header.retcode = buffer.getInt(); // 4 + header.bodyLength = buffer.getInt(); // 4 + return header; + } + + // 此处的array不包含开头headerSize的两字节,返回Header Size + public static SncpHeader read(ByteArray array, final int headerSize) { + SncpHeader header = new SncpHeader(); + header.valid = headerSize > HEADER_SUBSIZE; // 2 + int offset = 0; + header.sncpVersion = array.getInt(offset); // 4 + offset += 4; + header.seqid = array.getLong(offset); // 8 + offset += 8; + header.serviceid = array.getUint128(offset); // 16 + offset += 16; + header.actionid = array.getUint128(offset); // 16 + offset += 16; + header.addrBytes = array.getBytes(offset, 4); // addr 4 + offset += 4; + header.addrPort = array.getChar(offset); // port 2 + offset += 2; + header.keepAlive = array.get(offset); // 1 + offset += 1; + header.timestamp = array.getLong(offset); // 8 + offset += 8; + int traceSize = array.getChar(offset); // 2 + offset += 2; + if (traceSize > 0) { + byte[] traces = array.getBytes(offset, traceSize); + header.traceid = new String(traces, StandardCharsets.UTF_8); + offset += traceSize; + } + header.retcode = array.getInt(offset); // 4 + offset += 4; + header.bodyLength = array.getInt(offset); // 4 + return header; + } + + public ByteArray writeTo( + ByteArray array, SncpClientRequest clientRequest, byte keepAlive, int bodyLength, int retcode) { + return writeTo( + array, + this.addrBytes, + this.addrPort, + (Long) clientRequest.getRequestid(), + clientRequest.traceBytes(), + keepAlive, + bodyLength, + retcode); + } + + public ByteArray writeTo(ByteArray array, SncpResponse response, byte keepAlive, int bodyLength, int retcode) { + SncpRequest request = response.request(); + return writeTo( + array, + response.addrBytes, + response.addrPort, + (Long) request.getRequestid(), + request.traceBytes(), + keepAlive, + bodyLength, + retcode); + } + + private ByteArray writeTo( + ByteArray array, + byte[] newAddrBytes, + int newAddrPort, + long newSeqid, + byte[] traces, + byte keepAlive, + int bodyLength, + int retcode) { + if (newAddrBytes.length != 4) { + throw new SncpException("address bytes length must be 4, but " + newAddrBytes.length); + } + if (traces == null) { + traces = SncpClientRequest.EMPTY_TRACEID; + } + int size = HEADER_SUBSIZE + 2 + traces.length; + if (array.length() < size) { + throw new SncpException("ByteArray length must more " + size); + } + int offset = 0; + array.putChar(offset, (char) size); // 2 + offset += 2; + array.putInt(offset, sncpVersion); // 4 + offset += 4; + array.putLong(offset, newSeqid); // 8 + offset += 8; + array.putUint128(offset, serviceid); // 16 + offset += 16; + array.putUint128(offset, actionid); // 16 + offset += 16; + array.put(offset, newAddrBytes); // 4 + offset += 4; + array.putChar(offset, (char) newAddrPort); // 2 + offset += 2; + array.put(offset, keepAlive); // 1 + offset += 1; + array.putLong(offset, System.currentTimeMillis()); // 8 + offset += 8; + array.putChar(offset, (char) traces.length); // 2 + offset += 2; + if (traces.length > 0) { + array.put(offset, traces); // traces.length + offset += traces.length; + } + array.putInt(offset, retcode); // 4 + offset += 4; + array.putInt(offset, bodyLength); // 4 + return array; + } + + @Override + public String toString() { + return getClass().getSimpleName() + + (this.seqid == null + ? ("{serviceid=" + this.serviceid + ",serviceName=" + this.serviceName) + : ("{seqid=" + this.seqid + ",serviceid=" + this.serviceid + ",serviceName=" + + this.serviceName)) + + ",sncpVersion=" + this.sncpVersion + + ",actionid=" + this.actionid + + ",methodName=" + this.methodName + + ",address=" + getAddress() + + ",keepAlive=" + isKeepAlive() + + ",timestamp=" + this.timestamp + + ",traceid=" + getTraceid() + + ",retcode=" + this.retcode + + ",bodyLength=" + this.bodyLength + + "}"; + } + + public InetSocketAddress getAddress() { + return addrBytes == null + ? null + : new InetSocketAddress( + (0xff & addrBytes[0]) + "." + (0xff & addrBytes[1]) + "." + (0xff & addrBytes[2]) + "." + + (0xff & addrBytes[3]), + addrPort); + } + + public boolean isValid() { + return valid; + } + + public boolean isKeepAlive() { + return keepAlive != -1; + } + + // 供client端request和response的header判断 + public boolean checkValid(SncpHeader other) { + return Objects.equals(this.serviceid, other.serviceid) && Objects.equals(this.actionid, other.actionid); + } + + public static int calcHeaderSize(SncpClientRequest request) { + return HEADER_SUBSIZE + 2 + request.traceBytes().length; + } + + public static int calcHeaderSize(SncpRequest request) { + return HEADER_SUBSIZE + 2 + request.traceBytes().length; + } + + public Long getSeqid() { + return seqid; + } + + public Uint128 getServiceid() { + return serviceid; + } + + public int getSncpVersion() { + return sncpVersion; + } + + public Uint128 getActionid() { + return actionid; + } + + public byte[] getAddrBytes() { + return addrBytes; + } + + public int getAddrPort() { + return addrPort; + } + + public long getTimestamp() { + return timestamp; + } + + public String getTraceid() { + return traceid; + } + + public int getRetcode() { + return retcode; + } + + public int getBodyLength() { + return bodyLength; + } +} diff --git a/src/main/java/org/redkale/net/sncp/SncpRemoteInfo.java b/src/main/java/org/redkale/net/sncp/SncpRemoteInfo.java index 66993b5a8..e6a56bbbb 100644 --- a/src/main/java/org/redkale/net/sncp/SncpRemoteInfo.java +++ b/src/main/java/org/redkale/net/sncp/SncpRemoteInfo.java @@ -1,545 +1,545 @@ -/* - * - */ -package org.redkale.net.sncp; - -import static org.redkale.net.sncp.Sncp.loadRemoteMethodActions; -import static org.redkale.net.sncp.SncpHeader.HEADER_SUBSIZE; - -import java.lang.annotation.Annotation; -import java.lang.reflect.*; -import java.net.*; -import java.nio.ByteBuffer; -import java.nio.channels.CompletionHandler; -import java.util.*; -import java.util.concurrent.*; -import java.util.logging.*; -import org.redkale.convert.*; -import org.redkale.convert.json.JsonConvert; -import org.redkale.mq.spi.MessageAgent; -import org.redkale.mq.spi.MessageClient; -import org.redkale.mq.spi.MessageRecord; -import org.redkale.service.*; -import org.redkale.util.*; - -/** - * 每个Service的client相关信息对象 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @param Service泛型 - * @since 2.8.0 - */ -public class SncpRemoteInfo { - - protected static final Logger logger = Logger.getLogger(SncpRemoteInfo.class.getSimpleName()); - - protected final String name; - - protected final Class serviceType; - - protected final Uint128 serviceid; - - protected final String resourceid; - - protected final int serviceVersion; - - // key: actionid.Uint128.toString() - protected final Map actions = new HashMap<>(); - - // 非MQ模式下此字段才有值 - protected final SncpRpcGroups sncpRpcGroups; - - // 非MQ模式下此字段才有值 - protected final SncpClient sncpClient; - - // 非MQ模式下此字段才有值, 可能为null - protected String remoteGroup; - - // 非MQ模式下此字段才有值, 可能为null - protected Set remoteAddresses; - - // 默认值: BsonConvert.root() - protected final Convert convert; - - // MQ模式下此字段才有值 - protected final String topic; - - // MQ模式下此字段才有值 - protected final MessageAgent messageAgent; - - // MQ模式下此字段才有值 - protected final MessageClient messageClient; - - SncpRemoteInfo( - String resourceName, - Class resourceType, - Class serviceImplClass, - Convert convert, - SncpRpcGroups sncpRpcGroups, - SncpClient sncpClient, - MessageAgent messageAgent, - String remoteGroup) { - Objects.requireNonNull(sncpRpcGroups); - this.name = resourceName; - this.serviceType = resourceType; - this.resourceid = Sncp.resourceid(resourceName, resourceType); - this.serviceid = Sncp.serviceid(resourceName, resourceType); - this.convert = convert; - this.serviceVersion = 0; - this.sncpRpcGroups = sncpRpcGroups; - this.sncpClient = sncpClient; - this.messageAgent = messageAgent; - this.remoteGroup = remoteGroup; - this.messageClient = messageAgent == null ? null : messageAgent.getSncpMessageClient(); - this.topic = messageAgent == null - ? null - : Sncp.generateSncpReqTopic(resourceName, resourceType, messageAgent.getNodeid()); - - for (Map.Entry en : - loadRemoteMethodActions(Sncp.getServiceType(serviceImplClass)).entrySet()) { - this.actions.put( - en.getKey().toString(), - new SncpRemoteAction( - serviceImplClass, resourceType, en.getValue(), serviceid, en.getKey(), sncpClient)); - } - } - - // 由远程模式的DyncRemoveService调用 - public T remote(final String actionid, final Object... params) { - final SncpRemoteAction action = this.actions.get(actionid); - CompletionHandler callbackHandler = null; - Object callbackHandlerAttach = null; - if (action.paramHandlerIndex >= 0) { - callbackHandler = (CompletionHandler) params[action.paramHandlerIndex]; - params[action.paramHandlerIndex] = null; - if (action.paramHandlerAttachIndex >= 0) { - callbackHandlerAttach = params[action.paramHandlerAttachIndex]; - params[action.paramHandlerAttachIndex] = null; - } - } - final CompletableFuture future = remote(action, Traces.currentTraceid(), params); - if (action.paramHandlerIndex >= 0) { // 参数中存在CompletionHandler - final CompletionHandler handler = callbackHandler; - final Object attach = callbackHandlerAttach; - if (handler == null) { // 传入的CompletionHandler参数为null - future.join(); - } else { - future.whenComplete((v, t) -> { - if (t == null) { - // v,length-1为了读掉(byte)0 - handler.completed( - v == null - ? null - : convert.convertFrom(action.paramHandlerResultType, v, 1, v.length - 1), - attach); - } else { - handler.failed(t, attach); - } - }); - } - } else if (action.returnFutureClass != null) { // 返回类型为CompletableFuture - if (action.returnFutureClass == CompletableFuture.class) { - // v,length-1为了读掉(byte)0 - return (T) future.thenApply( - v -> v == null ? null : convert.convertFrom(action.returnFutureResultType, v, 1, v.length - 1)); - } else { - final CompletableFuture returnFuture = action.returnFutureCreator.create(); - future.whenComplete((v, t) -> { - if (t == null) { - // v,length-1为了读掉(byte)0 - returnFuture.complete( - v == null - ? null - : convert.convertFrom(action.returnFutureResultType, v, 1, v.length - 1)); - } else { - returnFuture.completeExceptionally(t); - } - }); - return (T) returnFuture; - } - } else if (action.returnObjectType != null) { // 返回类型为JavaBean - // v,length-1为了读掉(byte)0 - return (T) future.thenApply( - v -> v == null ? null : convert.convertFrom(action.returnObjectType, v, 1, v.length - 1)) - .join(); - } else { // 返回类型为void - future.join(); - } - return null; - } - - private CompletableFuture remote( - final SncpRemoteAction action, final String traceid, final Object[] params) { - if (messageAgent != null) { - return remoteMessage(action, traceid, params); - } else { - return remoteClient(action, traceid, params); - } - } - - // MQ模式RPC - private CompletableFuture remoteMessage( - final SncpRemoteAction action, final String traceid, final Object[] params) { - final SncpClientRequest request = - createSncpClientRequest(action, this.sncpClient.clientSncpAddress, traceid, params); - String targetTopic = - action.paramTopicTargetIndex >= 0 ? (String) params[action.paramTopicTargetIndex] : this.topic; - if (targetTopic == null) { - targetTopic = this.topic; - } - ByteArray array = new ByteArray(); - request.writeTo(null, array); - MessageRecord message = messageAgent - .getSncpMessageClient() - .createMessageRecord(MessageRecord.CTYPE_BSON, targetTopic, null, array.getBytes()); - final String tt = targetTopic; - message.localActionName(action.actionName()); - message.localParams(params); - return messageClient.sendMessage(message).thenApply(msg -> { - if (msg == null || msg.getContent() == null) { - logger.log( - Level.SEVERE, - action.method + " sncp mq(params: " + JsonConvert.root().convertTo(params) + ", message: " - + message + ") deal error, this.topic = " + this.topic + ", targetTopic = " + tt - + ", result = " + msg); - return null; - } - ByteBuffer buffer = ByteBuffer.wrap(msg.getContent()); - int headerSize = buffer.getChar(); - if (headerSize <= HEADER_SUBSIZE) { - throw new SncpException("sncp header length must more " + HEADER_SUBSIZE + ", but is " + headerSize); - } - SncpHeader header = SncpHeader.read(buffer, headerSize); - if (!header.checkValid(action.header)) { - throw new SncpException( - "sncp header error, response-header:" + action.header + "+, response-header:" + header); - } - final int retcode = header.getRetcode(); - if (retcode != 0) { - logger.log( - Level.SEVERE, - action.method + " sncp (params: " + JsonConvert.root().convertTo(params) - + ") deal error (retcode=" + retcode + ", retinfo=" - + SncpResponse.getRetCodeInfo(retcode) - + "), params=" + JsonConvert.root().convertTo(params)); - throw new SncpException("remote service(" + action.method + ") deal error (retcode=" + retcode - + ", retinfo=" + SncpResponse.getRetCodeInfo(retcode) + ")"); - } - final int respBodyLength = header.getBodyLength(); - byte[] body = new byte[respBodyLength]; - buffer.get(body, 0, respBodyLength); - return body; - }); - } - - // Client模式RPC - protected CompletableFuture remoteClient( - final SncpRemoteAction action, final String traceid, final Object[] params) { - final SncpClient client = this.sncpClient; - final SncpClientRequest request = createSncpClientRequest(action, client.clientSncpAddress, traceid, params); - final SocketAddress addr = action.paramAddressTargetIndex >= 0 - ? (SocketAddress) params[action.paramAddressTargetIndex] - : nextRemoteAddress(); - return client.connect(addr) - .thenCompose(conn -> client.writeChannel(conn, request).thenApply(rs -> rs.getBodyContent())); - } - - protected SncpClientRequest createSncpClientRequest( - SncpRemoteAction action, InetSocketAddress clientSncpAddress, String traceid, Object[] params) { - final Type[] myParamTypes = action.paramTypes; - final Class[] myParamClass = action.paramClasses; - if (action.paramAddressSourceIndex >= 0) { - params[action.paramAddressSourceIndex] = clientSncpAddress; - } - byte[] body = null; - if (myParamTypes.length > 0) { - Writer writer = convert.pollWriter(); - for (int i = 0; i < params.length; i++) { // service方法的参数 - convert.convertTo( - writer, - CompletionHandler.class.isAssignableFrom(myParamClass[i]) - ? CompletionHandler.class - : myParamTypes[i], - params[i]); - } - body = ((ByteTuple) writer).toArray(); - convert.offerWriter(writer); - } - final SncpClientRequest request = new SncpClientRequest(); - request.prepare(action.header, this.sncpClient.nextSeqno(), traceid, body); - return request; - } - - protected InetSocketAddress nextRemoteAddress() { - InetSocketAddress addr = sncpRpcGroups.nextRemoteAddress(resourceid); - if (addr != null) { - return addr; - } - SncpRpcGroup srg = sncpRpcGroups.getSncpRpcGroup(remoteGroup); - if (srg != null) { - Set addrs = srg.getAddresses(); - if (!addrs.isEmpty()) { - Iterator it = addrs.iterator(); - if (it.hasNext()) { - return it.next(); - } - } - } - throw new SncpException( - "Not found SocketAddress by remoteGroup = " + remoteGroup + ", resourceid = " + resourceid); - } - - @Override - public String toString() { - InetSocketAddress clientSncpAddress = sncpClient == null ? null : sncpClient.getClientSncpAddress(); - return this.getClass().getSimpleName() + "(service = " + serviceType.getSimpleName() + ", serviceid = " - + serviceid - + ", serviceVersion = " + serviceVersion + ", name = '" + name - + "', address = " - + (clientSncpAddress == null - ? "" - : (clientSncpAddress.getHostString() + ":" + clientSncpAddress.getPort())) - + ", actions.size = " + actions.size() + ")"; - } - - public String toSimpleString() { // 给Sncp产生的Service用 - InetSocketAddress clientSncpAddress = sncpClient == null ? null : sncpClient.getClientSncpAddress(); - return serviceType.getSimpleName() + "(name = '" + name + "', serviceid = " + serviceid + ", serviceVersion = " - + serviceVersion - + ", clientaddr = " - + (clientSncpAddress == null - ? "" - : (clientSncpAddress.getHostString() + ":" + clientSncpAddress.getPort())) - + ((remoteGroup == null || remoteGroup.isEmpty()) ? "" : ", remoteGroup = " + remoteGroup) - + ", actions.size = " + actions.size() + ")"; - } - - public void updateRemoteAddress(String remoteGroup, Set remoteAddresses) { - this.remoteGroup = remoteGroup; - this.remoteAddresses = remoteAddresses; - } - - public String getName() { - return name; - } - - public Class getServiceClass() { - return serviceType; - } - - public Uint128 getServiceid() { - return serviceid; - } - - public int getServiceVersion() { - return serviceVersion; - } - - public SncpRemoteAction[] getActions() { - return actions.values().toArray(new SncpRemoteAction[actions.size()]); - } - - public String getTopic() { - return topic; - } - - public String getRemoteGroup() { - return remoteGroup; - } - - public Set getRemoteAddresses() { - return remoteAddresses; - } - - public static final class SncpRemoteAction { - - protected final Uint128 actionid; - - protected final Method method; - - protected final Type returnObjectType; // void必须设为null - - protected final Type[] paramTypes; - - protected final Class[] paramClasses; - - protected final int paramHandlerIndex; - - protected final int paramHandlerAttachIndex; - - protected final int paramAddressTargetIndex; - - protected final int paramAddressSourceIndex; - - protected final int paramTopicTargetIndex; - - protected final Class paramHandlerClass; // CompletionHandler参数的类型 - - protected final java.lang.reflect.Type paramHandlerResultType; // CompletionHandler.completed第一个参数的类型 - - protected final java.lang.reflect.Type returnFutureResultType; // 返回结果的CompletableFuture的结果泛型类型 - - protected final Class returnFutureClass; // 返回结果的CompletableFuture类型 - - protected final Creator returnFutureCreator; // 返回CompletableFuture类型的构建器 - - protected final SncpHeader header; - - @SuppressWarnings("unchecked") - SncpRemoteAction( - final Class serviceImplClass, - Class resourceType, - Method method, - Uint128 serviceid, - Uint128 actionid, - final SncpClient sncpClient) { - this.actionid = actionid == null ? Sncp.actionid(method) : actionid; - Type rt = TypeToken.getGenericType(method.getGenericReturnType(), serviceImplClass); - this.returnObjectType = rt == void.class || rt == Void.class ? null : rt; - this.paramTypes = TypeToken.getGenericType(method.getGenericParameterTypes(), serviceImplClass); - this.paramClasses = method.getParameterTypes(); - this.method = method; - Annotation[][] anns = method.getParameterAnnotations(); - int tpoicAddrIndex = -1; - int targetAddrIndex = -1; - int sourceAddrIndex = -1; - int handlerAttachIndex = -1; - int handlerFuncIndex = -1; - Class handlerFuncClass = null; - java.lang.reflect.Type handlerResultType = null; - Class[] params = method.getParameterTypes(); - Type[] genericParams = method.getGenericParameterTypes(); - for (int i = 0; i < params.length; i++) { - if (CompletionHandler.class.isAssignableFrom(params[i])) { - if (Future.class.isAssignableFrom(method.getReturnType())) { - throw new SncpException(method + " have both CompletionHandler and CompletableFuture"); - } - if (handlerFuncIndex >= 0) { - throw new SncpException(method + " have more than one CompletionHandler type parameter"); - } - Sncp.checkAsyncModifier(params[i], method); - handlerFuncIndex = i; - handlerFuncClass = paramClasses[i]; - java.lang.reflect.Type handlerType = TypeToken.getGenericType(genericParams[i], serviceImplClass); - if (handlerType instanceof Class) { - handlerResultType = Object.class; - } else if (handlerType instanceof ParameterizedType) { - handlerResultType = TypeToken.getGenericType( - ((ParameterizedType) handlerType).getActualTypeArguments()[0], handlerType); - } else { - throw new SncpException(serviceImplClass + " had unknown genericType in " + method); - } - if (method.getReturnType() != void.class) { - throw new SncpException( - method + " have CompletionHandler type parameter but return type is not void"); - } - break; - } - } - if (anns.length > 0) { - for (int i = 0; i < anns.length; i++) { - if (anns[i].length > 0) { - for (Annotation ann : anns[i]) { - if (ann.annotationType() == RpcAttachment.class) { - if (handlerAttachIndex >= 0) { - throw new SncpException(method + " have more than one @RpcAttachment parameter"); - } - handlerAttachIndex = i; - } else if (ann.annotationType() == RpcTargetAddress.class) { - if (SocketAddress.class.isAssignableFrom(params[i])) { - if (sourceAddrIndex >= 0) { - throw new SncpException( - method + " have more than one @RpcTargetAddress parameter"); - } else { - targetAddrIndex = i; - } - } else { - throw new SncpException( - method + " must be SocketAddress Type on @RpcTargetAddress parameter"); - } - } else if (ann.annotationType() == RpcSourceAddress.class) { - if (SocketAddress.class.isAssignableFrom(params[i])) { - if (sourceAddrIndex >= 0) { - throw new SncpException( - method + " have more than one @RpcSourceAddress parameter"); - } else { - sourceAddrIndex = i; - } - } else { - throw new SncpException( - method + " must be SocketAddress Type on @RpcSourceAddress parameter"); - } - } else if (ann.annotationType() == RpcTargetTopic.class) { - if (String.class.isAssignableFrom(params[i])) { - if (sourceAddrIndex >= 0) { - throw new SncpException( - method + " have more than one @RpcTargetTopic parameter"); - } else { - tpoicAddrIndex = i; - } - } else { - throw new SncpException( - method + " must be String Type on @RpcTargetTopic parameter"); - } - } - } - } - } - } - this.paramTopicTargetIndex = tpoicAddrIndex; - this.paramAddressTargetIndex = targetAddrIndex; - this.paramAddressSourceIndex = sourceAddrIndex; - this.paramHandlerIndex = handlerFuncIndex; - this.paramHandlerClass = handlerFuncClass; - this.paramHandlerResultType = handlerResultType; - this.paramHandlerAttachIndex = handlerAttachIndex; - this.header = SncpHeader.create( - sncpClient == null ? null : sncpClient.getClientSncpAddress(), - serviceid, - resourceType.getName(), - actionid, - method.getName()); - if (this.paramHandlerIndex >= 0 && method.getReturnType() != void.class) { - throw new SncpException(method + " have CompletionHandler type parameter but return type is not void"); - } - if (Future.class.isAssignableFrom(method.getReturnType())) { - java.lang.reflect.Type futureType = - TypeToken.getGenericType(method.getGenericReturnType(), serviceImplClass); - java.lang.reflect.Type returnType = null; - if (futureType instanceof Class) { - returnType = Object.class; - } else if (futureType instanceof ParameterizedType) { - returnType = TypeToken.getGenericType( - ((ParameterizedType) futureType).getActualTypeArguments()[0], futureType); - } else { - throw new SncpException(serviceImplClass + " had unknown return genericType in " + method); - } - this.returnFutureResultType = returnType; - this.returnFutureClass = method.getReturnType().isAssignableFrom(CompletableFuture.class) - ? CompletableFuture.class - : (Class) method.getReturnType(); - if (method.getReturnType().isAssignableFrom(CompletableFuture.class) - || CompletableFuture.class.isAssignableFrom(method.getReturnType())) { - this.returnFutureCreator = (Creator) Creator.create(this.returnFutureClass); - } else { - throw new SncpException(serviceImplClass + " return must be CompletableFuture or subclass"); - } - } else { - this.returnFutureResultType = null; - this.returnFutureClass = null; - this.returnFutureCreator = null; - } - } - - public String actionName() { - return method.getDeclaringClass().getSimpleName() + "." + method.getName(); - } - - @Override - public String toString() { - return "{" + actionid + "," + (method == null ? "null" : method.getName()) + "}"; - } - } -} +/* + * + */ +package org.redkale.net.sncp; + +import static org.redkale.net.sncp.Sncp.loadRemoteMethodActions; +import static org.redkale.net.sncp.SncpHeader.HEADER_SUBSIZE; + +import java.lang.annotation.Annotation; +import java.lang.reflect.*; +import java.net.*; +import java.nio.ByteBuffer; +import java.nio.channels.CompletionHandler; +import java.util.*; +import java.util.concurrent.*; +import java.util.logging.*; +import org.redkale.convert.*; +import org.redkale.convert.json.JsonConvert; +import org.redkale.mq.spi.MessageAgent; +import org.redkale.mq.spi.MessageClient; +import org.redkale.mq.spi.MessageRecord; +import org.redkale.service.*; +import org.redkale.util.*; + +/** + * 每个Service的client相关信息对象 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @param Service泛型 + * @since 2.8.0 + */ +public class SncpRemoteInfo { + + protected static final Logger logger = Logger.getLogger(SncpRemoteInfo.class.getSimpleName()); + + protected final String name; + + protected final Class serviceType; + + protected final Uint128 serviceid; + + protected final String resourceid; + + protected final int serviceVersion; + + // key: actionid.Uint128.toString() + protected final Map actions = new HashMap<>(); + + // 非MQ模式下此字段才有值 + protected final SncpRpcGroups sncpRpcGroups; + + // 非MQ模式下此字段才有值 + protected final SncpClient sncpClient; + + // 非MQ模式下此字段才有值, 可能为null + protected String remoteGroup; + + // 非MQ模式下此字段才有值, 可能为null + protected Set remoteAddresses; + + // 默认值: BsonConvert.root() + protected final Convert convert; + + // MQ模式下此字段才有值 + protected final String topic; + + // MQ模式下此字段才有值 + protected final MessageAgent messageAgent; + + // MQ模式下此字段才有值 + protected final MessageClient messageClient; + + SncpRemoteInfo( + String resourceName, + Class resourceType, + Class serviceImplClass, + Convert convert, + SncpRpcGroups sncpRpcGroups, + SncpClient sncpClient, + MessageAgent messageAgent, + String remoteGroup) { + Objects.requireNonNull(sncpRpcGroups); + this.name = resourceName; + this.serviceType = resourceType; + this.resourceid = Sncp.resourceid(resourceName, resourceType); + this.serviceid = Sncp.serviceid(resourceName, resourceType); + this.convert = convert; + this.serviceVersion = 0; + this.sncpRpcGroups = sncpRpcGroups; + this.sncpClient = sncpClient; + this.messageAgent = messageAgent; + this.remoteGroup = remoteGroup; + this.messageClient = messageAgent == null ? null : messageAgent.getSncpMessageClient(); + this.topic = messageAgent == null + ? null + : Sncp.generateSncpReqTopic(resourceName, resourceType, messageAgent.getNodeid()); + + for (Map.Entry en : + loadRemoteMethodActions(Sncp.getServiceType(serviceImplClass)).entrySet()) { + this.actions.put( + en.getKey().toString(), + new SncpRemoteAction( + serviceImplClass, resourceType, en.getValue(), serviceid, en.getKey(), sncpClient)); + } + } + + // 由远程模式的DyncRemoveService调用 + public T remote(final String actionid, final Object... params) { + final SncpRemoteAction action = this.actions.get(actionid); + CompletionHandler callbackHandler = null; + Object callbackHandlerAttach = null; + if (action.paramHandlerIndex >= 0) { + callbackHandler = (CompletionHandler) params[action.paramHandlerIndex]; + params[action.paramHandlerIndex] = null; + if (action.paramHandlerAttachIndex >= 0) { + callbackHandlerAttach = params[action.paramHandlerAttachIndex]; + params[action.paramHandlerAttachIndex] = null; + } + } + final CompletableFuture future = remote(action, Traces.currentTraceid(), params); + if (action.paramHandlerIndex >= 0) { // 参数中存在CompletionHandler + final CompletionHandler handler = callbackHandler; + final Object attach = callbackHandlerAttach; + if (handler == null) { // 传入的CompletionHandler参数为null + future.join(); + } else { + future.whenComplete((v, t) -> { + if (t == null) { + // v,length-1为了读掉(byte)0 + handler.completed( + v == null + ? null + : convert.convertFrom(action.paramHandlerResultType, v, 1, v.length - 1), + attach); + } else { + handler.failed(t, attach); + } + }); + } + } else if (action.returnFutureClass != null) { // 返回类型为CompletableFuture + if (action.returnFutureClass == CompletableFuture.class) { + // v,length-1为了读掉(byte)0 + return (T) future.thenApply( + v -> v == null ? null : convert.convertFrom(action.returnFutureResultType, v, 1, v.length - 1)); + } else { + final CompletableFuture returnFuture = action.returnFutureCreator.create(); + future.whenComplete((v, t) -> { + if (t == null) { + // v,length-1为了读掉(byte)0 + returnFuture.complete( + v == null + ? null + : convert.convertFrom(action.returnFutureResultType, v, 1, v.length - 1)); + } else { + returnFuture.completeExceptionally(t); + } + }); + return (T) returnFuture; + } + } else if (action.returnObjectType != null) { // 返回类型为JavaBean + // v,length-1为了读掉(byte)0 + return (T) future.thenApply( + v -> v == null ? null : convert.convertFrom(action.returnObjectType, v, 1, v.length - 1)) + .join(); + } else { // 返回类型为void + future.join(); + } + return null; + } + + private CompletableFuture remote( + final SncpRemoteAction action, final String traceid, final Object[] params) { + if (messageAgent != null) { + return remoteMessage(action, traceid, params); + } else { + return remoteClient(action, traceid, params); + } + } + + // MQ模式RPC + private CompletableFuture remoteMessage( + final SncpRemoteAction action, final String traceid, final Object[] params) { + final SncpClientRequest request = + createSncpClientRequest(action, this.sncpClient.clientSncpAddress, traceid, params); + String targetTopic = + action.paramTopicTargetIndex >= 0 ? (String) params[action.paramTopicTargetIndex] : this.topic; + if (targetTopic == null) { + targetTopic = this.topic; + } + ByteArray array = new ByteArray(); + request.writeTo(null, array); + MessageRecord message = messageAgent + .getSncpMessageClient() + .createMessageRecord(MessageRecord.CTYPE_BSON, targetTopic, null, array.getBytes()); + final String tt = targetTopic; + message.localActionName(action.actionName()); + message.localParams(params); + return messageClient.sendMessage(message).thenApply(msg -> { + if (msg == null || msg.getContent() == null) { + logger.log( + Level.SEVERE, + action.method + " sncp mq(params: " + JsonConvert.root().convertTo(params) + ", message: " + + message + ") deal error, this.topic = " + this.topic + ", targetTopic = " + tt + + ", result = " + msg); + return null; + } + ByteBuffer buffer = ByteBuffer.wrap(msg.getContent()); + int headerSize = buffer.getChar(); + if (headerSize <= HEADER_SUBSIZE) { + throw new SncpException("sncp header length must more " + HEADER_SUBSIZE + ", but is " + headerSize); + } + SncpHeader header = SncpHeader.read(buffer, headerSize); + if (!header.checkValid(action.header)) { + throw new SncpException( + "sncp header error, response-header:" + action.header + "+, response-header:" + header); + } + final int retcode = header.getRetcode(); + if (retcode != 0) { + logger.log( + Level.SEVERE, + action.method + " sncp (params: " + JsonConvert.root().convertTo(params) + + ") deal error (retcode=" + retcode + ", retinfo=" + + SncpResponse.getRetCodeInfo(retcode) + + "), params=" + JsonConvert.root().convertTo(params)); + throw new SncpException("remote service(" + action.method + ") deal error (retcode=" + retcode + + ", retinfo=" + SncpResponse.getRetCodeInfo(retcode) + ")"); + } + final int respBodyLength = header.getBodyLength(); + byte[] body = new byte[respBodyLength]; + buffer.get(body, 0, respBodyLength); + return body; + }); + } + + // Client模式RPC + protected CompletableFuture remoteClient( + final SncpRemoteAction action, final String traceid, final Object[] params) { + final SncpClient client = this.sncpClient; + final SncpClientRequest request = createSncpClientRequest(action, client.clientSncpAddress, traceid, params); + final SocketAddress addr = action.paramAddressTargetIndex >= 0 + ? (SocketAddress) params[action.paramAddressTargetIndex] + : nextRemoteAddress(); + return client.connect(addr) + .thenCompose(conn -> client.writeChannel(conn, request).thenApply(rs -> rs.getBodyContent())); + } + + protected SncpClientRequest createSncpClientRequest( + SncpRemoteAction action, InetSocketAddress clientSncpAddress, String traceid, Object[] params) { + final Type[] myParamTypes = action.paramTypes; + final Class[] myParamClass = action.paramClasses; + if (action.paramAddressSourceIndex >= 0) { + params[action.paramAddressSourceIndex] = clientSncpAddress; + } + byte[] body = null; + if (myParamTypes.length > 0) { + Writer writer = convert.pollWriter(); + for (int i = 0; i < params.length; i++) { // service方法的参数 + convert.convertTo( + writer, + CompletionHandler.class.isAssignableFrom(myParamClass[i]) + ? CompletionHandler.class + : myParamTypes[i], + params[i]); + } + body = ((ByteTuple) writer).toArray(); + convert.offerWriter(writer); + } + final SncpClientRequest request = new SncpClientRequest(); + request.prepare(action.header, this.sncpClient.nextSeqno(), traceid, body); + return request; + } + + protected InetSocketAddress nextRemoteAddress() { + InetSocketAddress addr = sncpRpcGroups.nextRemoteAddress(resourceid); + if (addr != null) { + return addr; + } + SncpRpcGroup srg = sncpRpcGroups.getSncpRpcGroup(remoteGroup); + if (srg != null) { + Set addrs = srg.getAddresses(); + if (!addrs.isEmpty()) { + Iterator it = addrs.iterator(); + if (it.hasNext()) { + return it.next(); + } + } + } + throw new SncpException( + "Not found SocketAddress by remoteGroup = " + remoteGroup + ", resourceid = " + resourceid); + } + + @Override + public String toString() { + InetSocketAddress clientSncpAddress = sncpClient == null ? null : sncpClient.getClientSncpAddress(); + return this.getClass().getSimpleName() + "(service = " + serviceType.getSimpleName() + ", serviceid = " + + serviceid + + ", serviceVersion = " + serviceVersion + ", name = '" + name + + "', address = " + + (clientSncpAddress == null + ? "" + : (clientSncpAddress.getHostString() + ":" + clientSncpAddress.getPort())) + + ", actions.size = " + actions.size() + ")"; + } + + public String toSimpleString() { // 给Sncp产生的Service用 + InetSocketAddress clientSncpAddress = sncpClient == null ? null : sncpClient.getClientSncpAddress(); + return serviceType.getSimpleName() + "(name = '" + name + "', serviceid = " + serviceid + ", serviceVersion = " + + serviceVersion + + ", clientaddr = " + + (clientSncpAddress == null + ? "" + : (clientSncpAddress.getHostString() + ":" + clientSncpAddress.getPort())) + + ((remoteGroup == null || remoteGroup.isEmpty()) ? "" : ", remoteGroup = " + remoteGroup) + + ", actions.size = " + actions.size() + ")"; + } + + public void updateRemoteAddress(String remoteGroup, Set remoteAddresses) { + this.remoteGroup = remoteGroup; + this.remoteAddresses = remoteAddresses; + } + + public String getName() { + return name; + } + + public Class getServiceClass() { + return serviceType; + } + + public Uint128 getServiceid() { + return serviceid; + } + + public int getServiceVersion() { + return serviceVersion; + } + + public SncpRemoteAction[] getActions() { + return actions.values().toArray(new SncpRemoteAction[actions.size()]); + } + + public String getTopic() { + return topic; + } + + public String getRemoteGroup() { + return remoteGroup; + } + + public Set getRemoteAddresses() { + return remoteAddresses; + } + + public static final class SncpRemoteAction { + + protected final Uint128 actionid; + + protected final Method method; + + protected final Type returnObjectType; // void必须设为null + + protected final Type[] paramTypes; + + protected final Class[] paramClasses; + + protected final int paramHandlerIndex; + + protected final int paramHandlerAttachIndex; + + protected final int paramAddressTargetIndex; + + protected final int paramAddressSourceIndex; + + protected final int paramTopicTargetIndex; + + protected final Class paramHandlerClass; // CompletionHandler参数的类型 + + protected final java.lang.reflect.Type paramHandlerResultType; // CompletionHandler.completed第一个参数的类型 + + protected final java.lang.reflect.Type returnFutureResultType; // 返回结果的CompletableFuture的结果泛型类型 + + protected final Class returnFutureClass; // 返回结果的CompletableFuture类型 + + protected final Creator returnFutureCreator; // 返回CompletableFuture类型的构建器 + + protected final SncpHeader header; + + @SuppressWarnings("unchecked") + SncpRemoteAction( + final Class serviceImplClass, + Class resourceType, + Method method, + Uint128 serviceid, + Uint128 actionid, + final SncpClient sncpClient) { + this.actionid = actionid == null ? Sncp.actionid(method) : actionid; + Type rt = TypeToken.getGenericType(method.getGenericReturnType(), serviceImplClass); + this.returnObjectType = rt == void.class || rt == Void.class ? null : rt; + this.paramTypes = TypeToken.getGenericType(method.getGenericParameterTypes(), serviceImplClass); + this.paramClasses = method.getParameterTypes(); + this.method = method; + Annotation[][] anns = method.getParameterAnnotations(); + int tpoicAddrIndex = -1; + int targetAddrIndex = -1; + int sourceAddrIndex = -1; + int handlerAttachIndex = -1; + int handlerFuncIndex = -1; + Class handlerFuncClass = null; + java.lang.reflect.Type handlerResultType = null; + Class[] params = method.getParameterTypes(); + Type[] genericParams = method.getGenericParameterTypes(); + for (int i = 0; i < params.length; i++) { + if (CompletionHandler.class.isAssignableFrom(params[i])) { + if (Future.class.isAssignableFrom(method.getReturnType())) { + throw new SncpException(method + " have both CompletionHandler and CompletableFuture"); + } + if (handlerFuncIndex >= 0) { + throw new SncpException(method + " have more than one CompletionHandler type parameter"); + } + Sncp.checkAsyncModifier(params[i], method); + handlerFuncIndex = i; + handlerFuncClass = paramClasses[i]; + java.lang.reflect.Type handlerType = TypeToken.getGenericType(genericParams[i], serviceImplClass); + if (handlerType instanceof Class) { + handlerResultType = Object.class; + } else if (handlerType instanceof ParameterizedType) { + handlerResultType = TypeToken.getGenericType( + ((ParameterizedType) handlerType).getActualTypeArguments()[0], handlerType); + } else { + throw new SncpException(serviceImplClass + " had unknown genericType in " + method); + } + if (method.getReturnType() != void.class) { + throw new SncpException( + method + " have CompletionHandler type parameter but return type is not void"); + } + break; + } + } + if (anns.length > 0) { + for (int i = 0; i < anns.length; i++) { + if (anns[i].length > 0) { + for (Annotation ann : anns[i]) { + if (ann.annotationType() == RpcAttachment.class) { + if (handlerAttachIndex >= 0) { + throw new SncpException(method + " have more than one @RpcAttachment parameter"); + } + handlerAttachIndex = i; + } else if (ann.annotationType() == RpcTargetAddress.class) { + if (SocketAddress.class.isAssignableFrom(params[i])) { + if (sourceAddrIndex >= 0) { + throw new SncpException( + method + " have more than one @RpcTargetAddress parameter"); + } else { + targetAddrIndex = i; + } + } else { + throw new SncpException( + method + " must be SocketAddress Type on @RpcTargetAddress parameter"); + } + } else if (ann.annotationType() == RpcSourceAddress.class) { + if (SocketAddress.class.isAssignableFrom(params[i])) { + if (sourceAddrIndex >= 0) { + throw new SncpException( + method + " have more than one @RpcSourceAddress parameter"); + } else { + sourceAddrIndex = i; + } + } else { + throw new SncpException( + method + " must be SocketAddress Type on @RpcSourceAddress parameter"); + } + } else if (ann.annotationType() == RpcTargetTopic.class) { + if (String.class.isAssignableFrom(params[i])) { + if (sourceAddrIndex >= 0) { + throw new SncpException( + method + " have more than one @RpcTargetTopic parameter"); + } else { + tpoicAddrIndex = i; + } + } else { + throw new SncpException( + method + " must be String Type on @RpcTargetTopic parameter"); + } + } + } + } + } + } + this.paramTopicTargetIndex = tpoicAddrIndex; + this.paramAddressTargetIndex = targetAddrIndex; + this.paramAddressSourceIndex = sourceAddrIndex; + this.paramHandlerIndex = handlerFuncIndex; + this.paramHandlerClass = handlerFuncClass; + this.paramHandlerResultType = handlerResultType; + this.paramHandlerAttachIndex = handlerAttachIndex; + this.header = SncpHeader.create( + sncpClient == null ? null : sncpClient.getClientSncpAddress(), + serviceid, + resourceType.getName(), + actionid, + method.getName()); + if (this.paramHandlerIndex >= 0 && method.getReturnType() != void.class) { + throw new SncpException(method + " have CompletionHandler type parameter but return type is not void"); + } + if (Future.class.isAssignableFrom(method.getReturnType())) { + java.lang.reflect.Type futureType = + TypeToken.getGenericType(method.getGenericReturnType(), serviceImplClass); + java.lang.reflect.Type returnType = null; + if (futureType instanceof Class) { + returnType = Object.class; + } else if (futureType instanceof ParameterizedType) { + returnType = TypeToken.getGenericType( + ((ParameterizedType) futureType).getActualTypeArguments()[0], futureType); + } else { + throw new SncpException(serviceImplClass + " had unknown return genericType in " + method); + } + this.returnFutureResultType = returnType; + this.returnFutureClass = method.getReturnType().isAssignableFrom(CompletableFuture.class) + ? CompletableFuture.class + : (Class) method.getReturnType(); + if (method.getReturnType().isAssignableFrom(CompletableFuture.class) + || CompletableFuture.class.isAssignableFrom(method.getReturnType())) { + this.returnFutureCreator = (Creator) Creator.create(this.returnFutureClass); + } else { + throw new SncpException(serviceImplClass + " return must be CompletableFuture or subclass"); + } + } else { + this.returnFutureResultType = null; + this.returnFutureClass = null; + this.returnFutureCreator = null; + } + } + + public String actionName() { + return method.getDeclaringClass().getSimpleName() + "." + method.getName(); + } + + @Override + public String toString() { + return "{" + actionid + "," + (method == null ? "null" : method.getName()) + "}"; + } + } +} diff --git a/src/main/java/org/redkale/net/sncp/SncpRpcGroup.java b/src/main/java/org/redkale/net/sncp/SncpRpcGroup.java index bf50abbe1..559af1147 100644 --- a/src/main/java/org/redkale/net/sncp/SncpRpcGroup.java +++ b/src/main/java/org/redkale/net/sncp/SncpRpcGroup.java @@ -1,150 +1,150 @@ -/* - * - */ -package org.redkale.net.sncp; - -import java.net.InetSocketAddress; -import java.util.*; -import java.util.concurrent.locks.ReentrantLock; -import org.redkale.convert.ConvertColumn; -import org.redkale.convert.json.JsonConvert; -import org.redkale.util.Utility; - -/** - * 协议地址组合对象, 对应application.xml 中 resources->group 节点信息 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public class SncpRpcGroup { - - protected final ReentrantLock lock = new ReentrantLock(); - - @ConvertColumn(index = 1) - protected String name; // 地址 - - @ConvertColumn(index = 2) - protected String protocol; // 协议 取值范围: TCP、UDP - - @ConvertColumn(index = 3) - protected Set addresses; // 地址列表, 对应 resources->group->node节点信息 - - public SncpRpcGroup() {} - - public SncpRpcGroup(String name, InetSocketAddress... addrs) { - this(name, "TCP", Utility.ofSet(addrs)); - } - - public SncpRpcGroup(String name, Set addrs) { - this(name, "TCP", addrs); - } - - public SncpRpcGroup(String name, String protocol, InetSocketAddress... addrs) { - this(name, protocol, Utility.ofSet(addrs)); - } - - public SncpRpcGroup(String name, String protocol, Set addresses) { - Objects.requireNonNull(name, "rpc.group.name can not null"); - this.name = name; - this.protocol = protocol == null ? "TCP" : protocol; - this.addresses = addresses; - } - - public String getName() { - return name; - } - - public void setName(String name) { - Objects.requireNonNull(name, "rpc.group.name can not null"); - this.name = name; - } - - public String getProtocol() { - return protocol; - } - - public void setProtocol(String protocol) { - this.protocol = protocol == null ? "TCP" : protocol; - } - - public Set getAddresses() { - return addresses; - } - - public Set copyAddresses() { - lock.lock(); - try { - return addresses == null ? null : new LinkedHashSet<>(addresses); - } finally { - lock.unlock(); - } - } - - public void setAddresses(Set addresses) { - this.addresses = addresses; - } - - public boolean containsAddress(InetSocketAddress addr) { - lock.lock(); - try { - if (this.addresses == null) { - return false; - } - return this.addresses.contains(addr); - } finally { - lock.unlock(); - } - } - - public void removeAddress(InetSocketAddress addr) { - if (addr == null) { - return; - } - lock.lock(); - try { - if (this.addresses == null) { - return; - } - this.addresses.remove(addr); - } finally { - lock.unlock(); - } - } - - public void putAddress(InetSocketAddress addr) { - if (addr == null) { - return; - } - lock.lock(); - try { - if (this.addresses == null) { - this.addresses = new LinkedHashSet<>(); - } - this.addresses.add(addr); - } finally { - lock.unlock(); - } - } - - public void putAddress(Set addrs) { - if (addrs == null) { - return; - } - lock.lock(); - try { - if (this.addresses == null) { - this.addresses = new LinkedHashSet<>(); - } - this.addresses.addAll(addrs); - } finally { - lock.unlock(); - } - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } -} +/* + * + */ +package org.redkale.net.sncp; + +import java.net.InetSocketAddress; +import java.util.*; +import java.util.concurrent.locks.ReentrantLock; +import org.redkale.convert.ConvertColumn; +import org.redkale.convert.json.JsonConvert; +import org.redkale.util.Utility; + +/** + * 协议地址组合对象, 对应application.xml 中 resources->group 节点信息 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public class SncpRpcGroup { + + protected final ReentrantLock lock = new ReentrantLock(); + + @ConvertColumn(index = 1) + protected String name; // 地址 + + @ConvertColumn(index = 2) + protected String protocol; // 协议 取值范围: TCP、UDP + + @ConvertColumn(index = 3) + protected Set addresses; // 地址列表, 对应 resources->group->node节点信息 + + public SncpRpcGroup() {} + + public SncpRpcGroup(String name, InetSocketAddress... addrs) { + this(name, "TCP", Utility.ofSet(addrs)); + } + + public SncpRpcGroup(String name, Set addrs) { + this(name, "TCP", addrs); + } + + public SncpRpcGroup(String name, String protocol, InetSocketAddress... addrs) { + this(name, protocol, Utility.ofSet(addrs)); + } + + public SncpRpcGroup(String name, String protocol, Set addresses) { + Objects.requireNonNull(name, "rpc.group.name can not null"); + this.name = name; + this.protocol = protocol == null ? "TCP" : protocol; + this.addresses = addresses; + } + + public String getName() { + return name; + } + + public void setName(String name) { + Objects.requireNonNull(name, "rpc.group.name can not null"); + this.name = name; + } + + public String getProtocol() { + return protocol; + } + + public void setProtocol(String protocol) { + this.protocol = protocol == null ? "TCP" : protocol; + } + + public Set getAddresses() { + return addresses; + } + + public Set copyAddresses() { + lock.lock(); + try { + return addresses == null ? null : new LinkedHashSet<>(addresses); + } finally { + lock.unlock(); + } + } + + public void setAddresses(Set addresses) { + this.addresses = addresses; + } + + public boolean containsAddress(InetSocketAddress addr) { + lock.lock(); + try { + if (this.addresses == null) { + return false; + } + return this.addresses.contains(addr); + } finally { + lock.unlock(); + } + } + + public void removeAddress(InetSocketAddress addr) { + if (addr == null) { + return; + } + lock.lock(); + try { + if (this.addresses == null) { + return; + } + this.addresses.remove(addr); + } finally { + lock.unlock(); + } + } + + public void putAddress(InetSocketAddress addr) { + if (addr == null) { + return; + } + lock.lock(); + try { + if (this.addresses == null) { + this.addresses = new LinkedHashSet<>(); + } + this.addresses.add(addr); + } finally { + lock.unlock(); + } + } + + public void putAddress(Set addrs) { + if (addrs == null) { + return; + } + lock.lock(); + try { + if (this.addresses == null) { + this.addresses = new LinkedHashSet<>(); + } + this.addresses.addAll(addrs); + } finally { + lock.unlock(); + } + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } +} diff --git a/src/main/java/org/redkale/net/sncp/SncpRpcGroups.java b/src/main/java/org/redkale/net/sncp/SncpRpcGroups.java index b6b3655f3..79d7c1bb9 100644 --- a/src/main/java/org/redkale/net/sncp/SncpRpcGroups.java +++ b/src/main/java/org/redkale/net/sncp/SncpRpcGroups.java @@ -1,84 +1,84 @@ -/* - * - */ -package org.redkale.net.sncp; - -import java.net.InetSocketAddress; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import org.redkale.boot.ClassFilter; - -/** - * 协议地址组合对象, 对应application.xml中group节点信息 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public class SncpRpcGroups { - - protected final ConcurrentHashMap sncpRpcGroups = new ConcurrentHashMap<>(); - - // key: resourceid(serviceType:resourceName) - protected final ConcurrentHashMap> sncpClusters = new ConcurrentHashMap<>(); - - public SncpRpcGroup getSncpRpcGroup(String group) { - return sncpRpcGroups.get(group); - } - - public boolean containsGroup(String group) { - return sncpRpcGroups.containsKey(group); - } - - public SncpRpcGroup computeIfAbsent(String group, String protocol) { - return sncpRpcGroups.computeIfAbsent(group, g -> new SncpRpcGroup(group, protocol)); - } - - public InetSocketAddress nextRemoteAddress(String resourceid) { - if (sncpClusters.isEmpty()) { - return null; - } - Set addrs = sncpClusters.get(resourceid); - if (!addrs.isEmpty()) { - Iterator it = addrs.iterator(); - if (it.hasNext()) { - return it.next(); - } - } - return null; - } - - public void putClusterAddress(String resourceid, Set set) { - Objects.requireNonNull(resourceid); - Objects.requireNonNull(set); - sncpClusters.put(resourceid, set); - } - - public String getGroup(InetSocketAddress address) { - for (SncpRpcGroup g : sncpRpcGroups.values()) { - if (g.containsAddress(address)) { - return g.getName(); - } - } - return null; - } - - public boolean isLocalGroup(String sncpGroup, InetSocketAddress sncpAddress, ClassFilter.FilterEntry entry) { - if (sncpGroup != null && !sncpGroup.isEmpty() && sncpGroup.equals(entry.getGroup())) { - return true; - } - if (entry.isEmptyGroup()) { - return true; - } else if (entry.isRemote()) { - return false; - } else { - SncpRpcGroup group = sncpRpcGroups.get(entry.getGroup()); - if (group == null) { - throw new SncpException("Not found group(" + entry.getGroup() + ")"); - } else { - return sncpAddress != null && group.containsAddress(sncpAddress); - } - } - } -} +/* + * + */ +package org.redkale.net.sncp; + +import java.net.InetSocketAddress; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import org.redkale.boot.ClassFilter; + +/** + * 协议地址组合对象, 对应application.xml中group节点信息 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public class SncpRpcGroups { + + protected final ConcurrentHashMap sncpRpcGroups = new ConcurrentHashMap<>(); + + // key: resourceid(serviceType:resourceName) + protected final ConcurrentHashMap> sncpClusters = new ConcurrentHashMap<>(); + + public SncpRpcGroup getSncpRpcGroup(String group) { + return sncpRpcGroups.get(group); + } + + public boolean containsGroup(String group) { + return sncpRpcGroups.containsKey(group); + } + + public SncpRpcGroup computeIfAbsent(String group, String protocol) { + return sncpRpcGroups.computeIfAbsent(group, g -> new SncpRpcGroup(group, protocol)); + } + + public InetSocketAddress nextRemoteAddress(String resourceid) { + if (sncpClusters.isEmpty()) { + return null; + } + Set addrs = sncpClusters.get(resourceid); + if (!addrs.isEmpty()) { + Iterator it = addrs.iterator(); + if (it.hasNext()) { + return it.next(); + } + } + return null; + } + + public void putClusterAddress(String resourceid, Set set) { + Objects.requireNonNull(resourceid); + Objects.requireNonNull(set); + sncpClusters.put(resourceid, set); + } + + public String getGroup(InetSocketAddress address) { + for (SncpRpcGroup g : sncpRpcGroups.values()) { + if (g.containsAddress(address)) { + return g.getName(); + } + } + return null; + } + + public boolean isLocalGroup(String sncpGroup, InetSocketAddress sncpAddress, ClassFilter.FilterEntry entry) { + if (sncpGroup != null && !sncpGroup.isEmpty() && sncpGroup.equals(entry.getGroup())) { + return true; + } + if (entry.isEmptyGroup()) { + return true; + } else if (entry.isRemote()) { + return false; + } else { + SncpRpcGroup group = sncpRpcGroups.get(entry.getGroup()); + if (group == null) { + throw new SncpException("Not found group(" + entry.getGroup() + ")"); + } else { + return sncpAddress != null && group.containsAddress(sncpAddress); + } + } + } +} diff --git a/src/main/java/org/redkale/net/sncp/SncpServer.java b/src/main/java/org/redkale/net/sncp/SncpServer.java index bd14e1464..f72cd6a69 100644 --- a/src/main/java/org/redkale/net/sncp/SncpServer.java +++ b/src/main/java/org/redkale/net/sncp/SncpServer.java @@ -1,135 +1,135 @@ -/* - * 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.sncp; - -import java.util.List; -import java.util.concurrent.atomic.LongAdder; -import org.redkale.boot.Application; -import org.redkale.inject.ResourceFactory; -import org.redkale.net.Server; -import org.redkale.net.sncp.SncpContext.SncpContextConfig; -import org.redkale.service.Service; -import org.redkale.util.*; - -/** - * Service Node Communicate Protocol - * - *

详情见: https://redkale.org - * - * @author zhangjx - */ -@SuppressWarnings("unchecked") -public class SncpServer extends Server { - - public SncpServer() { - this(null, System.currentTimeMillis(), null, ResourceFactory.create()); - } - - public SncpServer(ResourceFactory resourceFactory) { - this(null, System.currentTimeMillis(), null, resourceFactory); - } - - public SncpServer( - Application application, long serverStartTime, AnyValue serconf, ResourceFactory resourceFactory) { - super(application, serverStartTime, netprotocol(serconf), resourceFactory, new SncpDispatcherServlet()); - } - - private static String netprotocol(AnyValue serconf) { - if (serconf == null) { - return "TCP"; - } - String protocol = serconf.getValue("protocol", "").toUpperCase(); - if (protocol.endsWith(".UDP")) { - return "UDP"; - } - return "TCP"; - } - - @Override - public void init(AnyValue config) throws Exception { - super.init(config); - } - - public List getSncpServlets() { - return this.dispatcher.getServlets(); - } - - public List getSncpFilters() { - return this.dispatcher.getFilters(); - } - - /** - * 删除SncpFilter - * - * @param 泛型 - * @param filterClass SncpFilter类 - * @return SncpFilter - */ - public T removeSncpFilter(Class filterClass) { - return (T) this.dispatcher.removeFilter(filterClass); - } - - /** - * 添加SncpFilter - * - * @param filter SncpFilter - * @param conf AnyValue - * @return SncpServer - */ - public SncpServer addSncpFilter(SncpFilter filter, AnyValue conf) { - this.dispatcher.addFilter(filter, conf); - return this; - } - - /** - * 删除SncpServlet - * - * @param sncpService Service - * @return SncpServlet - */ - public SncpServlet removeSncpServlet(Service sncpService) { - if (!Sncp.isSncpDyn(sncpService)) { - throw new SncpException(sncpService + " is not sncp dynamic-gen service"); - } - return ((SncpDispatcherServlet) this.dispatcher).removeSncpServlet(sncpService); - } - - public SncpServlet addSncpServlet(Service sncpService) { - if (!Sncp.isSncpDyn(sncpService)) { - throw new SncpException(sncpService + " is not sncp dynamic-gen service"); - } - SncpServlet sds = - new SncpServlet(Sncp.getResourceName(sncpService), Sncp.getResourceType(sncpService), sncpService); - this.dispatcher.addServlet(sds, null, Sncp.getResourceConf(sncpService)); - return sds; - } - - @Override - @SuppressWarnings("unchecked") - protected SncpContext createContext() { - if (!"UDP".equalsIgnoreCase(netprotocol)) { - this.bufferCapacity = Math.max(this.bufferCapacity, 8 * 1024); - } - final SncpContextConfig contextConfig = new SncpContextConfig(); - initContextConfig(contextConfig); - - return new SncpContext(contextConfig); - } - - @Override - protected ByteBufferPool createSafeBufferPool(LongAdder createCounter, LongAdder cycleCounter, int bufferPoolSize) { - return ByteBufferPool.createSafePool(createCounter, cycleCounter, bufferPoolSize, this.bufferCapacity); - } - - @Override - protected ObjectPool createSafeResponsePool( - LongAdder createCounter, LongAdder cycleCounter, int responsePoolSize) { - Creator creator = - (Object... params) -> new SncpResponse(this.context, new SncpRequest(this.context)); - return ObjectPool.createSafePool( - createCounter, cycleCounter, responsePoolSize, creator, SncpResponse::prepare, SncpResponse::recycle); - } -} +/* + * 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.sncp; + +import java.util.List; +import java.util.concurrent.atomic.LongAdder; +import org.redkale.boot.Application; +import org.redkale.inject.ResourceFactory; +import org.redkale.net.Server; +import org.redkale.net.sncp.SncpContext.SncpContextConfig; +import org.redkale.service.Service; +import org.redkale.util.*; + +/** + * Service Node Communicate Protocol + * + *

详情见: https://redkale.org + * + * @author zhangjx + */ +@SuppressWarnings("unchecked") +public class SncpServer extends Server { + + public SncpServer() { + this(null, System.currentTimeMillis(), null, ResourceFactory.create()); + } + + public SncpServer(ResourceFactory resourceFactory) { + this(null, System.currentTimeMillis(), null, resourceFactory); + } + + public SncpServer( + Application application, long serverStartTime, AnyValue serconf, ResourceFactory resourceFactory) { + super(application, serverStartTime, netprotocol(serconf), resourceFactory, new SncpDispatcherServlet()); + } + + private static String netprotocol(AnyValue serconf) { + if (serconf == null) { + return "TCP"; + } + String protocol = serconf.getValue("protocol", "").toUpperCase(); + if (protocol.endsWith(".UDP")) { + return "UDP"; + } + return "TCP"; + } + + @Override + public void init(AnyValue config) throws Exception { + super.init(config); + } + + public List getSncpServlets() { + return this.dispatcher.getServlets(); + } + + public List getSncpFilters() { + return this.dispatcher.getFilters(); + } + + /** + * 删除SncpFilter + * + * @param 泛型 + * @param filterClass SncpFilter类 + * @return SncpFilter + */ + public T removeSncpFilter(Class filterClass) { + return (T) this.dispatcher.removeFilter(filterClass); + } + + /** + * 添加SncpFilter + * + * @param filter SncpFilter + * @param conf AnyValue + * @return SncpServer + */ + public SncpServer addSncpFilter(SncpFilter filter, AnyValue conf) { + this.dispatcher.addFilter(filter, conf); + return this; + } + + /** + * 删除SncpServlet + * + * @param sncpService Service + * @return SncpServlet + */ + public SncpServlet removeSncpServlet(Service sncpService) { + if (!Sncp.isSncpDyn(sncpService)) { + throw new SncpException(sncpService + " is not sncp dynamic-gen service"); + } + return ((SncpDispatcherServlet) this.dispatcher).removeSncpServlet(sncpService); + } + + public SncpServlet addSncpServlet(Service sncpService) { + if (!Sncp.isSncpDyn(sncpService)) { + throw new SncpException(sncpService + " is not sncp dynamic-gen service"); + } + SncpServlet sds = + new SncpServlet(Sncp.getResourceName(sncpService), Sncp.getResourceType(sncpService), sncpService); + this.dispatcher.addServlet(sds, null, Sncp.getResourceConf(sncpService)); + return sds; + } + + @Override + @SuppressWarnings("unchecked") + protected SncpContext createContext() { + if (!"UDP".equalsIgnoreCase(netprotocol)) { + this.bufferCapacity = Math.max(this.bufferCapacity, 8 * 1024); + } + final SncpContextConfig contextConfig = new SncpContextConfig(); + initContextConfig(contextConfig); + + return new SncpContext(contextConfig); + } + + @Override + protected ByteBufferPool createSafeBufferPool(LongAdder createCounter, LongAdder cycleCounter, int bufferPoolSize) { + return ByteBufferPool.createSafePool(createCounter, cycleCounter, bufferPoolSize, this.bufferCapacity); + } + + @Override + protected ObjectPool createSafeResponsePool( + LongAdder createCounter, LongAdder cycleCounter, int responsePoolSize) { + Creator creator = + (Object... params) -> new SncpResponse(this.context, new SncpRequest(this.context)); + return ObjectPool.createSafePool( + createCounter, cycleCounter, responsePoolSize, creator, SncpResponse::prepare, SncpResponse::recycle); + } +} diff --git a/src/main/java/org/redkale/persistence/Column.java b/src/main/java/org/redkale/persistence/Column.java index fcb2e71cf..33d08f200 100644 --- a/src/main/java/org/redkale/persistence/Column.java +++ b/src/main/java/org/redkale/persistence/Column.java @@ -1,136 +1,136 @@ -/** - * ***************************************************************************** Copyright (c) 2008 - 2013 Oracle - * Corporation. All rights reserved. - * - *

This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v. 1.0 which accompanies this distribution. The Eclipse Public License is available - * at http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - *

Contributors: Linda DeMichiel - Java Persistence 2.1 Linda DeMichiel - Java Persistence 2.0 - * - *

**************************************************************************** - */ -package org.redkale.persistence; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.*; - -/** - * Specifies the mapped column for a persistent property or field. If no Column annotation is specified, - * the default values apply. - * - *

- * - *
- *    Example 1:
- *
- *    @Column(name="DESC", nullable=false, length=512)
- *    public String getDescription() { return description; }
- *
- *    Example 2:
- *
- *    @Column(name="DESC",
- *            columnDefinition="CLOB NOT NULL",
- *            table="EMP_DETAIL")
- *    @Lob
- *    public String getDescription() { return description; }
- *
- *    Example 3:
- *
- *    @Column(name="ORDER_COST", updatable=false, precision=12, scale=2)
- *    public BigDecimal getCost() { return cost; }
- *
- * 
- * - *
- * - * @since Java Persistence 1.0 - */ -@Target({METHOD, FIELD}) -@Retention(RUNTIME) -public @interface Column { - - /** - * (Optional) The name of the column. Defaults to the property or field name. - * - * @return String - */ - String name() default ""; - - /** - * (Optional) The comment of the column. - * - * @return String - */ - String comment() default ""; - - /** - * (Optional) Whether the column is a unique key. This is a shortcut for the UniqueConstraint - * annotation at the table level and is useful for when the unique key constraint corresponds to only a single - * column. This constraint applies in addition to any constraint entailed by primary key mapping and to constraints - * specified at the table level. - * - * @return boolean - */ - boolean unique() default false; - - /** - * (Optional) Whether the database column is required. - * - * @return boolean - */ - boolean nullable() default true; - - /** - * for OpenAPI Specification 3 - * - * @return String - */ - String example() default ""; - - /** - * (Optional) Whether the column is included in SQL INSERT statements generated by the persistence provider. - * - * @return boolean - */ - boolean insertable() default true; - - /** - * (Optional) Whether the column is included in SQL UPDATE statements generated by the persistence provider. - * - * @return boolean - */ - boolean updatable() default true; - - /** - * (Optional) The column length. (Applies only if a string-valued column is used.) if type==String and length == - * 65535 then sqltype is TEXT
- * if type==String and length <= 16777215 then sqltype is MEDIUMTEXT
- * if type==String and length > 16777215 then sqltype is LONGTEXT
- * if type==byte[] and length <= 65535 then sqltype is BLOB
- * if type==byte[] and length <= 16777215 then sqltype is MEDIUMBLOB
- * if type==byte[] and length > 16777215 then sqltype is LONGBLOB
- * - * @return int - */ - int length() default 255; - - /** - * (Optional) The precision for a decimal (exact numeric) column. (Applies only if a decimal column is used.) Value - * must be set by developer if used when generating the DDL for the column. - * - * @return int - */ - int precision() default 0; - - /** - * (Optional) The scale for a decimal (exact numeric) column. (Applies only if a decimal column is used.) - * - * @return int - */ - int scale() default 0; -} +/** + * ***************************************************************************** Copyright (c) 2008 - 2013 Oracle + * Corporation. All rights reserved. + * + *

This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v. 1.0 which accompanies this distribution. The Eclipse Public License is available + * at http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + *

Contributors: Linda DeMichiel - Java Persistence 2.1 Linda DeMichiel - Java Persistence 2.0 + * + *

**************************************************************************** + */ +package org.redkale.persistence; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.*; + +/** + * Specifies the mapped column for a persistent property or field. If no Column annotation is specified, + * the default values apply. + * + *

+ * + *
+ *    Example 1:
+ *
+ *    @Column(name="DESC", nullable=false, length=512)
+ *    public String getDescription() { return description; }
+ *
+ *    Example 2:
+ *
+ *    @Column(name="DESC",
+ *            columnDefinition="CLOB NOT NULL",
+ *            table="EMP_DETAIL")
+ *    @Lob
+ *    public String getDescription() { return description; }
+ *
+ *    Example 3:
+ *
+ *    @Column(name="ORDER_COST", updatable=false, precision=12, scale=2)
+ *    public BigDecimal getCost() { return cost; }
+ *
+ * 
+ * + *
+ * + * @since Java Persistence 1.0 + */ +@Target({METHOD, FIELD}) +@Retention(RUNTIME) +public @interface Column { + + /** + * (Optional) The name of the column. Defaults to the property or field name. + * + * @return String + */ + String name() default ""; + + /** + * (Optional) The comment of the column. + * + * @return String + */ + String comment() default ""; + + /** + * (Optional) Whether the column is a unique key. This is a shortcut for the UniqueConstraint + * annotation at the table level and is useful for when the unique key constraint corresponds to only a single + * column. This constraint applies in addition to any constraint entailed by primary key mapping and to constraints + * specified at the table level. + * + * @return boolean + */ + boolean unique() default false; + + /** + * (Optional) Whether the database column is required. + * + * @return boolean + */ + boolean nullable() default true; + + /** + * for OpenAPI Specification 3 + * + * @return String + */ + String example() default ""; + + /** + * (Optional) Whether the column is included in SQL INSERT statements generated by the persistence provider. + * + * @return boolean + */ + boolean insertable() default true; + + /** + * (Optional) Whether the column is included in SQL UPDATE statements generated by the persistence provider. + * + * @return boolean + */ + boolean updatable() default true; + + /** + * (Optional) The column length. (Applies only if a string-valued column is used.) if type==String and length == + * 65535 then sqltype is TEXT
+ * if type==String and length <= 16777215 then sqltype is MEDIUMTEXT
+ * if type==String and length > 16777215 then sqltype is LONGTEXT
+ * if type==byte[] and length <= 65535 then sqltype is BLOB
+ * if type==byte[] and length <= 16777215 then sqltype is MEDIUMBLOB
+ * if type==byte[] and length > 16777215 then sqltype is LONGBLOB
+ * + * @return int + */ + int length() default 255; + + /** + * (Optional) The precision for a decimal (exact numeric) column. (Applies only if a decimal column is used.) Value + * must be set by developer if used when generating the DDL for the column. + * + * @return int + */ + int precision() default 0; + + /** + * (Optional) The scale for a decimal (exact numeric) column. (Applies only if a decimal column is used.) + * + * @return int + */ + int scale() default 0; +} diff --git a/src/main/java/org/redkale/persistence/Entity.java b/src/main/java/org/redkale/persistence/Entity.java index 265a754c8..c0001e707 100644 --- a/src/main/java/org/redkale/persistence/Entity.java +++ b/src/main/java/org/redkale/persistence/Entity.java @@ -1,67 +1,67 @@ -/** - * ***************************************************************************** Copyright (c) 2008 - 2013 Oracle - * Corporation. All rights reserved. - * - *

This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v. 1.0 which accompanies this distribution. The Eclipse Public License is available - * at http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - *

Contributors: Linda DeMichiel - Java Persistence 2.1 Linda DeMichiel - Java Persistence 2.0 - * - *

**************************************************************************** - */ -package org.redkale.persistence; - -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.*; - -/** - * Specifies that the class is an entity. This annotation is applied to the entity class. - * - * @since Java Persistence 1.0 - */ -@Inherited -@Documented -@Target(TYPE) -@Retention(RUNTIME) -public @interface Entity { - - /** - * (Optional) The entity name. Defaults to the unqualified name of the entity class. This name is used to refer to - * the entity in queries. The name must not be a reserved literal in the Java Persistence query language. - * - * @return String - */ - String name() default ""; - - /** - * (Optional) The comment of the entity. - * - * @return String - */ - String comment() default ""; - - /** - * (Optional) 是否缓存实体对象 - * - * @return boolean - */ - boolean cacheable() default false; - - /** - * (Optional) 定时自动更新缓存的周期秒数,为0表示不做定时更新, 大于0表示每经过interval秒后会自动从数据库中拉取数据更新Cache - * - * @return int - */ - int cacheInterval() default 0; - - /** - * (Optional) DataSource是否直接返回对象的真实引用, 而不是copy一份 - * - * @return boolean - */ - boolean cacheDirect() default false; -} +/** + * ***************************************************************************** Copyright (c) 2008 - 2013 Oracle + * Corporation. All rights reserved. + * + *

This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v. 1.0 which accompanies this distribution. The Eclipse Public License is available + * at http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + *

Contributors: Linda DeMichiel - Java Persistence 2.1 Linda DeMichiel - Java Persistence 2.0 + * + *

**************************************************************************** + */ +package org.redkale.persistence; + +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.*; + +/** + * Specifies that the class is an entity. This annotation is applied to the entity class. + * + * @since Java Persistence 1.0 + */ +@Inherited +@Documented +@Target(TYPE) +@Retention(RUNTIME) +public @interface Entity { + + /** + * (Optional) The entity name. Defaults to the unqualified name of the entity class. This name is used to refer to + * the entity in queries. The name must not be a reserved literal in the Java Persistence query language. + * + * @return String + */ + String name() default ""; + + /** + * (Optional) The comment of the entity. + * + * @return String + */ + String comment() default ""; + + /** + * (Optional) 是否缓存实体对象 + * + * @return boolean + */ + boolean cacheable() default false; + + /** + * (Optional) 定时自动更新缓存的周期秒数,为0表示不做定时更新, 大于0表示每经过interval秒后会自动从数据库中拉取数据更新Cache + * + * @return int + */ + int cacheInterval() default 0; + + /** + * (Optional) DataSource是否直接返回对象的真实引用, 而不是copy一份 + * + * @return boolean + */ + boolean cacheDirect() default false; +} diff --git a/src/main/java/org/redkale/persistence/GeneratedValue.java b/src/main/java/org/redkale/persistence/GeneratedValue.java index 5b5671146..2215e36e4 100644 --- a/src/main/java/org/redkale/persistence/GeneratedValue.java +++ b/src/main/java/org/redkale/persistence/GeneratedValue.java @@ -1,52 +1,52 @@ -/** - * ***************************************************************************** Copyright (c) 2008 - 2013 Oracle - * Corporation. All rights reserved. - * - *

This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v. 1.0 which accompanies this distribution. The Eclipse Public License is available - * at http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - *

Contributors: Linda DeMichiel - Java Persistence 2.1 Linda DeMichiel - Java Persistence 2.0 - * - *

**************************************************************************** - */ -package org.redkale.persistence; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.*; - -/** - * Provides for the specification of generation strategies for the values of primary keys. - * - *

The GeneratedValue annotation may be applied to a primary key property or field of an entity or - * mapped superclass in conjunction with the {@link Id} annotation. The use of the GeneratedValue - * annotation is only required to be supported for simple primary keys. Use of the GeneratedValue - * annotation is not supported for derived primary keys. - * - *

- *
- *     Example 1:
- *
- *     @Id
- *     @GeneratedValue(strategy=SEQUENCE, generator="CUST_SEQ")
- *     @Column(name="CUST_ID")
- *     public Long getId() { return id; }
- *
- *     Example 2:
- *
- *     @Id
- *     @GeneratedValue(strategy=TABLE, generator="CUST_GEN")
- *     @Column(name="CUST_ID")
- *     Long id;
- * 
- * - * @see Id - * @since Java Persistence 1.0 - */ -@Target({METHOD, FIELD}) -@Retention(RUNTIME) -public @interface GeneratedValue {} +/** + * ***************************************************************************** Copyright (c) 2008 - 2013 Oracle + * Corporation. All rights reserved. + * + *

This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v. 1.0 which accompanies this distribution. The Eclipse Public License is available + * at http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + *

Contributors: Linda DeMichiel - Java Persistence 2.1 Linda DeMichiel - Java Persistence 2.0 + * + *

**************************************************************************** + */ +package org.redkale.persistence; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.*; + +/** + * Provides for the specification of generation strategies for the values of primary keys. + * + *

The GeneratedValue annotation may be applied to a primary key property or field of an entity or + * mapped superclass in conjunction with the {@link Id} annotation. The use of the GeneratedValue + * annotation is only required to be supported for simple primary keys. Use of the GeneratedValue + * annotation is not supported for derived primary keys. + * + *

+ *
+ *     Example 1:
+ *
+ *     @Id
+ *     @GeneratedValue(strategy=SEQUENCE, generator="CUST_SEQ")
+ *     @Column(name="CUST_ID")
+ *     public Long getId() { return id; }
+ *
+ *     Example 2:
+ *
+ *     @Id
+ *     @GeneratedValue(strategy=TABLE, generator="CUST_GEN")
+ *     @Column(name="CUST_ID")
+ *     Long id;
+ * 
+ * + * @see Id + * @since Java Persistence 1.0 + */ +@Target({METHOD, FIELD}) +@Retention(RUNTIME) +public @interface GeneratedValue {} diff --git a/src/main/java/org/redkale/persistence/Id.java b/src/main/java/org/redkale/persistence/Id.java index dbfc2ce3d..c33e314b1 100644 --- a/src/main/java/org/redkale/persistence/Id.java +++ b/src/main/java/org/redkale/persistence/Id.java @@ -1,45 +1,45 @@ -/** - * ***************************************************************************** Copyright (c) 2008 - 2013 Oracle - * Corporation. All rights reserved. - * - *

This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v. 1.0 which accompanies this distribution. The Eclipse Public License is available - * at http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - *

Contributors: Linda DeMichiel - Java Persistence 2.1 Linda DeMichiel - Java Persistence 2.0 - * - *

**************************************************************************** - */ -package org.redkale.persistence; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * Specifies the primary key of an entity. The field or property to which the Id annotation is applied - * should be one of the following types: any Java primitive type; any primitive wrapper type; String; - * java.util.Date; java.sql.Date; java.math.BigDecimal; - * java.math.BigInteger. - * - *

The mapped column for the primary key of the entity is assumed to be the primary key of the primary table. If no - * Column annotation is specified, the primary key column name is assumed to be the name of the primary key - * property or field. - * - *

- *   Example:
- *
- *   @Id
- *   public Long getId() { return id; }
- * 
- * - * @see Column see GeneratedValue - * @since Java Persistence 1.0 - */ -@Target({METHOD, FIELD}) -@Retention(RUNTIME) -public @interface Id {} +/** + * ***************************************************************************** Copyright (c) 2008 - 2013 Oracle + * Corporation. All rights reserved. + * + *

This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v. 1.0 which accompanies this distribution. The Eclipse Public License is available + * at http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + *

Contributors: Linda DeMichiel - Java Persistence 2.1 Linda DeMichiel - Java Persistence 2.0 + * + *

**************************************************************************** + */ +package org.redkale.persistence; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +/** + * Specifies the primary key of an entity. The field or property to which the Id annotation is applied + * should be one of the following types: any Java primitive type; any primitive wrapper type; String; + * java.util.Date; java.sql.Date; java.math.BigDecimal; + * java.math.BigInteger. + * + *

The mapped column for the primary key of the entity is assumed to be the primary key of the primary table. If no + * Column annotation is specified, the primary key column name is assumed to be the name of the primary key + * property or field. + * + *

+ *   Example:
+ *
+ *   @Id
+ *   public Long getId() { return id; }
+ * 
+ * + * @see Column see GeneratedValue + * @since Java Persistence 1.0 + */ +@Target({METHOD, FIELD}) +@Retention(RUNTIME) +public @interface Id {} diff --git a/src/main/java/org/redkale/persistence/Index.java b/src/main/java/org/redkale/persistence/Index.java index e209036c2..7fd0bc9bf 100644 --- a/src/main/java/org/redkale/persistence/Index.java +++ b/src/main/java/org/redkale/persistence/Index.java @@ -1,80 +1,80 @@ -/** - * ***************************************************************************** Copyright (c) 2011 - 2013 Oracle - * Corporation. All rights reserved. - * - *

This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v. 1.0 which accompanies this distribution. The Eclipse Public License is available - * at http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - *

Contributors: Linda DeMichiel - Java Persistence 2.1 - * - *

**************************************************************************** - */ -package org.redkale.persistence; - -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * Used in schema generation to specify creation of an index. - * - *

Note that it is not necessary to specify an index for a primary key, as the primary key index will be created - * automatically. - * - *

The syntax of the columnList element is a column_list, as follows: - * - *

- *    column::= index_column [,index_column]*
- *    index_column::= column_name [ASC | DESC]
- * 
- * - *

If ASC or DESC is not specified, ASC (ascending order) is assumed. - * - * @since Java Persistence 2.1 - */ -@Documented -@Target(TYPE) -@Retention(RUNTIME) -public @interface Index { - - /** - * (Optional) The name of the index; defaults to a provider-generated name. - * - * @return String - */ - String name() default ""; - - /** - * (Required) The names of the columns to be included in the index, in order. - * - * @return String[] - */ - String[] columns(); - - /** - * (Optional) Whether the index is unique. - * - * @return boolean - */ - boolean unique() default false; - - /** - * Index的多用类 - * - *

详情见: https://redkale.org - * - * @author zhangjx - */ - @Documented - @Target(TYPE) - @Retention(RUNTIME) - public static @interface Indexs { - - Index[] value(); - } -} +/** + * ***************************************************************************** Copyright (c) 2011 - 2013 Oracle + * Corporation. All rights reserved. + * + *

This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v. 1.0 which accompanies this distribution. The Eclipse Public License is available + * at http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + *

Contributors: Linda DeMichiel - Java Persistence 2.1 + * + *

**************************************************************************** + */ +package org.redkale.persistence; + +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +/** + * Used in schema generation to specify creation of an index. + * + *

Note that it is not necessary to specify an index for a primary key, as the primary key index will be created + * automatically. + * + *

The syntax of the columnList element is a column_list, as follows: + * + *

+ *    column::= index_column [,index_column]*
+ *    index_column::= column_name [ASC | DESC]
+ * 
+ * + *

If ASC or DESC is not specified, ASC (ascending order) is assumed. + * + * @since Java Persistence 2.1 + */ +@Documented +@Target(TYPE) +@Retention(RUNTIME) +public @interface Index { + + /** + * (Optional) The name of the index; defaults to a provider-generated name. + * + * @return String + */ + String name() default ""; + + /** + * (Required) The names of the columns to be included in the index, in order. + * + * @return String[] + */ + String[] columns(); + + /** + * (Optional) Whether the index is unique. + * + * @return boolean + */ + boolean unique() default false; + + /** + * Index的多用类 + * + *

详情见: https://redkale.org + * + * @author zhangjx + */ + @Documented + @Target(TYPE) + @Retention(RUNTIME) + public static @interface Indexs { + + Index[] value(); + } +} diff --git a/src/main/java/org/redkale/persistence/Sql.java b/src/main/java/org/redkale/persistence/Sql.java index 1a75e81f8..7832d81cb 100644 --- a/src/main/java/org/redkale/persistence/Sql.java +++ b/src/main/java/org/redkale/persistence/Sql.java @@ -1,39 +1,39 @@ -/* - * - */ -package org.redkale.persistence; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * 原始sql语句, 标记在{@link org.redkale.source.DataSqlMapper}方法上 - * - *

详情见: https://redkale.org - * - * @see org.redkale.source.DataSqlMapper - * @author zhangjx - * @since 2.8.0 - */ -@Documented -@Target({ElementType.METHOD}) -@Retention(RetentionPolicy.RUNTIME) -public @interface Sql { - - /** - * 原生sql语句 - * - * @return sql - */ - String value(); - - /** - * 备注说明 - * - * @return 备注说明 - */ - String comment() default ""; -} +/* + * + */ +package org.redkale.persistence; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 原始sql语句, 标记在{@link org.redkale.source.DataSqlMapper}方法上 + * + *

详情见: https://redkale.org + * + * @see org.redkale.source.DataSqlMapper + * @author zhangjx + * @since 2.8.0 + */ +@Documented +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface Sql { + + /** + * 原生sql语句 + * + * @return sql + */ + String value(); + + /** + * 备注说明 + * + * @return 备注说明 + */ + String comment() default ""; +} diff --git a/src/main/java/org/redkale/persistence/Table.java b/src/main/java/org/redkale/persistence/Table.java index 75b0cb65d..f2c7f0bd6 100644 --- a/src/main/java/org/redkale/persistence/Table.java +++ b/src/main/java/org/redkale/persistence/Table.java @@ -1,66 +1,66 @@ -/** - * ***************************************************************************** Copyright (c) 2008 - 2013 Oracle - * Corporation. All rights reserved. - * - *

This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v. 1.0 which accompanies this distribution. The Eclipse Public License is available - * at http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - *

Contributors: Linda DeMichiel - Java Persistence 2.1 Linda DeMichiel - Java Persistence 2.0 - * - *

**************************************************************************** - */ -package org.redkale.persistence; - -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * Specifies the primary table for the annotated entity. Additional tables may be specified using SecondaryTable or - * SecondaryTables annotation. - * - *

If no Table annotation is specified for an entity class, the default values apply. - * - *

- *    Example:
- *
- *    @Entity
- *    @Table(name="CUST", schema="RECORDS")
- *    public class Customer { ... }
- * 
- * - * @since Java Persistence 1.0 - */ -@Target(TYPE) -@Retention(RUNTIME) -public @interface Table { - - /** - * (Optional) The name of the table. - * - *

Defaults to the entity name. - * - * @return String - */ - String name() default ""; - - /** - * (Optional) The catalog of the table. - * - *

Defaults to the default catalog. - * - * @return String - */ - String catalog() default ""; - - /** - * comment - * - * @return String - */ - String comment() default ""; -} +/** + * ***************************************************************************** Copyright (c) 2008 - 2013 Oracle + * Corporation. All rights reserved. + * + *

This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v. 1.0 which accompanies this distribution. The Eclipse Public License is available + * at http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + *

Contributors: Linda DeMichiel - Java Persistence 2.1 Linda DeMichiel - Java Persistence 2.0 + * + *

**************************************************************************** + */ +package org.redkale.persistence; + +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +/** + * Specifies the primary table for the annotated entity. Additional tables may be specified using SecondaryTable or + * SecondaryTables annotation. + * + *

If no Table annotation is specified for an entity class, the default values apply. + * + *

+ *    Example:
+ *
+ *    @Entity
+ *    @Table(name="CUST", schema="RECORDS")
+ *    public class Customer { ... }
+ * 
+ * + * @since Java Persistence 1.0 + */ +@Target(TYPE) +@Retention(RUNTIME) +public @interface Table { + + /** + * (Optional) The name of the table. + * + *

Defaults to the entity name. + * + * @return String + */ + String name() default ""; + + /** + * (Optional) The catalog of the table. + * + *

Defaults to the default catalog. + * + * @return String + */ + String catalog() default ""; + + /** + * comment + * + * @return String + */ + String comment() default ""; +} diff --git a/src/main/java/org/redkale/persistence/Transient.java b/src/main/java/org/redkale/persistence/Transient.java index f52b78f52..0752e919f 100644 --- a/src/main/java/org/redkale/persistence/Transient.java +++ b/src/main/java/org/redkale/persistence/Transient.java @@ -1,42 +1,42 @@ -/** - * ***************************************************************************** Copyright (c) 2008 - 2013 Oracle - * Corporation. All rights reserved. - * - *

This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v. 1.0 which accompanies this distribution. The Eclipse Public License is available - * at http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - *

Contributors: Linda DeMichiel - Java Persistence 2.1 Linda DeMichiel - Java Persistence 2.0 - * - *

**************************************************************************** - */ -package org.redkale.persistence; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * Specifies that the property or field is not persistent. It is used to annotate a property or field of an entity - * class, mapped superclass, or embeddable class. - * - *

- *    Example:
- *
- *    @Entity
- *    public class Employee {
- *        @Id int id;
- *        @Transient User currentUser;
- *        ...
- *    }
- * 
- * - * @since Java Persistence 1.0 - */ -@Target({METHOD, FIELD}) -@Retention(RUNTIME) -public @interface Transient {} +/** + * ***************************************************************************** Copyright (c) 2008 - 2013 Oracle + * Corporation. All rights reserved. + * + *

This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v. 1.0 which accompanies this distribution. The Eclipse Public License is available + * at http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + *

Contributors: Linda DeMichiel - Java Persistence 2.1 Linda DeMichiel - Java Persistence 2.0 + * + *

**************************************************************************** + */ +package org.redkale.persistence; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +/** + * Specifies that the property or field is not persistent. It is used to annotate a property or field of an entity + * class, mapped superclass, or embeddable class. + * + *

+ *    Example:
+ *
+ *    @Entity
+ *    public class Employee {
+ *        @Id int id;
+ *        @Transient User currentUser;
+ *        ...
+ *    }
+ * 
+ * + * @since Java Persistence 1.0 + */ +@Target({METHOD, FIELD}) +@Retention(RUNTIME) +public @interface Transient {} diff --git a/src/main/java/org/redkale/props/spi/PropertiesModule.java b/src/main/java/org/redkale/props/spi/PropertiesModule.java index 02c6cd671..e698439a1 100644 --- a/src/main/java/org/redkale/props/spi/PropertiesModule.java +++ b/src/main/java/org/redkale/props/spi/PropertiesModule.java @@ -1,328 +1,328 @@ -/* - * - */ -package org.redkale.props.spi; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Properties; -import java.util.ServiceLoader; -import java.util.Set; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.locks.ReentrantLock; -import java.util.logging.Level; -import java.util.logging.Logger; -import org.redkale.boot.Application; -import org.redkale.boot.BootModule; -import org.redkale.boot.ModuleEngine; -import org.redkale.inject.ResourceEvent; -import org.redkale.util.AnyValue; -import org.redkale.util.Environment; -import org.redkale.util.InstanceProvider; -import org.redkale.util.RedkaleClassLoader; -import org.redkale.util.Utility; - -/** - * 配置模块组件 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public class PropertiesModule extends BootModule { - - private final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); - - // 配置源管理接口 - // @since 2.7.0 - private PropertiesAgent propertiesAgent; - - // envProperties更新锁 - private final ReentrantLock updateLock = new ReentrantLock(); - - public PropertiesModule(Application application) { - super(application); - } - - public void destroy() { - if (this.propertiesAgent != null) { - long s = System.currentTimeMillis(); - this.propertiesAgent.destroy(application.getAppConfig().getAnyValue("properties")); - logger.info(this.propertiesAgent.getClass().getSimpleName() + " destroy in " - + (System.currentTimeMillis() - s) + " ms"); - } - } - - /** 读取远程配置,并合并app.config */ - public void initRemoteProperties() { - final AnyValue config = application.getAppConfig(); - // 所有配置项,包含本地配置项、logging配置项和配置中心获取的配置项 - final Environment environment = application.getEnvironment(); - Properties logProps = null; // 新的日志配置项 - // ------------------------------------ 读取配置项 ------------------------------------ - AnyValue propsConf = config.getAnyValue("properties"); - if (propsConf == null) { - final AnyValue resources = config.getAnyValue("resources"); - if (resources != null) { - logger.log(Level.WARNING, " in application config file is deprecated"); - propsConf = resources.getAnyValue("properties"); - } - } - final Properties remoteEnvs = new Properties(); - if (propsConf != null) { - // 可能通过系统环境变量配置信息 - Iterator it = ServiceLoader.load( - PropertiesAgentProvider.class, application.getClassLoader()) - .iterator(); - RedkaleClassLoader.putServiceLoader(PropertiesAgentProvider.class); - List providers = new ArrayList<>(); - while (it.hasNext()) { - PropertiesAgentProvider provider = it.next(); - if (provider != null && provider.acceptsConf(propsConf)) { - RedkaleClassLoader.putReflectionPublicConstructors( - provider.getClass(), provider.getClass().getName()); - providers.add(provider); - } - } - for (PropertiesAgentProvider provider : InstanceProvider.sort(providers)) { - long s = System.currentTimeMillis(); - this.propertiesAgent = provider.createInstance(); - this.propertiesAgent.bootModule = this; - application.getResourceFactory().inject(this.propertiesAgent); - if (application.isCompileMode()) { - this.propertiesAgent.compile(propsConf); - } else { - Map propMap = this.propertiesAgent.init(application, propsConf); - int propCount = 0; - if (propMap != null) { - for (Map.Entry en : propMap.entrySet()) { - propCount += en.getValue().size(); - if (en.getKey().contains("logging")) { - if (logProps != null) { - logger.log( - Level.WARNING, - "skip repeat logging config properties(" + en.getKey() + ")"); - } else { - logProps = en.getValue(); - } - } else { - remoteEnvs.putAll(en.getValue()); - } - } - } - logger.info("PropertiesAgent (type = " - + this.propertiesAgent.getClass().getSimpleName() + ") load " + propCount + " data in " - + (System.currentTimeMillis() - s) + " ms"); - } - break; // only first provider - } - } - - // 重置远程日志配置 - if (Utility.isNotEmpty(logProps)) { - reconfigLogging(false, logProps); - } - - if (!remoteEnvs.isEmpty()) { - mergeEnvProperties(remoteEnvs, null); - } - } - - public void onEnvironmentUpdated(String namespace, List events) { - if (Utility.isEmpty(events)) { - return; - } - updateLock.lock(); - try { - if (namespace != null && namespace.contains("logging")) { - // 日志配置单独处理 - onEnvironmentUpdated(namespace, events); - return; - } - Set removedKeys = new HashSet<>(); - Properties newEnvs = environment.newProperties(); - for (ResourceEvent event : events) { - if (event.newValue() != null) { - newEnvs.put(event.name(), event.newValue()); - } else { - newEnvs.remove(event.name()); - removedKeys.add(event.name()); - } - } - mergeEnvProperties(newEnvs, removedKeys); - onEnvironmentChanged(namespace, events); - } finally { - updateLock.unlock(); - } - } - - private void mergeEnvProperties(final Properties remoteEnvs, final Set removedKeys) { - // 此时this.envProperties中的内容: - // 1、application.xml的properties.property节点配置项 - // 2、application.xml的properties.load节点的配置项 - // 3、logging.properties - // 4、source.properties - final Properties newMergeProps = new Properties(); - final AtomicInteger propertyIndex = new AtomicInteger(); - // remoteEnvs包含redkale.properties.mykey.name自定义配置项,也包含mykey.name的配置项 - remoteEnvs.forEach((k, v) -> { - String key = k.toString(); - if (key.startsWith("redkale.executor.") // 节点全局唯一 - || key.startsWith("redkale.transport.") // 节点全局唯一 - || key.startsWith("redkale.cluster.") // 节点全局唯一 - || key.startsWith("redkale.cache.") // 节点全局唯一 - || key.startsWith("redkale.schedule.") // 节点全局唯一 - || key.startsWith("redkale.lock.") // 节点全局唯一 - || key.startsWith("redkale.mq.") - || key.startsWith("redkale.mq[") - || key.startsWith("redkale.group.") - || key.startsWith("redkale.group[") - || key.startsWith("redkale.listener.") - || key.startsWith("redkale.listener[") - || key.startsWith("redkale.server.") - || key.startsWith("redkale.server[")) { - newMergeProps.put(k, v); - } else { // 其他视为普通配置项 - if (key.startsWith("system.property.")) { - putEnvValue(k, v); - } else if (key.startsWith("mimetype.property.")) { - putEnvValue(k, v); - } else if (key.startsWith("redkale.properties.property.")) { - newMergeProps.put(k, v); - String name = key.substring("redkale.properties.".length()); - putEnvValue(name, v); - } else if (key.startsWith("redkale.properties.property[")) { - newMergeProps.put(k, v); - String name = key.substring("redkale.properties[".length()); - name = name.substring(0, name.indexOf(']')); - putEnvValue(name, v); - } else if (key.startsWith("redkale.properties.")) { // 支持 -Dredkale.properties.mykey = myvalue - String prefix = "redkale.properties.property[" + propertyIndex.getAndIncrement() + "]"; - String name = key.substring("redkale.properties.".length()); - newMergeProps.put(prefix + ".name", name); - newMergeProps.put(prefix + ".value", v); - putEnvValue(name, v); - } else { // 独立的普通配置项文件,比如:config.properties文件中的配置项 - String prefix = "redkale.properties.property[" + propertyIndex.getAndIncrement() + "]"; - newMergeProps.put(prefix + ".name", k); - newMergeProps.put(prefix + ".value", v); - putEnvValue(k, v); - } - } - }); - if (removedKeys != null && !removedKeys.isEmpty()) { - removedKeys.forEach(this::removeEnvValue); - } - if (!newMergeProps.isEmpty()) { - Properties newDyncProps = new Properties(); - newMergeProps.forEach((k, v) -> newDyncProps.put( - k.toString(), application.getEnvironment().getPropertyValue(v.toString(), newMergeProps))); - // 合并配置 - application - .getAppConfig() - .merge(AnyValue.loadFromProperties(newDyncProps).getAnyValue("redkale"), createMergeStrategy()); - } - } - - /** 合并系统配置项的策略 */ - AnyValue.MergeStrategy createMergeStrategy() { - return (path, key, val1, val2) -> { - for (ModuleEngine m : getModuleEngines()) { - AnyValue.MergeEnum rs = m.mergeAppConfigStrategy(path, key, val1, val2); - if (rs != null) { - return rs; - } - } - if ("".equals(path)) { - if ("executor".equals(key)) { - return AnyValue.MergeEnum.REPLACE; - } - if ("listener".equals(key)) { - if (Objects.equals(val1.getValue("value"), val2.getValue("value"))) { - return AnyValue.MergeEnum.IGNORE; - } else { - return AnyValue.MergeEnum.DEFAULT; - } - } - if ("group".equals(key)) { - if (Objects.equals(val1.getValue("name"), val2.getValue("name"))) { - return AnyValue.MergeEnum.REPLACE; - } else { - return AnyValue.MergeEnum.DEFAULT; - } - } - if ("server".equals(key)) { - if (Objects.equals( - val1.getValue("name", val1.getValue("protocol") + "_" + val1.getValue("port")), - val2.getValue("name", val2.getValue("protocol") + "_" + val2.getValue("port")))) { - return AnyValue.MergeEnum.REPLACE; - } else { - return AnyValue.MergeEnum.DEFAULT; - } - } - } - if ("properties".equals(path)) { - if ("property".equals(key)) { - if (Objects.equals(val1.getValue("name"), val2.getValue("name"))) { - return AnyValue.MergeEnum.REPLACE; - } else { - return AnyValue.MergeEnum.DEFAULT; - } - } - } - if ("server".equals(path)) { - if ("ssl".equals(key)) { - return AnyValue.MergeEnum.REPLACE; - } - if ("render".equals(key)) { - return AnyValue.MergeEnum.REPLACE; - } - if ("resource-servlet".equals(key)) { - return AnyValue.MergeEnum.REPLACE; - } - } - if ("server.request".equals(path)) { - if ("remoteaddr".equals(key)) { - return AnyValue.MergeEnum.REPLACE; - } - if ("rpc".equals(key)) { - return AnyValue.MergeEnum.REPLACE; - } - if ("locale".equals(key)) { - if (Objects.equals(val1.getValue("name"), val2.getValue("name"))) { - return AnyValue.MergeEnum.REPLACE; - } else { - return AnyValue.MergeEnum.DEFAULT; - } - } - } - if ("server.response".equals(path)) { - if ("content-type".equals(key)) { - return AnyValue.MergeEnum.REPLACE; - } - if ("defcookie".equals(key)) { - return AnyValue.MergeEnum.REPLACE; - } - if ("options".equals(key)) { - return AnyValue.MergeEnum.REPLACE; - } - if ("date".equals(key)) { - return AnyValue.MergeEnum.REPLACE; - } - if ("addheader".equals(key) || "setheader".equals(key)) { - if (Objects.equals(val1.getValue("name"), val2.getValue("name"))) { - return AnyValue.MergeEnum.REPLACE; - } else { - return AnyValue.MergeEnum.DEFAULT; - } - } - } - return AnyValue.MergeEnum.MERGE; - }; - } -} +/* + * + */ +package org.redkale.props.spi; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Properties; +import java.util.ServiceLoader; +import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.ReentrantLock; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.redkale.boot.Application; +import org.redkale.boot.BootModule; +import org.redkale.boot.ModuleEngine; +import org.redkale.inject.ResourceEvent; +import org.redkale.util.AnyValue; +import org.redkale.util.Environment; +import org.redkale.util.InstanceProvider; +import org.redkale.util.RedkaleClassLoader; +import org.redkale.util.Utility; + +/** + * 配置模块组件 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public class PropertiesModule extends BootModule { + + private final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); + + // 配置源管理接口 + // @since 2.7.0 + private PropertiesAgent propertiesAgent; + + // envProperties更新锁 + private final ReentrantLock updateLock = new ReentrantLock(); + + public PropertiesModule(Application application) { + super(application); + } + + public void destroy() { + if (this.propertiesAgent != null) { + long s = System.currentTimeMillis(); + this.propertiesAgent.destroy(application.getAppConfig().getAnyValue("properties")); + logger.info(this.propertiesAgent.getClass().getSimpleName() + " destroy in " + + (System.currentTimeMillis() - s) + " ms"); + } + } + + /** 读取远程配置,并合并app.config */ + public void initRemoteProperties() { + final AnyValue config = application.getAppConfig(); + // 所有配置项,包含本地配置项、logging配置项和配置中心获取的配置项 + final Environment environment = application.getEnvironment(); + Properties logProps = null; // 新的日志配置项 + // ------------------------------------ 读取配置项 ------------------------------------ + AnyValue propsConf = config.getAnyValue("properties"); + if (propsConf == null) { + final AnyValue resources = config.getAnyValue("resources"); + if (resources != null) { + logger.log(Level.WARNING, " in application config file is deprecated"); + propsConf = resources.getAnyValue("properties"); + } + } + final Properties remoteEnvs = new Properties(); + if (propsConf != null) { + // 可能通过系统环境变量配置信息 + Iterator it = ServiceLoader.load( + PropertiesAgentProvider.class, application.getClassLoader()) + .iterator(); + RedkaleClassLoader.putServiceLoader(PropertiesAgentProvider.class); + List providers = new ArrayList<>(); + while (it.hasNext()) { + PropertiesAgentProvider provider = it.next(); + if (provider != null && provider.acceptsConf(propsConf)) { + RedkaleClassLoader.putReflectionPublicConstructors( + provider.getClass(), provider.getClass().getName()); + providers.add(provider); + } + } + for (PropertiesAgentProvider provider : InstanceProvider.sort(providers)) { + long s = System.currentTimeMillis(); + this.propertiesAgent = provider.createInstance(); + this.propertiesAgent.bootModule = this; + application.getResourceFactory().inject(this.propertiesAgent); + if (application.isCompileMode()) { + this.propertiesAgent.compile(propsConf); + } else { + Map propMap = this.propertiesAgent.init(application, propsConf); + int propCount = 0; + if (propMap != null) { + for (Map.Entry en : propMap.entrySet()) { + propCount += en.getValue().size(); + if (en.getKey().contains("logging")) { + if (logProps != null) { + logger.log( + Level.WARNING, + "skip repeat logging config properties(" + en.getKey() + ")"); + } else { + logProps = en.getValue(); + } + } else { + remoteEnvs.putAll(en.getValue()); + } + } + } + logger.info("PropertiesAgent (type = " + + this.propertiesAgent.getClass().getSimpleName() + ") load " + propCount + " data in " + + (System.currentTimeMillis() - s) + " ms"); + } + break; // only first provider + } + } + + // 重置远程日志配置 + if (Utility.isNotEmpty(logProps)) { + reconfigLogging(false, logProps); + } + + if (!remoteEnvs.isEmpty()) { + mergeEnvProperties(remoteEnvs, null); + } + } + + public void onEnvironmentUpdated(String namespace, List events) { + if (Utility.isEmpty(events)) { + return; + } + updateLock.lock(); + try { + if (namespace != null && namespace.contains("logging")) { + // 日志配置单独处理 + onEnvironmentUpdated(namespace, events); + return; + } + Set removedKeys = new HashSet<>(); + Properties newEnvs = environment.newProperties(); + for (ResourceEvent event : events) { + if (event.newValue() != null) { + newEnvs.put(event.name(), event.newValue()); + } else { + newEnvs.remove(event.name()); + removedKeys.add(event.name()); + } + } + mergeEnvProperties(newEnvs, removedKeys); + onEnvironmentChanged(namespace, events); + } finally { + updateLock.unlock(); + } + } + + private void mergeEnvProperties(final Properties remoteEnvs, final Set removedKeys) { + // 此时this.envProperties中的内容: + // 1、application.xml的properties.property节点配置项 + // 2、application.xml的properties.load节点的配置项 + // 3、logging.properties + // 4、source.properties + final Properties newMergeProps = new Properties(); + final AtomicInteger propertyIndex = new AtomicInteger(); + // remoteEnvs包含redkale.properties.mykey.name自定义配置项,也包含mykey.name的配置项 + remoteEnvs.forEach((k, v) -> { + String key = k.toString(); + if (key.startsWith("redkale.executor.") // 节点全局唯一 + || key.startsWith("redkale.transport.") // 节点全局唯一 + || key.startsWith("redkale.cluster.") // 节点全局唯一 + || key.startsWith("redkale.cache.") // 节点全局唯一 + || key.startsWith("redkale.schedule.") // 节点全局唯一 + || key.startsWith("redkale.lock.") // 节点全局唯一 + || key.startsWith("redkale.mq.") + || key.startsWith("redkale.mq[") + || key.startsWith("redkale.group.") + || key.startsWith("redkale.group[") + || key.startsWith("redkale.listener.") + || key.startsWith("redkale.listener[") + || key.startsWith("redkale.server.") + || key.startsWith("redkale.server[")) { + newMergeProps.put(k, v); + } else { // 其他视为普通配置项 + if (key.startsWith("system.property.")) { + putEnvValue(k, v); + } else if (key.startsWith("mimetype.property.")) { + putEnvValue(k, v); + } else if (key.startsWith("redkale.properties.property.")) { + newMergeProps.put(k, v); + String name = key.substring("redkale.properties.".length()); + putEnvValue(name, v); + } else if (key.startsWith("redkale.properties.property[")) { + newMergeProps.put(k, v); + String name = key.substring("redkale.properties[".length()); + name = name.substring(0, name.indexOf(']')); + putEnvValue(name, v); + } else if (key.startsWith("redkale.properties.")) { // 支持 -Dredkale.properties.mykey = myvalue + String prefix = "redkale.properties.property[" + propertyIndex.getAndIncrement() + "]"; + String name = key.substring("redkale.properties.".length()); + newMergeProps.put(prefix + ".name", name); + newMergeProps.put(prefix + ".value", v); + putEnvValue(name, v); + } else { // 独立的普通配置项文件,比如:config.properties文件中的配置项 + String prefix = "redkale.properties.property[" + propertyIndex.getAndIncrement() + "]"; + newMergeProps.put(prefix + ".name", k); + newMergeProps.put(prefix + ".value", v); + putEnvValue(k, v); + } + } + }); + if (removedKeys != null && !removedKeys.isEmpty()) { + removedKeys.forEach(this::removeEnvValue); + } + if (!newMergeProps.isEmpty()) { + Properties newDyncProps = new Properties(); + newMergeProps.forEach((k, v) -> newDyncProps.put( + k.toString(), application.getEnvironment().getPropertyValue(v.toString(), newMergeProps))); + // 合并配置 + application + .getAppConfig() + .merge(AnyValue.loadFromProperties(newDyncProps).getAnyValue("redkale"), createMergeStrategy()); + } + } + + /** 合并系统配置项的策略 */ + AnyValue.MergeStrategy createMergeStrategy() { + return (path, key, val1, val2) -> { + for (ModuleEngine m : getModuleEngines()) { + AnyValue.MergeEnum rs = m.mergeAppConfigStrategy(path, key, val1, val2); + if (rs != null) { + return rs; + } + } + if ("".equals(path)) { + if ("executor".equals(key)) { + return AnyValue.MergeEnum.REPLACE; + } + if ("listener".equals(key)) { + if (Objects.equals(val1.getValue("value"), val2.getValue("value"))) { + return AnyValue.MergeEnum.IGNORE; + } else { + return AnyValue.MergeEnum.DEFAULT; + } + } + if ("group".equals(key)) { + if (Objects.equals(val1.getValue("name"), val2.getValue("name"))) { + return AnyValue.MergeEnum.REPLACE; + } else { + return AnyValue.MergeEnum.DEFAULT; + } + } + if ("server".equals(key)) { + if (Objects.equals( + val1.getValue("name", val1.getValue("protocol") + "_" + val1.getValue("port")), + val2.getValue("name", val2.getValue("protocol") + "_" + val2.getValue("port")))) { + return AnyValue.MergeEnum.REPLACE; + } else { + return AnyValue.MergeEnum.DEFAULT; + } + } + } + if ("properties".equals(path)) { + if ("property".equals(key)) { + if (Objects.equals(val1.getValue("name"), val2.getValue("name"))) { + return AnyValue.MergeEnum.REPLACE; + } else { + return AnyValue.MergeEnum.DEFAULT; + } + } + } + if ("server".equals(path)) { + if ("ssl".equals(key)) { + return AnyValue.MergeEnum.REPLACE; + } + if ("render".equals(key)) { + return AnyValue.MergeEnum.REPLACE; + } + if ("resource-servlet".equals(key)) { + return AnyValue.MergeEnum.REPLACE; + } + } + if ("server.request".equals(path)) { + if ("remoteaddr".equals(key)) { + return AnyValue.MergeEnum.REPLACE; + } + if ("rpc".equals(key)) { + return AnyValue.MergeEnum.REPLACE; + } + if ("locale".equals(key)) { + if (Objects.equals(val1.getValue("name"), val2.getValue("name"))) { + return AnyValue.MergeEnum.REPLACE; + } else { + return AnyValue.MergeEnum.DEFAULT; + } + } + } + if ("server.response".equals(path)) { + if ("content-type".equals(key)) { + return AnyValue.MergeEnum.REPLACE; + } + if ("defcookie".equals(key)) { + return AnyValue.MergeEnum.REPLACE; + } + if ("options".equals(key)) { + return AnyValue.MergeEnum.REPLACE; + } + if ("date".equals(key)) { + return AnyValue.MergeEnum.REPLACE; + } + if ("addheader".equals(key) || "setheader".equals(key)) { + if (Objects.equals(val1.getValue("name"), val2.getValue("name"))) { + return AnyValue.MergeEnum.REPLACE; + } else { + return AnyValue.MergeEnum.DEFAULT; + } + } + } + return AnyValue.MergeEnum.MERGE; + }; + } +} diff --git a/src/main/java/org/redkale/schedule/ScheduleEvent.java b/src/main/java/org/redkale/schedule/ScheduleEvent.java index 80e1efceb..5b4ba058b 100644 --- a/src/main/java/org/redkale/schedule/ScheduleEvent.java +++ b/src/main/java/org/redkale/schedule/ScheduleEvent.java @@ -1,79 +1,79 @@ -/* - * - */ -package org.redkale.schedule; - -import java.lang.reflect.Type; -import java.util.HashMap; -import java.util.Map; -import org.redkale.convert.json.JsonConvert; -import org.redkale.util.Utility; - -/** - * 定时任务的参数 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public final class ScheduleEvent { - - private final Map map; - - public ScheduleEvent() { - this.map = new HashMap<>(); - } - - public ScheduleEvent(Map map) { - this.map = map; - } - - @SuppressWarnings("unchecked") - public T get(String name) { - return (T) map.get(name); - } - - public T getJson(String name, Type type) { - Object obj = get(name); - return obj == null ? null : JsonConvert.root().convertFrom(type, obj.toString()); - } - - public String getString(String name) { - return Utility.convertValue(String.class, map.get(name)); - } - - public Integer getInteger(String name) { - return Utility.convertValue(int.class, map.get(name)); - } - - public Long getLong(String name) { - return Utility.convertValue(Long.class, map.get(name)); - } - - public int getInt(String name, int defValue) { - Object val = map.get(name); - if (val == null) { - return defValue; - } - return Utility.convertValue(int.class, val); - } - - public long getLong(String name, long defValue) { - Object val = map.get(name); - if (val == null) { - return defValue; - } - return Utility.convertValue(long.class, val); - } - - public ScheduleEvent clear() { - map.clear(); - return this; - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(map); - } -} +/* + * + */ +package org.redkale.schedule; + +import java.lang.reflect.Type; +import java.util.HashMap; +import java.util.Map; +import org.redkale.convert.json.JsonConvert; +import org.redkale.util.Utility; + +/** + * 定时任务的参数 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public final class ScheduleEvent { + + private final Map map; + + public ScheduleEvent() { + this.map = new HashMap<>(); + } + + public ScheduleEvent(Map map) { + this.map = map; + } + + @SuppressWarnings("unchecked") + public T get(String name) { + return (T) map.get(name); + } + + public T getJson(String name, Type type) { + Object obj = get(name); + return obj == null ? null : JsonConvert.root().convertFrom(type, obj.toString()); + } + + public String getString(String name) { + return Utility.convertValue(String.class, map.get(name)); + } + + public Integer getInteger(String name) { + return Utility.convertValue(int.class, map.get(name)); + } + + public Long getLong(String name) { + return Utility.convertValue(Long.class, map.get(name)); + } + + public int getInt(String name, int defValue) { + Object val = map.get(name); + if (val == null) { + return defValue; + } + return Utility.convertValue(int.class, val); + } + + public long getLong(String name, long defValue) { + Object val = map.get(name); + if (val == null) { + return defValue; + } + return Utility.convertValue(long.class, val); + } + + public ScheduleEvent clear() { + map.clear(); + return this; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(map); + } +} diff --git a/src/main/java/org/redkale/schedule/ScheduleManager.java b/src/main/java/org/redkale/schedule/ScheduleManager.java index e2f578537..b1722b289 100644 --- a/src/main/java/org/redkale/schedule/ScheduleManager.java +++ b/src/main/java/org/redkale/schedule/ScheduleManager.java @@ -1,47 +1,47 @@ -/* - * - */ -package org.redkale.schedule; - -/** - * 定时管理器 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public interface ScheduleManager { - - /** - * 开启宿主对象中所有的定时任务方法. 存在定时任务方法返回true,否则返回false - * - * @param service 宿主对象 - */ - public void schedule(Object service); - - /** - * 开启所有宿主对象中指定的任务名 - * - * @see org.redkale.schedule.Scheduled#name() - * @param scheduleName 定时任务名称 - * @return 返回任务数量 - */ - public int start(String scheduleName); - - /** - * 关闭宿主对象中所有的定时任务方法 - * - * @param service 宿主对象 - */ - public void unschedule(Object service); - - /** - * 关闭所有宿主对象中指定的任务名 - * - * @see org.redkale.schedule.Scheduled#name() - * @param scheduleName 定时任务名称 - * @return 返回任务数量 - */ - public int stop(String scheduleName); -} +/* + * + */ +package org.redkale.schedule; + +/** + * 定时管理器 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public interface ScheduleManager { + + /** + * 开启宿主对象中所有的定时任务方法. 存在定时任务方法返回true,否则返回false + * + * @param service 宿主对象 + */ + public void schedule(Object service); + + /** + * 开启所有宿主对象中指定的任务名 + * + * @see org.redkale.schedule.Scheduled#name() + * @param scheduleName 定时任务名称 + * @return 返回任务数量 + */ + public int start(String scheduleName); + + /** + * 关闭宿主对象中所有的定时任务方法 + * + * @param service 宿主对象 + */ + public void unschedule(Object service); + + /** + * 关闭所有宿主对象中指定的任务名 + * + * @see org.redkale.schedule.Scheduled#name() + * @param scheduleName 定时任务名称 + * @return 返回任务数量 + */ + public int stop(String scheduleName); +} diff --git a/src/main/java/org/redkale/schedule/Scheduled.java b/src/main/java/org/redkale/schedule/Scheduled.java index 31ade8c88..80750f4a4 100644 --- a/src/main/java/org/redkale/schedule/Scheduled.java +++ b/src/main/java/org/redkale/schedule/Scheduled.java @@ -1,100 +1,100 @@ -/* - * - */ -package org.redkale.schedule; - -import java.lang.annotation.*; -import java.util.concurrent.TimeUnit; -import org.redkale.service.LoadMode; - -/** - * 定时任务标记,只能作用于Service的无参数或者单一ScheduleEvent参数的菲static方法上, 功能类似Spring里的Scheduled注解 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -@Documented -@Target({ElementType.METHOD}) -@Retention(RetentionPolicy.RUNTIME) -public @interface Scheduled { - - /** - * 名称, 可用于第三方实现的定时任务组件的key - * - * @return 名称 - */ - String name() default ""; - - /** - * cron表达式, 特殊值:
- * @yearly、@annually、@monthly、@weekly、@daily、@midnight、@hourly、@minutely - * @1m、@2m、@3m、@5m、@10m、@15m、@30m、 @1h、@2h、@3h、@6h - * ${env.scheduling.cron}: 读取系统配置项 - * - * @return cron表达式 - */ - String cron() default ""; - - /** - * 时区, 例如: Asia/Shanghai - * - * @return 时区 - */ - String zone() default ""; - - /** - * 延迟时间,支持参数配置、乘法表达式和对象字段值
- * 参数值支持方式:
- * 100: 设置数值 ${env.scheduling.fixedDelay}: 读取系统配置项 - * - *

值大于0且fixedRate小于0则使用 ScheduledThreadPoolExecutor.scheduleWithFixedDelay - * - * @return 延迟时间 - */ - String fixedDelay() default "-1"; - - /** - * 周期时间,支持参数配置、乘法表达式和对象字段值
- * 参数值支持方式:
- * 100: 设置数值 ${env.scheduling.fixedRate}: 读取系统配置项 - * - *

值大于0则使用 ScheduledThreadPoolExecutor.scheduleAtFixedRate - * - * @return 周期时间 - */ - String fixedRate() default "-1"; - - /** - * 起始延迟时间,支持参数配置、乘法表达式和对象字段值
- * 参数值支持方式:
- * 100: 设置数值 ${env.scheduling.initialDelay}: 读取系统配置项 - * - *

值大于0且fixedRate和fixedDelay小于0则使用 ScheduledThreadPoolExecutor.schedule - * - * @return 起始延迟时间 - */ - String initialDelay() default "-1"; - - /** - * 时间单元 - * - * @return 时间单元 - */ - TimeUnit timeUnit() default TimeUnit.SECONDS; - - /** - * 备注 - * - * @return 备注 - */ - String comment() default ""; - - /** - * Service加载模式 - * - * @return 模式 - */ - LoadMode mode() default LoadMode.LOCAL; -} +/* + * + */ +package org.redkale.schedule; + +import java.lang.annotation.*; +import java.util.concurrent.TimeUnit; +import org.redkale.service.LoadMode; + +/** + * 定时任务标记,只能作用于Service的无参数或者单一ScheduleEvent参数的菲static方法上, 功能类似Spring里的Scheduled注解 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +@Documented +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface Scheduled { + + /** + * 名称, 可用于第三方实现的定时任务组件的key + * + * @return 名称 + */ + String name() default ""; + + /** + * cron表达式, 特殊值:
+ * @yearly、@annually、@monthly、@weekly、@daily、@midnight、@hourly、@minutely + * @1m、@2m、@3m、@5m、@10m、@15m、@30m、 @1h、@2h、@3h、@6h + * ${env.scheduling.cron}: 读取系统配置项 + * + * @return cron表达式 + */ + String cron() default ""; + + /** + * 时区, 例如: Asia/Shanghai + * + * @return 时区 + */ + String zone() default ""; + + /** + * 延迟时间,支持参数配置、乘法表达式和对象字段值
+ * 参数值支持方式:
+ * 100: 设置数值 ${env.scheduling.fixedDelay}: 读取系统配置项 + * + *

值大于0且fixedRate小于0则使用 ScheduledThreadPoolExecutor.scheduleWithFixedDelay + * + * @return 延迟时间 + */ + String fixedDelay() default "-1"; + + /** + * 周期时间,支持参数配置、乘法表达式和对象字段值
+ * 参数值支持方式:
+ * 100: 设置数值 ${env.scheduling.fixedRate}: 读取系统配置项 + * + *

值大于0则使用 ScheduledThreadPoolExecutor.scheduleAtFixedRate + * + * @return 周期时间 + */ + String fixedRate() default "-1"; + + /** + * 起始延迟时间,支持参数配置、乘法表达式和对象字段值
+ * 参数值支持方式:
+ * 100: 设置数值 ${env.scheduling.initialDelay}: 读取系统配置项 + * + *

值大于0且fixedRate和fixedDelay小于0则使用 ScheduledThreadPoolExecutor.schedule + * + * @return 起始延迟时间 + */ + String initialDelay() default "-1"; + + /** + * 时间单元 + * + * @return 时间单元 + */ + TimeUnit timeUnit() default TimeUnit.SECONDS; + + /** + * 备注 + * + * @return 备注 + */ + String comment() default ""; + + /** + * Service加载模式 + * + * @return 模式 + */ + LoadMode mode() default LoadMode.LOCAL; +} diff --git a/src/main/java/org/redkale/schedule/spi/CronExpression.java b/src/main/java/org/redkale/schedule/spi/CronExpression.java index 879c68534..8473e53f1 100644 --- a/src/main/java/org/redkale/schedule/spi/CronExpression.java +++ b/src/main/java/org/redkale/schedule/spi/CronExpression.java @@ -1,718 +1,718 @@ -/* - * - */ -package org.redkale.schedule.spi; - -import java.time.DateTimeException; -import java.time.temporal.ChronoField; -import java.time.temporal.ChronoUnit; -import java.time.temporal.Temporal; -import java.time.temporal.ValueRange; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import org.redkale.annotation.Nullable; -import org.redkale.util.RedkaleException; -import org.redkale.util.Utility; - -/** - * cron定时表达式解析器
- * 代码复制于org.springframework.scheduling.support.CronExpression - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public class CronExpression { - - static final int MAX_ATTEMPTS = 366; - - private static final String[] MACROS = new String[] { - "@yearly", "0 0 0 1 1 *", - "@annually", "0 0 0 1 1 *", - "@monthly", "0 0 0 1 * *", - "@monthly10s", "10 0 0 1 * *", - "@monthly30s", "30 0 0 1 * *", - "@monthly1m", "0 1 0 1 * *", - "@monthly5m", "0 5 0 1 * *", - "@monthly15m", "0 15 0 1 * *", - "@monthly30m", "0 30 0 1 * *", - "@monthly1h", "0 0 1 1 * *", - "@monthly2h", "0 0 2 1 * *", - "@weekly", "0 0 0 * * 0", - "@daily", "0 0 0 * * *", - "@daily10s", "10 0 0 * * *", - "@daily30s", "30 0 0 * * *", - "@daily1m", "0 1 0 * * *", - "@daily5m", "0 5 0 * * *", - "@daily15m", "0 15 0 * * *", - "@daily30m", "0 30 0 * * *", - "@daily1h", "0 0 1 * * *", - "@daily2h", "0 0 2 * * *", - "@midnight", "0 0 0 * * *", - "@midnight10s", "10 0 0 * * *", - "@midnight30s", "30 0 0 * * *", - "@midnight1m", "0 1 0 * * *", - "@midnight5m", "0 5 0 * * *", - "@midnight15m", "0 15 0 * * *", - "@midnight30m", "0 30 0 * * *", - "@midnight1h", "0 0 1 * * *", - "@midnight2h", "0 0 2 * * *", - "@hourly", "0 0 * * * *", - "@minutely", "0 0/1 * * * *", - "@1m", "0 0/1 * * * *", - "@2m", "0 0/2 * * * *", - "@3m", "0 0/3 * * * *", - "@5m", "0 0/5 * * * *", - "@10m", "0 0/10 * * * *", - "@15m", "0 0/15 * * * *", - "@30m", "0 0/30 * * * *", - "@1h", "0 0 * * * *", - "@2h", "0 0 0/2 * * *", - "@3h", "0 0 0/3 * * *", - "@6h", "0 0 0/6 * * *" - }; - - private final CronField[] fields; - - private final String expression; - - private CronExpression( - CronField seconds, - CronField minutes, - CronField hours, - CronField daysOfMonth, - CronField months, - CronField daysOfWeek, - String expression) { - this.fields = new CronField[] {daysOfWeek, months, daysOfMonth, hours, minutes, seconds, CronField.zeroNanos()}; - this.expression = expression; - } - - public static CronExpression parse(String expression) { - if (Utility.isBlank(expression)) { - throw new RedkaleException("Expression string must not be empty"); - } - expression = resolveMacros(expression); - String[] fields = expression.split("\\s+"); - if (fields.length != 6) { - throw new RedkaleException(String.format( - "Cron expression must consist of 6 fields (found %d in \"%s\")", fields.length, expression)); - } - try { - CronField seconds = CronField.parseSeconds(fields[0]); - CronField minutes = CronField.parseMinutes(fields[1]); - CronField hours = CronField.parseHours(fields[2]); - CronField daysOfMonth = CronField.parseDaysOfMonth(fields[3]); - CronField months = CronField.parseMonth(fields[4]); - CronField daysOfWeek = CronField.parseDaysOfWeek(fields[5]); - return new CronExpression(seconds, minutes, hours, daysOfMonth, months, daysOfWeek, expression); - } catch (IllegalArgumentException ex) { - String msg = ex.getMessage() + " in cron expression \"" + expression + "\""; - throw new RedkaleException(msg, ex); - } - } - - private static String resolveMacros(String expression) { - expression = expression.trim(); - for (int i = 0; i < MACROS.length; i = i + 2) { - if (MACROS[i].equalsIgnoreCase(expression)) { - return MACROS[i + 1]; - } - } - return expression; - } - - @Nullable - public > T next(T temporal) { - return nextOrSame(ChronoUnit.NANOS.addTo(temporal, 1)); - } - - @Nullable - private > T nextOrSame(T temporal) { - for (int i = 0; i < MAX_ATTEMPTS; i++) { - T result = nextOrSameInternal(temporal); - if (result == null || result.equals(temporal)) { - return result; - } - temporal = result; - } - return null; - } - - @Nullable - private > T nextOrSameInternal(T temporal) { - for (CronField field : this.fields) { - temporal = field.nextOrSame(temporal); - if (temporal == null) { - return null; - } - } - return temporal; - } - - @Override - public boolean equals(@Nullable Object other) { - if (this == other) { - return true; - } - if (!(other instanceof CronExpression)) { - return false; - } - CronExpression that = (CronExpression) other; - return Arrays.equals(this.fields, that.fields); - } - - @Override - public int hashCode() { - return Arrays.hashCode(this.fields); - } - - @Override - public String toString() { - return this.expression; - } - - abstract static class CronField { - - private static final String[] MONTHS = - new String[] {"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"}; - - private static final String[] DAYS = new String[] {"MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"}; - - private final Type type; - - protected CronField(Type type) { - this.type = type; - } - - public static CronField zeroNanos() { - return BitsCronField.zeroNanos(); - } - - public static CronField parseSeconds(String value) { - return BitsCronField.parseSeconds(value); - } - - public static CronField parseMinutes(String value) { - return BitsCronField.parseMinutes(value); - } - - public static CronField parseHours(String value) { - return BitsCronField.parseHours(value); - } - - public static CronField parseDaysOfMonth(String value) { - return BitsCronField.parseDaysOfMonth(value); - } - - public static CronField parseMonth(String value) { - value = replaceOrdinals(value, MONTHS); - return BitsCronField.parseMonth(value); - } - - public static CronField parseDaysOfWeek(String value) { - value = replaceOrdinals(value, DAYS); - return BitsCronField.parseDaysOfWeek(value); - } - - private static String replaceOrdinals(String value, String[] list) { - value = value.toUpperCase(); - for (int i = 0; i < list.length; i++) { - String replacement = Integer.toString(i + 1); - value = replace(value, list[i], replacement); - } - return value; - } - - private static String replace(String inString, String oldPattern, @Nullable String newPattern) { - if (Utility.isEmpty(inString) || Utility.isEmpty(oldPattern) || newPattern == null) { - return inString; - } - int index = inString.indexOf(oldPattern); - if (index == -1) { - // no occurrence -> can return input as-is - return inString; - } - - int capacity = inString.length(); - if (newPattern.length() > oldPattern.length()) { - capacity += 16; - } - StringBuilder sb = new StringBuilder(capacity); - - int pos = 0; // our position in the old string - int patLen = oldPattern.length(); - while (index >= 0) { - sb.append(inString, pos, index); - sb.append(newPattern); - pos = index + patLen; - index = inString.indexOf(oldPattern, pos); - } - - // append any characters to the right of a match - sb.append(inString, pos, inString.length()); - return sb.toString(); - } - - private static String[] delimitedListToStringArray(@Nullable String str, @Nullable String delimiter) { - return delimitedListToStringArray(str, delimiter, null); - } - - private static String[] delimitedListToStringArray(String str, String delimiter, String charsToDelete) { - - if (str == null) { - return new String[0]; - } - if (delimiter == null) { - return new String[] {str}; - } - - List result = new ArrayList<>(); - if (delimiter.isEmpty()) { - for (int i = 0; i < str.length(); i++) { - result.add(deleteAny(str.substring(i, i + 1), charsToDelete)); - } - } else { - int pos = 0; - int delPos; - while ((delPos = str.indexOf(delimiter, pos)) != -1) { - result.add(deleteAny(str.substring(pos, delPos), charsToDelete)); - pos = delPos + delimiter.length(); - } - if (str.length() > 0 && pos <= str.length()) { - // Add rest of String, but not in case of empty input. - result.add(deleteAny(str.substring(pos), charsToDelete)); - } - } - return result.toArray(new String[result.size()]); - } - - private static String deleteAny(String inString, @Nullable String charsToDelete) { - if (Utility.isEmpty(inString) || Utility.isEmpty(charsToDelete)) { - return inString; - } - int lastCharIndex = 0; - char[] result = new char[inString.length()]; - for (int i = 0; i < inString.length(); i++) { - char c = inString.charAt(i); - if (charsToDelete.indexOf(c) == -1) { - result[lastCharIndex++] = c; - } - } - if (lastCharIndex == inString.length()) { - return inString; - } - return new String(result, 0, lastCharIndex); - } - - @Nullable - public abstract > T nextOrSame(T temporal); - - protected Type type() { - return this.type; - } - - @SuppressWarnings("unchecked") - protected static > T cast(Temporal temporal) { - return (T) temporal; - } - - protected enum Type { - NANO(ChronoField.NANO_OF_SECOND, ChronoUnit.SECONDS), - SECOND(ChronoField.SECOND_OF_MINUTE, ChronoUnit.MINUTES, ChronoField.NANO_OF_SECOND), - MINUTE( - ChronoField.MINUTE_OF_HOUR, - ChronoUnit.HOURS, - ChronoField.SECOND_OF_MINUTE, - ChronoField.NANO_OF_SECOND), - HOUR( - ChronoField.HOUR_OF_DAY, - ChronoUnit.DAYS, - ChronoField.MINUTE_OF_HOUR, - ChronoField.SECOND_OF_MINUTE, - ChronoField.NANO_OF_SECOND), - DAY_OF_MONTH( - ChronoField.DAY_OF_MONTH, - ChronoUnit.MONTHS, - ChronoField.HOUR_OF_DAY, - ChronoField.MINUTE_OF_HOUR, - ChronoField.SECOND_OF_MINUTE, - ChronoField.NANO_OF_SECOND), - MONTH( - ChronoField.MONTH_OF_YEAR, - ChronoUnit.YEARS, - ChronoField.DAY_OF_MONTH, - ChronoField.HOUR_OF_DAY, - ChronoField.MINUTE_OF_HOUR, - ChronoField.SECOND_OF_MINUTE, - ChronoField.NANO_OF_SECOND), - DAY_OF_WEEK( - ChronoField.DAY_OF_WEEK, - ChronoUnit.WEEKS, - ChronoField.HOUR_OF_DAY, - ChronoField.MINUTE_OF_HOUR, - ChronoField.SECOND_OF_MINUTE, - ChronoField.NANO_OF_SECOND); - - private final ChronoField field; - - private final ChronoUnit higherOrder; - - private final ChronoField[] lowerOrders; - - Type(ChronoField field, ChronoUnit higherOrder, ChronoField... lowerOrders) { - this.field = field; - this.higherOrder = higherOrder; - this.lowerOrders = lowerOrders; - } - - public int get(Temporal date) { - return date.get(this.field); - } - - public ValueRange range() { - return this.field.range(); - } - - public int checkValidValue(int value) { - if (this == DAY_OF_WEEK && value == 0) { - return value; - } else { - try { - return this.field.checkValidIntValue(value); - } catch (DateTimeException ex) { - throw new IllegalArgumentException(ex.getMessage(), ex); - } - } - } - - public > T elapseUntil(T temporal, int goal) { - int current = get(temporal); - ValueRange range = temporal.range(this.field); - if (current < goal) { - if (range.isValidIntValue(goal)) { - return cast(temporal.with(this.field, goal)); - } else { - // goal is invalid, eg. 29th Feb, so roll forward - long amount = range.getMaximum() - current + 1; - return this.field.getBaseUnit().addTo(temporal, amount); - } - } else { - long amount = goal + range.getMaximum() - current + 1 - range.getMinimum(); - return this.field.getBaseUnit().addTo(temporal, amount); - } - } - - public > T rollForward(T temporal) { - T result = this.higherOrder.addTo(temporal, 1); - ValueRange range = result.range(this.field); - return this.field.adjustInto(result, range.getMinimum()); - } - - public T reset(T temporal) { - for (ChronoField lowerOrder : this.lowerOrders) { - if (temporal.isSupported(lowerOrder)) { - temporal = lowerOrder.adjustInto( - temporal, temporal.range(lowerOrder).getMinimum()); - } - } - return temporal; - } - - @Override - public String toString() { - return this.field.toString(); - } - } - } - - static class BitsCronField extends CronField { - - private static final long MASK = 0xFFFFFFFFFFFFFFFFL; - - @Nullable - private static BitsCronField zeroNanos = null; - - // we store at most 60 bits, for seconds and minutes, so a 64-bit long suffices - private long bits; - - private BitsCronField(Type type) { - super(type); - } - - public static BitsCronField zeroNanos() { - if (zeroNanos == null) { - BitsCronField field = new BitsCronField(Type.NANO); - field.setBit(0); - zeroNanos = field; - } - return zeroNanos; - } - - public static BitsCronField parseSeconds(String value) { - return parseField(value, Type.SECOND); - } - - public static BitsCronField parseMinutes(String value) { - return BitsCronField.parseField(value, Type.MINUTE); - } - - public static BitsCronField parseHours(String value) { - return BitsCronField.parseField(value, Type.HOUR); - } - - public static BitsCronField parseDaysOfMonth(String value) { - return parseDate(value, Type.DAY_OF_MONTH); - } - - public static BitsCronField parseMonth(String value) { - return BitsCronField.parseField(value, Type.MONTH); - } - - public static BitsCronField parseDaysOfWeek(String value) { - BitsCronField result = parseDate(value, Type.DAY_OF_WEEK); - if (result.getBit(0)) { - // cron supports 0 for Sunday; we use 7 like java.time - result.setBit(7); - result.clearBit(0); - } - return result; - } - - private static BitsCronField parseDate(String value, BitsCronField.Type type) { - if (value.equals("?")) { - value = "*"; - } - return BitsCronField.parseField(value, type); - } - - private static BitsCronField parseField(String value, Type type) { - if (Utility.isBlank(value)) { - throw new RedkaleException("Value must not be empty"); - } - if (type == null) { - throw new RedkaleException("Type must not be null"); - } - try { - BitsCronField result = new BitsCronField(type); - String[] fields = CronField.delimitedListToStringArray(value, ","); - for (String field : fields) { - int slashPos = field.indexOf('/'); - if (slashPos == -1) { - ValueRange range = parseRange(field, type); - result.setBits(range); - } else { - String rangeStr = field.substring(0, slashPos); - String deltaStr = field.substring(slashPos + 1); - ValueRange range = parseRange(rangeStr, type); - if (rangeStr.indexOf('-') == -1) { - range = ValueRange.of( - range.getMinimum(), type.range().getMaximum()); - } - int delta = Integer.parseInt(deltaStr); - if (delta <= 0) { - throw new IllegalArgumentException("Incrementer delta must be 1 or higher"); - } - result.setBits(range, delta); - } - } - return result; - } catch (DateTimeException | IllegalArgumentException ex) { - String msg = ex.getMessage() + " '" + value + "'"; - throw new IllegalArgumentException(msg, ex); - } - } - - private static ValueRange parseRange(String value, Type type) { - if (value.equals("*")) { - return type.range(); - } else { - int hyphenPos = value.indexOf('-'); - if (hyphenPos == -1) { - int result = type.checkValidValue(Integer.parseInt(value)); - return ValueRange.of(result, result); - } else { - int min = Integer.parseInt(value, 0, hyphenPos, 10); - int max = Integer.parseInt(value, hyphenPos + 1, value.length(), 10); - min = type.checkValidValue(min); - max = type.checkValidValue(max); - if (type == Type.DAY_OF_WEEK && min == 7) { - // If used as a minimum in a range, Sunday means 0 (not 7) - min = 0; - } - return ValueRange.of(min, max); - } - } - } - - @Nullable - @Override - public > T nextOrSame(T temporal) { - int current = type().get(temporal); - int next = nextSetBit(current); - if (next == -1) { - temporal = type().rollForward(temporal); - next = nextSetBit(0); - } - if (next == current) { - return temporal; - } else { - int count = 0; - current = type().get(temporal); - while (current != next && count++ < CronExpression.MAX_ATTEMPTS) { - temporal = type().elapseUntil(temporal, next); - current = type().get(temporal); - next = nextSetBit(current); - if (next == -1) { - temporal = type().rollForward(temporal); - next = nextSetBit(0); - } - } - if (count >= CronExpression.MAX_ATTEMPTS) { - return null; - } - return type().reset(temporal); - } - } - - boolean getBit(int index) { - return (this.bits & (1L << index)) != 0; - } - - private int nextSetBit(int fromIndex) { - long result = this.bits & (MASK << fromIndex); - if (result != 0) { - return Long.numberOfTrailingZeros(result); - } else { - return -1; - } - } - - private void setBits(ValueRange range) { - if (range.getMinimum() == range.getMaximum()) { - setBit((int) range.getMinimum()); - } else { - long minMask = MASK << range.getMinimum(); - long maxMask = MASK >>> -(range.getMaximum() + 1); - this.bits |= (minMask & maxMask); - } - } - - private void setBits(ValueRange range, int delta) { - if (delta == 1) { - setBits(range); - } else { - for (int i = (int) range.getMinimum(); i <= range.getMaximum(); i += delta) { - setBit(i); - } - } - } - - private void setBit(int index) { - this.bits |= (1L << index); - } - - private void clearBit(int index) { - this.bits &= ~(1L << index); - } - - @Override - public int hashCode() { - return Long.hashCode(this.bits); - } - - @Override - public boolean equals(@Nullable Object o) { - if (this == o) { - return true; - } - if (!(o instanceof BitsCronField)) { - return false; - } - BitsCronField other = (BitsCronField) o; - return type() == other.type() && this.bits == other.bits; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(type().toString()); - builder.append(" {"); - int i = nextSetBit(0); - if (i != -1) { - builder.append(i); - i = nextSetBit(i + 1); - while (i != -1) { - builder.append(", "); - builder.append(i); - i = nextSetBit(i + 1); - } - } - builder.append('}'); - return builder.toString(); - } - } - - static class CompositeCronField extends CronField { - - private final CronField[] fields; - - private final String value; - - private CompositeCronField(Type type, CronField[] fields, String value) { - super(type); - this.fields = fields; - this.value = value; - } - - public static CronField compose(CronField[] fields, Type type, String value) { - if (fields == null || fields.length < 1) { - throw new RedkaleException("Fields must not be empty"); - } - if (Utility.isBlank(value)) { - throw new RedkaleException("Value must not be empty"); - } - if (fields.length == 1) { - return fields[0]; - } else { - return new CompositeCronField(type, fields, value); - } - } - - @Nullable - @Override - public > T nextOrSame(T temporal) { - T result = null; - for (CronField field : this.fields) { - T candidate = field.nextOrSame(temporal); - if (result == null || candidate != null && candidate.compareTo(result) < 0) { - result = candidate; - } - } - return result; - } - - @Override - public int hashCode() { - return this.value.hashCode(); - } - - @Override - public boolean equals(@Nullable Object o) { - if (this == o) { - return true; - } - if (!(o instanceof CompositeCronField)) { - return false; - } - CompositeCronField other = (CompositeCronField) o; - return type() == other.type() && this.value.equals(other.value); - } - - @Override - public String toString() { - return type() + " '" + this.value + "'"; - } - } -} +/* + * + */ +package org.redkale.schedule.spi; + +import java.time.DateTimeException; +import java.time.temporal.ChronoField; +import java.time.temporal.ChronoUnit; +import java.time.temporal.Temporal; +import java.time.temporal.ValueRange; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import org.redkale.annotation.Nullable; +import org.redkale.util.RedkaleException; +import org.redkale.util.Utility; + +/** + * cron定时表达式解析器
+ * 代码复制于org.springframework.scheduling.support.CronExpression + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public class CronExpression { + + static final int MAX_ATTEMPTS = 366; + + private static final String[] MACROS = new String[] { + "@yearly", "0 0 0 1 1 *", + "@annually", "0 0 0 1 1 *", + "@monthly", "0 0 0 1 * *", + "@monthly10s", "10 0 0 1 * *", + "@monthly30s", "30 0 0 1 * *", + "@monthly1m", "0 1 0 1 * *", + "@monthly5m", "0 5 0 1 * *", + "@monthly15m", "0 15 0 1 * *", + "@monthly30m", "0 30 0 1 * *", + "@monthly1h", "0 0 1 1 * *", + "@monthly2h", "0 0 2 1 * *", + "@weekly", "0 0 0 * * 0", + "@daily", "0 0 0 * * *", + "@daily10s", "10 0 0 * * *", + "@daily30s", "30 0 0 * * *", + "@daily1m", "0 1 0 * * *", + "@daily5m", "0 5 0 * * *", + "@daily15m", "0 15 0 * * *", + "@daily30m", "0 30 0 * * *", + "@daily1h", "0 0 1 * * *", + "@daily2h", "0 0 2 * * *", + "@midnight", "0 0 0 * * *", + "@midnight10s", "10 0 0 * * *", + "@midnight30s", "30 0 0 * * *", + "@midnight1m", "0 1 0 * * *", + "@midnight5m", "0 5 0 * * *", + "@midnight15m", "0 15 0 * * *", + "@midnight30m", "0 30 0 * * *", + "@midnight1h", "0 0 1 * * *", + "@midnight2h", "0 0 2 * * *", + "@hourly", "0 0 * * * *", + "@minutely", "0 0/1 * * * *", + "@1m", "0 0/1 * * * *", + "@2m", "0 0/2 * * * *", + "@3m", "0 0/3 * * * *", + "@5m", "0 0/5 * * * *", + "@10m", "0 0/10 * * * *", + "@15m", "0 0/15 * * * *", + "@30m", "0 0/30 * * * *", + "@1h", "0 0 * * * *", + "@2h", "0 0 0/2 * * *", + "@3h", "0 0 0/3 * * *", + "@6h", "0 0 0/6 * * *" + }; + + private final CronField[] fields; + + private final String expression; + + private CronExpression( + CronField seconds, + CronField minutes, + CronField hours, + CronField daysOfMonth, + CronField months, + CronField daysOfWeek, + String expression) { + this.fields = new CronField[] {daysOfWeek, months, daysOfMonth, hours, minutes, seconds, CronField.zeroNanos()}; + this.expression = expression; + } + + public static CronExpression parse(String expression) { + if (Utility.isBlank(expression)) { + throw new RedkaleException("Expression string must not be empty"); + } + expression = resolveMacros(expression); + String[] fields = expression.split("\\s+"); + if (fields.length != 6) { + throw new RedkaleException(String.format( + "Cron expression must consist of 6 fields (found %d in \"%s\")", fields.length, expression)); + } + try { + CronField seconds = CronField.parseSeconds(fields[0]); + CronField minutes = CronField.parseMinutes(fields[1]); + CronField hours = CronField.parseHours(fields[2]); + CronField daysOfMonth = CronField.parseDaysOfMonth(fields[3]); + CronField months = CronField.parseMonth(fields[4]); + CronField daysOfWeek = CronField.parseDaysOfWeek(fields[5]); + return new CronExpression(seconds, minutes, hours, daysOfMonth, months, daysOfWeek, expression); + } catch (IllegalArgumentException ex) { + String msg = ex.getMessage() + " in cron expression \"" + expression + "\""; + throw new RedkaleException(msg, ex); + } + } + + private static String resolveMacros(String expression) { + expression = expression.trim(); + for (int i = 0; i < MACROS.length; i = i + 2) { + if (MACROS[i].equalsIgnoreCase(expression)) { + return MACROS[i + 1]; + } + } + return expression; + } + + @Nullable + public > T next(T temporal) { + return nextOrSame(ChronoUnit.NANOS.addTo(temporal, 1)); + } + + @Nullable + private > T nextOrSame(T temporal) { + for (int i = 0; i < MAX_ATTEMPTS; i++) { + T result = nextOrSameInternal(temporal); + if (result == null || result.equals(temporal)) { + return result; + } + temporal = result; + } + return null; + } + + @Nullable + private > T nextOrSameInternal(T temporal) { + for (CronField field : this.fields) { + temporal = field.nextOrSame(temporal); + if (temporal == null) { + return null; + } + } + return temporal; + } + + @Override + public boolean equals(@Nullable Object other) { + if (this == other) { + return true; + } + if (!(other instanceof CronExpression)) { + return false; + } + CronExpression that = (CronExpression) other; + return Arrays.equals(this.fields, that.fields); + } + + @Override + public int hashCode() { + return Arrays.hashCode(this.fields); + } + + @Override + public String toString() { + return this.expression; + } + + abstract static class CronField { + + private static final String[] MONTHS = + new String[] {"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"}; + + private static final String[] DAYS = new String[] {"MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"}; + + private final Type type; + + protected CronField(Type type) { + this.type = type; + } + + public static CronField zeroNanos() { + return BitsCronField.zeroNanos(); + } + + public static CronField parseSeconds(String value) { + return BitsCronField.parseSeconds(value); + } + + public static CronField parseMinutes(String value) { + return BitsCronField.parseMinutes(value); + } + + public static CronField parseHours(String value) { + return BitsCronField.parseHours(value); + } + + public static CronField parseDaysOfMonth(String value) { + return BitsCronField.parseDaysOfMonth(value); + } + + public static CronField parseMonth(String value) { + value = replaceOrdinals(value, MONTHS); + return BitsCronField.parseMonth(value); + } + + public static CronField parseDaysOfWeek(String value) { + value = replaceOrdinals(value, DAYS); + return BitsCronField.parseDaysOfWeek(value); + } + + private static String replaceOrdinals(String value, String[] list) { + value = value.toUpperCase(); + for (int i = 0; i < list.length; i++) { + String replacement = Integer.toString(i + 1); + value = replace(value, list[i], replacement); + } + return value; + } + + private static String replace(String inString, String oldPattern, @Nullable String newPattern) { + if (Utility.isEmpty(inString) || Utility.isEmpty(oldPattern) || newPattern == null) { + return inString; + } + int index = inString.indexOf(oldPattern); + if (index == -1) { + // no occurrence -> can return input as-is + return inString; + } + + int capacity = inString.length(); + if (newPattern.length() > oldPattern.length()) { + capacity += 16; + } + StringBuilder sb = new StringBuilder(capacity); + + int pos = 0; // our position in the old string + int patLen = oldPattern.length(); + while (index >= 0) { + sb.append(inString, pos, index); + sb.append(newPattern); + pos = index + patLen; + index = inString.indexOf(oldPattern, pos); + } + + // append any characters to the right of a match + sb.append(inString, pos, inString.length()); + return sb.toString(); + } + + private static String[] delimitedListToStringArray(@Nullable String str, @Nullable String delimiter) { + return delimitedListToStringArray(str, delimiter, null); + } + + private static String[] delimitedListToStringArray(String str, String delimiter, String charsToDelete) { + + if (str == null) { + return new String[0]; + } + if (delimiter == null) { + return new String[] {str}; + } + + List result = new ArrayList<>(); + if (delimiter.isEmpty()) { + for (int i = 0; i < str.length(); i++) { + result.add(deleteAny(str.substring(i, i + 1), charsToDelete)); + } + } else { + int pos = 0; + int delPos; + while ((delPos = str.indexOf(delimiter, pos)) != -1) { + result.add(deleteAny(str.substring(pos, delPos), charsToDelete)); + pos = delPos + delimiter.length(); + } + if (str.length() > 0 && pos <= str.length()) { + // Add rest of String, but not in case of empty input. + result.add(deleteAny(str.substring(pos), charsToDelete)); + } + } + return result.toArray(new String[result.size()]); + } + + private static String deleteAny(String inString, @Nullable String charsToDelete) { + if (Utility.isEmpty(inString) || Utility.isEmpty(charsToDelete)) { + return inString; + } + int lastCharIndex = 0; + char[] result = new char[inString.length()]; + for (int i = 0; i < inString.length(); i++) { + char c = inString.charAt(i); + if (charsToDelete.indexOf(c) == -1) { + result[lastCharIndex++] = c; + } + } + if (lastCharIndex == inString.length()) { + return inString; + } + return new String(result, 0, lastCharIndex); + } + + @Nullable + public abstract > T nextOrSame(T temporal); + + protected Type type() { + return this.type; + } + + @SuppressWarnings("unchecked") + protected static > T cast(Temporal temporal) { + return (T) temporal; + } + + protected enum Type { + NANO(ChronoField.NANO_OF_SECOND, ChronoUnit.SECONDS), + SECOND(ChronoField.SECOND_OF_MINUTE, ChronoUnit.MINUTES, ChronoField.NANO_OF_SECOND), + MINUTE( + ChronoField.MINUTE_OF_HOUR, + ChronoUnit.HOURS, + ChronoField.SECOND_OF_MINUTE, + ChronoField.NANO_OF_SECOND), + HOUR( + ChronoField.HOUR_OF_DAY, + ChronoUnit.DAYS, + ChronoField.MINUTE_OF_HOUR, + ChronoField.SECOND_OF_MINUTE, + ChronoField.NANO_OF_SECOND), + DAY_OF_MONTH( + ChronoField.DAY_OF_MONTH, + ChronoUnit.MONTHS, + ChronoField.HOUR_OF_DAY, + ChronoField.MINUTE_OF_HOUR, + ChronoField.SECOND_OF_MINUTE, + ChronoField.NANO_OF_SECOND), + MONTH( + ChronoField.MONTH_OF_YEAR, + ChronoUnit.YEARS, + ChronoField.DAY_OF_MONTH, + ChronoField.HOUR_OF_DAY, + ChronoField.MINUTE_OF_HOUR, + ChronoField.SECOND_OF_MINUTE, + ChronoField.NANO_OF_SECOND), + DAY_OF_WEEK( + ChronoField.DAY_OF_WEEK, + ChronoUnit.WEEKS, + ChronoField.HOUR_OF_DAY, + ChronoField.MINUTE_OF_HOUR, + ChronoField.SECOND_OF_MINUTE, + ChronoField.NANO_OF_SECOND); + + private final ChronoField field; + + private final ChronoUnit higherOrder; + + private final ChronoField[] lowerOrders; + + Type(ChronoField field, ChronoUnit higherOrder, ChronoField... lowerOrders) { + this.field = field; + this.higherOrder = higherOrder; + this.lowerOrders = lowerOrders; + } + + public int get(Temporal date) { + return date.get(this.field); + } + + public ValueRange range() { + return this.field.range(); + } + + public int checkValidValue(int value) { + if (this == DAY_OF_WEEK && value == 0) { + return value; + } else { + try { + return this.field.checkValidIntValue(value); + } catch (DateTimeException ex) { + throw new IllegalArgumentException(ex.getMessage(), ex); + } + } + } + + public > T elapseUntil(T temporal, int goal) { + int current = get(temporal); + ValueRange range = temporal.range(this.field); + if (current < goal) { + if (range.isValidIntValue(goal)) { + return cast(temporal.with(this.field, goal)); + } else { + // goal is invalid, eg. 29th Feb, so roll forward + long amount = range.getMaximum() - current + 1; + return this.field.getBaseUnit().addTo(temporal, amount); + } + } else { + long amount = goal + range.getMaximum() - current + 1 - range.getMinimum(); + return this.field.getBaseUnit().addTo(temporal, amount); + } + } + + public > T rollForward(T temporal) { + T result = this.higherOrder.addTo(temporal, 1); + ValueRange range = result.range(this.field); + return this.field.adjustInto(result, range.getMinimum()); + } + + public T reset(T temporal) { + for (ChronoField lowerOrder : this.lowerOrders) { + if (temporal.isSupported(lowerOrder)) { + temporal = lowerOrder.adjustInto( + temporal, temporal.range(lowerOrder).getMinimum()); + } + } + return temporal; + } + + @Override + public String toString() { + return this.field.toString(); + } + } + } + + static class BitsCronField extends CronField { + + private static final long MASK = 0xFFFFFFFFFFFFFFFFL; + + @Nullable + private static BitsCronField zeroNanos = null; + + // we store at most 60 bits, for seconds and minutes, so a 64-bit long suffices + private long bits; + + private BitsCronField(Type type) { + super(type); + } + + public static BitsCronField zeroNanos() { + if (zeroNanos == null) { + BitsCronField field = new BitsCronField(Type.NANO); + field.setBit(0); + zeroNanos = field; + } + return zeroNanos; + } + + public static BitsCronField parseSeconds(String value) { + return parseField(value, Type.SECOND); + } + + public static BitsCronField parseMinutes(String value) { + return BitsCronField.parseField(value, Type.MINUTE); + } + + public static BitsCronField parseHours(String value) { + return BitsCronField.parseField(value, Type.HOUR); + } + + public static BitsCronField parseDaysOfMonth(String value) { + return parseDate(value, Type.DAY_OF_MONTH); + } + + public static BitsCronField parseMonth(String value) { + return BitsCronField.parseField(value, Type.MONTH); + } + + public static BitsCronField parseDaysOfWeek(String value) { + BitsCronField result = parseDate(value, Type.DAY_OF_WEEK); + if (result.getBit(0)) { + // cron supports 0 for Sunday; we use 7 like java.time + result.setBit(7); + result.clearBit(0); + } + return result; + } + + private static BitsCronField parseDate(String value, BitsCronField.Type type) { + if (value.equals("?")) { + value = "*"; + } + return BitsCronField.parseField(value, type); + } + + private static BitsCronField parseField(String value, Type type) { + if (Utility.isBlank(value)) { + throw new RedkaleException("Value must not be empty"); + } + if (type == null) { + throw new RedkaleException("Type must not be null"); + } + try { + BitsCronField result = new BitsCronField(type); + String[] fields = CronField.delimitedListToStringArray(value, ","); + for (String field : fields) { + int slashPos = field.indexOf('/'); + if (slashPos == -1) { + ValueRange range = parseRange(field, type); + result.setBits(range); + } else { + String rangeStr = field.substring(0, slashPos); + String deltaStr = field.substring(slashPos + 1); + ValueRange range = parseRange(rangeStr, type); + if (rangeStr.indexOf('-') == -1) { + range = ValueRange.of( + range.getMinimum(), type.range().getMaximum()); + } + int delta = Integer.parseInt(deltaStr); + if (delta <= 0) { + throw new IllegalArgumentException("Incrementer delta must be 1 or higher"); + } + result.setBits(range, delta); + } + } + return result; + } catch (DateTimeException | IllegalArgumentException ex) { + String msg = ex.getMessage() + " '" + value + "'"; + throw new IllegalArgumentException(msg, ex); + } + } + + private static ValueRange parseRange(String value, Type type) { + if (value.equals("*")) { + return type.range(); + } else { + int hyphenPos = value.indexOf('-'); + if (hyphenPos == -1) { + int result = type.checkValidValue(Integer.parseInt(value)); + return ValueRange.of(result, result); + } else { + int min = Integer.parseInt(value, 0, hyphenPos, 10); + int max = Integer.parseInt(value, hyphenPos + 1, value.length(), 10); + min = type.checkValidValue(min); + max = type.checkValidValue(max); + if (type == Type.DAY_OF_WEEK && min == 7) { + // If used as a minimum in a range, Sunday means 0 (not 7) + min = 0; + } + return ValueRange.of(min, max); + } + } + } + + @Nullable + @Override + public > T nextOrSame(T temporal) { + int current = type().get(temporal); + int next = nextSetBit(current); + if (next == -1) { + temporal = type().rollForward(temporal); + next = nextSetBit(0); + } + if (next == current) { + return temporal; + } else { + int count = 0; + current = type().get(temporal); + while (current != next && count++ < CronExpression.MAX_ATTEMPTS) { + temporal = type().elapseUntil(temporal, next); + current = type().get(temporal); + next = nextSetBit(current); + if (next == -1) { + temporal = type().rollForward(temporal); + next = nextSetBit(0); + } + } + if (count >= CronExpression.MAX_ATTEMPTS) { + return null; + } + return type().reset(temporal); + } + } + + boolean getBit(int index) { + return (this.bits & (1L << index)) != 0; + } + + private int nextSetBit(int fromIndex) { + long result = this.bits & (MASK << fromIndex); + if (result != 0) { + return Long.numberOfTrailingZeros(result); + } else { + return -1; + } + } + + private void setBits(ValueRange range) { + if (range.getMinimum() == range.getMaximum()) { + setBit((int) range.getMinimum()); + } else { + long minMask = MASK << range.getMinimum(); + long maxMask = MASK >>> -(range.getMaximum() + 1); + this.bits |= (minMask & maxMask); + } + } + + private void setBits(ValueRange range, int delta) { + if (delta == 1) { + setBits(range); + } else { + for (int i = (int) range.getMinimum(); i <= range.getMaximum(); i += delta) { + setBit(i); + } + } + } + + private void setBit(int index) { + this.bits |= (1L << index); + } + + private void clearBit(int index) { + this.bits &= ~(1L << index); + } + + @Override + public int hashCode() { + return Long.hashCode(this.bits); + } + + @Override + public boolean equals(@Nullable Object o) { + if (this == o) { + return true; + } + if (!(o instanceof BitsCronField)) { + return false; + } + BitsCronField other = (BitsCronField) o; + return type() == other.type() && this.bits == other.bits; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(type().toString()); + builder.append(" {"); + int i = nextSetBit(0); + if (i != -1) { + builder.append(i); + i = nextSetBit(i + 1); + while (i != -1) { + builder.append(", "); + builder.append(i); + i = nextSetBit(i + 1); + } + } + builder.append('}'); + return builder.toString(); + } + } + + static class CompositeCronField extends CronField { + + private final CronField[] fields; + + private final String value; + + private CompositeCronField(Type type, CronField[] fields, String value) { + super(type); + this.fields = fields; + this.value = value; + } + + public static CronField compose(CronField[] fields, Type type, String value) { + if (fields == null || fields.length < 1) { + throw new RedkaleException("Fields must not be empty"); + } + if (Utility.isBlank(value)) { + throw new RedkaleException("Value must not be empty"); + } + if (fields.length == 1) { + return fields[0]; + } else { + return new CompositeCronField(type, fields, value); + } + } + + @Nullable + @Override + public > T nextOrSame(T temporal) { + T result = null; + for (CronField field : this.fields) { + T candidate = field.nextOrSame(temporal); + if (result == null || candidate != null && candidate.compareTo(result) < 0) { + result = candidate; + } + } + return result; + } + + @Override + public int hashCode() { + return this.value.hashCode(); + } + + @Override + public boolean equals(@Nullable Object o) { + if (this == o) { + return true; + } + if (!(o instanceof CompositeCronField)) { + return false; + } + CompositeCronField other = (CompositeCronField) o; + return type() == other.type() && this.value.equals(other.value); + } + + @Override + public String toString() { + return type() + " '" + this.value + "'"; + } + } +} diff --git a/src/main/java/org/redkale/schedule/spi/ScheduleManagerProvider.java b/src/main/java/org/redkale/schedule/spi/ScheduleManagerProvider.java index 157d57767..ab92b5cf1 100644 --- a/src/main/java/org/redkale/schedule/spi/ScheduleManagerProvider.java +++ b/src/main/java/org/redkale/schedule/spi/ScheduleManagerProvider.java @@ -1,17 +1,17 @@ -/* - * - */ -package org.redkale.schedule.spi; - -import org.redkale.schedule.ScheduleManager; -import org.redkale.util.InstanceProvider; - -/** - * 自定义的ScheduleManager加载器, 如果标记@Priority加载器的优先级需要大于1000, 1000以下预留给官方加载器 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public interface ScheduleManagerProvider extends InstanceProvider {} +/* + * + */ +package org.redkale.schedule.spi; + +import org.redkale.schedule.ScheduleManager; +import org.redkale.util.InstanceProvider; + +/** + * 自定义的ScheduleManager加载器, 如果标记@Priority加载器的优先级需要大于1000, 1000以下预留给官方加载器 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public interface ScheduleManagerProvider extends InstanceProvider {} diff --git a/src/main/java/org/redkale/schedule/spi/ScheduleManagerService.java b/src/main/java/org/redkale/schedule/spi/ScheduleManagerService.java index 49acff648..d133d936a 100644 --- a/src/main/java/org/redkale/schedule/spi/ScheduleManagerService.java +++ b/src/main/java/org/redkale/schedule/spi/ScheduleManagerService.java @@ -1,490 +1,490 @@ -/* - * - */ -package org.redkale.schedule.spi; - -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.ref.WeakReference; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.time.Duration; -import java.time.LocalDateTime; -import java.time.ZoneId; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.locks.ReentrantLock; -import java.util.function.Function; -import java.util.function.UnaryOperator; -import java.util.logging.Level; -import java.util.logging.Logger; -import org.redkale.annotation.AutoLoad; -import org.redkale.annotation.Component; -import org.redkale.annotation.Nullable; -import org.redkale.annotation.Resource; -import org.redkale.annotation.ResourceType; -import org.redkale.boot.Application; -import org.redkale.net.sncp.Sncp; -import org.redkale.schedule.ScheduleEvent; -import org.redkale.schedule.ScheduleManager; -import org.redkale.schedule.Scheduled; -import org.redkale.service.LoadMode; -import org.redkale.service.Local; -import org.redkale.service.Service; -import org.redkale.util.AnyValue; -import org.redkale.util.RedkaleClassLoader; -import org.redkale.util.RedkaleException; -import org.redkale.util.Utility; - -/** - * 定时任务管理器 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -@Local -@Component -@AutoLoad(false) -@ResourceType(ScheduleManager.class) -public class ScheduleManagerService implements ScheduleManager, Service { - - protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); - - protected final ConcurrentHashMap> refTaskMap = new ConcurrentHashMap<>(); - - protected final ReentrantLock lock = new ReentrantLock(); - - @Resource(required = false) - protected Application application; - - @Nullable - private UnaryOperator propertyFunc; - - private ScheduledThreadPoolExecutor scheduler; - - protected boolean enabled = true; - - protected AnyValue config; - - protected ScheduleManagerService(UnaryOperator propertyFunc) { - this.propertyFunc = propertyFunc; - } - - // 一般用于独立组件 - public static ScheduleManagerService create(UnaryOperator propertyFunc) { - return new ScheduleManagerService(propertyFunc); - } - - public boolean enabled() { - return this.enabled; - } - - public ScheduleManagerService enabled(boolean val) { - this.enabled = val; - return this; - } - - @Override - public void init(AnyValue conf) { - if (conf == null) { - conf = AnyValue.create(); - } - this.config = conf; - this.enabled = config.getBoolValue("enabled", true); - if (this.enabled) { - if (this.propertyFunc == null && application != null) { - UnaryOperator func = application.getEnvironment()::getPropertyValue; - this.propertyFunc = func; - } - this.scheduler = new ScheduledThreadPoolExecutor( - Utility.cpus(), Utility.newThreadFactory("Redkale-Scheduled-Task-Thread-%s")); - this.scheduler.setRemoveOnCancelPolicy(true); - } - } - - @Override - public void destroy(AnyValue conf) { - if (scheduler != null) { - scheduler.shutdown(); - } - } - - public void onServersPreStart() { - // do nothing - } - - public void onServersPostStart() { - // do nothing - } - - @Override - public void schedule(Object service) { - lock.lock(); - try { - boolean remoteMode = service instanceof Service && Sncp.isRemote((Service) service); - for (WeakReference item : refTaskMap.keySet()) { - if (item.get() == service) { - logger.log(Level.WARNING, service + " repeat schedule"); - } - } - Map tasks = new LinkedHashMap<>(); - Class clazz = service.getClass(); - WeakReference ref = new WeakReference(service); - Set methodKeys = new HashSet<>(); - do { - for (final Method method : clazz.getDeclaredMethods()) { - if (method.getAnnotation(Scheduled.class) == null) { - continue; - } - String mk = Utility.methodKey(method); - if (methodKeys.contains(mk)) { - // 跳过已处理的继承方法 - continue; - } - methodKeys.add(mk); - if (method.getParameterCount() != 0 - && !(method.getParameterCount() == 1 - && method.getParameterTypes()[0] == ScheduleEvent.class)) { - throw new RedkaleException( - "@" + Scheduled.class.getSimpleName() + " must be on non-parameter or " - + ScheduleEvent.class.getSimpleName() + "-parameter method, but on " + method); - } - ScheduledTask task = schedule(ref, method, remoteMode); - // 时间没配置: task=null - if (task != null) { - tasks.put(method.getName(), task); - RedkaleClassLoader.putReflectionMethod(clazz.getName(), method); - } - } - } while ((clazz = clazz.getSuperclass()) != Object.class); - // 开始执行定时任务 - if (enabled && !tasks.isEmpty()) { - tasks.forEach((name, task) -> task.init()); - refTaskMap.put(ref, new ArrayList<>(tasks.values())); - } - } finally { - lock.unlock(); - } - } - - @Override - public void unschedule(Object service) { - lock.lock(); - try { - for (Map.Entry> item : refTaskMap.entrySet()) { - if (item.getKey().get() == service) { - refTaskMap.remove(item.getKey()); - for (ScheduledTask task : item.getValue()) { - task.stop(); - } - } - } - } finally { - lock.unlock(); - } - } - - protected ScheduledTask schedule(WeakReference ref, Method method, boolean remoteMode) { - Scheduled ann = method.getAnnotation(Scheduled.class); - if (!LoadMode.matches(remoteMode, ann.mode())) { - return null; - } - String name = getProperty(ann.name()); - String cron = getProperty(ann.cron()); - String fixedDelay = getProperty(ann.fixedDelay()); - String fixedRate = getProperty(ann.fixedRate()); - String initialDelay = getProperty(ann.initialDelay()); - String zone = getProperty(ann.zone()); - TimeUnit timeUnit = ann.timeUnit(); - return scheduleTask(ref, method, name, cron, fixedDelay, fixedRate, initialDelay, zone, timeUnit); - } - - protected ScheduledTask scheduleTask( - WeakReference ref, - Method method, - String name, - String cron, - String fixedDelay, - String fixedRate, - String initialDelay, - String zone, - TimeUnit timeUnit) { - if ((cron.isEmpty() || "-".equals(cron)) && "-1".equals(fixedRate) && "-1".endsWith(fixedDelay)) { - return createdOnlyNameTask( - ref, method, name, cron, fixedDelay, fixedRate, initialDelay, zone, timeUnit); // 时间都没配置 - } - ZoneId zoneId = Utility.isEmpty(zone) ? null : ZoneId.of(zone); - if (!cron.isEmpty() && !"-".equals(cron)) { - CronExpression cronExpr = CronExpression.parse(cron); - return new CronTask(ref, name, method, cronExpr, zoneId); - } else { - long fixedDelayLong = Long.parseLong(fixedDelay); - long fixedRateLong = Long.parseLong(fixedRate); - long initialDelayLong = Long.parseLong(initialDelay); - return new FixedTask(ref, name, method, fixedDelayLong, fixedRateLong, initialDelayLong, timeUnit); - } - } - - protected ScheduledTask createdOnlyNameTask( - WeakReference ref, - Method method, - String name, - String cron, - String fixedDelay, - String fixedRate, - String initialDelay, - String zone, - TimeUnit timeUnit) { - return null; - } - - protected Function createFuncJob(final WeakReference ref, Method method) { - try { - if (!Modifier.isPublic(method.getModifiers())) { - method.setAccessible(true); - } - MethodHandle mh = MethodHandles.lookup().unreflect(method); - return event -> { - Object rs = null; - try { - Object obj = ref.get(); - if (obj != null) { - if (event == null) { - rs = mh.invoke(obj); - } else { - rs = mh.invoke(obj, event); - } - } - } catch (Throwable t) { - logger.log(Level.SEVERE, "schedule task error", t); - } - if (event != null) { - event.clear(); - } - return rs; - }; - } catch (IllegalAccessException e) { - throw new RedkaleException(e); - } - } - - protected String getProperty(String value) { - if (propertyFunc == null || value == null || value.indexOf('}') < 0) { - return value; - } - return propertyFunc.apply(value); - } - - @Override - public int start(String scheduleName) { - int c = 0; - lock.lock(); - try { - for (Map.Entry> item : refTaskMap.entrySet()) { - for (ScheduledTask task : item.getValue()) { - if (Objects.equals(task.name(), scheduleName)) { - c++; - task.start(); - } - } - } - } finally { - lock.unlock(); - } - return c; - } - - @Override - public int stop(String scheduleName) { - int c = 0; - lock.lock(); - try { - for (Map.Entry> item : refTaskMap.entrySet()) { - for (ScheduledTask task : item.getValue()) { - if (Objects.equals(task.name(), scheduleName)) { - c++; - task.stop(); - } - } - } - } finally { - lock.unlock(); - } - return c; - } - - protected abstract class ScheduledTask { - - protected final WeakReference ref; - - protected final String name; - - protected final Method method; - - protected final AtomicBoolean started = new AtomicBoolean(); - - protected ScheduledFuture future; - - protected final ScheduleEvent event; - - protected final Map eventMap; - - // 任务是否正运行中 - protected final AtomicBoolean doing = new AtomicBoolean(); - - protected ScheduledTask(WeakReference ref, String name, Method method) { - Objects.requireNonNull(ref); - Objects.requireNonNull(name); - Objects.requireNonNull(method); - this.ref = ref; - this.name = name; - this.method = method; - this.eventMap = method.getParameterCount() == 0 ? null : new HashMap<>(); - this.event = eventMap == null ? null : new ScheduleEvent(eventMap); - } - - public void init() { - start(); - } - - public abstract void start(); - - public void stop() { - if (future != null) { - future.cancel(true); - future = null; - } - this.started.set(false); - } - - public boolean doing() { - return doing.get(); - } - - public Map eventMap() { - return eventMap; - } - - public Method method() { - return method; - } - - public String name() { - return name; - } - } - - protected class FixedTask extends ScheduledTask implements Runnable { - - private final Function delegate; - - private final long fixedDelay; - - private final long fixedRate; - - private final long initialDelay; - - private final TimeUnit timeUnit; - - public FixedTask( - final WeakReference ref, - String name, - Method method, - long fixedDelay, - long fixedRate, - long initialDelay, - TimeUnit timeUnit) { - super(ref, name, method); - this.delegate = createFuncJob(ref, method); - this.fixedDelay = fixedDelay; - this.fixedRate = fixedRate; - this.initialDelay = initialDelay; - this.timeUnit = timeUnit; - } - - @Override - public void run() { - doing.set(true); - try { - delegate.apply(event); - } catch (Throwable t) { - logger.log(Level.SEVERE, "schedule task error", t); - } finally { - doing.set(false); - } - if (ref.get() == null) { - stop(); - } - } - - @Override - public void start() { - if (started.compareAndSet(false, true)) { - if (fixedRate > 0) { - this.future = scheduler.scheduleAtFixedRate( - this, initialDelay > 0 ? initialDelay : 0, fixedRate, timeUnit); - } else if (fixedDelay > 0) { - this.future = scheduler.scheduleWithFixedDelay(this, initialDelay, fixedDelay, timeUnit); - } else if (initialDelay > 0) { - this.future = scheduler.schedule(this, initialDelay, timeUnit); - } - } - } - } - - protected class CronTask extends ScheduledTask implements Runnable { - - private final Function delegate; - - private final CronExpression cron; - - @Nullable - private final ZoneId zoneId; - - public CronTask(WeakReference ref, String name, Method method, CronExpression cron, ZoneId zoneId) { - super(ref, name, method); - this.delegate = createFuncJob(ref, method); - this.cron = cron; - this.zoneId = zoneId; - } - - @Override - public void run() { - doing.set(true); - try { - delegate.apply(event); - } catch (Throwable t) { - logger.log(Level.SEVERE, "schedule task error", t); - } finally { - doing.set(false); - } - start(); - } - - @Override - public void start() { - if (ref.get() == null) { - return; - } - if (started.compareAndSet(false, true)) { - LocalDateTime now = zoneId == null ? LocalDateTime.now() : LocalDateTime.now(zoneId); - LocalDateTime next = cron.next(now); - Duration delay = Duration.between(now, next); - this.future = scheduler.schedule(this, delay.toNanos(), TimeUnit.NANOSECONDS); - } - } - } -} +/* + * + */ +package org.redkale.schedule.spi; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.ref.WeakReference; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.time.Duration; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.locks.ReentrantLock; +import java.util.function.Function; +import java.util.function.UnaryOperator; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.redkale.annotation.AutoLoad; +import org.redkale.annotation.Component; +import org.redkale.annotation.Nullable; +import org.redkale.annotation.Resource; +import org.redkale.annotation.ResourceType; +import org.redkale.boot.Application; +import org.redkale.net.sncp.Sncp; +import org.redkale.schedule.ScheduleEvent; +import org.redkale.schedule.ScheduleManager; +import org.redkale.schedule.Scheduled; +import org.redkale.service.LoadMode; +import org.redkale.service.Local; +import org.redkale.service.Service; +import org.redkale.util.AnyValue; +import org.redkale.util.RedkaleClassLoader; +import org.redkale.util.RedkaleException; +import org.redkale.util.Utility; + +/** + * 定时任务管理器 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +@Local +@Component +@AutoLoad(false) +@ResourceType(ScheduleManager.class) +public class ScheduleManagerService implements ScheduleManager, Service { + + protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); + + protected final ConcurrentHashMap> refTaskMap = new ConcurrentHashMap<>(); + + protected final ReentrantLock lock = new ReentrantLock(); + + @Resource(required = false) + protected Application application; + + @Nullable + private UnaryOperator propertyFunc; + + private ScheduledThreadPoolExecutor scheduler; + + protected boolean enabled = true; + + protected AnyValue config; + + protected ScheduleManagerService(UnaryOperator propertyFunc) { + this.propertyFunc = propertyFunc; + } + + // 一般用于独立组件 + public static ScheduleManagerService create(UnaryOperator propertyFunc) { + return new ScheduleManagerService(propertyFunc); + } + + public boolean enabled() { + return this.enabled; + } + + public ScheduleManagerService enabled(boolean val) { + this.enabled = val; + return this; + } + + @Override + public void init(AnyValue conf) { + if (conf == null) { + conf = AnyValue.create(); + } + this.config = conf; + this.enabled = config.getBoolValue("enabled", true); + if (this.enabled) { + if (this.propertyFunc == null && application != null) { + UnaryOperator func = application.getEnvironment()::getPropertyValue; + this.propertyFunc = func; + } + this.scheduler = new ScheduledThreadPoolExecutor( + Utility.cpus(), Utility.newThreadFactory("Redkale-Scheduled-Task-Thread-%s")); + this.scheduler.setRemoveOnCancelPolicy(true); + } + } + + @Override + public void destroy(AnyValue conf) { + if (scheduler != null) { + scheduler.shutdown(); + } + } + + public void onServersPreStart() { + // do nothing + } + + public void onServersPostStart() { + // do nothing + } + + @Override + public void schedule(Object service) { + lock.lock(); + try { + boolean remoteMode = service instanceof Service && Sncp.isRemote((Service) service); + for (WeakReference item : refTaskMap.keySet()) { + if (item.get() == service) { + logger.log(Level.WARNING, service + " repeat schedule"); + } + } + Map tasks = new LinkedHashMap<>(); + Class clazz = service.getClass(); + WeakReference ref = new WeakReference(service); + Set methodKeys = new HashSet<>(); + do { + for (final Method method : clazz.getDeclaredMethods()) { + if (method.getAnnotation(Scheduled.class) == null) { + continue; + } + String mk = Utility.methodKey(method); + if (methodKeys.contains(mk)) { + // 跳过已处理的继承方法 + continue; + } + methodKeys.add(mk); + if (method.getParameterCount() != 0 + && !(method.getParameterCount() == 1 + && method.getParameterTypes()[0] == ScheduleEvent.class)) { + throw new RedkaleException( + "@" + Scheduled.class.getSimpleName() + " must be on non-parameter or " + + ScheduleEvent.class.getSimpleName() + "-parameter method, but on " + method); + } + ScheduledTask task = schedule(ref, method, remoteMode); + // 时间没配置: task=null + if (task != null) { + tasks.put(method.getName(), task); + RedkaleClassLoader.putReflectionMethod(clazz.getName(), method); + } + } + } while ((clazz = clazz.getSuperclass()) != Object.class); + // 开始执行定时任务 + if (enabled && !tasks.isEmpty()) { + tasks.forEach((name, task) -> task.init()); + refTaskMap.put(ref, new ArrayList<>(tasks.values())); + } + } finally { + lock.unlock(); + } + } + + @Override + public void unschedule(Object service) { + lock.lock(); + try { + for (Map.Entry> item : refTaskMap.entrySet()) { + if (item.getKey().get() == service) { + refTaskMap.remove(item.getKey()); + for (ScheduledTask task : item.getValue()) { + task.stop(); + } + } + } + } finally { + lock.unlock(); + } + } + + protected ScheduledTask schedule(WeakReference ref, Method method, boolean remoteMode) { + Scheduled ann = method.getAnnotation(Scheduled.class); + if (!LoadMode.matches(remoteMode, ann.mode())) { + return null; + } + String name = getProperty(ann.name()); + String cron = getProperty(ann.cron()); + String fixedDelay = getProperty(ann.fixedDelay()); + String fixedRate = getProperty(ann.fixedRate()); + String initialDelay = getProperty(ann.initialDelay()); + String zone = getProperty(ann.zone()); + TimeUnit timeUnit = ann.timeUnit(); + return scheduleTask(ref, method, name, cron, fixedDelay, fixedRate, initialDelay, zone, timeUnit); + } + + protected ScheduledTask scheduleTask( + WeakReference ref, + Method method, + String name, + String cron, + String fixedDelay, + String fixedRate, + String initialDelay, + String zone, + TimeUnit timeUnit) { + if ((cron.isEmpty() || "-".equals(cron)) && "-1".equals(fixedRate) && "-1".endsWith(fixedDelay)) { + return createdOnlyNameTask( + ref, method, name, cron, fixedDelay, fixedRate, initialDelay, zone, timeUnit); // 时间都没配置 + } + ZoneId zoneId = Utility.isEmpty(zone) ? null : ZoneId.of(zone); + if (!cron.isEmpty() && !"-".equals(cron)) { + CronExpression cronExpr = CronExpression.parse(cron); + return new CronTask(ref, name, method, cronExpr, zoneId); + } else { + long fixedDelayLong = Long.parseLong(fixedDelay); + long fixedRateLong = Long.parseLong(fixedRate); + long initialDelayLong = Long.parseLong(initialDelay); + return new FixedTask(ref, name, method, fixedDelayLong, fixedRateLong, initialDelayLong, timeUnit); + } + } + + protected ScheduledTask createdOnlyNameTask( + WeakReference ref, + Method method, + String name, + String cron, + String fixedDelay, + String fixedRate, + String initialDelay, + String zone, + TimeUnit timeUnit) { + return null; + } + + protected Function createFuncJob(final WeakReference ref, Method method) { + try { + if (!Modifier.isPublic(method.getModifiers())) { + method.setAccessible(true); + } + MethodHandle mh = MethodHandles.lookup().unreflect(method); + return event -> { + Object rs = null; + try { + Object obj = ref.get(); + if (obj != null) { + if (event == null) { + rs = mh.invoke(obj); + } else { + rs = mh.invoke(obj, event); + } + } + } catch (Throwable t) { + logger.log(Level.SEVERE, "schedule task error", t); + } + if (event != null) { + event.clear(); + } + return rs; + }; + } catch (IllegalAccessException e) { + throw new RedkaleException(e); + } + } + + protected String getProperty(String value) { + if (propertyFunc == null || value == null || value.indexOf('}') < 0) { + return value; + } + return propertyFunc.apply(value); + } + + @Override + public int start(String scheduleName) { + int c = 0; + lock.lock(); + try { + for (Map.Entry> item : refTaskMap.entrySet()) { + for (ScheduledTask task : item.getValue()) { + if (Objects.equals(task.name(), scheduleName)) { + c++; + task.start(); + } + } + } + } finally { + lock.unlock(); + } + return c; + } + + @Override + public int stop(String scheduleName) { + int c = 0; + lock.lock(); + try { + for (Map.Entry> item : refTaskMap.entrySet()) { + for (ScheduledTask task : item.getValue()) { + if (Objects.equals(task.name(), scheduleName)) { + c++; + task.stop(); + } + } + } + } finally { + lock.unlock(); + } + return c; + } + + protected abstract class ScheduledTask { + + protected final WeakReference ref; + + protected final String name; + + protected final Method method; + + protected final AtomicBoolean started = new AtomicBoolean(); + + protected ScheduledFuture future; + + protected final ScheduleEvent event; + + protected final Map eventMap; + + // 任务是否正运行中 + protected final AtomicBoolean doing = new AtomicBoolean(); + + protected ScheduledTask(WeakReference ref, String name, Method method) { + Objects.requireNonNull(ref); + Objects.requireNonNull(name); + Objects.requireNonNull(method); + this.ref = ref; + this.name = name; + this.method = method; + this.eventMap = method.getParameterCount() == 0 ? null : new HashMap<>(); + this.event = eventMap == null ? null : new ScheduleEvent(eventMap); + } + + public void init() { + start(); + } + + public abstract void start(); + + public void stop() { + if (future != null) { + future.cancel(true); + future = null; + } + this.started.set(false); + } + + public boolean doing() { + return doing.get(); + } + + public Map eventMap() { + return eventMap; + } + + public Method method() { + return method; + } + + public String name() { + return name; + } + } + + protected class FixedTask extends ScheduledTask implements Runnable { + + private final Function delegate; + + private final long fixedDelay; + + private final long fixedRate; + + private final long initialDelay; + + private final TimeUnit timeUnit; + + public FixedTask( + final WeakReference ref, + String name, + Method method, + long fixedDelay, + long fixedRate, + long initialDelay, + TimeUnit timeUnit) { + super(ref, name, method); + this.delegate = createFuncJob(ref, method); + this.fixedDelay = fixedDelay; + this.fixedRate = fixedRate; + this.initialDelay = initialDelay; + this.timeUnit = timeUnit; + } + + @Override + public void run() { + doing.set(true); + try { + delegate.apply(event); + } catch (Throwable t) { + logger.log(Level.SEVERE, "schedule task error", t); + } finally { + doing.set(false); + } + if (ref.get() == null) { + stop(); + } + } + + @Override + public void start() { + if (started.compareAndSet(false, true)) { + if (fixedRate > 0) { + this.future = scheduler.scheduleAtFixedRate( + this, initialDelay > 0 ? initialDelay : 0, fixedRate, timeUnit); + } else if (fixedDelay > 0) { + this.future = scheduler.scheduleWithFixedDelay(this, initialDelay, fixedDelay, timeUnit); + } else if (initialDelay > 0) { + this.future = scheduler.schedule(this, initialDelay, timeUnit); + } + } + } + } + + protected class CronTask extends ScheduledTask implements Runnable { + + private final Function delegate; + + private final CronExpression cron; + + @Nullable + private final ZoneId zoneId; + + public CronTask(WeakReference ref, String name, Method method, CronExpression cron, ZoneId zoneId) { + super(ref, name, method); + this.delegate = createFuncJob(ref, method); + this.cron = cron; + this.zoneId = zoneId; + } + + @Override + public void run() { + doing.set(true); + try { + delegate.apply(event); + } catch (Throwable t) { + logger.log(Level.SEVERE, "schedule task error", t); + } finally { + doing.set(false); + } + start(); + } + + @Override + public void start() { + if (ref.get() == null) { + return; + } + if (started.compareAndSet(false, true)) { + LocalDateTime now = zoneId == null ? LocalDateTime.now() : LocalDateTime.now(zoneId); + LocalDateTime next = cron.next(now); + Duration delay = Duration.between(now, next); + this.future = scheduler.schedule(this, delay.toNanos(), TimeUnit.NANOSECONDS); + } + } + } +} diff --git a/src/main/java/org/redkale/schedule/spi/ScheduleModuleEngine.java b/src/main/java/org/redkale/schedule/spi/ScheduleModuleEngine.java index 3fc7a7c7a..48785b882 100644 --- a/src/main/java/org/redkale/schedule/spi/ScheduleModuleEngine.java +++ b/src/main/java/org/redkale/schedule/spi/ScheduleModuleEngine.java @@ -1,126 +1,126 @@ -/* - * - */ -package org.redkale.schedule.spi; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.ServiceLoader; -import org.redkale.boot.Application; -import org.redkale.boot.ModuleEngine; -import org.redkale.schedule.ScheduleManager; -import org.redkale.service.Service; -import org.redkale.util.AnyValue; -import org.redkale.util.InstanceProvider; -import org.redkale.util.RedkaleClassLoader; - -/** @author zhangjx */ -public class ScheduleModuleEngine extends ModuleEngine { - - // 全局定时任务管理器 - private ScheduleManager scheduleManager; - - // 配置 - protected AnyValue config; - - public ScheduleModuleEngine(Application application) { - super(application); - } - - /** - * 判断模块的配置项合并策略, 返回null表示模块不识别此配置项 - * - * @param path 配置项路径 - * @param key 配置项名称 - * @param val1 配置项原值 - * @param val2 配置项新值 - * @return MergeEnum - */ - @Override - public AnyValue.MergeEnum mergeAppConfigStrategy(String path, String key, AnyValue val1, AnyValue val2) { - if ("".equals(path) && "schedule".equals(key)) { - return AnyValue.MergeEnum.REPLACE; - } - return null; - } - - /** 结束Application.init方法前被调用 */ - @Override - public void onAppPostInit() { - // 设置定时管理器 - this.config = application.getAppConfig().getAnyValue("schedule"); - this.scheduleManager = createManager(this.config); - if (!application.isCompileMode()) { - this.resourceFactory.inject(this.scheduleManager); - if (this.scheduleManager instanceof Service) { - ((Service) this.scheduleManager).init(this.config); - } - } - this.resourceFactory.register("", ScheduleManager.class, this.scheduleManager); - } - - /** - * 执行Service.init方法后被调用 - * - * @param service Service - */ - @Override - public void onServicePostInit(Service service) { - this.scheduleManager.schedule(service); - } - - /** - * 执行Service.destroy方法后被调用 - * - * @param service Service - */ - @Override - public void onServicePreDestroy(Service service) { - this.scheduleManager.unschedule(service); - } - - /** 服务全部启动前被调用 */ - @Override - public void onServersPreStart() { - if (this.scheduleManager instanceof ScheduleManagerService) { - ((ScheduleManagerService) this.scheduleManager).onServersPreStart(); - } - } - - /** 服务全部启动后被调用 */ - @Override - public void onServersPostStart() { - if (this.scheduleManager instanceof ScheduleManagerService) { - ((ScheduleManagerService) this.scheduleManager).onServersPostStart(); - } - } - - /** 进入Application.shutdown方法被调用 */ - @Override - public void onAppPreShutdown() { - if (!application.isCompileMode() && this.scheduleManager instanceof Service) { - ((Service) this.scheduleManager).destroy(this.config); - } - } - - private ScheduleManager createManager(AnyValue conf) { - Iterator it = ServiceLoader.load( - ScheduleManagerProvider.class, application.getClassLoader()) - .iterator(); - RedkaleClassLoader.putServiceLoader(ScheduleManagerProvider.class); - List providers = new ArrayList<>(); - while (it.hasNext()) { - ScheduleManagerProvider provider = it.next(); - if (provider != null && provider.acceptsConf(conf)) { - RedkaleClassLoader.putReflectionPublicConstructors( - provider.getClass(), provider.getClass().getName()); - providers.add(provider); - } - } - for (ScheduleManagerProvider provider : InstanceProvider.sort(providers)) { - return provider.createInstance(); - } - return ScheduleManagerService.create(null).enabled(false); - } -} +/* + * + */ +package org.redkale.schedule.spi; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.ServiceLoader; +import org.redkale.boot.Application; +import org.redkale.boot.ModuleEngine; +import org.redkale.schedule.ScheduleManager; +import org.redkale.service.Service; +import org.redkale.util.AnyValue; +import org.redkale.util.InstanceProvider; +import org.redkale.util.RedkaleClassLoader; + +/** @author zhangjx */ +public class ScheduleModuleEngine extends ModuleEngine { + + // 全局定时任务管理器 + private ScheduleManager scheduleManager; + + // 配置 + protected AnyValue config; + + public ScheduleModuleEngine(Application application) { + super(application); + } + + /** + * 判断模块的配置项合并策略, 返回null表示模块不识别此配置项 + * + * @param path 配置项路径 + * @param key 配置项名称 + * @param val1 配置项原值 + * @param val2 配置项新值 + * @return MergeEnum + */ + @Override + public AnyValue.MergeEnum mergeAppConfigStrategy(String path, String key, AnyValue val1, AnyValue val2) { + if ("".equals(path) && "schedule".equals(key)) { + return AnyValue.MergeEnum.REPLACE; + } + return null; + } + + /** 结束Application.init方法前被调用 */ + @Override + public void onAppPostInit() { + // 设置定时管理器 + this.config = application.getAppConfig().getAnyValue("schedule"); + this.scheduleManager = createManager(this.config); + if (!application.isCompileMode()) { + this.resourceFactory.inject(this.scheduleManager); + if (this.scheduleManager instanceof Service) { + ((Service) this.scheduleManager).init(this.config); + } + } + this.resourceFactory.register("", ScheduleManager.class, this.scheduleManager); + } + + /** + * 执行Service.init方法后被调用 + * + * @param service Service + */ + @Override + public void onServicePostInit(Service service) { + this.scheduleManager.schedule(service); + } + + /** + * 执行Service.destroy方法后被调用 + * + * @param service Service + */ + @Override + public void onServicePreDestroy(Service service) { + this.scheduleManager.unschedule(service); + } + + /** 服务全部启动前被调用 */ + @Override + public void onServersPreStart() { + if (this.scheduleManager instanceof ScheduleManagerService) { + ((ScheduleManagerService) this.scheduleManager).onServersPreStart(); + } + } + + /** 服务全部启动后被调用 */ + @Override + public void onServersPostStart() { + if (this.scheduleManager instanceof ScheduleManagerService) { + ((ScheduleManagerService) this.scheduleManager).onServersPostStart(); + } + } + + /** 进入Application.shutdown方法被调用 */ + @Override + public void onAppPreShutdown() { + if (!application.isCompileMode() && this.scheduleManager instanceof Service) { + ((Service) this.scheduleManager).destroy(this.config); + } + } + + private ScheduleManager createManager(AnyValue conf) { + Iterator it = ServiceLoader.load( + ScheduleManagerProvider.class, application.getClassLoader()) + .iterator(); + RedkaleClassLoader.putServiceLoader(ScheduleManagerProvider.class); + List providers = new ArrayList<>(); + while (it.hasNext()) { + ScheduleManagerProvider provider = it.next(); + if (provider != null && provider.acceptsConf(conf)) { + RedkaleClassLoader.putReflectionPublicConstructors( + provider.getClass(), provider.getClass().getName()); + providers.add(provider); + } + } + for (ScheduleManagerProvider provider : InstanceProvider.sort(providers)) { + return provider.createInstance(); + } + return ScheduleManagerService.create(null).enabled(false); + } +} diff --git a/src/main/java/org/redkale/service/AbstractService.java b/src/main/java/org/redkale/service/AbstractService.java index 5aa589abc..752698563 100644 --- a/src/main/java/org/redkale/service/AbstractService.java +++ b/src/main/java/org/redkale/service/AbstractService.java @@ -1,73 +1,73 @@ -/* - * 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.service; - -import java.util.concurrent.*; -import org.redkale.annotation.Resource; -import org.redkale.boot.Application; -import org.redkale.net.WorkThread; -import org.redkale.net.sncp.Sncp; - -/** @author zhangjx */ -public abstract class AbstractService implements Service { - - // 配置 APP_EXECUTOR资源为null - @Resource(name = Application.RESNAME_APP_EXECUTOR, required = false) - private ExecutorService workExecutor; - - @Resource(name = Resource.SELF_NAME, required = false) - private String serviceName; - - @Resource(name = Resource.SELF_TYPE, required = false) - private Class serviceType; - - protected String serviceName() { - return serviceName; - } - - protected Class serviceType() { - return serviceType == null ? Sncp.getServiceType(getClass()) : serviceType; - } - - /** - * 异步执行任务 - * - * @param command 任务 - */ - protected void runAsync(Runnable command) { - ExecutorService executor = this.workExecutor; - if (executor != null) { - executor.execute(command); - } else { - Thread thread = Thread.currentThread(); - if (thread instanceof WorkThread) { - ((WorkThread) thread).runWork(command); - } else { - ForkJoinPool.commonPool().execute(command); - } - } - } - - /** - * 获取线程池 - * - * @return ExecutorService - */ - protected ExecutorService getExecutor() { - ExecutorService executor = this.workExecutor; - if (executor != null) { - return executor; - } - Thread thread = Thread.currentThread(); - if (thread instanceof WorkThread) { - ExecutorService e = ((WorkThread) thread).getWorkExecutor(); - if (e != null) { - return e; - } - } - return ForkJoinPool.commonPool(); - } -} +/* + * 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.service; + +import java.util.concurrent.*; +import org.redkale.annotation.Resource; +import org.redkale.boot.Application; +import org.redkale.net.WorkThread; +import org.redkale.net.sncp.Sncp; + +/** @author zhangjx */ +public abstract class AbstractService implements Service { + + // 配置 APP_EXECUTOR资源为null + @Resource(name = Application.RESNAME_APP_EXECUTOR, required = false) + private ExecutorService workExecutor; + + @Resource(name = Resource.SELF_NAME, required = false) + private String serviceName; + + @Resource(name = Resource.SELF_TYPE, required = false) + private Class serviceType; + + protected String serviceName() { + return serviceName; + } + + protected Class serviceType() { + return serviceType == null ? Sncp.getServiceType(getClass()) : serviceType; + } + + /** + * 异步执行任务 + * + * @param command 任务 + */ + protected void runAsync(Runnable command) { + ExecutorService executor = this.workExecutor; + if (executor != null) { + executor.execute(command); + } else { + Thread thread = Thread.currentThread(); + if (thread instanceof WorkThread) { + ((WorkThread) thread).runWork(command); + } else { + ForkJoinPool.commonPool().execute(command); + } + } + } + + /** + * 获取线程池 + * + * @return ExecutorService + */ + protected ExecutorService getExecutor() { + ExecutorService executor = this.workExecutor; + if (executor != null) { + return executor; + } + Thread thread = Thread.currentThread(); + if (thread instanceof WorkThread) { + ExecutorService e = ((WorkThread) thread).getWorkExecutor(); + if (e != null) { + return e; + } + } + return ForkJoinPool.commonPool(); + } +} diff --git a/src/main/java/org/redkale/service/LoadMode.java b/src/main/java/org/redkale/service/LoadMode.java index c02b22cac..2b81f6d98 100644 --- a/src/main/java/org/redkale/service/LoadMode.java +++ b/src/main/java/org/redkale/service/LoadMode.java @@ -1,47 +1,47 @@ -/* - * - */ -package org.redkale.service; - -/** - * Service加载模式 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public enum LoadMode { - /** 本地模式 */ - LOCAL, - /** 远程模式 */ - REMOTE, - /** 任意模式 */ - ANY; - - /** - * 是否匹配当前模式 - * - * @param mode 模式 - * @return 是否匹配 - */ - public boolean matches(LoadMode mode) { - return this == mode || this == ANY; - } - - /** - * 是否匹配当前模式 - * - * @param remote 是否远程 - * @param mode 模式 - * @return 是否匹配 - */ - public static boolean matches(boolean remote, LoadMode mode) { - if (remote && mode == LoadMode.LOCAL) { // 只容许本地模式 - return false; - } else if (!remote && mode == LoadMode.REMOTE) { // 只容许远程模式 - return false; - } - return true; - } -} +/* + * + */ +package org.redkale.service; + +/** + * Service加载模式 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public enum LoadMode { + /** 本地模式 */ + LOCAL, + /** 远程模式 */ + REMOTE, + /** 任意模式 */ + ANY; + + /** + * 是否匹配当前模式 + * + * @param mode 模式 + * @return 是否匹配 + */ + public boolean matches(LoadMode mode) { + return this == mode || this == ANY; + } + + /** + * 是否匹配当前模式 + * + * @param remote 是否远程 + * @param mode 模式 + * @return 是否匹配 + */ + public static boolean matches(boolean remote, LoadMode mode) { + if (remote && mode == LoadMode.LOCAL) { // 只容许本地模式 + return false; + } else if (!remote && mode == LoadMode.REMOTE) { // 只容许远程模式 + return false; + } + return true; + } +} diff --git a/src/main/java/org/redkale/service/RpcAction.java b/src/main/java/org/redkale/service/RpcAction.java index eddab35a4..8a2b57071 100644 --- a/src/main/java/org/redkale/service/RpcAction.java +++ b/src/main/java/org/redkale/service/RpcAction.java @@ -1,25 +1,25 @@ -/* - * - */ -package org.redkale.service; - -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.*; - -/** - * 用于自定义SncpActionid,默认会根据Method.toString来计算actionid - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -@Documented -@Target({METHOD}) -@Retention(RUNTIME) -public @interface RpcAction { - - String name(); -} +/* + * + */ +package org.redkale.service; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.*; + +/** + * 用于自定义SncpActionid,默认会根据Method.toString来计算actionid + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +@Documented +@Target({METHOD}) +@Retention(RUNTIME) +public @interface RpcAction { + + String name(); +} diff --git a/src/main/java/org/redkale/source/AbstractDataSource.java b/src/main/java/org/redkale/source/AbstractDataSource.java index 7980b4174..ce7c622a4 100644 --- a/src/main/java/org/redkale/source/AbstractDataSource.java +++ b/src/main/java/org/redkale/source/AbstractDataSource.java @@ -1,1535 +1,1535 @@ -/* - * 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.source; - -import static org.redkale.boot.Application.RESNAME_APP_EXECUTOR; -import static org.redkale.source.DataSources.*; - -import java.io.Serializable; -import java.net.InetSocketAddress; -import java.util.*; -import java.util.concurrent.*; -import java.util.concurrent.locks.ReentrantLock; -import java.util.function.*; -import java.util.stream.Stream; -import org.redkale.annotation.*; -import org.redkale.annotation.AutoLoad; -import org.redkale.annotation.Comment; -import org.redkale.annotation.ResourceType; -import org.redkale.convert.json.JsonConvert; -import org.redkale.inject.Resourcable; -import org.redkale.inject.ResourceEvent; -import org.redkale.net.WorkThread; -import org.redkale.persistence.Entity; -import org.redkale.service.*; -import org.redkale.util.*; - -/** - * DataSource的S抽象实现类
- * 注意: 所有的操作只能作用在一张表上,不能同时变更多张表 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.5.0 - */ -@Local -@AutoLoad(false) -@SuppressWarnings("unchecked") -@ResourceType(DataSource.class) -public abstract class AbstractDataSource extends AbstractService implements DataSource, AutoCloseable, Resourcable { - - protected final IntFunction serialArrayFunc = Utility.serialArrayFunc(); - - private final ReentrantLock executorLock = new ReentrantLock(); - - protected int sourceThreads = Utility.cpus(); - - @Resource(name = RESNAME_APP_EXECUTOR, required = false) - private ExecutorService sourceExecutor; - - protected String name; - - @Override - public void init(AnyValue conf) { - super.init(conf); - if (conf.getAnyValue("read") == null) { - this.sourceThreads = - conf.getIntValue(DATA_SOURCE_THREADS, conf.getIntValue(DATA_SOURCE_MAXCONNS, Utility.cpus())); - } else { - this.sourceThreads = conf.getAnyValue("read") - .getIntValue(DATA_SOURCE_THREADS, conf.getIntValue(DATA_SOURCE_MAXCONNS, Utility.cpus())); - } - } - - @Override - public final String resourceName() { - return name; - } - - @ResourceChanged - public abstract void onResourceChange(ResourceEvent[] events); - - protected void setSourceExecutor(ExecutorService executor) { - this.sourceExecutor = executor; - } - - protected SourceUrlInfo parseSourceUrl(final String url) { - final SourceUrlInfo info = new SourceUrlInfo(); - info.url = url; - if (url.startsWith("jdbc:h2:")) { - return info; - } - String url0 = url.substring(url.indexOf("://") + 3); - int pos = url0.indexOf('?'); // 127.0.0.1:5432/db?charset=utr8&xxx=yy - if (pos > 0) { - String params = url0.substring(pos + 1).replace("&", "&"); - for (String param : params.split("&")) { - int p = param.indexOf('='); - if (p < 1) { - continue; - } - info.attributes.put(param.substring(0, p), param.substring(p + 1)); - } - url0 = url0.substring(0, pos); - } - pos = url0.indexOf('/'); // 127.0.0.1:5432/db - if (pos > 0) { - info.database = url0.substring(pos + 1); - url0 = url0.substring(0, pos); - } - pos = url0.indexOf(':'); - if (pos > 0) { - info.servaddr = new InetSocketAddress(url0.substring(0, pos), Integer.parseInt(url0.substring(pos + 1))); - } else if (url.startsWith("http://")) { - info.servaddr = new InetSocketAddress(url0, 80); - } else if (url.startsWith("https://")) { - info.servaddr = new InetSocketAddress(url0, 443); - } else { - throw new SourceException(url + " parse port error"); - } - return info; - } - - public static class SourceUrlInfo { - - public Properties attributes = new Properties(); - - public String url; - - public String database; - - public InetSocketAddress servaddr; - - public String username; - - public String password; - - public String encoding; - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } - } - - @Override - protected ExecutorService getExecutor() { - ExecutorService executor = this.sourceExecutor; - if (executor == null) { - executorLock.lock(); - try { - if (this.sourceExecutor == null) { - this.sourceExecutor = WorkThread.createWorkExecutor( - sourceThreads, "Redkale-DataSource-WorkThread-" + resourceName() + "-%s"); - } - } finally { - executorLock.unlock(); - } - executor = this.sourceExecutor; - } - return executor; - } - - protected void complete(WorkThread workThread, CompletableFuture future, T value) { - getExecutor().execute(() -> future.complete(value)); - } - - protected void completeExceptionally(WorkThread workThread, CompletableFuture future, Throwable exp) { - getExecutor().execute(() -> future.completeExceptionally(exp)); - } - - protected String executorToString() { - ExecutorService executor = this.sourceExecutor; - if (executor == null) { - return ""; - } - if (executor.getClass().getSimpleName().contains("ThreadPerTaskExecutor")) { - return ", thread-pool=[virtual]"; - } - if (executor instanceof ThreadPoolExecutor) { - ThreadPoolExecutor re = (ThreadPoolExecutor) executor; - return ", pool-size=" + re.getMaximumPoolSize(); - } - return ""; - } - - /** - * 是否虚拟化的持久对象 - * - * @param info EntityInfo - * @return boolean - */ - protected boolean isOnlyCache(EntityInfo info) { - return info.isVirtualEntity(); - } - - /** - * 是否可以使用缓存,一般包含关联查询就不使用缓存 - * - * @param node 过滤条件 - * @param entityApplyer 函数 - * @return boolean - */ - protected boolean isCacheUseable(FilterNode node, Function entityApplyer) { - return node.isCacheUseable(entityApplyer); - } - - /** - * 生成过滤函数 - * - * @param 泛型 - * @param node 过滤条件 - * @param cache 缓存 - * @return Predicate - */ - protected Predicate createPredicate(FilterNode node, EntityCache cache) { - return node.createPredicate(cache); - } - - /** - * 根据ResultSet获取对象 - * - * @param 泛型 - * @param info EntityInfo - * @param sels 过滤字段 - * @param row ResultSet - * @return 对象 - */ - protected T getEntityValue(EntityInfo info, final SelectColumn sels, final EntityInfo.DataResultSetRow row) { - return info.getBuilder().getEntityValue(sels, row); - } - - /** - * 根据翻页参数构建排序SQL - * - * @param 泛型 - * @param info EntityInfo - * @param flipper 翻页参数 - * @return SQL - */ - protected String createSQLOrderby(EntityInfo info, Flipper flipper) { - return info.createSQLOrderby(flipper); - } - - /** - * 根据过滤条件生成关联表与别名的映射关系 - * - * @param node 过滤条件 - * @return Map - */ - protected Map getJoinTabalis(FilterNode node) { - return node == null ? null : node.getJoinTabalis(); - } - - /** - * 加载指定类的EntityInfo - * - * @param 泛型 - * @param clazz 类 - * @param cacheForbidden 是否屏蔽缓存 - * @param props 配置信息 - * @param fullloader 加载器 - * @return EntityInfo - */ - protected EntityInfo loadEntityInfo( - Class clazz, - final boolean cacheForbidden, - final Properties props, - BiFunction> fullloader) { - return EntityInfo.load(clazz, cacheForbidden, props, this, fullloader); - } - - /** - * 检查对象是否都是同一个Entity类 - * - * @param 泛型 - * @param action 操作 - * @param entitys 对象集合 - */ - protected void checkEntity(String action, T... entitys) { - Class clazz = null; - for (T val : entitys) { - if (clazz == null) { - clazz = val.getClass(); - if (clazz.getAnnotation(Entity.class) == null - && clazz.getAnnotation(javax.persistence.Entity.class) == null) { - throw new SourceException("Entity Class " + clazz + " must be on Annotation @Entity"); - } - } else if (clazz != val.getClass()) { - throw new SourceException("DataSource." + action + " must the same Class Entity, but diff is " + clazz - + " and " + val.getClass()); - } - } - } - - protected CompletableFuture supplyAsync(Supplier supplier) { - return CompletableFuture.supplyAsync(supplier, getExecutor()); - } - - @Override - public int batch(final DataBatch batch) { - return batchAsync(batch).join(); - } - - @Override - public CompletableFuture batchAsync(final DataBatch batch) { - return CompletableFuture.failedFuture(new UnsupportedOperationException("Not supported yet.")); - } - - @Override - public final int insert(final Collection entitys) { - if (entitys == null || entitys.isEmpty()) { - return 0; - } - return insert(entitys.toArray()); - } - - @Override - public final int insert(final Stream entitys) { - if (entitys == null) { - return 0; - } - return insert(entitys.toArray()); - } - - @Override - public final CompletableFuture insertAsync(final Collection entitys) { - if (entitys == null || entitys.isEmpty()) { - return CompletableFuture.completedFuture(0); - } - return insertAsync(entitys.toArray()); - } - - @Override - public final CompletableFuture insertAsync(final Stream entitys) { - if (entitys == null) { - return CompletableFuture.completedFuture(0); - } - return insertAsync(entitys.toArray()); - } - - @Override - public CompletableFuture clearTableAsync(final Class clazz) { - return clearTableAsync(clazz, (FilterNode) null); - } - - @Override - public int dropTable(Class clazz) { - return dropTable(clazz, (FilterNode) null); - } - - @Override - public CompletableFuture dropTableAsync(final Class clazz) { - return dropTableAsync(clazz, (FilterNode) null); - } - - /** - * 根据主键值更新对象的多个column对应的值, 必须是Entity Class - * - * @param Entity类的泛型 - * @param clazz Entity类 - * @param node 过滤条件 - * @param values 字段值 - * @return 更新的数据条数 - */ - @Override - public int updateColumn(final Class clazz, final FilterNode node, final ColumnValue... values) { - return updateColumn(clazz, node, null, values); - } - - @Override - public CompletableFuture updateColumnAsync( - final Class clazz, final FilterNode node, final ColumnValue... values) { - return updateColumnAsync(clazz, node, null, values); - } - - @Override - public int updateColumn(final T entity, final String... columns) { - return updateColumn(entity, SelectColumn.includes(columns)); - } - - @Override - public CompletableFuture updateColumnAsync(final T entity, final String... columns) { - return updateColumnAsync(entity, SelectColumn.includes(columns)); - } - - @Override - public int updateColumn(final T entity, final FilterNode node, final String... columns) { - return updateColumn(entity, node, SelectColumn.includes(columns)); - } - - @Override - public CompletableFuture updateColumnAsync( - final T entity, final FilterNode node, final String... columns) { - return updateColumnAsync(entity, node, SelectColumn.includes(columns)); - } - - @Override - public Map getNumberMap(final Class entityClass, final FilterFuncColumn... columns) { - return getNumberMap(entityClass, (FilterNode) null, columns); - } - - @Override - public CompletableFuture> getNumberMapAsync( - final Class entityClass, final FilterFuncColumn... columns) { - return getNumberMapAsync(entityClass, (FilterNode) null, columns); - } - - @Override - public Map getNumberMap( - final Class entityClass, final FilterBean bean, final FilterFuncColumn... columns) { - return getNumberMap(entityClass, FilterNodeBean.createFilterNode(bean), columns); - } - - @Override - public CompletableFuture> getNumberMapAsync( - final Class entityClass, final FilterBean bean, final FilterFuncColumn... columns) { - return getNumberMapAsync(entityClass, FilterNodeBean.createFilterNode(bean), columns); - } - - @Override - public Number getNumberResult(final Class entityClass, final FilterFunc func, final String column) { - return getNumberResult(entityClass, func, null, column, (FilterNode) null); - } - - @Override - public CompletableFuture getNumberResultAsync( - final Class entityClass, final FilterFunc func, final String column) { - return getNumberResultAsync(entityClass, func, null, column, (FilterNode) null); - } - - @Override - public Number getNumberResult( - final Class entityClass, final FilterFunc func, final String column, FilterBean bean) { - return getNumberResult(entityClass, func, null, column, FilterNodeBean.createFilterNode(bean)); - } - - @Override - public CompletableFuture getNumberResultAsync( - final Class entityClass, final FilterFunc func, final String column, final FilterBean bean) { - return getNumberResultAsync(entityClass, func, null, column, FilterNodeBean.createFilterNode(bean)); - } - - @Override - public Number getNumberResult( - final Class entityClass, final FilterFunc func, final String column, final FilterNode node) { - return getNumberResult(entityClass, func, null, column, node); - } - - @Override - public CompletableFuture getNumberResultAsync( - final Class entityClass, final FilterFunc func, final String column, final FilterNode node) { - return getNumberResultAsync(entityClass, func, null, column, node); - } - - @Override - public Number getNumberResult( - final Class entityClass, final FilterFunc func, final Number defVal, final String column) { - return getNumberResult(entityClass, func, defVal, column, (FilterNode) null); - } - - @Override - public CompletableFuture getNumberResultAsync( - final Class entityClass, final FilterFunc func, final Number defVal, final String column) { - return getNumberResultAsync(entityClass, func, defVal, column, (FilterNode) null); - } - - @Override - public Number getNumberResult( - final Class entityClass, final FilterFunc func, final Number defVal, final String column, FilterBean bean) { - return getNumberResult(entityClass, func, defVal, column, FilterNodeBean.createFilterNode(bean)); - } - - @Override - public CompletableFuture getNumberResultAsync( - final Class entityClass, final FilterFunc func, final Number defVal, final String column, FilterBean bean) { - return getNumberResultAsync(entityClass, func, defVal, column, FilterNodeBean.createFilterNode(bean)); - } - - // ------------------------ queryColumnMapCompose ------------------------ - @Override - public Map queryColumnMap( - final Class entityClass, final String keyColumn, final FilterFunc func, final String funcColumn) { - return queryColumnMap(entityClass, keyColumn, func, funcColumn, (FilterNode) null); - } - - @Override - public CompletableFuture> queryColumnMapAsync( - final Class entityClass, final String keyColumn, final FilterFunc func, final String funcColumn) { - return queryColumnMapAsync(entityClass, keyColumn, func, funcColumn, (FilterNode) null); - } - - @Override - public Map queryColumnMap( - final Class entityClass, - final String keyColumn, - final FilterFunc func, - final String funcColumn, - final FilterBean bean) { - return queryColumnMap(entityClass, keyColumn, func, funcColumn, FilterNodeBean.createFilterNode(bean)); - } - - @Override - public CompletableFuture> queryColumnMapAsync( - final Class entityClass, - final String keyColumn, - final FilterFunc func, - final String funcColumn, - final FilterBean bean) { - return queryColumnMapAsync(entityClass, keyColumn, func, funcColumn, FilterNodeBean.createFilterNode(bean)); - } - - @Override - public Map queryColumnMap( - final Class entityClass, final ColumnNode[] funcNodes, final String groupByColumn) { - return queryColumnMap(entityClass, funcNodes, groupByColumn, (FilterNode) null); - } - - @Override - public CompletableFuture> queryColumnMapAsync( - final Class entityClass, final ColumnNode[] funcNodes, final String groupByColumn) { - return queryColumnMapAsync(entityClass, funcNodes, groupByColumn, (FilterNode) null); - } - - @Override - public Map queryColumnMap( - final Class entityClass, - final ColumnNode[] funcNodes, - final String groupByColumn, - final FilterBean bean) { - return queryColumnMap(entityClass, funcNodes, groupByColumn, FilterNodeBean.createFilterNode(bean)); - } - - @Override - public CompletableFuture> queryColumnMapAsync( - final Class entityClass, - final ColumnNode[] funcNodes, - final String groupByColumn, - final FilterBean bean) { - return queryColumnMapAsync(entityClass, funcNodes, groupByColumn, FilterNodeBean.createFilterNode(bean)); - } - - @Override - public Map queryColumnMap( - final Class entityClass, final ColumnNode[] funcNodes, final String[] groupByColumns) { - return queryColumnMap(entityClass, funcNodes, groupByColumns, (FilterNode) null); - } - - @Override - public CompletableFuture> queryColumnMapAsync( - final Class entityClass, final ColumnNode[] funcNodes, final String[] groupByColumns) { - return queryColumnMapAsync(entityClass, funcNodes, groupByColumns, (FilterNode) null); - } - - @Override - public Map queryColumnMap( - final Class entityClass, - final ColumnNode[] funcNodes, - final String[] groupByColumns, - final FilterBean bean) { - return queryColumnMap(entityClass, funcNodes, groupByColumns, FilterNodeBean.createFilterNode(bean)); - } - - @Override - public CompletableFuture> queryColumnMapAsync( - final Class entityClass, - final ColumnNode[] funcNodes, - final String[] groupByColumns, - final FilterBean bean) { - return queryColumnMapAsync(entityClass, funcNodes, groupByColumns, FilterNodeBean.createFilterNode(bean)); - } - - // ----------------------------- findCompose ----------------------------- - /** - * 根据主键获取对象 - * - * @param Entity类的泛型 - * @param clazz Entity类 - * @param pk 主键值 - * @return Entity对象 - */ - @Override - public T find(Class clazz, Serializable pk) { - return find(clazz, (SelectColumn) null, pk); - } - - @Override - public CompletableFuture findAsync(final Class clazz, final Serializable pk) { - return findAsync(clazz, (SelectColumn) null, pk); - } - - @Override - public T find(final Class clazz, final String column, final Serializable colval) { - return find(clazz, null, FilterNodes.create(column, colval)); - } - - @Override - public CompletableFuture findAsync(final Class clazz, final String column, final Serializable colval) { - return findAsync(clazz, null, FilterNodes.create(column, colval)); - } - - @Override - public T find(final Class clazz, final FilterBean bean) { - return find(clazz, null, FilterNodeBean.createFilterNode(bean)); - } - - @Override - public CompletableFuture findAsync(final Class clazz, final FilterBean bean) { - return findAsync(clazz, null, FilterNodeBean.createFilterNode(bean)); - } - - @Override - public T find(final Class clazz, final FilterNode node) { - return find(clazz, null, node); - } - - @Override - public CompletableFuture findAsync(final Class clazz, final FilterNode node) { - return findAsync(clazz, null, node); - } - - @Override - public T find(final Class clazz, final SelectColumn selects, final FilterBean bean) { - return find(clazz, selects, FilterNodeBean.createFilterNode(bean)); - } - - @Override - public CompletableFuture findAsync(final Class clazz, final SelectColumn selects, final FilterBean bean) { - return findAsync(clazz, selects, FilterNodeBean.createFilterNode(bean)); - } - - @Override - public Serializable findColumn(final Class clazz, final String column, final Serializable pk) { - return findColumn(clazz, column, null, pk); - } - - @Override - public CompletableFuture findColumnAsync( - final Class clazz, final String column, final Serializable pk) { - return findColumnAsync(clazz, column, null, pk); - } - - @Override - public Serializable findColumn(final Class clazz, final String column, final FilterBean bean) { - return findColumn(clazz, column, null, FilterNodeBean.createFilterNode(bean)); - } - - @Override - public CompletableFuture findColumnAsync( - final Class clazz, final String column, final FilterBean bean) { - return findColumnAsync(clazz, column, null, FilterNodeBean.createFilterNode(bean)); - } - - @Override - public Serializable findColumn(final Class clazz, final String column, final FilterNode node) { - return findColumn(clazz, column, null, node); - } - - @Override - public CompletableFuture findColumnAsync( - final Class clazz, final String column, final FilterNode node) { - return findColumnAsync(clazz, column, null, node); - } - - @Override - public Serializable findColumn( - final Class clazz, final String column, final Serializable defValue, final FilterBean bean) { - return findColumn(clazz, column, defValue, FilterNodeBean.createFilterNode(bean)); - } - - @Override - public CompletableFuture findColumnAsync( - final Class clazz, final String column, final Serializable defValue, final FilterBean bean) { - return findColumnAsync(clazz, column, defValue, FilterNodeBean.createFilterNode(bean)); - } - - @Override - public boolean exists(final Class clazz, final FilterBean bean) { - return exists(clazz, FilterNodeBean.createFilterNode(bean)); - } - - @Override - public CompletableFuture existsAsync(final Class clazz, final FilterBean bean) { - return existsAsync(clazz, FilterNodeBean.createFilterNode(bean)); - } - - // -----------------------list set---------------------------- - @Override - public Set queryColumnSet( - final String selectedColumn, final Class clazz, final String column, final Serializable colval) { - return queryColumnSet(selectedColumn, clazz, null, FilterNodes.create(column, colval)); - } - - @Override - public CompletableFuture> queryColumnSetAsync( - final String selectedColumn, final Class clazz, final String column, final Serializable colval) { - return queryColumnSetAsync(selectedColumn, clazz, null, FilterNodes.create(column, colval)); - } - - @Override - public Set queryColumnSet( - final String selectedColumn, final Class clazz, final FilterBean bean) { - return queryColumnSet(selectedColumn, clazz, null, FilterNodeBean.createFilterNode(bean)); - } - - @Override - public CompletableFuture> queryColumnSetAsync( - final String selectedColumn, final Class clazz, final FilterBean bean) { - return queryColumnSetAsync(selectedColumn, clazz, null, FilterNodeBean.createFilterNode(bean)); - } - - @Override - public Set queryColumnSet( - final String selectedColumn, final Class clazz, final FilterNode node) { - return queryColumnSet(selectedColumn, clazz, null, node); - } - - @Override - public CompletableFuture> queryColumnSetAsync( - final String selectedColumn, final Class clazz, final FilterNode node) { - return queryColumnSetAsync(selectedColumn, clazz, null, node); - } - - @Override - public Set queryColumnSet( - final String selectedColumn, final Class clazz, final Flipper flipper, final FilterBean bean) { - return queryColumnSet(selectedColumn, clazz, flipper, FilterNodeBean.createFilterNode(bean)); - } - - @Override - public CompletableFuture> queryColumnSetAsync( - final String selectedColumn, final Class clazz, final Flipper flipper, final FilterBean bean) { - return queryColumnSetAsync(selectedColumn, clazz, flipper, FilterNodeBean.createFilterNode(bean)); - } - - @Override - public List queryColumnList( - final String selectedColumn, final Class clazz, final String column, final Serializable colval) { - return queryColumnList(selectedColumn, clazz, null, FilterNodes.create(column, colval)); - } - - @Override - public CompletableFuture> queryColumnListAsync( - final String selectedColumn, final Class clazz, final String column, final Serializable colval) { - return queryColumnListAsync(selectedColumn, clazz, null, FilterNodes.create(column, colval)); - } - - @Override - public List queryColumnList( - final String selectedColumn, final Class clazz, final FilterBean bean) { - return queryColumnList(selectedColumn, clazz, null, FilterNodeBean.createFilterNode(bean)); - } - - @Override - public CompletableFuture> queryColumnListAsync( - final String selectedColumn, final Class clazz, final FilterBean bean) { - return queryColumnListAsync(selectedColumn, clazz, null, FilterNodeBean.createFilterNode(bean)); - } - - @Override - public List queryColumnList( - final String selectedColumn, final Class clazz, final FilterNode node) { - return queryColumnList(selectedColumn, clazz, null, node); - } - - @Override - public CompletableFuture> queryColumnListAsync( - final String selectedColumn, final Class clazz, final FilterNode node) { - return queryColumnListAsync(selectedColumn, clazz, null, node); - } - - @Override - public List queryColumnList( - final String selectedColumn, final Class clazz, final Flipper flipper, final FilterBean bean) { - return queryColumnList(selectedColumn, clazz, flipper, FilterNodeBean.createFilterNode(bean)); - } - - @Override - public CompletableFuture> queryColumnListAsync( - final String selectedColumn, final Class clazz, final Flipper flipper, final FilterBean bean) { - return queryColumnListAsync(selectedColumn, clazz, flipper, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 根据指定参数查询对象某个字段的集合 - * - * @param Entity类的泛型 - * @param 字段值的类型 - * @param selectedColumn 字段名 - * @param clazz Entity类 - * @param flipper 翻页对象 - * @param bean 过滤Bean - * @return 字段集合 - */ - @Override - public Sheet queryColumnSheet( - final String selectedColumn, Class clazz, final Flipper flipper, final FilterBean bean) { - return queryColumnSheet(selectedColumn, clazz, flipper, FilterNodeBean.createFilterNode(bean)); - } - - @Override - public CompletableFuture> queryColumnSheetAsync( - final String selectedColumn, final Class clazz, final Flipper flipper, final FilterBean bean) { - return queryColumnSheetAsync(selectedColumn, clazz, flipper, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 查询符合过滤条件记录的Map集合, 主键值为key
- * 等价SQL: SELECT * FROM {table} WHERE {column} = {key} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param 主键泛型 - * @param Entity泛型 - * @param clazz Entity类 - * @param keyStream 主键Stream - * @return Entity的集合 - */ - @Override - public Map queryMap(final Class clazz, final Stream keyStream) { - return queryMap(clazz, null, keyStream); - } - - @Override - public CompletableFuture> queryMapAsync( - final Class clazz, final Stream keyStream) { - return queryMapAsync(clazz, null, keyStream); - } - - /** - * 查询符合过滤条件记录的Map集合, 主键值为key
- * 等价SQL: SELECT * FROM {table} WHERE {column} = {key} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param 主键泛型 - * @param Entity泛型 - * @param clazz Entity类 - * @param bean FilterBean - * @return Entity的集合 - */ - @Override - public Map queryMap(final Class clazz, final FilterBean bean) { - return queryMap(clazz, null, FilterNodeBean.createFilterNode(bean)); - } - - @Override - public CompletableFuture> queryMapAsync( - final Class clazz, final FilterBean bean) { - return queryMapAsync(clazz, null, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 查询符合过滤条件记录的Map集合, 主键值为key
- * 等价SQL: SELECT * FROM {table} WHERE {column} = {key} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param 主键泛型 - * @param Entity泛型 - * @param clazz Entity类 - * @param node FilterNode - * @return Entity的集合 - */ - @Override - public Map queryMap(final Class clazz, final FilterNode node) { - return queryMap(clazz, null, node); - } - - @Override - public CompletableFuture> queryMapAsync( - final Class clazz, final FilterNode node) { - return queryMapAsync(clazz, null, node); - } - - /** - * 查询符合过滤条件记录的Map集合, 主键值为key
- * 等价SQL: SELECT * FROM {table} WHERE {column} = {key} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param 主键泛型 - * @param Entity泛型 - * @param clazz Entity类 - * @param selects 指定字段 - * @param bean FilterBean - * @return Entity的集合 - */ - @Override - public Map queryMap( - final Class clazz, final SelectColumn selects, final FilterBean bean) { - return queryMap(clazz, selects, FilterNodeBean.createFilterNode(bean)); - } - - @Override - public CompletableFuture> queryMapAsync( - final Class clazz, final SelectColumn selects, final FilterBean bean) { - return queryMapAsync(clazz, selects, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 根据指定字段值查询对象集合 - * - * @param Entity类的泛型 - * @param clazz Entity类 - * @param column 过滤字段名 - * @param colval 过滤字段值 - * @return Entity对象的集合 - */ - @Override - public Set querySet(final Class clazz, final String column, final Serializable colval) { - return querySet(clazz, (SelectColumn) null, null, FilterNodes.create(column, colval)); - } - - @Override - public CompletableFuture> querySetAsync( - final Class clazz, final String column, final Serializable colval) { - return querySetAsync(clazz, (SelectColumn) null, null, FilterNodes.create(column, colval)); - } - - @Override - public Set querySet(final Class clazz) { - return querySet(clazz, (SelectColumn) null, null, (FilterNode) null); - } - - @Override - public CompletableFuture> querySetAsync(final Class clazz) { - return querySetAsync(clazz, (SelectColumn) null, null, (FilterNode) null); - } - - /** - * 根据过滤对象FilterBean查询对象集合 - * - * @param Entity类的泛型 - * @param clazz Entity类 - * @param bean 过滤Bean - * @return Entity对象集合 - */ - @Override - public Set querySet(final Class clazz, final FilterBean bean) { - return querySet(clazz, (SelectColumn) null, null, FilterNodeBean.createFilterNode(bean)); - } - - @Override - public CompletableFuture> querySetAsync(final Class clazz, final FilterBean bean) { - return querySetAsync(clazz, (SelectColumn) null, null, FilterNodeBean.createFilterNode(bean)); - } - - @Override - public Set querySet(final Class clazz, final FilterNode node) { - return querySet(clazz, (SelectColumn) null, null, node); - } - - @Override - public CompletableFuture> querySetAsync(final Class clazz, final FilterNode node) { - return querySetAsync(clazz, (SelectColumn) null, null, node); - } - - /** - * 根据过滤对象FilterBean查询对象集合, 对象只填充或排除SelectField指定的字段 - * - * @param Entity类的泛型 - * @param clazz Entity类 - * @param selects 收集的字段 - * @param bean 过滤Bean - * @return Entity对象的集合 - */ - @Override - public Set querySet(final Class clazz, final SelectColumn selects, final FilterBean bean) { - return querySet(clazz, selects, null, FilterNodeBean.createFilterNode(bean)); - } - - @Override - public CompletableFuture> querySetAsync( - final Class clazz, SelectColumn selects, final FilterBean bean) { - return querySetAsync(clazz, selects, null, FilterNodeBean.createFilterNode(bean)); - } - - @Override - public Set querySet(final Class clazz, final SelectColumn selects, final FilterNode node) { - return querySet(clazz, selects, null, node); - } - - @Override - public CompletableFuture> querySetAsync( - final Class clazz, SelectColumn selects, final FilterNode node) { - return querySetAsync(clazz, selects, null, node); - } - - @Override - public Set querySet( - final Class clazz, final Flipper flipper, final String column, final Serializable colval) { - return querySet(clazz, null, flipper, FilterNodes.create(column, colval)); - } - - @Override - public CompletableFuture> querySetAsync( - final Class clazz, final Flipper flipper, final String column, final Serializable colval) { - return querySetAsync(clazz, null, flipper, FilterNodes.create(column, colval)); - } - - @Override - public Set querySet(final Class clazz, final Flipper flipper, final FilterBean bean) { - return querySet(clazz, null, flipper, FilterNodeBean.createFilterNode(bean)); - } - - @Override - public CompletableFuture> querySetAsync( - final Class clazz, final Flipper flipper, final FilterBean bean) { - return querySetAsync(clazz, null, flipper, FilterNodeBean.createFilterNode(bean)); - } - - @Override - public Set querySet(final Class clazz, final Flipper flipper, final FilterNode node) { - return querySet(clazz, null, flipper, node); - } - - @Override - public CompletableFuture> querySetAsync( - final Class clazz, final Flipper flipper, final FilterNode node) { - return querySetAsync(clazz, null, flipper, node); - } - - @Override - public Set querySet( - final Class clazz, final SelectColumn selects, final Flipper flipper, final FilterBean bean) { - return querySet(clazz, selects, flipper, FilterNodeBean.createFilterNode(bean)); - } - - @Override - public CompletableFuture> querySetAsync( - final Class clazz, final SelectColumn selects, final Flipper flipper, final FilterBean bean) { - return querySetAsync(clazz, selects, flipper, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 根据指定字段值查询对象集合 - * - * @param Entity类的泛型 - * @param clazz Entity类 - * @param column 过滤字段名 - * @param colval 过滤字段值 - * @return Entity对象的集合 - */ - @Override - public List queryList(final Class clazz, final String column, final Serializable colval) { - return queryList(clazz, (SelectColumn) null, null, FilterNodes.create(column, colval)); - } - - @Override - public CompletableFuture> queryListAsync( - final Class clazz, final String column, final Serializable colval) { - return queryListAsync(clazz, (SelectColumn) null, null, FilterNodes.create(column, colval)); - } - - @Override - public List queryList(final Class clazz) { - return queryList(clazz, (SelectColumn) null, null, (FilterNode) null); - } - - @Override - public CompletableFuture> queryListAsync(final Class clazz) { - return queryListAsync(clazz, (SelectColumn) null, null, (FilterNode) null); - } - - /** - * 根据过滤对象FilterBean查询对象集合 - * - * @param Entity类的泛型 - * @param clazz Entity类 - * @param bean 过滤Bean - * @return Entity对象集合 - */ - @Override - public List queryList(final Class clazz, final FilterBean bean) { - return queryList(clazz, (SelectColumn) null, null, FilterNodeBean.createFilterNode(bean)); - } - - @Override - public CompletableFuture> queryListAsync(final Class clazz, final FilterBean bean) { - return queryListAsync(clazz, (SelectColumn) null, null, FilterNodeBean.createFilterNode(bean)); - } - - @Override - public List queryList(final Class clazz, final FilterNode node) { - return queryList(clazz, (SelectColumn) null, null, node); - } - - @Override - public CompletableFuture> queryListAsync(final Class clazz, final FilterNode node) { - return queryListAsync(clazz, (SelectColumn) null, null, node); - } - - /** - * 根据过滤对象FilterBean查询对象集合, 对象只填充或排除SelectField指定的字段 - * - * @param Entity类的泛型 - * @param clazz Entity类 - * @param selects 收集的字段 - * @param bean 过滤Bean - * @return Entity对象的集合 - */ - @Override - public List queryList(final Class clazz, final SelectColumn selects, final FilterBean bean) { - return queryList(clazz, selects, null, FilterNodeBean.createFilterNode(bean)); - } - - @Override - public CompletableFuture> queryListAsync( - final Class clazz, SelectColumn selects, final FilterBean bean) { - return queryListAsync(clazz, selects, null, FilterNodeBean.createFilterNode(bean)); - } - - @Override - public List queryList(final Class clazz, final SelectColumn selects, final FilterNode node) { - return queryList(clazz, selects, null, node); - } - - @Override - public CompletableFuture> queryListAsync( - final Class clazz, SelectColumn selects, final FilterNode node) { - return queryListAsync(clazz, selects, null, node); - } - - @Override - public List queryList( - final Class clazz, final Flipper flipper, final String column, final Serializable colval) { - return queryList(clazz, null, flipper, FilterNodes.create(column, colval)); - } - - @Override - public CompletableFuture> queryListAsync( - final Class clazz, final Flipper flipper, final String column, final Serializable colval) { - return queryListAsync(clazz, null, flipper, FilterNodes.create(column, colval)); - } - - @Override - public List queryList(final Class clazz, final Flipper flipper, final FilterBean bean) { - return queryList(clazz, null, flipper, FilterNodeBean.createFilterNode(bean)); - } - - @Override - public CompletableFuture> queryListAsync( - final Class clazz, final Flipper flipper, final FilterBean bean) { - return queryListAsync(clazz, null, flipper, FilterNodeBean.createFilterNode(bean)); - } - - @Override - public List queryList(final Class clazz, final Flipper flipper, final FilterNode node) { - return queryList(clazz, null, flipper, node); - } - - @Override - public CompletableFuture> queryListAsync( - final Class clazz, final Flipper flipper, final FilterNode node) { - return queryListAsync(clazz, null, flipper, node); - } - - @Override - public List queryList( - final Class clazz, final SelectColumn selects, final Flipper flipper, final FilterBean bean) { - return queryList(clazz, selects, flipper, FilterNodeBean.createFilterNode(bean)); - } - - @Override - public CompletableFuture> queryListAsync( - final Class clazz, final SelectColumn selects, final Flipper flipper, final FilterBean bean) { - return queryListAsync(clazz, selects, flipper, FilterNodeBean.createFilterNode(bean)); - } - - // -----------------------sheet---------------------------- - /** - * 根据过滤对象FilterBean和翻页对象Flipper查询一页的数据 - * - * @param Entity类的泛型 - * @param clazz Entity类 - * @param flipper 翻页对象 - * @param bean 过滤Bean - * @return Entity对象的集合 - */ - @Override - public Sheet querySheet(final Class clazz, final Flipper flipper, final FilterBean bean) { - return querySheet(clazz, null, flipper, FilterNodeBean.createFilterNode(bean)); - } - - @Override - public CompletableFuture> querySheetAsync( - final Class clazz, final Flipper flipper, final FilterBean bean) { - return querySheetAsync(clazz, null, flipper, FilterNodeBean.createFilterNode(bean)); - } - - @Override - public Sheet querySheet(final Class clazz, final Flipper flipper, final FilterNode node) { - return querySheet(clazz, null, flipper, node); - } - - @Override - public CompletableFuture> querySheetAsync( - final Class clazz, final Flipper flipper, final FilterNode node) { - return querySheetAsync(clazz, null, flipper, node); - } - - /** - * 根据过滤对象FilterBean和翻页对象Flipper查询一页的数据, 对象只填充或排除SelectField指定的字段 - * - * @param Entity类的泛型 - * @param clazz Entity类 - * @param selects 收集的字段集合 - * @param flipper 翻页对象 - * @param bean 过滤Bean - * @return Entity对象的集合 - */ - @Override - public Sheet querySheet( - final Class clazz, final SelectColumn selects, final Flipper flipper, final FilterBean bean) { - return querySheet(clazz, selects, flipper, FilterNodeBean.createFilterNode(bean)); - } - - @Override - public CompletableFuture> querySheetAsync( - final Class clazz, final SelectColumn selects, final Flipper flipper, final FilterBean bean) { - return querySheetAsync(clazz, selects, flipper, FilterNodeBean.createFilterNode(bean)); - } - - protected static class DefaultDataBatch implements DataBatch { - - @Comment("操作对象") - public final List actions = new ArrayList(); - - protected DefaultDataBatch() {} - - public DataBatch run(Runnable task) { - Objects.requireNonNull(task); - this.actions.add(new RunnableBatchAction(task)); - return this; - } - - @Override // entitys不一定是同一表的数据 - public DataBatch insert(T... entitys) { - for (T t : entitys) { - Objects.requireNonNull(t); - if (t.getClass().getAnnotation(Entity.class) == null) { - throw new SourceException("Entity Class " + t.getClass() + " must be on Annotation @Entity"); - } - this.actions.add(new InsertBatchAction1(t)); - } - return this; - } - - @Override // entitys不一定是同一表的数据 - public DataBatch insert(Collection entitys) { - for (T t : entitys) { - Objects.requireNonNull(t); - if (t.getClass().getAnnotation(Entity.class) == null) { - throw new SourceException("Entity Class " + t.getClass() + " must be on Annotation @Entity"); - } - this.actions.add(new InsertBatchAction1(t)); - } - return this; - } - - @Override // entitys不一定是同一表的数据 - public DataBatch delete(T... entitys) { - for (T t : entitys) { - Objects.requireNonNull(t); - if (t.getClass().getAnnotation(Entity.class) == null) { - throw new SourceException("Entity Class " + t.getClass() + " must be on Annotation @Entity"); - } - this.actions.add(new DeleteBatchAction1(t)); - } - return this; - } - - @Override // entitys不一定是同一表的数据 - public DataBatch delete(Collection entitys) { - for (T t : entitys) { - Objects.requireNonNull(t); - if (t.getClass().getAnnotation(Entity.class) == null) { - throw new SourceException("Entity Class " + t.getClass() + " must be on Annotation @Entity"); - } - this.actions.add(new DeleteBatchAction1(t)); - } - return this; - } - - @Override - public DataBatch delete(Class clazz, Serializable... pks) { - Objects.requireNonNull(clazz); - if (clazz.getAnnotation(Entity.class) == null) { - throw new SourceException("Entity Class " + clazz + " must be on Annotation @Entity"); - } - if (pks.length < 1) { - throw new SourceException("delete pk length is zero "); - } - for (Serializable pk : pks) { - Objects.requireNonNull(pk); - this.actions.add(new DeleteBatchAction2(clazz, pk)); - } - return this; - } - - @Override - public DataBatch delete(Class clazz, FilterNode node) { - return delete(clazz, node, (Flipper) null); - } - - @Override - public DataBatch delete(Class clazz, FilterNode node, Flipper flipper) { - Objects.requireNonNull(clazz); - if (clazz.getAnnotation(Entity.class) == null) { - throw new SourceException("Entity Class " + clazz + " must be on Annotation @Entity"); - } - this.actions.add(new DeleteBatchAction3(clazz, node, flipper)); - return this; - } - - @Override // entitys不一定是同一表的数据 - public DataBatch update(T... entitys) { - for (T t : entitys) { - Objects.requireNonNull(t); - if (t.getClass().getAnnotation(Entity.class) == null) { - throw new SourceException("Entity Class " + t.getClass() + " must be on Annotation @Entity"); - } - this.actions.add(new UpdateBatchAction1(t)); - } - return this; - } - - @Override // entitys不一定是同一表的数据 - public DataBatch update(Collection entitys) { - for (T t : entitys) { - Objects.requireNonNull(t); - if (t.getClass().getAnnotation(Entity.class) == null) { - throw new SourceException("Entity Class " + t.getClass() + " must be on Annotation @Entity"); - } - this.actions.add(new UpdateBatchAction1(t)); - } - return this; - } - - @Override - public DataBatch updateColumn(Class clazz, Serializable pk, String column, Serializable value) { - return updateColumn(clazz, pk, ColumnValue.set(column, value)); - } - - @Override - public DataBatch updateColumn(Class clazz, Serializable pk, ColumnValue... values) { - Objects.requireNonNull(clazz); - if (clazz.getAnnotation(Entity.class) == null) { - throw new SourceException("Entity Class " + clazz + " must be on Annotation @Entity"); - } - Objects.requireNonNull(pk); - if (values.length < 1) { - throw new SourceException("update column-value length is zero "); - } - for (ColumnValue val : values) { - Objects.requireNonNull(val); - } - this.actions.add(new UpdateBatchAction2(clazz, pk, values)); - return this; - } - - @Override - public DataBatch updateColumn(Class clazz, FilterNode node, String column, Serializable value) { - return updateColumn(clazz, node, (Flipper) null, ColumnValue.set(column, value)); - } - - @Override - public DataBatch updateColumn(Class clazz, FilterNode node, ColumnValue... values) { - return updateColumn(clazz, node, (Flipper) null, values); - } - - @Override - public DataBatch updateColumn(Class clazz, FilterNode node, Flipper flipper, ColumnValue... values) { - Objects.requireNonNull(clazz); - if (clazz.getAnnotation(Entity.class) == null) { - throw new SourceException("Entity Class " + clazz + " must be on Annotation @Entity"); - } - if (values.length < 1) { - throw new SourceException("update column-value length is zero "); - } - for (ColumnValue val : values) { - Objects.requireNonNull(val); - } - this.actions.add(new UpdateBatchAction3(clazz, node, flipper, values)); - return this; - } - - @Override - public DataBatch updateColumn(T entity, final String... columns) { - if (columns.length < 1) { - throw new SourceException("update column length is zero "); - } - for (String val : columns) { - Objects.requireNonNull(val); - } - return updateColumn(entity, (FilterNode) null, SelectColumn.includes(columns)); - } - - @Override - public DataBatch updateColumn(T entity, final FilterNode node, final String... columns) { - return updateColumn(entity, node, SelectColumn.includes(columns)); - } - - @Override - public DataBatch updateColumn(T entity, SelectColumn selects) { - return updateColumn(entity, (FilterNode) null, selects); - } - - @Override - public DataBatch updateColumn(T entity, final FilterNode node, SelectColumn selects) { - Objects.requireNonNull(entity); - if (entity.getClass().getAnnotation(Entity.class) == null) { - throw new SourceException("Entity Class " + entity.getClass() + " must be on Annotation @Entity"); - } - Objects.requireNonNull(selects); - this.actions.add(new UpdateBatchAction4(entity, node, selects)); - return this; - } - } - - protected abstract static class BatchAction {} - - protected static class RunnableBatchAction extends BatchAction { - - public Runnable task; - - public RunnableBatchAction(Runnable task) { - this.task = task; - } - } - - protected static class InsertBatchAction1 extends BatchAction { - - public Object entity; - - public InsertBatchAction1(Object entity) { - this.entity = entity; - } - } - - protected static class DeleteBatchAction1 extends BatchAction { - - public Object entity; - - public DeleteBatchAction1(Object entity) { - this.entity = entity; - } - } - - protected static class DeleteBatchAction2 extends BatchAction { - - public Class clazz; - - public Serializable pk; - - public DeleteBatchAction2(Class clazz, Serializable pk) { - this.clazz = clazz; - this.pk = pk; - } - } - - protected static class DeleteBatchAction3 extends BatchAction { - - public Class clazz; - - public FilterNode node; - - public Flipper flipper; - - public DeleteBatchAction3(Class clazz, FilterNode node) { - this.clazz = clazz; - this.node = node; - } - - public DeleteBatchAction3(Class clazz, FilterNode node, Flipper flipper) { - this.clazz = clazz; - this.node = node; - this.flipper = flipper; - } - } - - protected static class UpdateBatchAction1 extends BatchAction { - - public Object entity; - - public UpdateBatchAction1(Object entity) { - this.entity = entity; - } - } - - protected static class UpdateBatchAction2 extends BatchAction { - - public Class clazz; - - public Serializable pk; - - public ColumnValue[] values; - - public UpdateBatchAction2(Class clazz, Serializable pk, ColumnValue... values) { - this.clazz = clazz; - this.pk = pk; - this.values = values; - } - } - - protected static class UpdateBatchAction3 extends BatchAction { - - public Class clazz; - - public FilterNode node; - - public Flipper flipper; - - public ColumnValue[] values; - - public UpdateBatchAction3(Class clazz, FilterNode node, ColumnValue... values) { - this.clazz = clazz; - this.node = node; - this.values = values; - } - - public UpdateBatchAction3(Class clazz, FilterNode node, Flipper flipper, ColumnValue... values) { - this.clazz = clazz; - this.node = node; - this.flipper = flipper; - this.values = values; - } - } - - protected static class UpdateBatchAction4 extends BatchAction { - - public Object entity; - - public FilterNode node; - - public SelectColumn selects; - - public UpdateBatchAction4(Object entity, SelectColumn selects) { - this.entity = entity; - this.selects = selects; - } - - public UpdateBatchAction4(Object entity, FilterNode node, SelectColumn selects) { - this.entity = entity; - this.node = node; - this.selects = selects; - } - } -} +/* + * 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.source; + +import static org.redkale.boot.Application.RESNAME_APP_EXECUTOR; +import static org.redkale.source.DataSources.*; + +import java.io.Serializable; +import java.net.InetSocketAddress; +import java.util.*; +import java.util.concurrent.*; +import java.util.concurrent.locks.ReentrantLock; +import java.util.function.*; +import java.util.stream.Stream; +import org.redkale.annotation.*; +import org.redkale.annotation.AutoLoad; +import org.redkale.annotation.Comment; +import org.redkale.annotation.ResourceType; +import org.redkale.convert.json.JsonConvert; +import org.redkale.inject.Resourcable; +import org.redkale.inject.ResourceEvent; +import org.redkale.net.WorkThread; +import org.redkale.persistence.Entity; +import org.redkale.service.*; +import org.redkale.util.*; + +/** + * DataSource的S抽象实现类
+ * 注意: 所有的操作只能作用在一张表上,不能同时变更多张表 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.5.0 + */ +@Local +@AutoLoad(false) +@SuppressWarnings("unchecked") +@ResourceType(DataSource.class) +public abstract class AbstractDataSource extends AbstractService implements DataSource, AutoCloseable, Resourcable { + + protected final IntFunction serialArrayFunc = Utility.serialArrayFunc(); + + private final ReentrantLock executorLock = new ReentrantLock(); + + protected int sourceThreads = Utility.cpus(); + + @Resource(name = RESNAME_APP_EXECUTOR, required = false) + private ExecutorService sourceExecutor; + + protected String name; + + @Override + public void init(AnyValue conf) { + super.init(conf); + if (conf.getAnyValue("read") == null) { + this.sourceThreads = + conf.getIntValue(DATA_SOURCE_THREADS, conf.getIntValue(DATA_SOURCE_MAXCONNS, Utility.cpus())); + } else { + this.sourceThreads = conf.getAnyValue("read") + .getIntValue(DATA_SOURCE_THREADS, conf.getIntValue(DATA_SOURCE_MAXCONNS, Utility.cpus())); + } + } + + @Override + public final String resourceName() { + return name; + } + + @ResourceChanged + public abstract void onResourceChange(ResourceEvent[] events); + + protected void setSourceExecutor(ExecutorService executor) { + this.sourceExecutor = executor; + } + + protected SourceUrlInfo parseSourceUrl(final String url) { + final SourceUrlInfo info = new SourceUrlInfo(); + info.url = url; + if (url.startsWith("jdbc:h2:")) { + return info; + } + String url0 = url.substring(url.indexOf("://") + 3); + int pos = url0.indexOf('?'); // 127.0.0.1:5432/db?charset=utr8&xxx=yy + if (pos > 0) { + String params = url0.substring(pos + 1).replace("&", "&"); + for (String param : params.split("&")) { + int p = param.indexOf('='); + if (p < 1) { + continue; + } + info.attributes.put(param.substring(0, p), param.substring(p + 1)); + } + url0 = url0.substring(0, pos); + } + pos = url0.indexOf('/'); // 127.0.0.1:5432/db + if (pos > 0) { + info.database = url0.substring(pos + 1); + url0 = url0.substring(0, pos); + } + pos = url0.indexOf(':'); + if (pos > 0) { + info.servaddr = new InetSocketAddress(url0.substring(0, pos), Integer.parseInt(url0.substring(pos + 1))); + } else if (url.startsWith("http://")) { + info.servaddr = new InetSocketAddress(url0, 80); + } else if (url.startsWith("https://")) { + info.servaddr = new InetSocketAddress(url0, 443); + } else { + throw new SourceException(url + " parse port error"); + } + return info; + } + + public static class SourceUrlInfo { + + public Properties attributes = new Properties(); + + public String url; + + public String database; + + public InetSocketAddress servaddr; + + public String username; + + public String password; + + public String encoding; + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + } + + @Override + protected ExecutorService getExecutor() { + ExecutorService executor = this.sourceExecutor; + if (executor == null) { + executorLock.lock(); + try { + if (this.sourceExecutor == null) { + this.sourceExecutor = WorkThread.createWorkExecutor( + sourceThreads, "Redkale-DataSource-WorkThread-" + resourceName() + "-%s"); + } + } finally { + executorLock.unlock(); + } + executor = this.sourceExecutor; + } + return executor; + } + + protected void complete(WorkThread workThread, CompletableFuture future, T value) { + getExecutor().execute(() -> future.complete(value)); + } + + protected void completeExceptionally(WorkThread workThread, CompletableFuture future, Throwable exp) { + getExecutor().execute(() -> future.completeExceptionally(exp)); + } + + protected String executorToString() { + ExecutorService executor = this.sourceExecutor; + if (executor == null) { + return ""; + } + if (executor.getClass().getSimpleName().contains("ThreadPerTaskExecutor")) { + return ", thread-pool=[virtual]"; + } + if (executor instanceof ThreadPoolExecutor) { + ThreadPoolExecutor re = (ThreadPoolExecutor) executor; + return ", pool-size=" + re.getMaximumPoolSize(); + } + return ""; + } + + /** + * 是否虚拟化的持久对象 + * + * @param info EntityInfo + * @return boolean + */ + protected boolean isOnlyCache(EntityInfo info) { + return info.isVirtualEntity(); + } + + /** + * 是否可以使用缓存,一般包含关联查询就不使用缓存 + * + * @param node 过滤条件 + * @param entityApplyer 函数 + * @return boolean + */ + protected boolean isCacheUseable(FilterNode node, Function entityApplyer) { + return node.isCacheUseable(entityApplyer); + } + + /** + * 生成过滤函数 + * + * @param 泛型 + * @param node 过滤条件 + * @param cache 缓存 + * @return Predicate + */ + protected Predicate createPredicate(FilterNode node, EntityCache cache) { + return node.createPredicate(cache); + } + + /** + * 根据ResultSet获取对象 + * + * @param 泛型 + * @param info EntityInfo + * @param sels 过滤字段 + * @param row ResultSet + * @return 对象 + */ + protected T getEntityValue(EntityInfo info, final SelectColumn sels, final EntityInfo.DataResultSetRow row) { + return info.getBuilder().getEntityValue(sels, row); + } + + /** + * 根据翻页参数构建排序SQL + * + * @param 泛型 + * @param info EntityInfo + * @param flipper 翻页参数 + * @return SQL + */ + protected String createSQLOrderby(EntityInfo info, Flipper flipper) { + return info.createSQLOrderby(flipper); + } + + /** + * 根据过滤条件生成关联表与别名的映射关系 + * + * @param node 过滤条件 + * @return Map + */ + protected Map getJoinTabalis(FilterNode node) { + return node == null ? null : node.getJoinTabalis(); + } + + /** + * 加载指定类的EntityInfo + * + * @param 泛型 + * @param clazz 类 + * @param cacheForbidden 是否屏蔽缓存 + * @param props 配置信息 + * @param fullloader 加载器 + * @return EntityInfo + */ + protected EntityInfo loadEntityInfo( + Class clazz, + final boolean cacheForbidden, + final Properties props, + BiFunction> fullloader) { + return EntityInfo.load(clazz, cacheForbidden, props, this, fullloader); + } + + /** + * 检查对象是否都是同一个Entity类 + * + * @param 泛型 + * @param action 操作 + * @param entitys 对象集合 + */ + protected void checkEntity(String action, T... entitys) { + Class clazz = null; + for (T val : entitys) { + if (clazz == null) { + clazz = val.getClass(); + if (clazz.getAnnotation(Entity.class) == null + && clazz.getAnnotation(javax.persistence.Entity.class) == null) { + throw new SourceException("Entity Class " + clazz + " must be on Annotation @Entity"); + } + } else if (clazz != val.getClass()) { + throw new SourceException("DataSource." + action + " must the same Class Entity, but diff is " + clazz + + " and " + val.getClass()); + } + } + } + + protected CompletableFuture supplyAsync(Supplier supplier) { + return CompletableFuture.supplyAsync(supplier, getExecutor()); + } + + @Override + public int batch(final DataBatch batch) { + return batchAsync(batch).join(); + } + + @Override + public CompletableFuture batchAsync(final DataBatch batch) { + return CompletableFuture.failedFuture(new UnsupportedOperationException("Not supported yet.")); + } + + @Override + public final int insert(final Collection entitys) { + if (entitys == null || entitys.isEmpty()) { + return 0; + } + return insert(entitys.toArray()); + } + + @Override + public final int insert(final Stream entitys) { + if (entitys == null) { + return 0; + } + return insert(entitys.toArray()); + } + + @Override + public final CompletableFuture insertAsync(final Collection entitys) { + if (entitys == null || entitys.isEmpty()) { + return CompletableFuture.completedFuture(0); + } + return insertAsync(entitys.toArray()); + } + + @Override + public final CompletableFuture insertAsync(final Stream entitys) { + if (entitys == null) { + return CompletableFuture.completedFuture(0); + } + return insertAsync(entitys.toArray()); + } + + @Override + public CompletableFuture clearTableAsync(final Class clazz) { + return clearTableAsync(clazz, (FilterNode) null); + } + + @Override + public int dropTable(Class clazz) { + return dropTable(clazz, (FilterNode) null); + } + + @Override + public CompletableFuture dropTableAsync(final Class clazz) { + return dropTableAsync(clazz, (FilterNode) null); + } + + /** + * 根据主键值更新对象的多个column对应的值, 必须是Entity Class + * + * @param Entity类的泛型 + * @param clazz Entity类 + * @param node 过滤条件 + * @param values 字段值 + * @return 更新的数据条数 + */ + @Override + public int updateColumn(final Class clazz, final FilterNode node, final ColumnValue... values) { + return updateColumn(clazz, node, null, values); + } + + @Override + public CompletableFuture updateColumnAsync( + final Class clazz, final FilterNode node, final ColumnValue... values) { + return updateColumnAsync(clazz, node, null, values); + } + + @Override + public int updateColumn(final T entity, final String... columns) { + return updateColumn(entity, SelectColumn.includes(columns)); + } + + @Override + public CompletableFuture updateColumnAsync(final T entity, final String... columns) { + return updateColumnAsync(entity, SelectColumn.includes(columns)); + } + + @Override + public int updateColumn(final T entity, final FilterNode node, final String... columns) { + return updateColumn(entity, node, SelectColumn.includes(columns)); + } + + @Override + public CompletableFuture updateColumnAsync( + final T entity, final FilterNode node, final String... columns) { + return updateColumnAsync(entity, node, SelectColumn.includes(columns)); + } + + @Override + public Map getNumberMap(final Class entityClass, final FilterFuncColumn... columns) { + return getNumberMap(entityClass, (FilterNode) null, columns); + } + + @Override + public CompletableFuture> getNumberMapAsync( + final Class entityClass, final FilterFuncColumn... columns) { + return getNumberMapAsync(entityClass, (FilterNode) null, columns); + } + + @Override + public Map getNumberMap( + final Class entityClass, final FilterBean bean, final FilterFuncColumn... columns) { + return getNumberMap(entityClass, FilterNodeBean.createFilterNode(bean), columns); + } + + @Override + public CompletableFuture> getNumberMapAsync( + final Class entityClass, final FilterBean bean, final FilterFuncColumn... columns) { + return getNumberMapAsync(entityClass, FilterNodeBean.createFilterNode(bean), columns); + } + + @Override + public Number getNumberResult(final Class entityClass, final FilterFunc func, final String column) { + return getNumberResult(entityClass, func, null, column, (FilterNode) null); + } + + @Override + public CompletableFuture getNumberResultAsync( + final Class entityClass, final FilterFunc func, final String column) { + return getNumberResultAsync(entityClass, func, null, column, (FilterNode) null); + } + + @Override + public Number getNumberResult( + final Class entityClass, final FilterFunc func, final String column, FilterBean bean) { + return getNumberResult(entityClass, func, null, column, FilterNodeBean.createFilterNode(bean)); + } + + @Override + public CompletableFuture getNumberResultAsync( + final Class entityClass, final FilterFunc func, final String column, final FilterBean bean) { + return getNumberResultAsync(entityClass, func, null, column, FilterNodeBean.createFilterNode(bean)); + } + + @Override + public Number getNumberResult( + final Class entityClass, final FilterFunc func, final String column, final FilterNode node) { + return getNumberResult(entityClass, func, null, column, node); + } + + @Override + public CompletableFuture getNumberResultAsync( + final Class entityClass, final FilterFunc func, final String column, final FilterNode node) { + return getNumberResultAsync(entityClass, func, null, column, node); + } + + @Override + public Number getNumberResult( + final Class entityClass, final FilterFunc func, final Number defVal, final String column) { + return getNumberResult(entityClass, func, defVal, column, (FilterNode) null); + } + + @Override + public CompletableFuture getNumberResultAsync( + final Class entityClass, final FilterFunc func, final Number defVal, final String column) { + return getNumberResultAsync(entityClass, func, defVal, column, (FilterNode) null); + } + + @Override + public Number getNumberResult( + final Class entityClass, final FilterFunc func, final Number defVal, final String column, FilterBean bean) { + return getNumberResult(entityClass, func, defVal, column, FilterNodeBean.createFilterNode(bean)); + } + + @Override + public CompletableFuture getNumberResultAsync( + final Class entityClass, final FilterFunc func, final Number defVal, final String column, FilterBean bean) { + return getNumberResultAsync(entityClass, func, defVal, column, FilterNodeBean.createFilterNode(bean)); + } + + // ------------------------ queryColumnMapCompose ------------------------ + @Override + public Map queryColumnMap( + final Class entityClass, final String keyColumn, final FilterFunc func, final String funcColumn) { + return queryColumnMap(entityClass, keyColumn, func, funcColumn, (FilterNode) null); + } + + @Override + public CompletableFuture> queryColumnMapAsync( + final Class entityClass, final String keyColumn, final FilterFunc func, final String funcColumn) { + return queryColumnMapAsync(entityClass, keyColumn, func, funcColumn, (FilterNode) null); + } + + @Override + public Map queryColumnMap( + final Class entityClass, + final String keyColumn, + final FilterFunc func, + final String funcColumn, + final FilterBean bean) { + return queryColumnMap(entityClass, keyColumn, func, funcColumn, FilterNodeBean.createFilterNode(bean)); + } + + @Override + public CompletableFuture> queryColumnMapAsync( + final Class entityClass, + final String keyColumn, + final FilterFunc func, + final String funcColumn, + final FilterBean bean) { + return queryColumnMapAsync(entityClass, keyColumn, func, funcColumn, FilterNodeBean.createFilterNode(bean)); + } + + @Override + public Map queryColumnMap( + final Class entityClass, final ColumnNode[] funcNodes, final String groupByColumn) { + return queryColumnMap(entityClass, funcNodes, groupByColumn, (FilterNode) null); + } + + @Override + public CompletableFuture> queryColumnMapAsync( + final Class entityClass, final ColumnNode[] funcNodes, final String groupByColumn) { + return queryColumnMapAsync(entityClass, funcNodes, groupByColumn, (FilterNode) null); + } + + @Override + public Map queryColumnMap( + final Class entityClass, + final ColumnNode[] funcNodes, + final String groupByColumn, + final FilterBean bean) { + return queryColumnMap(entityClass, funcNodes, groupByColumn, FilterNodeBean.createFilterNode(bean)); + } + + @Override + public CompletableFuture> queryColumnMapAsync( + final Class entityClass, + final ColumnNode[] funcNodes, + final String groupByColumn, + final FilterBean bean) { + return queryColumnMapAsync(entityClass, funcNodes, groupByColumn, FilterNodeBean.createFilterNode(bean)); + } + + @Override + public Map queryColumnMap( + final Class entityClass, final ColumnNode[] funcNodes, final String[] groupByColumns) { + return queryColumnMap(entityClass, funcNodes, groupByColumns, (FilterNode) null); + } + + @Override + public CompletableFuture> queryColumnMapAsync( + final Class entityClass, final ColumnNode[] funcNodes, final String[] groupByColumns) { + return queryColumnMapAsync(entityClass, funcNodes, groupByColumns, (FilterNode) null); + } + + @Override + public Map queryColumnMap( + final Class entityClass, + final ColumnNode[] funcNodes, + final String[] groupByColumns, + final FilterBean bean) { + return queryColumnMap(entityClass, funcNodes, groupByColumns, FilterNodeBean.createFilterNode(bean)); + } + + @Override + public CompletableFuture> queryColumnMapAsync( + final Class entityClass, + final ColumnNode[] funcNodes, + final String[] groupByColumns, + final FilterBean bean) { + return queryColumnMapAsync(entityClass, funcNodes, groupByColumns, FilterNodeBean.createFilterNode(bean)); + } + + // ----------------------------- findCompose ----------------------------- + /** + * 根据主键获取对象 + * + * @param Entity类的泛型 + * @param clazz Entity类 + * @param pk 主键值 + * @return Entity对象 + */ + @Override + public T find(Class clazz, Serializable pk) { + return find(clazz, (SelectColumn) null, pk); + } + + @Override + public CompletableFuture findAsync(final Class clazz, final Serializable pk) { + return findAsync(clazz, (SelectColumn) null, pk); + } + + @Override + public T find(final Class clazz, final String column, final Serializable colval) { + return find(clazz, null, FilterNodes.create(column, colval)); + } + + @Override + public CompletableFuture findAsync(final Class clazz, final String column, final Serializable colval) { + return findAsync(clazz, null, FilterNodes.create(column, colval)); + } + + @Override + public T find(final Class clazz, final FilterBean bean) { + return find(clazz, null, FilterNodeBean.createFilterNode(bean)); + } + + @Override + public CompletableFuture findAsync(final Class clazz, final FilterBean bean) { + return findAsync(clazz, null, FilterNodeBean.createFilterNode(bean)); + } + + @Override + public T find(final Class clazz, final FilterNode node) { + return find(clazz, null, node); + } + + @Override + public CompletableFuture findAsync(final Class clazz, final FilterNode node) { + return findAsync(clazz, null, node); + } + + @Override + public T find(final Class clazz, final SelectColumn selects, final FilterBean bean) { + return find(clazz, selects, FilterNodeBean.createFilterNode(bean)); + } + + @Override + public CompletableFuture findAsync(final Class clazz, final SelectColumn selects, final FilterBean bean) { + return findAsync(clazz, selects, FilterNodeBean.createFilterNode(bean)); + } + + @Override + public Serializable findColumn(final Class clazz, final String column, final Serializable pk) { + return findColumn(clazz, column, null, pk); + } + + @Override + public CompletableFuture findColumnAsync( + final Class clazz, final String column, final Serializable pk) { + return findColumnAsync(clazz, column, null, pk); + } + + @Override + public Serializable findColumn(final Class clazz, final String column, final FilterBean bean) { + return findColumn(clazz, column, null, FilterNodeBean.createFilterNode(bean)); + } + + @Override + public CompletableFuture findColumnAsync( + final Class clazz, final String column, final FilterBean bean) { + return findColumnAsync(clazz, column, null, FilterNodeBean.createFilterNode(bean)); + } + + @Override + public Serializable findColumn(final Class clazz, final String column, final FilterNode node) { + return findColumn(clazz, column, null, node); + } + + @Override + public CompletableFuture findColumnAsync( + final Class clazz, final String column, final FilterNode node) { + return findColumnAsync(clazz, column, null, node); + } + + @Override + public Serializable findColumn( + final Class clazz, final String column, final Serializable defValue, final FilterBean bean) { + return findColumn(clazz, column, defValue, FilterNodeBean.createFilterNode(bean)); + } + + @Override + public CompletableFuture findColumnAsync( + final Class clazz, final String column, final Serializable defValue, final FilterBean bean) { + return findColumnAsync(clazz, column, defValue, FilterNodeBean.createFilterNode(bean)); + } + + @Override + public boolean exists(final Class clazz, final FilterBean bean) { + return exists(clazz, FilterNodeBean.createFilterNode(bean)); + } + + @Override + public CompletableFuture existsAsync(final Class clazz, final FilterBean bean) { + return existsAsync(clazz, FilterNodeBean.createFilterNode(bean)); + } + + // -----------------------list set---------------------------- + @Override + public Set queryColumnSet( + final String selectedColumn, final Class clazz, final String column, final Serializable colval) { + return queryColumnSet(selectedColumn, clazz, null, FilterNodes.create(column, colval)); + } + + @Override + public CompletableFuture> queryColumnSetAsync( + final String selectedColumn, final Class clazz, final String column, final Serializable colval) { + return queryColumnSetAsync(selectedColumn, clazz, null, FilterNodes.create(column, colval)); + } + + @Override + public Set queryColumnSet( + final String selectedColumn, final Class clazz, final FilterBean bean) { + return queryColumnSet(selectedColumn, clazz, null, FilterNodeBean.createFilterNode(bean)); + } + + @Override + public CompletableFuture> queryColumnSetAsync( + final String selectedColumn, final Class clazz, final FilterBean bean) { + return queryColumnSetAsync(selectedColumn, clazz, null, FilterNodeBean.createFilterNode(bean)); + } + + @Override + public Set queryColumnSet( + final String selectedColumn, final Class clazz, final FilterNode node) { + return queryColumnSet(selectedColumn, clazz, null, node); + } + + @Override + public CompletableFuture> queryColumnSetAsync( + final String selectedColumn, final Class clazz, final FilterNode node) { + return queryColumnSetAsync(selectedColumn, clazz, null, node); + } + + @Override + public Set queryColumnSet( + final String selectedColumn, final Class clazz, final Flipper flipper, final FilterBean bean) { + return queryColumnSet(selectedColumn, clazz, flipper, FilterNodeBean.createFilterNode(bean)); + } + + @Override + public CompletableFuture> queryColumnSetAsync( + final String selectedColumn, final Class clazz, final Flipper flipper, final FilterBean bean) { + return queryColumnSetAsync(selectedColumn, clazz, flipper, FilterNodeBean.createFilterNode(bean)); + } + + @Override + public List queryColumnList( + final String selectedColumn, final Class clazz, final String column, final Serializable colval) { + return queryColumnList(selectedColumn, clazz, null, FilterNodes.create(column, colval)); + } + + @Override + public CompletableFuture> queryColumnListAsync( + final String selectedColumn, final Class clazz, final String column, final Serializable colval) { + return queryColumnListAsync(selectedColumn, clazz, null, FilterNodes.create(column, colval)); + } + + @Override + public List queryColumnList( + final String selectedColumn, final Class clazz, final FilterBean bean) { + return queryColumnList(selectedColumn, clazz, null, FilterNodeBean.createFilterNode(bean)); + } + + @Override + public CompletableFuture> queryColumnListAsync( + final String selectedColumn, final Class clazz, final FilterBean bean) { + return queryColumnListAsync(selectedColumn, clazz, null, FilterNodeBean.createFilterNode(bean)); + } + + @Override + public List queryColumnList( + final String selectedColumn, final Class clazz, final FilterNode node) { + return queryColumnList(selectedColumn, clazz, null, node); + } + + @Override + public CompletableFuture> queryColumnListAsync( + final String selectedColumn, final Class clazz, final FilterNode node) { + return queryColumnListAsync(selectedColumn, clazz, null, node); + } + + @Override + public List queryColumnList( + final String selectedColumn, final Class clazz, final Flipper flipper, final FilterBean bean) { + return queryColumnList(selectedColumn, clazz, flipper, FilterNodeBean.createFilterNode(bean)); + } + + @Override + public CompletableFuture> queryColumnListAsync( + final String selectedColumn, final Class clazz, final Flipper flipper, final FilterBean bean) { + return queryColumnListAsync(selectedColumn, clazz, flipper, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 根据指定参数查询对象某个字段的集合 + * + * @param Entity类的泛型 + * @param 字段值的类型 + * @param selectedColumn 字段名 + * @param clazz Entity类 + * @param flipper 翻页对象 + * @param bean 过滤Bean + * @return 字段集合 + */ + @Override + public Sheet queryColumnSheet( + final String selectedColumn, Class clazz, final Flipper flipper, final FilterBean bean) { + return queryColumnSheet(selectedColumn, clazz, flipper, FilterNodeBean.createFilterNode(bean)); + } + + @Override + public CompletableFuture> queryColumnSheetAsync( + final String selectedColumn, final Class clazz, final Flipper flipper, final FilterBean bean) { + return queryColumnSheetAsync(selectedColumn, clazz, flipper, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 查询符合过滤条件记录的Map集合, 主键值为key
+ * 等价SQL: SELECT * FROM {table} WHERE {column} = {key} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param 主键泛型 + * @param Entity泛型 + * @param clazz Entity类 + * @param keyStream 主键Stream + * @return Entity的集合 + */ + @Override + public Map queryMap(final Class clazz, final Stream keyStream) { + return queryMap(clazz, null, keyStream); + } + + @Override + public CompletableFuture> queryMapAsync( + final Class clazz, final Stream keyStream) { + return queryMapAsync(clazz, null, keyStream); + } + + /** + * 查询符合过滤条件记录的Map集合, 主键值为key
+ * 等价SQL: SELECT * FROM {table} WHERE {column} = {key} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param 主键泛型 + * @param Entity泛型 + * @param clazz Entity类 + * @param bean FilterBean + * @return Entity的集合 + */ + @Override + public Map queryMap(final Class clazz, final FilterBean bean) { + return queryMap(clazz, null, FilterNodeBean.createFilterNode(bean)); + } + + @Override + public CompletableFuture> queryMapAsync( + final Class clazz, final FilterBean bean) { + return queryMapAsync(clazz, null, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 查询符合过滤条件记录的Map集合, 主键值为key
+ * 等价SQL: SELECT * FROM {table} WHERE {column} = {key} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param 主键泛型 + * @param Entity泛型 + * @param clazz Entity类 + * @param node FilterNode + * @return Entity的集合 + */ + @Override + public Map queryMap(final Class clazz, final FilterNode node) { + return queryMap(clazz, null, node); + } + + @Override + public CompletableFuture> queryMapAsync( + final Class clazz, final FilterNode node) { + return queryMapAsync(clazz, null, node); + } + + /** + * 查询符合过滤条件记录的Map集合, 主键值为key
+ * 等价SQL: SELECT * FROM {table} WHERE {column} = {key} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param 主键泛型 + * @param Entity泛型 + * @param clazz Entity类 + * @param selects 指定字段 + * @param bean FilterBean + * @return Entity的集合 + */ + @Override + public Map queryMap( + final Class clazz, final SelectColumn selects, final FilterBean bean) { + return queryMap(clazz, selects, FilterNodeBean.createFilterNode(bean)); + } + + @Override + public CompletableFuture> queryMapAsync( + final Class clazz, final SelectColumn selects, final FilterBean bean) { + return queryMapAsync(clazz, selects, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 根据指定字段值查询对象集合 + * + * @param Entity类的泛型 + * @param clazz Entity类 + * @param column 过滤字段名 + * @param colval 过滤字段值 + * @return Entity对象的集合 + */ + @Override + public Set querySet(final Class clazz, final String column, final Serializable colval) { + return querySet(clazz, (SelectColumn) null, null, FilterNodes.create(column, colval)); + } + + @Override + public CompletableFuture> querySetAsync( + final Class clazz, final String column, final Serializable colval) { + return querySetAsync(clazz, (SelectColumn) null, null, FilterNodes.create(column, colval)); + } + + @Override + public Set querySet(final Class clazz) { + return querySet(clazz, (SelectColumn) null, null, (FilterNode) null); + } + + @Override + public CompletableFuture> querySetAsync(final Class clazz) { + return querySetAsync(clazz, (SelectColumn) null, null, (FilterNode) null); + } + + /** + * 根据过滤对象FilterBean查询对象集合 + * + * @param Entity类的泛型 + * @param clazz Entity类 + * @param bean 过滤Bean + * @return Entity对象集合 + */ + @Override + public Set querySet(final Class clazz, final FilterBean bean) { + return querySet(clazz, (SelectColumn) null, null, FilterNodeBean.createFilterNode(bean)); + } + + @Override + public CompletableFuture> querySetAsync(final Class clazz, final FilterBean bean) { + return querySetAsync(clazz, (SelectColumn) null, null, FilterNodeBean.createFilterNode(bean)); + } + + @Override + public Set querySet(final Class clazz, final FilterNode node) { + return querySet(clazz, (SelectColumn) null, null, node); + } + + @Override + public CompletableFuture> querySetAsync(final Class clazz, final FilterNode node) { + return querySetAsync(clazz, (SelectColumn) null, null, node); + } + + /** + * 根据过滤对象FilterBean查询对象集合, 对象只填充或排除SelectField指定的字段 + * + * @param Entity类的泛型 + * @param clazz Entity类 + * @param selects 收集的字段 + * @param bean 过滤Bean + * @return Entity对象的集合 + */ + @Override + public Set querySet(final Class clazz, final SelectColumn selects, final FilterBean bean) { + return querySet(clazz, selects, null, FilterNodeBean.createFilterNode(bean)); + } + + @Override + public CompletableFuture> querySetAsync( + final Class clazz, SelectColumn selects, final FilterBean bean) { + return querySetAsync(clazz, selects, null, FilterNodeBean.createFilterNode(bean)); + } + + @Override + public Set querySet(final Class clazz, final SelectColumn selects, final FilterNode node) { + return querySet(clazz, selects, null, node); + } + + @Override + public CompletableFuture> querySetAsync( + final Class clazz, SelectColumn selects, final FilterNode node) { + return querySetAsync(clazz, selects, null, node); + } + + @Override + public Set querySet( + final Class clazz, final Flipper flipper, final String column, final Serializable colval) { + return querySet(clazz, null, flipper, FilterNodes.create(column, colval)); + } + + @Override + public CompletableFuture> querySetAsync( + final Class clazz, final Flipper flipper, final String column, final Serializable colval) { + return querySetAsync(clazz, null, flipper, FilterNodes.create(column, colval)); + } + + @Override + public Set querySet(final Class clazz, final Flipper flipper, final FilterBean bean) { + return querySet(clazz, null, flipper, FilterNodeBean.createFilterNode(bean)); + } + + @Override + public CompletableFuture> querySetAsync( + final Class clazz, final Flipper flipper, final FilterBean bean) { + return querySetAsync(clazz, null, flipper, FilterNodeBean.createFilterNode(bean)); + } + + @Override + public Set querySet(final Class clazz, final Flipper flipper, final FilterNode node) { + return querySet(clazz, null, flipper, node); + } + + @Override + public CompletableFuture> querySetAsync( + final Class clazz, final Flipper flipper, final FilterNode node) { + return querySetAsync(clazz, null, flipper, node); + } + + @Override + public Set querySet( + final Class clazz, final SelectColumn selects, final Flipper flipper, final FilterBean bean) { + return querySet(clazz, selects, flipper, FilterNodeBean.createFilterNode(bean)); + } + + @Override + public CompletableFuture> querySetAsync( + final Class clazz, final SelectColumn selects, final Flipper flipper, final FilterBean bean) { + return querySetAsync(clazz, selects, flipper, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 根据指定字段值查询对象集合 + * + * @param Entity类的泛型 + * @param clazz Entity类 + * @param column 过滤字段名 + * @param colval 过滤字段值 + * @return Entity对象的集合 + */ + @Override + public List queryList(final Class clazz, final String column, final Serializable colval) { + return queryList(clazz, (SelectColumn) null, null, FilterNodes.create(column, colval)); + } + + @Override + public CompletableFuture> queryListAsync( + final Class clazz, final String column, final Serializable colval) { + return queryListAsync(clazz, (SelectColumn) null, null, FilterNodes.create(column, colval)); + } + + @Override + public List queryList(final Class clazz) { + return queryList(clazz, (SelectColumn) null, null, (FilterNode) null); + } + + @Override + public CompletableFuture> queryListAsync(final Class clazz) { + return queryListAsync(clazz, (SelectColumn) null, null, (FilterNode) null); + } + + /** + * 根据过滤对象FilterBean查询对象集合 + * + * @param Entity类的泛型 + * @param clazz Entity类 + * @param bean 过滤Bean + * @return Entity对象集合 + */ + @Override + public List queryList(final Class clazz, final FilterBean bean) { + return queryList(clazz, (SelectColumn) null, null, FilterNodeBean.createFilterNode(bean)); + } + + @Override + public CompletableFuture> queryListAsync(final Class clazz, final FilterBean bean) { + return queryListAsync(clazz, (SelectColumn) null, null, FilterNodeBean.createFilterNode(bean)); + } + + @Override + public List queryList(final Class clazz, final FilterNode node) { + return queryList(clazz, (SelectColumn) null, null, node); + } + + @Override + public CompletableFuture> queryListAsync(final Class clazz, final FilterNode node) { + return queryListAsync(clazz, (SelectColumn) null, null, node); + } + + /** + * 根据过滤对象FilterBean查询对象集合, 对象只填充或排除SelectField指定的字段 + * + * @param Entity类的泛型 + * @param clazz Entity类 + * @param selects 收集的字段 + * @param bean 过滤Bean + * @return Entity对象的集合 + */ + @Override + public List queryList(final Class clazz, final SelectColumn selects, final FilterBean bean) { + return queryList(clazz, selects, null, FilterNodeBean.createFilterNode(bean)); + } + + @Override + public CompletableFuture> queryListAsync( + final Class clazz, SelectColumn selects, final FilterBean bean) { + return queryListAsync(clazz, selects, null, FilterNodeBean.createFilterNode(bean)); + } + + @Override + public List queryList(final Class clazz, final SelectColumn selects, final FilterNode node) { + return queryList(clazz, selects, null, node); + } + + @Override + public CompletableFuture> queryListAsync( + final Class clazz, SelectColumn selects, final FilterNode node) { + return queryListAsync(clazz, selects, null, node); + } + + @Override + public List queryList( + final Class clazz, final Flipper flipper, final String column, final Serializable colval) { + return queryList(clazz, null, flipper, FilterNodes.create(column, colval)); + } + + @Override + public CompletableFuture> queryListAsync( + final Class clazz, final Flipper flipper, final String column, final Serializable colval) { + return queryListAsync(clazz, null, flipper, FilterNodes.create(column, colval)); + } + + @Override + public List queryList(final Class clazz, final Flipper flipper, final FilterBean bean) { + return queryList(clazz, null, flipper, FilterNodeBean.createFilterNode(bean)); + } + + @Override + public CompletableFuture> queryListAsync( + final Class clazz, final Flipper flipper, final FilterBean bean) { + return queryListAsync(clazz, null, flipper, FilterNodeBean.createFilterNode(bean)); + } + + @Override + public List queryList(final Class clazz, final Flipper flipper, final FilterNode node) { + return queryList(clazz, null, flipper, node); + } + + @Override + public CompletableFuture> queryListAsync( + final Class clazz, final Flipper flipper, final FilterNode node) { + return queryListAsync(clazz, null, flipper, node); + } + + @Override + public List queryList( + final Class clazz, final SelectColumn selects, final Flipper flipper, final FilterBean bean) { + return queryList(clazz, selects, flipper, FilterNodeBean.createFilterNode(bean)); + } + + @Override + public CompletableFuture> queryListAsync( + final Class clazz, final SelectColumn selects, final Flipper flipper, final FilterBean bean) { + return queryListAsync(clazz, selects, flipper, FilterNodeBean.createFilterNode(bean)); + } + + // -----------------------sheet---------------------------- + /** + * 根据过滤对象FilterBean和翻页对象Flipper查询一页的数据 + * + * @param Entity类的泛型 + * @param clazz Entity类 + * @param flipper 翻页对象 + * @param bean 过滤Bean + * @return Entity对象的集合 + */ + @Override + public Sheet querySheet(final Class clazz, final Flipper flipper, final FilterBean bean) { + return querySheet(clazz, null, flipper, FilterNodeBean.createFilterNode(bean)); + } + + @Override + public CompletableFuture> querySheetAsync( + final Class clazz, final Flipper flipper, final FilterBean bean) { + return querySheetAsync(clazz, null, flipper, FilterNodeBean.createFilterNode(bean)); + } + + @Override + public Sheet querySheet(final Class clazz, final Flipper flipper, final FilterNode node) { + return querySheet(clazz, null, flipper, node); + } + + @Override + public CompletableFuture> querySheetAsync( + final Class clazz, final Flipper flipper, final FilterNode node) { + return querySheetAsync(clazz, null, flipper, node); + } + + /** + * 根据过滤对象FilterBean和翻页对象Flipper查询一页的数据, 对象只填充或排除SelectField指定的字段 + * + * @param Entity类的泛型 + * @param clazz Entity类 + * @param selects 收集的字段集合 + * @param flipper 翻页对象 + * @param bean 过滤Bean + * @return Entity对象的集合 + */ + @Override + public Sheet querySheet( + final Class clazz, final SelectColumn selects, final Flipper flipper, final FilterBean bean) { + return querySheet(clazz, selects, flipper, FilterNodeBean.createFilterNode(bean)); + } + + @Override + public CompletableFuture> querySheetAsync( + final Class clazz, final SelectColumn selects, final Flipper flipper, final FilterBean bean) { + return querySheetAsync(clazz, selects, flipper, FilterNodeBean.createFilterNode(bean)); + } + + protected static class DefaultDataBatch implements DataBatch { + + @Comment("操作对象") + public final List actions = new ArrayList(); + + protected DefaultDataBatch() {} + + public DataBatch run(Runnable task) { + Objects.requireNonNull(task); + this.actions.add(new RunnableBatchAction(task)); + return this; + } + + @Override // entitys不一定是同一表的数据 + public DataBatch insert(T... entitys) { + for (T t : entitys) { + Objects.requireNonNull(t); + if (t.getClass().getAnnotation(Entity.class) == null) { + throw new SourceException("Entity Class " + t.getClass() + " must be on Annotation @Entity"); + } + this.actions.add(new InsertBatchAction1(t)); + } + return this; + } + + @Override // entitys不一定是同一表的数据 + public DataBatch insert(Collection entitys) { + for (T t : entitys) { + Objects.requireNonNull(t); + if (t.getClass().getAnnotation(Entity.class) == null) { + throw new SourceException("Entity Class " + t.getClass() + " must be on Annotation @Entity"); + } + this.actions.add(new InsertBatchAction1(t)); + } + return this; + } + + @Override // entitys不一定是同一表的数据 + public DataBatch delete(T... entitys) { + for (T t : entitys) { + Objects.requireNonNull(t); + if (t.getClass().getAnnotation(Entity.class) == null) { + throw new SourceException("Entity Class " + t.getClass() + " must be on Annotation @Entity"); + } + this.actions.add(new DeleteBatchAction1(t)); + } + return this; + } + + @Override // entitys不一定是同一表的数据 + public DataBatch delete(Collection entitys) { + for (T t : entitys) { + Objects.requireNonNull(t); + if (t.getClass().getAnnotation(Entity.class) == null) { + throw new SourceException("Entity Class " + t.getClass() + " must be on Annotation @Entity"); + } + this.actions.add(new DeleteBatchAction1(t)); + } + return this; + } + + @Override + public DataBatch delete(Class clazz, Serializable... pks) { + Objects.requireNonNull(clazz); + if (clazz.getAnnotation(Entity.class) == null) { + throw new SourceException("Entity Class " + clazz + " must be on Annotation @Entity"); + } + if (pks.length < 1) { + throw new SourceException("delete pk length is zero "); + } + for (Serializable pk : pks) { + Objects.requireNonNull(pk); + this.actions.add(new DeleteBatchAction2(clazz, pk)); + } + return this; + } + + @Override + public DataBatch delete(Class clazz, FilterNode node) { + return delete(clazz, node, (Flipper) null); + } + + @Override + public DataBatch delete(Class clazz, FilterNode node, Flipper flipper) { + Objects.requireNonNull(clazz); + if (clazz.getAnnotation(Entity.class) == null) { + throw new SourceException("Entity Class " + clazz + " must be on Annotation @Entity"); + } + this.actions.add(new DeleteBatchAction3(clazz, node, flipper)); + return this; + } + + @Override // entitys不一定是同一表的数据 + public DataBatch update(T... entitys) { + for (T t : entitys) { + Objects.requireNonNull(t); + if (t.getClass().getAnnotation(Entity.class) == null) { + throw new SourceException("Entity Class " + t.getClass() + " must be on Annotation @Entity"); + } + this.actions.add(new UpdateBatchAction1(t)); + } + return this; + } + + @Override // entitys不一定是同一表的数据 + public DataBatch update(Collection entitys) { + for (T t : entitys) { + Objects.requireNonNull(t); + if (t.getClass().getAnnotation(Entity.class) == null) { + throw new SourceException("Entity Class " + t.getClass() + " must be on Annotation @Entity"); + } + this.actions.add(new UpdateBatchAction1(t)); + } + return this; + } + + @Override + public DataBatch updateColumn(Class clazz, Serializable pk, String column, Serializable value) { + return updateColumn(clazz, pk, ColumnValue.set(column, value)); + } + + @Override + public DataBatch updateColumn(Class clazz, Serializable pk, ColumnValue... values) { + Objects.requireNonNull(clazz); + if (clazz.getAnnotation(Entity.class) == null) { + throw new SourceException("Entity Class " + clazz + " must be on Annotation @Entity"); + } + Objects.requireNonNull(pk); + if (values.length < 1) { + throw new SourceException("update column-value length is zero "); + } + for (ColumnValue val : values) { + Objects.requireNonNull(val); + } + this.actions.add(new UpdateBatchAction2(clazz, pk, values)); + return this; + } + + @Override + public DataBatch updateColumn(Class clazz, FilterNode node, String column, Serializable value) { + return updateColumn(clazz, node, (Flipper) null, ColumnValue.set(column, value)); + } + + @Override + public DataBatch updateColumn(Class clazz, FilterNode node, ColumnValue... values) { + return updateColumn(clazz, node, (Flipper) null, values); + } + + @Override + public DataBatch updateColumn(Class clazz, FilterNode node, Flipper flipper, ColumnValue... values) { + Objects.requireNonNull(clazz); + if (clazz.getAnnotation(Entity.class) == null) { + throw new SourceException("Entity Class " + clazz + " must be on Annotation @Entity"); + } + if (values.length < 1) { + throw new SourceException("update column-value length is zero "); + } + for (ColumnValue val : values) { + Objects.requireNonNull(val); + } + this.actions.add(new UpdateBatchAction3(clazz, node, flipper, values)); + return this; + } + + @Override + public DataBatch updateColumn(T entity, final String... columns) { + if (columns.length < 1) { + throw new SourceException("update column length is zero "); + } + for (String val : columns) { + Objects.requireNonNull(val); + } + return updateColumn(entity, (FilterNode) null, SelectColumn.includes(columns)); + } + + @Override + public DataBatch updateColumn(T entity, final FilterNode node, final String... columns) { + return updateColumn(entity, node, SelectColumn.includes(columns)); + } + + @Override + public DataBatch updateColumn(T entity, SelectColumn selects) { + return updateColumn(entity, (FilterNode) null, selects); + } + + @Override + public DataBatch updateColumn(T entity, final FilterNode node, SelectColumn selects) { + Objects.requireNonNull(entity); + if (entity.getClass().getAnnotation(Entity.class) == null) { + throw new SourceException("Entity Class " + entity.getClass() + " must be on Annotation @Entity"); + } + Objects.requireNonNull(selects); + this.actions.add(new UpdateBatchAction4(entity, node, selects)); + return this; + } + } + + protected abstract static class BatchAction {} + + protected static class RunnableBatchAction extends BatchAction { + + public Runnable task; + + public RunnableBatchAction(Runnable task) { + this.task = task; + } + } + + protected static class InsertBatchAction1 extends BatchAction { + + public Object entity; + + public InsertBatchAction1(Object entity) { + this.entity = entity; + } + } + + protected static class DeleteBatchAction1 extends BatchAction { + + public Object entity; + + public DeleteBatchAction1(Object entity) { + this.entity = entity; + } + } + + protected static class DeleteBatchAction2 extends BatchAction { + + public Class clazz; + + public Serializable pk; + + public DeleteBatchAction2(Class clazz, Serializable pk) { + this.clazz = clazz; + this.pk = pk; + } + } + + protected static class DeleteBatchAction3 extends BatchAction { + + public Class clazz; + + public FilterNode node; + + public Flipper flipper; + + public DeleteBatchAction3(Class clazz, FilterNode node) { + this.clazz = clazz; + this.node = node; + } + + public DeleteBatchAction3(Class clazz, FilterNode node, Flipper flipper) { + this.clazz = clazz; + this.node = node; + this.flipper = flipper; + } + } + + protected static class UpdateBatchAction1 extends BatchAction { + + public Object entity; + + public UpdateBatchAction1(Object entity) { + this.entity = entity; + } + } + + protected static class UpdateBatchAction2 extends BatchAction { + + public Class clazz; + + public Serializable pk; + + public ColumnValue[] values; + + public UpdateBatchAction2(Class clazz, Serializable pk, ColumnValue... values) { + this.clazz = clazz; + this.pk = pk; + this.values = values; + } + } + + protected static class UpdateBatchAction3 extends BatchAction { + + public Class clazz; + + public FilterNode node; + + public Flipper flipper; + + public ColumnValue[] values; + + public UpdateBatchAction3(Class clazz, FilterNode node, ColumnValue... values) { + this.clazz = clazz; + this.node = node; + this.values = values; + } + + public UpdateBatchAction3(Class clazz, FilterNode node, Flipper flipper, ColumnValue... values) { + this.clazz = clazz; + this.node = node; + this.flipper = flipper; + this.values = values; + } + } + + protected static class UpdateBatchAction4 extends BatchAction { + + public Object entity; + + public FilterNode node; + + public SelectColumn selects; + + public UpdateBatchAction4(Object entity, SelectColumn selects) { + this.entity = entity; + this.selects = selects; + } + + public UpdateBatchAction4(Object entity, FilterNode node, SelectColumn selects) { + this.entity = entity; + this.node = node; + this.selects = selects; + } + } +} diff --git a/src/main/java/org/redkale/source/CacheEventListener.java b/src/main/java/org/redkale/source/CacheEventListener.java index 18cb5ead4..0a7ef8be3 100644 --- a/src/main/java/org/redkale/source/CacheEventListener.java +++ b/src/main/java/org/redkale/source/CacheEventListener.java @@ -1,17 +1,17 @@ -/* - * - */ -package org.redkale.source; - -/** - * CacheSource订阅频道的消费监听器 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public interface CacheEventListener { - - public void onMessage(String topic, T message); -} +/* + * + */ +package org.redkale.source; + +/** + * CacheSource订阅频道的消费监听器 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public interface CacheEventListener { + + public void onMessage(String topic, T message); +} diff --git a/src/main/java/org/redkale/source/CacheScoredValue.java b/src/main/java/org/redkale/source/CacheScoredValue.java index 2ce43432e..4be768e4a 100644 --- a/src/main/java/org/redkale/source/CacheScoredValue.java +++ b/src/main/java/org/redkale/source/CacheScoredValue.java @@ -1,89 +1,89 @@ -/* - * - */ -package org.redkale.source; - -import java.io.Serializable; -import java.util.Objects; -import org.redkale.convert.ConvertColumn; - -/** - * 有序集合的对象类 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public class CacheScoredValue implements Serializable, Comparable { - - @ConvertColumn(index = 1) - private Number score; - - @ConvertColumn(index = 2) - private String value; - - public CacheScoredValue() {} - - protected CacheScoredValue(Number score, String value) { - Objects.requireNonNull(score); - Objects.requireNonNull(value); - this.score = score; - this.value = value; - } - - protected CacheScoredValue(CacheScoredValue scoredValue) { - this.score = scoredValue.getScore(); - this.value = scoredValue.getValue(); - } - - public static CacheScoredValue create(Number score, String value) { - return new CacheScoredValue(score, value); - } - - public Number getScore() { - return score; - } - - public String getValue() { - return value; - } - - public void setScore(Number score) { - this.score = score; - } - - public void setValue(String value) { - this.value = value; - } - - @Override - public int compareTo(CacheScoredValue o) { - return ((Comparable) this.score).compareTo((Number) o.getScore()); - } - - @Override - public int hashCode() { - return Objects.hashCode(this.value); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final CacheScoredValue other = (CacheScoredValue) obj; - return Objects.equals(this.value, other.value); - } - - @Override - public String toString() { - return "{score:" + score + ", value:" + value + "}"; - } -} +/* + * + */ +package org.redkale.source; + +import java.io.Serializable; +import java.util.Objects; +import org.redkale.convert.ConvertColumn; + +/** + * 有序集合的对象类 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public class CacheScoredValue implements Serializable, Comparable { + + @ConvertColumn(index = 1) + private Number score; + + @ConvertColumn(index = 2) + private String value; + + public CacheScoredValue() {} + + protected CacheScoredValue(Number score, String value) { + Objects.requireNonNull(score); + Objects.requireNonNull(value); + this.score = score; + this.value = value; + } + + protected CacheScoredValue(CacheScoredValue scoredValue) { + this.score = scoredValue.getScore(); + this.value = scoredValue.getValue(); + } + + public static CacheScoredValue create(Number score, String value) { + return new CacheScoredValue(score, value); + } + + public Number getScore() { + return score; + } + + public String getValue() { + return value; + } + + public void setScore(Number score) { + this.score = score; + } + + public void setValue(String value) { + this.value = value; + } + + @Override + public int compareTo(CacheScoredValue o) { + return ((Comparable) this.score).compareTo((Number) o.getScore()); + } + + @Override + public int hashCode() { + return Objects.hashCode(this.value); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final CacheScoredValue other = (CacheScoredValue) obj; + return Objects.equals(this.value, other.value); + } + + @Override + public String toString() { + return "{score:" + score + ", value:" + value + "}"; + } +} diff --git a/src/main/java/org/redkale/source/ColumnBytesNode.java b/src/main/java/org/redkale/source/ColumnBytesNode.java index 5e69d3ae5..4d18a80ae 100644 --- a/src/main/java/org/redkale/source/ColumnBytesNode.java +++ b/src/main/java/org/redkale/source/ColumnBytesNode.java @@ -1,43 +1,43 @@ -/* - * - */ -package org.redkale.source; - -import org.redkale.convert.ConvertColumn; - -/** - * byte[]的ColumnNode - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public class ColumnBytesNode implements ColumnNode { - - @ConvertColumn(index = 1) - private byte[] value; - - public ColumnBytesNode() {} - - public ColumnBytesNode(byte[] value) { - this.value = value; - } - - public static ColumnBytesNode create(byte[] value) { - return new ColumnBytesNode(value); - } - - public byte[] getValue() { - return value; - } - - public void setValue(byte[] value) { - this.value = value; - } - - @Override - public String toString() { - return "{\"value\":" + value + "}"; - } -} +/* + * + */ +package org.redkale.source; + +import org.redkale.convert.ConvertColumn; + +/** + * byte[]的ColumnNode + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public class ColumnBytesNode implements ColumnNode { + + @ConvertColumn(index = 1) + private byte[] value; + + public ColumnBytesNode() {} + + public ColumnBytesNode(byte[] value) { + this.value = value; + } + + public static ColumnBytesNode create(byte[] value) { + return new ColumnBytesNode(value); + } + + public byte[] getValue() { + return value; + } + + public void setValue(byte[] value) { + this.value = value; + } + + @Override + public String toString() { + return "{\"value\":" + value + "}"; + } +} diff --git a/src/main/java/org/redkale/source/ColumnNameNode.java b/src/main/java/org/redkale/source/ColumnNameNode.java index ba7e8ce26..ef366644e 100644 --- a/src/main/java/org/redkale/source/ColumnNameNode.java +++ b/src/main/java/org/redkale/source/ColumnNameNode.java @@ -1,41 +1,41 @@ -/* - * - */ -package org.redkale.source; - -import java.util.Objects; -import org.redkale.convert.ConvertColumn; - -/** - * 字段名的ColumnNode - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public class ColumnNameNode implements ColumnNode { - - @ConvertColumn(index = 1) - private String column; - - public ColumnNameNode() {} - - public ColumnNameNode(String column) { - Objects.requireNonNull(column, "column is null"); - this.column = column; - } - - public String getColumn() { - return column; - } - - public void setColumn(String column) { - this.column = column; - } - - @Override - public String toString() { - return "{\"column\":\"" + column + "\"}"; - } -} +/* + * + */ +package org.redkale.source; + +import java.util.Objects; +import org.redkale.convert.ConvertColumn; + +/** + * 字段名的ColumnNode + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public class ColumnNameNode implements ColumnNode { + + @ConvertColumn(index = 1) + private String column; + + public ColumnNameNode() {} + + public ColumnNameNode(String column) { + Objects.requireNonNull(column, "column is null"); + this.column = column; + } + + public String getColumn() { + return column; + } + + public void setColumn(String column) { + this.column = column; + } + + @Override + public String toString() { + return "{\"column\":\"" + column + "\"}"; + } +} diff --git a/src/main/java/org/redkale/source/ColumnNodes.java b/src/main/java/org/redkale/source/ColumnNodes.java index 3f7fc2d5f..b010c1007 100644 --- a/src/main/java/org/redkale/source/ColumnNodes.java +++ b/src/main/java/org/redkale/source/ColumnNodes.java @@ -1,213 +1,213 @@ -/* - * - */ -package org.redkale.source; - -import static org.redkale.source.ColumnExpress.*; - -/** - * 创建ColumnNode的工具类 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public abstract class ColumnNodes { - - private ColumnNodes() { - // do nothing - } - - public static ColumnNameNode column(String column) { - return new ColumnNameNode(column); - } - - public static ColumnNumberNode number(Number value) { - return new ColumnNumberNode(value); - } - - public static ColumnStringNode string(String value) { - return new ColumnStringNode(value); - } - - public static ColumnFuncNode func(FilterFunc func, String column) { - return new ColumnFuncNode(func, column(column)); - } - - public static ColumnFuncNode func(FilterFunc func, ColumnNode node) { - return new ColumnFuncNode(func, node); - } - - public static ColumnFuncNode avg(String column) { - return new ColumnFuncNode(FilterFunc.AVG, column(column)); - } - - public static ColumnFuncNode avg(ColumnNode node) { - return new ColumnFuncNode(FilterFunc.AVG, node); - } - - public static ColumnFuncNode count(String column) { - return new ColumnFuncNode(FilterFunc.COUNT, column(column)); - } - - public static ColumnFuncNode count(ColumnNode node) { - return new ColumnFuncNode(FilterFunc.COUNT, node); - } - - public static ColumnFuncNode distinctCount(String column) { - return new ColumnFuncNode(FilterFunc.DISTINCTCOUNT, column(column)); - } - - public static ColumnFuncNode distinctCount(ColumnNode node) { - return new ColumnFuncNode(FilterFunc.DISTINCTCOUNT, node); - } - - public static ColumnFuncNode max(String column) { - return new ColumnFuncNode(FilterFunc.MAX, column(column)); - } - - public static ColumnFuncNode max(ColumnNode node) { - return new ColumnFuncNode(FilterFunc.MAX, node); - } - - public static ColumnFuncNode min(String column) { - return new ColumnFuncNode(FilterFunc.MIN, column(column)); - } - - public static ColumnFuncNode min(ColumnNode node) { - return new ColumnFuncNode(FilterFunc.MIN, node); - } - - public static ColumnFuncNode sum(String column) { - return new ColumnFuncNode(FilterFunc.SUM, column(column)); - } - - public static ColumnFuncNode sum(ColumnNode node) { - return new ColumnFuncNode(FilterFunc.SUM, node); - } - - public static ColumnExpNode exp(ColumnNode left, ColumnExpress express, ColumnNode right) { - return new ColumnExpNode(left, express, right); - } - - public static ColumnExpNode set(String column) { - return new ColumnExpNode(column, SET, null); - } - - public static ColumnExpNode set(ColumnNameNode left) { - return new ColumnExpNode(left, SET, null); - } - - public static ColumnExpNode inc(String leftColumn, Number rightValue) { - return new ColumnExpNode(column(leftColumn), INC, number(rightValue)); - } - - public static ColumnExpNode inc(ColumnNode left, ColumnNode right) { - return new ColumnExpNode(left, INC, right); - } - - public static ColumnExpNode inc(ColumnNode left, String rightColumn) { - return new ColumnExpNode(left, INC, column(rightColumn)); - } - - public static ColumnExpNode inc(ColumnNode left, Number rightValue) { - return new ColumnExpNode(left, INC, number(rightValue)); - } - - public static ColumnExpNode dec(String leftColumn, Number rightValue) { - return new ColumnExpNode(column(leftColumn), DEC, number(rightValue)); - } - - public static ColumnExpNode dec(ColumnNode left, ColumnNode right) { - return new ColumnExpNode(left, DEC, right); - } - - public static ColumnExpNode dec(ColumnNode left, String rightColumn) { - return new ColumnExpNode(left, DEC, column(rightColumn)); - } - - public static ColumnExpNode dec(ColumnNode left, Number rightValue) { - return new ColumnExpNode(left, DEC, number(rightValue)); - } - - public static ColumnExpNode mul(String leftColumn, Number rightValue) { - return new ColumnExpNode(column(leftColumn), MUL, number(rightValue)); - } - - public static ColumnExpNode mul(ColumnNode left, ColumnNode right) { - return new ColumnExpNode(left, MUL, right); - } - - public static ColumnExpNode mul(ColumnNode left, String rightColumn) { - return new ColumnExpNode(left, MUL, column(rightColumn)); - } - - public static ColumnExpNode mul(ColumnNode left, Number rightValue) { - return new ColumnExpNode(left, MUL, number(rightValue)); - } - - public static ColumnExpNode div(String leftColumn, Number rightValue) { - return new ColumnExpNode(column(leftColumn), DIV, number(rightValue)); - } - - public static ColumnExpNode div(ColumnNode left, ColumnNode right) { - return new ColumnExpNode(left, DIV, right); - } - - public static ColumnExpNode div(ColumnNode left, String rightColumn) { - return new ColumnExpNode(left, DIV, column(rightColumn)); - } - - public static ColumnExpNode div(ColumnNode left, Number rightValue) { - return new ColumnExpNode(left, DIV, number(rightValue)); - } - - public static ColumnExpNode mod(String leftColumn, Number rightValue) { - return new ColumnExpNode(column(leftColumn), MOD, number(rightValue)); - } - - public static ColumnExpNode mod(ColumnNode left, ColumnNode right) { - return new ColumnExpNode(left, MOD, right); - } - - public static ColumnExpNode mod(ColumnNode left, String rightColumn) { - return new ColumnExpNode(left, MOD, column(rightColumn)); - } - - public static ColumnExpNode mod(ColumnNode left, Number rightValue) { - return new ColumnExpNode(left, MOD, number(rightValue)); - } - - public static ColumnExpNode and(String leftColumn, Number rightValue) { - return new ColumnExpNode(column(leftColumn), AND, number(rightValue)); - } - - public static ColumnExpNode and(ColumnNode left, ColumnNode right) { - return new ColumnExpNode(left, AND, right); - } - - public static ColumnExpNode and(ColumnNode left, String rightColumn) { - return new ColumnExpNode(left, AND, column(rightColumn)); - } - - public static ColumnExpNode and(ColumnNode left, Number rightValue) { - return new ColumnExpNode(left, AND, number(rightValue)); - } - - public static ColumnExpNode orr(String leftColumn, Number rightValue) { - return new ColumnExpNode(column(leftColumn), ORR, number(rightValue)); - } - - public static ColumnExpNode orr(ColumnNode left, ColumnNode right) { - return new ColumnExpNode(left, ORR, right); - } - - public static ColumnExpNode orr(ColumnNode left, String rightColumn) { - return new ColumnExpNode(left, ORR, column(rightColumn)); - } - - public static ColumnExpNode orr(ColumnNode left, Number rightValue) { - return new ColumnExpNode(left, ORR, number(rightValue)); - } -} +/* + * + */ +package org.redkale.source; + +import static org.redkale.source.ColumnExpress.*; + +/** + * 创建ColumnNode的工具类 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public abstract class ColumnNodes { + + private ColumnNodes() { + // do nothing + } + + public static ColumnNameNode column(String column) { + return new ColumnNameNode(column); + } + + public static ColumnNumberNode number(Number value) { + return new ColumnNumberNode(value); + } + + public static ColumnStringNode string(String value) { + return new ColumnStringNode(value); + } + + public static ColumnFuncNode func(FilterFunc func, String column) { + return new ColumnFuncNode(func, column(column)); + } + + public static ColumnFuncNode func(FilterFunc func, ColumnNode node) { + return new ColumnFuncNode(func, node); + } + + public static ColumnFuncNode avg(String column) { + return new ColumnFuncNode(FilterFunc.AVG, column(column)); + } + + public static ColumnFuncNode avg(ColumnNode node) { + return new ColumnFuncNode(FilterFunc.AVG, node); + } + + public static ColumnFuncNode count(String column) { + return new ColumnFuncNode(FilterFunc.COUNT, column(column)); + } + + public static ColumnFuncNode count(ColumnNode node) { + return new ColumnFuncNode(FilterFunc.COUNT, node); + } + + public static ColumnFuncNode distinctCount(String column) { + return new ColumnFuncNode(FilterFunc.DISTINCTCOUNT, column(column)); + } + + public static ColumnFuncNode distinctCount(ColumnNode node) { + return new ColumnFuncNode(FilterFunc.DISTINCTCOUNT, node); + } + + public static ColumnFuncNode max(String column) { + return new ColumnFuncNode(FilterFunc.MAX, column(column)); + } + + public static ColumnFuncNode max(ColumnNode node) { + return new ColumnFuncNode(FilterFunc.MAX, node); + } + + public static ColumnFuncNode min(String column) { + return new ColumnFuncNode(FilterFunc.MIN, column(column)); + } + + public static ColumnFuncNode min(ColumnNode node) { + return new ColumnFuncNode(FilterFunc.MIN, node); + } + + public static ColumnFuncNode sum(String column) { + return new ColumnFuncNode(FilterFunc.SUM, column(column)); + } + + public static ColumnFuncNode sum(ColumnNode node) { + return new ColumnFuncNode(FilterFunc.SUM, node); + } + + public static ColumnExpNode exp(ColumnNode left, ColumnExpress express, ColumnNode right) { + return new ColumnExpNode(left, express, right); + } + + public static ColumnExpNode set(String column) { + return new ColumnExpNode(column, SET, null); + } + + public static ColumnExpNode set(ColumnNameNode left) { + return new ColumnExpNode(left, SET, null); + } + + public static ColumnExpNode inc(String leftColumn, Number rightValue) { + return new ColumnExpNode(column(leftColumn), INC, number(rightValue)); + } + + public static ColumnExpNode inc(ColumnNode left, ColumnNode right) { + return new ColumnExpNode(left, INC, right); + } + + public static ColumnExpNode inc(ColumnNode left, String rightColumn) { + return new ColumnExpNode(left, INC, column(rightColumn)); + } + + public static ColumnExpNode inc(ColumnNode left, Number rightValue) { + return new ColumnExpNode(left, INC, number(rightValue)); + } + + public static ColumnExpNode dec(String leftColumn, Number rightValue) { + return new ColumnExpNode(column(leftColumn), DEC, number(rightValue)); + } + + public static ColumnExpNode dec(ColumnNode left, ColumnNode right) { + return new ColumnExpNode(left, DEC, right); + } + + public static ColumnExpNode dec(ColumnNode left, String rightColumn) { + return new ColumnExpNode(left, DEC, column(rightColumn)); + } + + public static ColumnExpNode dec(ColumnNode left, Number rightValue) { + return new ColumnExpNode(left, DEC, number(rightValue)); + } + + public static ColumnExpNode mul(String leftColumn, Number rightValue) { + return new ColumnExpNode(column(leftColumn), MUL, number(rightValue)); + } + + public static ColumnExpNode mul(ColumnNode left, ColumnNode right) { + return new ColumnExpNode(left, MUL, right); + } + + public static ColumnExpNode mul(ColumnNode left, String rightColumn) { + return new ColumnExpNode(left, MUL, column(rightColumn)); + } + + public static ColumnExpNode mul(ColumnNode left, Number rightValue) { + return new ColumnExpNode(left, MUL, number(rightValue)); + } + + public static ColumnExpNode div(String leftColumn, Number rightValue) { + return new ColumnExpNode(column(leftColumn), DIV, number(rightValue)); + } + + public static ColumnExpNode div(ColumnNode left, ColumnNode right) { + return new ColumnExpNode(left, DIV, right); + } + + public static ColumnExpNode div(ColumnNode left, String rightColumn) { + return new ColumnExpNode(left, DIV, column(rightColumn)); + } + + public static ColumnExpNode div(ColumnNode left, Number rightValue) { + return new ColumnExpNode(left, DIV, number(rightValue)); + } + + public static ColumnExpNode mod(String leftColumn, Number rightValue) { + return new ColumnExpNode(column(leftColumn), MOD, number(rightValue)); + } + + public static ColumnExpNode mod(ColumnNode left, ColumnNode right) { + return new ColumnExpNode(left, MOD, right); + } + + public static ColumnExpNode mod(ColumnNode left, String rightColumn) { + return new ColumnExpNode(left, MOD, column(rightColumn)); + } + + public static ColumnExpNode mod(ColumnNode left, Number rightValue) { + return new ColumnExpNode(left, MOD, number(rightValue)); + } + + public static ColumnExpNode and(String leftColumn, Number rightValue) { + return new ColumnExpNode(column(leftColumn), AND, number(rightValue)); + } + + public static ColumnExpNode and(ColumnNode left, ColumnNode right) { + return new ColumnExpNode(left, AND, right); + } + + public static ColumnExpNode and(ColumnNode left, String rightColumn) { + return new ColumnExpNode(left, AND, column(rightColumn)); + } + + public static ColumnExpNode and(ColumnNode left, Number rightValue) { + return new ColumnExpNode(left, AND, number(rightValue)); + } + + public static ColumnExpNode orr(String leftColumn, Number rightValue) { + return new ColumnExpNode(column(leftColumn), ORR, number(rightValue)); + } + + public static ColumnExpNode orr(ColumnNode left, ColumnNode right) { + return new ColumnExpNode(left, ORR, right); + } + + public static ColumnExpNode orr(ColumnNode left, String rightColumn) { + return new ColumnExpNode(left, ORR, column(rightColumn)); + } + + public static ColumnExpNode orr(ColumnNode left, Number rightValue) { + return new ColumnExpNode(left, ORR, number(rightValue)); + } +} diff --git a/src/main/java/org/redkale/source/ColumnNumberNode.java b/src/main/java/org/redkale/source/ColumnNumberNode.java index 10ca7152b..a7fa84f93 100644 --- a/src/main/java/org/redkale/source/ColumnNumberNode.java +++ b/src/main/java/org/redkale/source/ColumnNumberNode.java @@ -1,41 +1,41 @@ -/* - * - */ -package org.redkale.source; - -import java.util.Objects; -import org.redkale.convert.ConvertColumn; - -/** - * 数值的ColumnNode - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public class ColumnNumberNode implements ColumnNode { - - @ConvertColumn(index = 1) - private Number value; - - public ColumnNumberNode() {} - - public ColumnNumberNode(Number value) { - Objects.requireNonNull(value, "number is null"); - this.value = value; - } - - public Number getValue() { - return value; - } - - public void setValue(Number value) { - this.value = value; - } - - @Override - public String toString() { - return "{\"value\":" + value + "}"; - } -} +/* + * + */ +package org.redkale.source; + +import java.util.Objects; +import org.redkale.convert.ConvertColumn; + +/** + * 数值的ColumnNode + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public class ColumnNumberNode implements ColumnNode { + + @ConvertColumn(index = 1) + private Number value; + + public ColumnNumberNode() {} + + public ColumnNumberNode(Number value) { + Objects.requireNonNull(value, "number is null"); + this.value = value; + } + + public Number getValue() { + return value; + } + + public void setValue(Number value) { + this.value = value; + } + + @Override + public String toString() { + return "{\"value\":" + value + "}"; + } +} diff --git a/src/main/java/org/redkale/source/ColumnStringNode.java b/src/main/java/org/redkale/source/ColumnStringNode.java index f7e0aa273..e7861232a 100644 --- a/src/main/java/org/redkale/source/ColumnStringNode.java +++ b/src/main/java/org/redkale/source/ColumnStringNode.java @@ -1,41 +1,41 @@ -/* - * - */ -package org.redkale.source; - -import java.util.Objects; -import org.redkale.convert.ConvertColumn; - -/** - * 字符串的ColumnNode - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public class ColumnStringNode implements ColumnNode { - - @ConvertColumn(index = 1) - private String value; - - public ColumnStringNode() {} - - public ColumnStringNode(String value) { - Objects.requireNonNull(value, "string value is null"); - this.value = value; - } - - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } - - @Override - public String toString() { - return "{\"value\":\"" + value + "\"}"; - } -} +/* + * + */ +package org.redkale.source; + +import java.util.Objects; +import org.redkale.convert.ConvertColumn; + +/** + * 字符串的ColumnNode + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public class ColumnStringNode implements ColumnNode { + + @ConvertColumn(index = 1) + private String value; + + public ColumnStringNode() {} + + public ColumnStringNode(String value) { + Objects.requireNonNull(value, "string value is null"); + this.value = value; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + @Override + public String toString() { + return "{\"value\":\"" + value + "\"}"; + } +} diff --git a/src/main/java/org/redkale/source/ColumnValues.java b/src/main/java/org/redkale/source/ColumnValues.java index cb5dba2c0..f31917d4a 100644 --- a/src/main/java/org/redkale/source/ColumnValues.java +++ b/src/main/java/org/redkale/source/ColumnValues.java @@ -1,386 +1,386 @@ -/* - * - */ -package org.redkale.source; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; -import org.redkale.util.LambdaFunction; -import org.redkale.util.LambdaSupplier; - -/** - * ColumnValue的集合类 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public class ColumnValues { - - private final List list = new ArrayList<>(); - - public static ColumnValues create() { - return new ColumnValues(); - } - - /** - * 返回 {column} = {value} 操作 - * - * @param column 字段名 - * @param value 字段值 - * @return ColumnValues - */ - public ColumnValues set(String column, Serializable value) { - list.add(ColumnValue.set(column, value)); - return this; - } - - /** - * 返回 {column} = {column} + {value} 操作 - * - * @param column 字段名 - * @param value 字段值 - * @return ColumnValues - */ - public ColumnValues inc(String column, Number value) { - list.add(ColumnValue.set(column, value)); - return this; - } - - /** - * 返回 {column} = {column} + 1 操作 - * - * @param column 字段名 - * @return ColumnValues - */ - public ColumnValues inc(String column) { - list.add(ColumnValue.inc(column)); - return this; - } - - /** - * 返回 {column} = {column} - {value} 操作 - * - * @param column 字段名 - * @param value 字段值 - * @return ColumnValues - */ - public ColumnValues dec(String column, Number value) { - list.add(ColumnValue.dec(column, value)); - return this; - } - - /** - * 返回 {column} = {column} - 1 操作 - * - * @param column 字段名 - * @return ColumnValues - */ - public ColumnValues dec(String column) { - list.add(ColumnValue.dec(column)); - return this; - } - - /** - * 返回 {column} = {column} * {value} 操作 - * - * @param column 字段名 - * @param value 字段值 - * @return ColumnValues - */ - public ColumnValues mul(String column, Number value) { - list.add(ColumnValue.mul(column, value)); - return this; - } - - /** - * 返回 {column} = {column} / {value} 操作 - * - * @param column 字段名 - * @param value 字段值 - * @return ColumnValues - */ - public ColumnValues div(String column, Number value) { - list.add(ColumnValue.div(column, value)); - return this; - } - - /** - * 返回 {column} = {column} % {value} 操作 - * - * @param column 字段名 - * @param value 字段值 - * @return ColumnValues - */ - public ColumnValues mod(String column, Serializable value) { - list.add(ColumnValue.mod(column, value)); - return this; - } - - /** - * 返回 {column} = {column} & {value} 操作 - * - * @param column 字段名 - * @param value 字段值 - * @return ColumnValues - */ - public ColumnValues and(String column, Serializable value) { - list.add(ColumnValue.and(column, value)); - return this; - } - - /** - * 返回 {column} = {column} | {value} 操作 - * - * @param column 字段名 - * @param value 字段值 - * @return ColumnValues - */ - public ColumnValues orr(String column, Serializable value) { - list.add(ColumnValue.orr(column, value)); - return this; - } - - /** - * 返回 {column} = {value} 操作 - * - * @param func 字段名Lambda - * @param 值的泛型 - * @return ColumnValues - * @since 2.8.0 - */ - public ColumnValues set(LambdaSupplier func) { - list.add(ColumnValue.set(func)); - return this; - } - - /** - * 返回 {column} = {column} + {value} 操作 - * - * @param func 字段名Lambda - * @param 值的泛型 - * @return ColumnValues - */ - public ColumnValues inc(LambdaSupplier func) { - list.add(ColumnValue.inc(func)); - return this; - } - - /** - * 返回 {column} = {column} - {value} 操作 - * - * @param func 字段名Lambda - * @param 值的泛型 - * @return ColumnValues - */ - public ColumnValues dec(LambdaSupplier func) { - list.add(ColumnValue.dec(func)); - return this; - } - - /** - * 返回 {column} = {column} * {value} 操作 - * - * @param func 字段名Lambda - * @param 值的泛型 - * @return ColumnValues - */ - public ColumnValues mul(LambdaSupplier func) { - list.add(ColumnValue.mul(func)); - return this; - } - - /** - * 返回 {column} = {column} / {value} 操作 - * - * @param func 字段名Lambda - * @param 值的泛型 - * @return ColumnValues - */ - public ColumnValues div(LambdaSupplier func) { - list.add(ColumnValue.div(func)); - return this; - } - - /** - * 返回 {column} = {column} % {value} 操作 - * - * @param func 字段名Lambda - * @param 值的泛型 - * @return ColumnValues - * @since 2.8.0 - */ - public ColumnValues mod(LambdaSupplier func) { - list.add(ColumnValue.mod(func)); - return this; - } - - /** - * 返回 {column} = {column} & {value} 操作 - * - * @param func 字段名Lambda - * @param 值的泛型 - * @return ColumnValues - */ - public ColumnValues and(LambdaSupplier func) { - list.add(ColumnValue.and(func)); - return this; - } - - /** - * 返回 {column} = {column} | {value} 操作 - * - * @param func 字段名Lambda - * @param 值的泛型 - * @return ColumnValues - */ - public ColumnValues orr(LambdaSupplier func) { - list.add(ColumnValue.orr(func)); - return this; - } - - /** - * 返回 {column} = {value} 操作 - * - * @param func 字段名Lambda - * @param value 字段值 - * @param 值的泛型 - * @return ColumnValues - */ - public ColumnValues set(LambdaFunction func, Serializable value) { - list.add(ColumnValue.set(func, value)); - return this; - } - - /** - * 返回 {column} = {column} + {value} 操作 - * - * @param func 字段名Lambda - * @param value 字段值 - * @param 值的泛型 - * @return ColumnValues - */ - public ColumnValues inc(LambdaFunction func, Serializable value) { - list.add(ColumnValue.inc(func, value)); - return this; - } - - /** - * 返回 {column} = {column} + 1 操作 - * - * @param func 字段名Lambda - * @param 值的泛型 - * @return ColumnValues - */ - public ColumnValues inc(LambdaFunction func) { - list.add(ColumnValue.inc(func)); - return this; - } - - /** - * 返回 {column} = {column} - {value} 操作 - * - * @param func 字段名Lambda - * @param value 字段值 - * @param 值的泛型 - * @return ColumnValues - */ - public ColumnValues dec(LambdaFunction func, Serializable value) { - list.add(ColumnValue.dec(func, value)); - return this; - } - - /** - * 返回 {column} = {column} - 1 操作 - * - * @param func 字段名Lambda - * @param 值的泛型 - * @return ColumnValues - */ - public ColumnValues dec(LambdaFunction func) { - list.add(ColumnValue.dec(func)); - return this; - } - - /** - * 返回 {column} = {column} * {value} 操作 - * - * @param func 字段名Lambda - * @param value 字段值 - * @param 值的泛型 - * @return ColumnValues - * @since 2.8.0 - */ - public ColumnValues mul(LambdaFunction func, Serializable value) { - list.add(ColumnValue.mul(func, value)); - return this; - } - - /** - * 返回 {column} = {column} / {value} 操作 - * - * @param func 字段名Lambda - * @param value 字段值 - * @param 值的泛型 - * @return ColumnValues - */ - public ColumnValues div(LambdaFunction func, Serializable value) { - list.add(ColumnValue.div(func, value)); - return this; - } - - /** - * 返回 {column} = {column} % {value} 操作 - * - * @param func 字段名Lambda - * @param value 字段值 - * @param 值的泛型 - * @return ColumnValues - */ - public ColumnValues mod(LambdaFunction func, Serializable value) { - list.add(ColumnValue.mod(func, value)); - return this; - } - - /** - * 返回 {column} = {column} & {value} 操作 - * - * @param func 字段名Lambda - * @param value 字段值 - * @param 值的泛型 - * @return ColumnValues - */ - public ColumnValues and(LambdaFunction func, Serializable value) { - list.add(ColumnValue.and(func, value)); - return this; - } - - /** - * 返回 {column} = {column} | {value} 操作 - * - * @param func 字段名Lambda - * @param value 字段值 - * @param 值的泛型 - * @return ColumnValues - */ - public ColumnValues orr(LambdaFunction func, Serializable value) { - list.add(ColumnValue.orr(func, value)); - return this; - } - - /** - * 获取ColumnValue数组 - * - * @return ColumnValue[] - */ - public ColumnValue[] getValues() { - return list.toArray(new ColumnValue[list.size()]); - } - - @Override - public String toString() { - return String.valueOf(list); - } -} +/* + * + */ +package org.redkale.source; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import org.redkale.util.LambdaFunction; +import org.redkale.util.LambdaSupplier; + +/** + * ColumnValue的集合类 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public class ColumnValues { + + private final List list = new ArrayList<>(); + + public static ColumnValues create() { + return new ColumnValues(); + } + + /** + * 返回 {column} = {value} 操作 + * + * @param column 字段名 + * @param value 字段值 + * @return ColumnValues + */ + public ColumnValues set(String column, Serializable value) { + list.add(ColumnValue.set(column, value)); + return this; + } + + /** + * 返回 {column} = {column} + {value} 操作 + * + * @param column 字段名 + * @param value 字段值 + * @return ColumnValues + */ + public ColumnValues inc(String column, Number value) { + list.add(ColumnValue.set(column, value)); + return this; + } + + /** + * 返回 {column} = {column} + 1 操作 + * + * @param column 字段名 + * @return ColumnValues + */ + public ColumnValues inc(String column) { + list.add(ColumnValue.inc(column)); + return this; + } + + /** + * 返回 {column} = {column} - {value} 操作 + * + * @param column 字段名 + * @param value 字段值 + * @return ColumnValues + */ + public ColumnValues dec(String column, Number value) { + list.add(ColumnValue.dec(column, value)); + return this; + } + + /** + * 返回 {column} = {column} - 1 操作 + * + * @param column 字段名 + * @return ColumnValues + */ + public ColumnValues dec(String column) { + list.add(ColumnValue.dec(column)); + return this; + } + + /** + * 返回 {column} = {column} * {value} 操作 + * + * @param column 字段名 + * @param value 字段值 + * @return ColumnValues + */ + public ColumnValues mul(String column, Number value) { + list.add(ColumnValue.mul(column, value)); + return this; + } + + /** + * 返回 {column} = {column} / {value} 操作 + * + * @param column 字段名 + * @param value 字段值 + * @return ColumnValues + */ + public ColumnValues div(String column, Number value) { + list.add(ColumnValue.div(column, value)); + return this; + } + + /** + * 返回 {column} = {column} % {value} 操作 + * + * @param column 字段名 + * @param value 字段值 + * @return ColumnValues + */ + public ColumnValues mod(String column, Serializable value) { + list.add(ColumnValue.mod(column, value)); + return this; + } + + /** + * 返回 {column} = {column} & {value} 操作 + * + * @param column 字段名 + * @param value 字段值 + * @return ColumnValues + */ + public ColumnValues and(String column, Serializable value) { + list.add(ColumnValue.and(column, value)); + return this; + } + + /** + * 返回 {column} = {column} | {value} 操作 + * + * @param column 字段名 + * @param value 字段值 + * @return ColumnValues + */ + public ColumnValues orr(String column, Serializable value) { + list.add(ColumnValue.orr(column, value)); + return this; + } + + /** + * 返回 {column} = {value} 操作 + * + * @param func 字段名Lambda + * @param 值的泛型 + * @return ColumnValues + * @since 2.8.0 + */ + public ColumnValues set(LambdaSupplier func) { + list.add(ColumnValue.set(func)); + return this; + } + + /** + * 返回 {column} = {column} + {value} 操作 + * + * @param func 字段名Lambda + * @param 值的泛型 + * @return ColumnValues + */ + public ColumnValues inc(LambdaSupplier func) { + list.add(ColumnValue.inc(func)); + return this; + } + + /** + * 返回 {column} = {column} - {value} 操作 + * + * @param func 字段名Lambda + * @param 值的泛型 + * @return ColumnValues + */ + public ColumnValues dec(LambdaSupplier func) { + list.add(ColumnValue.dec(func)); + return this; + } + + /** + * 返回 {column} = {column} * {value} 操作 + * + * @param func 字段名Lambda + * @param 值的泛型 + * @return ColumnValues + */ + public ColumnValues mul(LambdaSupplier func) { + list.add(ColumnValue.mul(func)); + return this; + } + + /** + * 返回 {column} = {column} / {value} 操作 + * + * @param func 字段名Lambda + * @param 值的泛型 + * @return ColumnValues + */ + public ColumnValues div(LambdaSupplier func) { + list.add(ColumnValue.div(func)); + return this; + } + + /** + * 返回 {column} = {column} % {value} 操作 + * + * @param func 字段名Lambda + * @param 值的泛型 + * @return ColumnValues + * @since 2.8.0 + */ + public ColumnValues mod(LambdaSupplier func) { + list.add(ColumnValue.mod(func)); + return this; + } + + /** + * 返回 {column} = {column} & {value} 操作 + * + * @param func 字段名Lambda + * @param 值的泛型 + * @return ColumnValues + */ + public ColumnValues and(LambdaSupplier func) { + list.add(ColumnValue.and(func)); + return this; + } + + /** + * 返回 {column} = {column} | {value} 操作 + * + * @param func 字段名Lambda + * @param 值的泛型 + * @return ColumnValues + */ + public ColumnValues orr(LambdaSupplier func) { + list.add(ColumnValue.orr(func)); + return this; + } + + /** + * 返回 {column} = {value} 操作 + * + * @param func 字段名Lambda + * @param value 字段值 + * @param 值的泛型 + * @return ColumnValues + */ + public ColumnValues set(LambdaFunction func, Serializable value) { + list.add(ColumnValue.set(func, value)); + return this; + } + + /** + * 返回 {column} = {column} + {value} 操作 + * + * @param func 字段名Lambda + * @param value 字段值 + * @param 值的泛型 + * @return ColumnValues + */ + public ColumnValues inc(LambdaFunction func, Serializable value) { + list.add(ColumnValue.inc(func, value)); + return this; + } + + /** + * 返回 {column} = {column} + 1 操作 + * + * @param func 字段名Lambda + * @param 值的泛型 + * @return ColumnValues + */ + public ColumnValues inc(LambdaFunction func) { + list.add(ColumnValue.inc(func)); + return this; + } + + /** + * 返回 {column} = {column} - {value} 操作 + * + * @param func 字段名Lambda + * @param value 字段值 + * @param 值的泛型 + * @return ColumnValues + */ + public ColumnValues dec(LambdaFunction func, Serializable value) { + list.add(ColumnValue.dec(func, value)); + return this; + } + + /** + * 返回 {column} = {column} - 1 操作 + * + * @param func 字段名Lambda + * @param 值的泛型 + * @return ColumnValues + */ + public ColumnValues dec(LambdaFunction func) { + list.add(ColumnValue.dec(func)); + return this; + } + + /** + * 返回 {column} = {column} * {value} 操作 + * + * @param func 字段名Lambda + * @param value 字段值 + * @param 值的泛型 + * @return ColumnValues + * @since 2.8.0 + */ + public ColumnValues mul(LambdaFunction func, Serializable value) { + list.add(ColumnValue.mul(func, value)); + return this; + } + + /** + * 返回 {column} = {column} / {value} 操作 + * + * @param func 字段名Lambda + * @param value 字段值 + * @param 值的泛型 + * @return ColumnValues + */ + public ColumnValues div(LambdaFunction func, Serializable value) { + list.add(ColumnValue.div(func, value)); + return this; + } + + /** + * 返回 {column} = {column} % {value} 操作 + * + * @param func 字段名Lambda + * @param value 字段值 + * @param 值的泛型 + * @return ColumnValues + */ + public ColumnValues mod(LambdaFunction func, Serializable value) { + list.add(ColumnValue.mod(func, value)); + return this; + } + + /** + * 返回 {column} = {column} & {value} 操作 + * + * @param func 字段名Lambda + * @param value 字段值 + * @param 值的泛型 + * @return ColumnValues + */ + public ColumnValues and(LambdaFunction func, Serializable value) { + list.add(ColumnValue.and(func, value)); + return this; + } + + /** + * 返回 {column} = {column} | {value} 操作 + * + * @param func 字段名Lambda + * @param value 字段值 + * @param 值的泛型 + * @return ColumnValues + */ + public ColumnValues orr(LambdaFunction func, Serializable value) { + list.add(ColumnValue.orr(func, value)); + return this; + } + + /** + * 获取ColumnValue数组 + * + * @return ColumnValue[] + */ + public ColumnValue[] getValues() { + return list.toArray(new ColumnValue[list.size()]); + } + + @Override + public String toString() { + return String.valueOf(list); + } +} diff --git a/src/main/java/org/redkale/source/DataBatch.java b/src/main/java/org/redkale/source/DataBatch.java index d86d51ad1..f146f7148 100644 --- a/src/main/java/org/redkale/source/DataBatch.java +++ b/src/main/java/org/redkale/source/DataBatch.java @@ -1,84 +1,84 @@ -/* - * - */ -package org.redkale.source; - -import java.io.Serializable; -import java.util.Collection; -import org.redkale.util.LambdaFunction; -import org.redkale.util.LambdaSupplier; -import org.redkale.util.SelectColumn; - -/** - * DataSource批量操作对象,操作类型只能是增删改
- * 非线程安全类 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public interface DataBatch { - - public static DataBatch create() { - return new AbstractDataSource.DefaultDataBatch(); - } - - public DataBatch run(Runnable task); - - public DataBatch insert(T... entitys); - - public DataBatch insert(Collection entitys); - - public DataBatch delete(T... entitys); - - public DataBatch delete(Collection entitys); - - public DataBatch delete(Class clazz, Serializable... pks); - - public DataBatch delete(Class clazz, FilterNode node); - - public DataBatch delete(Class clazz, FilterNode node, Flipper flipper); - - public DataBatch update(T... entitys); - - public DataBatch update(Collection entitys); - - public DataBatch updateColumn(Class clazz, Serializable pk, String column, Serializable value); - - public DataBatch updateColumn(Class clazz, Serializable pk, ColumnValue... values); - - public DataBatch updateColumn(Class clazz, FilterNode node, String column, Serializable value); - - public DataBatch updateColumn(Class clazz, FilterNode node, Flipper flipper, ColumnValue... values); - - public DataBatch updateColumn(T entity, final String... columns); - - public DataBatch updateColumn(T entity, final FilterNode node, final String... columns); - - public DataBatch updateColumn(T entity, SelectColumn selects); - - public DataBatch updateColumn(T entity, final FilterNode node, SelectColumn selects); - - default DataBatch updateColumn( - final Class clazz, final Serializable pk, final LambdaSupplier func) { - return updateColumn(clazz, pk, LambdaSupplier.readColumn(func), func.get()); - } - - default DataBatch updateColumn( - final Class clazz, final Serializable pk, LambdaFunction func, Serializable value) { - return updateColumn(clazz, pk, ColumnValue.set(func, value)); - } - - default DataBatch updateColumn(final Class clazz, final FilterNode node, final ColumnValue... values) { - return updateColumn(clazz, node, (Flipper) null, values); - } - - default DataBatch updateColumn(final T entity, final LambdaFunction... funcs) { - return updateColumn(entity, (FilterNode) null, LambdaFunction.readColumns(funcs)); - } - - default DataBatch updateColumn(final T entity, final FilterNode node, final LambdaFunction... funcs) { - return updateColumn(entity, node, LambdaFunction.readColumns(funcs)); - } -} +/* + * + */ +package org.redkale.source; + +import java.io.Serializable; +import java.util.Collection; +import org.redkale.util.LambdaFunction; +import org.redkale.util.LambdaSupplier; +import org.redkale.util.SelectColumn; + +/** + * DataSource批量操作对象,操作类型只能是增删改
+ * 非线程安全类 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public interface DataBatch { + + public static DataBatch create() { + return new AbstractDataSource.DefaultDataBatch(); + } + + public DataBatch run(Runnable task); + + public DataBatch insert(T... entitys); + + public DataBatch insert(Collection entitys); + + public DataBatch delete(T... entitys); + + public DataBatch delete(Collection entitys); + + public DataBatch delete(Class clazz, Serializable... pks); + + public DataBatch delete(Class clazz, FilterNode node); + + public DataBatch delete(Class clazz, FilterNode node, Flipper flipper); + + public DataBatch update(T... entitys); + + public DataBatch update(Collection entitys); + + public DataBatch updateColumn(Class clazz, Serializable pk, String column, Serializable value); + + public DataBatch updateColumn(Class clazz, Serializable pk, ColumnValue... values); + + public DataBatch updateColumn(Class clazz, FilterNode node, String column, Serializable value); + + public DataBatch updateColumn(Class clazz, FilterNode node, Flipper flipper, ColumnValue... values); + + public DataBatch updateColumn(T entity, final String... columns); + + public DataBatch updateColumn(T entity, final FilterNode node, final String... columns); + + public DataBatch updateColumn(T entity, SelectColumn selects); + + public DataBatch updateColumn(T entity, final FilterNode node, SelectColumn selects); + + default DataBatch updateColumn( + final Class clazz, final Serializable pk, final LambdaSupplier func) { + return updateColumn(clazz, pk, LambdaSupplier.readColumn(func), func.get()); + } + + default DataBatch updateColumn( + final Class clazz, final Serializable pk, LambdaFunction func, Serializable value) { + return updateColumn(clazz, pk, ColumnValue.set(func, value)); + } + + default DataBatch updateColumn(final Class clazz, final FilterNode node, final ColumnValue... values) { + return updateColumn(clazz, node, (Flipper) null, values); + } + + default DataBatch updateColumn(final T entity, final LambdaFunction... funcs) { + return updateColumn(entity, (FilterNode) null, LambdaFunction.readColumns(funcs)); + } + + default DataBatch updateColumn(final T entity, final FilterNode node, final LambdaFunction... funcs) { + return updateColumn(entity, node, LambdaFunction.readColumns(funcs)); + } +} diff --git a/src/main/java/org/redkale/source/DataJdbcConnection.java b/src/main/java/org/redkale/source/DataJdbcConnection.java index d1c2ce3dc..97fcb0fa4 100644 --- a/src/main/java/org/redkale/source/DataJdbcConnection.java +++ b/src/main/java/org/redkale/source/DataJdbcConnection.java @@ -1,25 +1,25 @@ -/* - * - */ -package org.redkale.source; - -import java.sql.Connection; - -/** - * 用于获取jdbc的物理连接对象 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public abstract class DataJdbcConnection { - - final boolean readFlag; - - public abstract Connection getConnection(); - - DataJdbcConnection(boolean readFlag) { - this.readFlag = readFlag; - } -} +/* + * + */ +package org.redkale.source; + +import java.sql.Connection; + +/** + * 用于获取jdbc的物理连接对象 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public abstract class DataJdbcConnection { + + final boolean readFlag; + + public abstract Connection getConnection(); + + DataJdbcConnection(boolean readFlag) { + this.readFlag = readFlag; + } +} diff --git a/src/main/java/org/redkale/source/DataMemorySource.java b/src/main/java/org/redkale/source/DataMemorySource.java index 88a1bee1b..dde2679a9 100644 --- a/src/main/java/org/redkale/source/DataMemorySource.java +++ b/src/main/java/org/redkale/source/DataMemorySource.java @@ -1,446 +1,446 @@ -/* - * 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.source; - -import java.io.Serializable; -import java.util.*; -import java.util.concurrent.CompletableFuture; -import java.util.stream.Stream; -import org.redkale.annotation.AutoLoad; -import org.redkale.annotation.ResourceChanged; -import org.redkale.annotation.ResourceType; -import org.redkale.inject.ResourceEvent; -import org.redkale.service.Local; -import org.redkale.util.*; - -/** @author zhangjx */ -/** - * DataSource的Memory实现类
- * 注意: url 需要指定为 memory:datasource - * - *

详情见: https://redkale.org - * - * @author zhangjx - */ -@Local -@AutoLoad(false) -@SuppressWarnings("unchecked") -@ResourceType(DataSource.class) -public class DataMemorySource extends AbstractDataSource { - - public DataMemorySource(String name) { - this.name = name; - } - - @Local - @Override - public String getType() { - return "memory"; - } - - @Override - @ResourceChanged - public void onResourceChange(ResourceEvent[] events) { - // do nothing - } - - public static boolean acceptsConf(AnyValue config) { - return config.getValue(DataSources.DATA_SOURCE_URL).startsWith("memory:"); - } - // - // public static boolean isSearchType(AnyValue config) { - // return config.getValue(DATA_SOURCE_URL).startsWith("memory:search"); - // } - - @Local - @Override - public void compile(Class clazz) { - EntityInfo entityInfo = EntityInfo.compile(clazz, this); - if (entityInfo.getCache() == null) { - new EntityCache<>(entityInfo, null).clear(); - } - } - - @Override - protected final boolean isOnlyCache(EntityInfo info) { - return true; - } - - @Override - public String toString() { - return getClass().getSimpleName() + "{type=memory, name='" + resourceName() + "'}"; - } - - @Override - public int insert(T... entitys) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public CompletableFuture insertAsync(T... entitys) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public int delete(T... entitys) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public CompletableFuture deleteAsync(T... entitys) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public int delete(Class clazz, Serializable... pks) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public CompletableFuture deleteAsync(Class clazz, Serializable... pks) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public int delete(Class clazz, Flipper flipper, FilterNode node) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public CompletableFuture deleteAsync(Class clazz, Flipper flipper, FilterNode node) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public int clearTable(Class clazz, FilterNode node) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public CompletableFuture clearTableAsync(Class clazz, FilterNode node) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public int createTable(Class clazz, Serializable pk) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public CompletableFuture createTableAsync(Class clazz, Serializable pk) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public int dropTable(Class clazz, FilterNode node) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public CompletableFuture dropTableAsync(Class clazz, FilterNode node) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public int update(T... entitys) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public CompletableFuture updateAsync(T... entitys) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public int updateColumn(Class clazz, Serializable pk, String column, Serializable value) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public CompletableFuture updateColumnAsync( - Class clazz, Serializable pk, String column, Serializable value) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public int updateColumn(Class clazz, String column, Serializable value, FilterNode node) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public CompletableFuture updateColumnAsync( - Class clazz, String column, Serializable value, FilterNode node) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public int updateColumn(Class clazz, Serializable pk, ColumnValue... values) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public CompletableFuture updateColumnAsync(Class clazz, Serializable pk, ColumnValue... values) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public int updateColumn(Class clazz, FilterNode node, Flipper flipper, ColumnValue... values) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public CompletableFuture updateColumnAsync( - Class clazz, FilterNode node, Flipper flipper, ColumnValue... values) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public int updateColumn(T entity, FilterNode node, SelectColumn selects) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public CompletableFuture updateColumnAsync(T entity, FilterNode node, SelectColumn selects) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public Number getNumberResult(Class entityClass, FilterFunc func, Number defVal, String column, FilterNode node) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public CompletableFuture getNumberResultAsync( - Class entityClass, FilterFunc func, Number defVal, String column, FilterNode node) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public Map getNumberMap( - Class entityClass, FilterNode node, FilterFuncColumn... columns) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public CompletableFuture> getNumberMapAsync( - Class entityClass, FilterNode node, FilterFuncColumn... columns) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public Map queryColumnMap( - Class entityClass, String keyColumn, FilterFunc func, String funcColumn, FilterNode node) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public CompletableFuture> queryColumnMapAsync( - Class entityClass, String keyColumn, FilterFunc func, String funcColumn, FilterNode node) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public Map queryColumnMap( - Class entityClass, ColumnNode[] funcNodes, String groupByColumn, FilterNode node) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public CompletableFuture> queryColumnMapAsync( - Class entityClass, ColumnNode[] funcNodes, String groupByColumn, FilterNode node) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public Map queryColumnMap( - Class entityClass, ColumnNode[] funcNodes, String[] groupByColumns, FilterNode node) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public CompletableFuture> queryColumnMapAsync( - Class entityClass, ColumnNode[] funcNodes, String[] groupByColumns, FilterNode node) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public T find(Class clazz, SelectColumn selects, Serializable pk) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public CompletableFuture findAsync(Class clazz, SelectColumn selects, Serializable pk) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public T[] finds(Class clazz, SelectColumn selects, Serializable... pks) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public CompletableFuture findsAsync(Class clazz, SelectColumn selects, Serializable... pks) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public List findsList(Class clazz, Stream pks) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public CompletableFuture> findsListAsync(Class clazz, Stream pks) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public T find(Class clazz, SelectColumn selects, FilterNode node) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public CompletableFuture findAsync(Class clazz, SelectColumn selects, FilterNode node) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public Serializable findColumn(Class clazz, String column, Serializable defValue, Serializable pk) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public CompletableFuture findColumnAsync( - Class clazz, String column, Serializable defValue, Serializable pk) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public Serializable findColumn(Class clazz, String column, Serializable defValue, FilterNode node) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public CompletableFuture findColumnAsync( - Class clazz, String column, Serializable defValue, FilterNode node) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public boolean exists(Class clazz, Serializable pk) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public CompletableFuture existsAsync(Class clazz, Serializable pk) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public boolean exists(Class clazz, FilterNode node) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public CompletableFuture existsAsync(Class clazz, FilterNode node) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public Set queryColumnSet( - String selectedColumn, Class clazz, Flipper flipper, FilterNode node) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public CompletableFuture> queryColumnSetAsync( - String selectedColumn, Class clazz, Flipper flipper, FilterNode node) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public List queryColumnList( - String selectedColumn, Class clazz, Flipper flipper, FilterNode node) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public CompletableFuture> queryColumnListAsync( - String selectedColumn, Class clazz, Flipper flipper, FilterNode node) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public Sheet queryColumnSheet( - String selectedColumn, Class clazz, Flipper flipper, FilterNode node) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public CompletableFuture> queryColumnSheetAsync( - String selectedColumn, Class clazz, Flipper flipper, FilterNode node) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public Map queryMap(Class clazz, SelectColumn selects, Stream keyStream) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public CompletableFuture> queryMapAsync( - Class clazz, SelectColumn selects, Stream keyStream) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public Map queryMap(Class clazz, SelectColumn selects, FilterNode node) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public CompletableFuture> queryMapAsync( - Class clazz, SelectColumn selects, FilterNode node) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public Set querySet(Class clazz, SelectColumn selects, Flipper flipper, FilterNode node) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public CompletableFuture> querySetAsync( - Class clazz, SelectColumn selects, Flipper flipper, FilterNode node) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public List queryList(Class clazz, SelectColumn selects, Flipper flipper, FilterNode node) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public CompletableFuture> queryListAsync( - Class clazz, SelectColumn selects, Flipper flipper, FilterNode node) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public Sheet querySheet(Class clazz, SelectColumn selects, Flipper flipper, FilterNode node) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public CompletableFuture> querySheetAsync( - Class clazz, SelectColumn selects, Flipper flipper, FilterNode node) { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public void close() throws Exception { - throw new UnsupportedOperationException("Not supported yet."); - } -} +/* + * 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.source; + +import java.io.Serializable; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Stream; +import org.redkale.annotation.AutoLoad; +import org.redkale.annotation.ResourceChanged; +import org.redkale.annotation.ResourceType; +import org.redkale.inject.ResourceEvent; +import org.redkale.service.Local; +import org.redkale.util.*; + +/** @author zhangjx */ +/** + * DataSource的Memory实现类
+ * 注意: url 需要指定为 memory:datasource + * + *

详情见: https://redkale.org + * + * @author zhangjx + */ +@Local +@AutoLoad(false) +@SuppressWarnings("unchecked") +@ResourceType(DataSource.class) +public class DataMemorySource extends AbstractDataSource { + + public DataMemorySource(String name) { + this.name = name; + } + + @Local + @Override + public String getType() { + return "memory"; + } + + @Override + @ResourceChanged + public void onResourceChange(ResourceEvent[] events) { + // do nothing + } + + public static boolean acceptsConf(AnyValue config) { + return config.getValue(DataSources.DATA_SOURCE_URL).startsWith("memory:"); + } + // + // public static boolean isSearchType(AnyValue config) { + // return config.getValue(DATA_SOURCE_URL).startsWith("memory:search"); + // } + + @Local + @Override + public void compile(Class clazz) { + EntityInfo entityInfo = EntityInfo.compile(clazz, this); + if (entityInfo.getCache() == null) { + new EntityCache<>(entityInfo, null).clear(); + } + } + + @Override + protected final boolean isOnlyCache(EntityInfo info) { + return true; + } + + @Override + public String toString() { + return getClass().getSimpleName() + "{type=memory, name='" + resourceName() + "'}"; + } + + @Override + public int insert(T... entitys) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public CompletableFuture insertAsync(T... entitys) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int delete(T... entitys) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public CompletableFuture deleteAsync(T... entitys) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int delete(Class clazz, Serializable... pks) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public CompletableFuture deleteAsync(Class clazz, Serializable... pks) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int delete(Class clazz, Flipper flipper, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public CompletableFuture deleteAsync(Class clazz, Flipper flipper, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int clearTable(Class clazz, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public CompletableFuture clearTableAsync(Class clazz, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int createTable(Class clazz, Serializable pk) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public CompletableFuture createTableAsync(Class clazz, Serializable pk) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int dropTable(Class clazz, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public CompletableFuture dropTableAsync(Class clazz, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int update(T... entitys) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public CompletableFuture updateAsync(T... entitys) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int updateColumn(Class clazz, Serializable pk, String column, Serializable value) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public CompletableFuture updateColumnAsync( + Class clazz, Serializable pk, String column, Serializable value) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int updateColumn(Class clazz, String column, Serializable value, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public CompletableFuture updateColumnAsync( + Class clazz, String column, Serializable value, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int updateColumn(Class clazz, Serializable pk, ColumnValue... values) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public CompletableFuture updateColumnAsync(Class clazz, Serializable pk, ColumnValue... values) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int updateColumn(Class clazz, FilterNode node, Flipper flipper, ColumnValue... values) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public CompletableFuture updateColumnAsync( + Class clazz, FilterNode node, Flipper flipper, ColumnValue... values) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int updateColumn(T entity, FilterNode node, SelectColumn selects) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public CompletableFuture updateColumnAsync(T entity, FilterNode node, SelectColumn selects) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Number getNumberResult(Class entityClass, FilterFunc func, Number defVal, String column, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public CompletableFuture getNumberResultAsync( + Class entityClass, FilterFunc func, Number defVal, String column, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Map getNumberMap( + Class entityClass, FilterNode node, FilterFuncColumn... columns) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public CompletableFuture> getNumberMapAsync( + Class entityClass, FilterNode node, FilterFuncColumn... columns) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Map queryColumnMap( + Class entityClass, String keyColumn, FilterFunc func, String funcColumn, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public CompletableFuture> queryColumnMapAsync( + Class entityClass, String keyColumn, FilterFunc func, String funcColumn, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Map queryColumnMap( + Class entityClass, ColumnNode[] funcNodes, String groupByColumn, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public CompletableFuture> queryColumnMapAsync( + Class entityClass, ColumnNode[] funcNodes, String groupByColumn, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Map queryColumnMap( + Class entityClass, ColumnNode[] funcNodes, String[] groupByColumns, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public CompletableFuture> queryColumnMapAsync( + Class entityClass, ColumnNode[] funcNodes, String[] groupByColumns, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public T find(Class clazz, SelectColumn selects, Serializable pk) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public CompletableFuture findAsync(Class clazz, SelectColumn selects, Serializable pk) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public T[] finds(Class clazz, SelectColumn selects, Serializable... pks) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public CompletableFuture findsAsync(Class clazz, SelectColumn selects, Serializable... pks) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public List findsList(Class clazz, Stream pks) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public CompletableFuture> findsListAsync(Class clazz, Stream pks) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public T find(Class clazz, SelectColumn selects, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public CompletableFuture findAsync(Class clazz, SelectColumn selects, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Serializable findColumn(Class clazz, String column, Serializable defValue, Serializable pk) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public CompletableFuture findColumnAsync( + Class clazz, String column, Serializable defValue, Serializable pk) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Serializable findColumn(Class clazz, String column, Serializable defValue, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public CompletableFuture findColumnAsync( + Class clazz, String column, Serializable defValue, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean exists(Class clazz, Serializable pk) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public CompletableFuture existsAsync(Class clazz, Serializable pk) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean exists(Class clazz, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public CompletableFuture existsAsync(Class clazz, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Set queryColumnSet( + String selectedColumn, Class clazz, Flipper flipper, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public CompletableFuture> queryColumnSetAsync( + String selectedColumn, Class clazz, Flipper flipper, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public List queryColumnList( + String selectedColumn, Class clazz, Flipper flipper, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public CompletableFuture> queryColumnListAsync( + String selectedColumn, Class clazz, Flipper flipper, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Sheet queryColumnSheet( + String selectedColumn, Class clazz, Flipper flipper, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public CompletableFuture> queryColumnSheetAsync( + String selectedColumn, Class clazz, Flipper flipper, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Map queryMap(Class clazz, SelectColumn selects, Stream keyStream) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public CompletableFuture> queryMapAsync( + Class clazz, SelectColumn selects, Stream keyStream) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Map queryMap(Class clazz, SelectColumn selects, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public CompletableFuture> queryMapAsync( + Class clazz, SelectColumn selects, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Set querySet(Class clazz, SelectColumn selects, Flipper flipper, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public CompletableFuture> querySetAsync( + Class clazz, SelectColumn selects, Flipper flipper, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public List queryList(Class clazz, SelectColumn selects, Flipper flipper, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public CompletableFuture> queryListAsync( + Class clazz, SelectColumn selects, Flipper flipper, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Sheet querySheet(Class clazz, SelectColumn selects, Flipper flipper, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public CompletableFuture> querySheetAsync( + Class clazz, SelectColumn selects, Flipper flipper, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void close() throws Exception { + throw new UnsupportedOperationException("Not supported yet."); + } +} diff --git a/src/main/java/org/redkale/source/DataNativeSqlInfo.java b/src/main/java/org/redkale/source/DataNativeSqlInfo.java index 18a7e8b87..dc262dd60 100644 --- a/src/main/java/org/redkale/source/DataNativeSqlInfo.java +++ b/src/main/java/org/redkale/source/DataNativeSqlInfo.java @@ -1,69 +1,69 @@ -/* - * - */ -package org.redkale.source; - -import java.util.ArrayList; -import java.util.List; -import org.redkale.annotation.Nullable; -import org.redkale.convert.ConvertDisabled; - -/** - * 原生的sql解析基本信息对象
- * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public class DataNativeSqlInfo { - - // 原始sql语句 - protected String rawSql; - - // 不包含${}且参数为:arg0xx格式的jdbc版sql语句, 只有dollarNames为空时才有值 - @Nullable - protected String templetSql; - - // 包含IN表达式的参数, 例如: name IN #{names}、status IN (1,2,#{status.normal}) - protected boolean containsInExpr; - - // sql类型 - protected SqlMode sqlMode; - - // 根参数名, 如bean.userid、bean.username的根参数名为: bean - protected final List rootParamNames = new ArrayList<>(); - - @ConvertDisabled - public boolean isDynamic() { - return templetSql == null || containsInExpr; - } - - public boolean isContainsInExpr() { - return containsInExpr; - } - - public String getRawSql() { - return rawSql; - } - - public String getTempletSql() { - return templetSql; - } - - public SqlMode getSqlMode() { - return sqlMode; - } - - public List getRootParamNames() { - return rootParamNames; - } - - public enum SqlMode { - SELECT, - INSERT, - DELETE, - UPDATE, - OTHERS; - } -} +/* + * + */ +package org.redkale.source; + +import java.util.ArrayList; +import java.util.List; +import org.redkale.annotation.Nullable; +import org.redkale.convert.ConvertDisabled; + +/** + * 原生的sql解析基本信息对象
+ * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public class DataNativeSqlInfo { + + // 原始sql语句 + protected String rawSql; + + // 不包含${}且参数为:arg0xx格式的jdbc版sql语句, 只有dollarNames为空时才有值 + @Nullable + protected String templetSql; + + // 包含IN表达式的参数, 例如: name IN #{names}、status IN (1,2,#{status.normal}) + protected boolean containsInExpr; + + // sql类型 + protected SqlMode sqlMode; + + // 根参数名, 如bean.userid、bean.username的根参数名为: bean + protected final List rootParamNames = new ArrayList<>(); + + @ConvertDisabled + public boolean isDynamic() { + return templetSql == null || containsInExpr; + } + + public boolean isContainsInExpr() { + return containsInExpr; + } + + public String getRawSql() { + return rawSql; + } + + public String getTempletSql() { + return templetSql; + } + + public SqlMode getSqlMode() { + return sqlMode; + } + + public List getRootParamNames() { + return rootParamNames; + } + + public enum SqlMode { + SELECT, + INSERT, + DELETE, + UPDATE, + OTHERS; + } +} diff --git a/src/main/java/org/redkale/source/DataNativeSqlParser.java b/src/main/java/org/redkale/source/DataNativeSqlParser.java index 98e7acdaf..9911c2ac3 100644 --- a/src/main/java/org/redkale/source/DataNativeSqlParser.java +++ b/src/main/java/org/redkale/source/DataNativeSqlParser.java @@ -1,45 +1,45 @@ -/* - * - */ -package org.redkale.source; - -import java.util.*; -import java.util.function.IntFunction; -import org.redkale.source.spi.DataNativeSqlParserProvider; -import org.redkale.util.RedkaleClassLoader; - -/** - * 原生的sql解析器
- * 参数变量有三种方式(与Mybatis的占位符类似):
- * ${xx.xx}: 用于直接拼接sql的变量,不做任何转义, 变量值必需的 #{xx.xx}: 用于预编译的sql的参数变量, UPDATE SET中的#{xx.xx}变量自动转成必需的 ##{xx.xx}: - * 用于预编译的sql的参数变量, 变量值必需的 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public interface DataNativeSqlParser { - - public DataNativeSqlInfo parse(IntFunction signFunc, String dbType, String rawSql); - - public DataNativeSqlStatement parse( - IntFunction signFunc, String dbType, String rawSql, boolean countable, Map params); - - public static DataNativeSqlParser loadFirst() { - if (DataNativeSqlStatement._first_parser != DataNativeSqlStatement.PARSER_NIL) { - return DataNativeSqlStatement._first_parser; - } - Iterator it = - ServiceLoader.load(DataNativeSqlParserProvider.class).iterator(); - RedkaleClassLoader.putServiceLoader(DataNativeSqlParserProvider.class); - while (it.hasNext()) { - DataNativeSqlParserProvider provider = it.next(); - if (provider != null && provider.acceptsConf(null)) { - return provider.createInstance(); - } - } - DataNativeSqlStatement._first_parser = null; - return null; - } -} +/* + * + */ +package org.redkale.source; + +import java.util.*; +import java.util.function.IntFunction; +import org.redkale.source.spi.DataNativeSqlParserProvider; +import org.redkale.util.RedkaleClassLoader; + +/** + * 原生的sql解析器
+ * 参数变量有三种方式(与Mybatis的占位符类似):
+ * ${xx.xx}: 用于直接拼接sql的变量,不做任何转义, 变量值必需的 #{xx.xx}: 用于预编译的sql的参数变量, UPDATE SET中的#{xx.xx}变量自动转成必需的 ##{xx.xx}: + * 用于预编译的sql的参数变量, 变量值必需的 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public interface DataNativeSqlParser { + + public DataNativeSqlInfo parse(IntFunction signFunc, String dbType, String rawSql); + + public DataNativeSqlStatement parse( + IntFunction signFunc, String dbType, String rawSql, boolean countable, Map params); + + public static DataNativeSqlParser loadFirst() { + if (DataNativeSqlStatement._first_parser != DataNativeSqlStatement.PARSER_NIL) { + return DataNativeSqlStatement._first_parser; + } + Iterator it = + ServiceLoader.load(DataNativeSqlParserProvider.class).iterator(); + RedkaleClassLoader.putServiceLoader(DataNativeSqlParserProvider.class); + while (it.hasNext()) { + DataNativeSqlParserProvider provider = it.next(); + if (provider != null && provider.acceptsConf(null)) { + return provider.createInstance(); + } + } + DataNativeSqlStatement._first_parser = null; + return null; + } +} diff --git a/src/main/java/org/redkale/source/DataNativeSqlStatement.java b/src/main/java/org/redkale/source/DataNativeSqlStatement.java index 4af066c32..e9a78bb7a 100644 --- a/src/main/java/org/redkale/source/DataNativeSqlStatement.java +++ b/src/main/java/org/redkale/source/DataNativeSqlStatement.java @@ -1,112 +1,112 @@ -/* - * - */ -package org.redkale.source; - -import java.util.List; -import java.util.Map; -import java.util.function.IntFunction; -import org.redkale.annotation.Nullable; -import org.redkale.convert.ConvertDisabled; -import org.redkale.convert.json.JsonConvert; - -/** - * 原生的sql解析对象
- * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public class DataNativeSqlStatement { - - static final DataNativeSqlParser PARSER_NIL = new DataNativeSqlParser() { - @Override - public DataNativeSqlInfo parse(IntFunction signFunc, String dbType, String rawSql) { - throw new UnsupportedOperationException("No available instances found"); - } - - @Override - public DataNativeSqlStatement parse( - IntFunction signFunc, - String dbType, - String rawSql, - boolean countable, - Map params) { - throw new UnsupportedOperationException("No available instances found"); - } - }; - - static DataNativeSqlParser _first_parser = PARSER_NIL; - - // 根据参数值集合重新生成的带?参数可执行的sql - protected String nativeSql; - - // 根据参数值集合重新生成的带?参数可执行的计算总数sql,用于返回Sheet对象 - @Nullable - protected String nativeCountSql; - - // 需要预编译的##{xxx}、#{xxx}参数名, 数量与sql中的?数量一致 - protected List paramNames; - - // 需要预编译的jdbc参数名, 数量与sql中的?数量一致 - protected List jdbcNames; - - // jdbc参数值集合, paramNames中的key必然会存在 - protected Map paramValues; - - /** - * 是否带有参数 - * - * @return 是否带有参数 - */ - @ConvertDisabled - public boolean isEmptyNamed() { - return paramNames == null || paramNames.isEmpty(); - } - - public String getNativeSql() { - return nativeSql; - } - - public void setNativeSql(String nativeSql) { - this.nativeSql = nativeSql; - } - - public String getNativeCountSql() { - return nativeCountSql; - } - - public void setNativeCountSql(String nativeCountSql) { - this.nativeCountSql = nativeCountSql; - } - - public List getParamNames() { - return paramNames; - } - - public void setParamNames(List paramNames) { - this.paramNames = paramNames; - } - - public Map getParamValues() { - return paramValues; - } - - public void setParamValues(Map paramValues) { - this.paramValues = paramValues; - } - - public List getJdbcNames() { - return jdbcNames; - } - - public void setJdbcNames(List jdbcNames) { - this.jdbcNames = jdbcNames; - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } -} +/* + * + */ +package org.redkale.source; + +import java.util.List; +import java.util.Map; +import java.util.function.IntFunction; +import org.redkale.annotation.Nullable; +import org.redkale.convert.ConvertDisabled; +import org.redkale.convert.json.JsonConvert; + +/** + * 原生的sql解析对象
+ * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public class DataNativeSqlStatement { + + static final DataNativeSqlParser PARSER_NIL = new DataNativeSqlParser() { + @Override + public DataNativeSqlInfo parse(IntFunction signFunc, String dbType, String rawSql) { + throw new UnsupportedOperationException("No available instances found"); + } + + @Override + public DataNativeSqlStatement parse( + IntFunction signFunc, + String dbType, + String rawSql, + boolean countable, + Map params) { + throw new UnsupportedOperationException("No available instances found"); + } + }; + + static DataNativeSqlParser _first_parser = PARSER_NIL; + + // 根据参数值集合重新生成的带?参数可执行的sql + protected String nativeSql; + + // 根据参数值集合重新生成的带?参数可执行的计算总数sql,用于返回Sheet对象 + @Nullable + protected String nativeCountSql; + + // 需要预编译的##{xxx}、#{xxx}参数名, 数量与sql中的?数量一致 + protected List paramNames; + + // 需要预编译的jdbc参数名, 数量与sql中的?数量一致 + protected List jdbcNames; + + // jdbc参数值集合, paramNames中的key必然会存在 + protected Map paramValues; + + /** + * 是否带有参数 + * + * @return 是否带有参数 + */ + @ConvertDisabled + public boolean isEmptyNamed() { + return paramNames == null || paramNames.isEmpty(); + } + + public String getNativeSql() { + return nativeSql; + } + + public void setNativeSql(String nativeSql) { + this.nativeSql = nativeSql; + } + + public String getNativeCountSql() { + return nativeCountSql; + } + + public void setNativeCountSql(String nativeCountSql) { + this.nativeCountSql = nativeCountSql; + } + + public List getParamNames() { + return paramNames; + } + + public void setParamNames(List paramNames) { + this.paramNames = paramNames; + } + + public Map getParamValues() { + return paramValues; + } + + public void setParamValues(Map paramValues) { + this.paramValues = paramValues; + } + + public List getJdbcNames() { + return jdbcNames; + } + + public void setJdbcNames(List jdbcNames) { + this.jdbcNames = jdbcNames; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } +} diff --git a/src/main/java/org/redkale/source/DataSqlMapper.java b/src/main/java/org/redkale/source/DataSqlMapper.java index 1c66a2764..faa47af63 100644 --- a/src/main/java/org/redkale/source/DataSqlMapper.java +++ b/src/main/java/org/redkale/source/DataSqlMapper.java @@ -1,3102 +1,3102 @@ -/* - * - */ -package org.redkale.source; - -import java.io.Serializable; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.CompletableFuture; -import java.util.stream.Stream; -import org.redkale.annotation.ClassDepends; -import org.redkale.util.LambdaFunction; -import org.redkale.util.LambdaSupplier; -import org.redkale.util.SelectColumn; -import org.redkale.util.Sheet; - -/** - * 类似Mybatis的Mapper接口类, 接口系列和DataSource相似度高
- * 自定义的sql接口的返回结果类型只能是: void/基本数据类型/JavaBean/Map/List/Sheet
- * 异步接口返回的是泛型为以上类型的CompletableFuture - * - *

- * - *
- * public interface ForumInfoMapper extends BaseMapper<ForumInfo> {
- *
- *   @Sql("SELECT f.forum_groupid, s.forum_section_color "
- *      + "FROM forum_info f, forum_section s "
- *      + " WHERE f.forumid = s.forumid AND "
- *      + "s.forum_sectionid = #{bean.forumSectionid} AND "
- *      + "f.forumid = #{bean.forumid} AND s.forum_section_color = #{bean.forumSectionColor}")
- *   public ForumResult findForumResult(ForumBean bean);
- *
- *   @Sql("SELECT f.forum_groupid, s.forum_section_color "
- *      + "FROM forum_info f, forum_section s "
- *      + " WHERE f.forumid = s.forumid AND "
- *      + "s.forum_sectionid = #{bean.forumSectionid} AND "
- *      + "f.forumid = #{bean.forumid} AND s.forum_section_color = #{bean.forumSectionColor}")
- *   public CompletableFuture<ForumResult> findForumResultAsync(ForumBean bean);
- *
- *   @Sql("SELECT f.forum_groupid, s.forum_section_color "
- *      + "FROM forum_info f, forum_section s "
- *      + " WHERE f.forumid = s.forumid AND "
- *      + "s.forum_sectionid = #{bean.forumSectionid} AND "
- *      + "f.forumid = #{bean.forumid} AND s.forum_section_color = #{bean.forumSectionColor}")
- *   public List<ForumResult> queryForumResult(@Param("bean") ForumBean bean0);
- *
- *   @Sql("SELECT f.forum_groupid, s.forum_section_color "
- *      + "FROM forum_info f, forum_section s "
- *      + " WHERE f.forumid = s.forumid AND "
- *      + "s.forum_sectionid = #{bean.forumSectionid} AND "
- *      + "f.forumid = #{bean.forumid} AND s.forum_section_color = #{bean.forumSectionColor}")
- *   public CompletableFuture<List<ForumResult>> queryForumResultAsync(ForumBean bean);
- * }
- * 
- * - *
- * - *

详情见: https://redkale.org - * - * @see org.redkale.source.spi.DataSqlMapperBuilder - * @see org.redkale.persistence.Sql - * @author zhangjx - * @param T - * @since 2.8.0 - */ -public interface DataSqlMapper { - - /** - * 获取当前数据源 - * - * @return DataSqlSource - */ - @ClassDepends - DataSqlSource dataSource(); - - /** - * 获取当前实体类型 - * - * @return Class - */ - @ClassDepends - Class entityType(); - - /** - * 新增记录
- * - * @param entitys Entity对象 - * @return CompletableFuture - */ - default int insert(T... entitys) { - return dataSource().insert(entitys); - } - - /** - * 新增记录
- * - * @param entitys Entity对象 - * @return CompletableFuture - */ - default int insert(Collection entitys) { - return dataSource().insert(entitys); - } - - /** - * 新增记录
- * - * @param entitys Entity对象 - * @return CompletableFuture - */ - default int insert(Stream entitys) { - return dataSource().insert(entitys); - } - - /** - * 新增记录
- * - * @param entitys Entity对象 - * @return CompletableFuture - */ - default CompletableFuture insertAsync(T... entitys) { - return dataSource().insertAsync(entitys); - } - - /** - * 新增记录
- * - * @param entitys Entity对象 - * @return CompletableFuture - */ - default CompletableFuture insertAsync(Collection entitys) { - return dataSource().insertAsync(entitys); - } - - /** - * 新增记录
- * - * @param entitys Entity对象 - * @return CompletableFuture - */ - default CompletableFuture insertAsync(Stream entitys) { - return dataSource().insertAsync(entitys); - } - - /** - * 删除指定主键值的记录
- * 等价SQL: DELETE FROM {table} WHERE {primary} IN {values.id}
- * - * @param entitys Entity对象 - * @return 影响的记录条数CompletableFuture - */ - default int delete(T... entitys) { - return dataSource().delete(entitys); - } - - /** - * 删除指定主键值的记录
- * 等价SQL: DELETE FROM {table} WHERE {primary} IN {values.id}
- * - * @param entitys Entity对象 - * @return 影响的记录条数CompletableFuture - */ - default int delete(Collection entitys) { - return dataSource().delete(entitys); - } - - /** - * 删除指定主键值的记录
- * 等价SQL: DELETE FROM {table} WHERE {primary} IN {values.id}
- * - * @param entitys Entity对象 - * @return 影响的记录条数CompletableFuture - */ - default int delete(Stream entitys) { - return dataSource().delete(entitys); - } - - /** - * 删除指定主键值的记录
- * 等价SQL: DELETE FROM {table} WHERE {primary} IN {values.id}
- * - * @param entitys Entity对象 - * @return 影响的记录条数CompletableFuture - */ - default CompletableFuture deleteAsync(T... entitys) { - return dataSource().deleteAsync(entitys); - } - - /** - * 删除指定主键值的记录
- * 等价SQL: DELETE FROM {table} WHERE {primary} IN {values.id}
- * - * @param entitys Entity对象 - * @return 影响的记录条数CompletableFuture - */ - default CompletableFuture deleteAsync(Collection entitys) { - return dataSource().deleteAsync(entitys); - } - - /** - * 删除指定主键值的记录
- * 等价SQL: DELETE FROM {table} WHERE {primary} IN {values.id}
- * - * @param entitys Entity对象 - * @return 影响的记录条数CompletableFuture - */ - default CompletableFuture deleteAsync(Stream entitys) { - return dataSource().deleteAsync(entitys); - } - - /** - * 删除指定主键值的记录,多主键值必须在同一张表中
- * 等价SQL: DELETE FROM {table} WHERE {primary} IN {ids}
- * - * @param pks 主键值 - * @return 影响的记录条数 - */ - default int deleteById(Serializable... pks) { - return dataSource().delete(entityType(), pks); - } - - /** - * 删除指定主键值的记录,多主键值必须在同一张表中
- * 等价SQL: DELETE FROM {table} WHERE {primary} IN {ids}
- * - * @param pks 主键值 - * @return 影响的记录条数CompletableFuture - */ - default CompletableFuture deleteByIdAsync(Serializable... pks) { - return dataSource().deleteAsync(entityType(), pks); - } - - // ------------------------update--------------------------- - /** - * 更新记录
- * 等价SQL:
- * UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id1}
- * UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id2}
- * ···
- * - * @param entitys Entity对象 - * @return 影响的记录条数 - */ - default int update(T... entitys) { - return dataSource().update(entitys); - } - - /** - * 更新记录
- * 等价SQL:
- * UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id1}
- * UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id2}
- * ···
- * - * @param entitys Entity对象 - * @return 影响的记录条数 - */ - default int update(Collection entitys) { - return dataSource().update(entitys); - } - - /** - * 更新记录
- * 等价SQL:
- * UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id1}
- * UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id2}
- * ···
- * - * @param entitys Entity对象 - * @return 影响的记录条数 - */ - default int update(Stream entitys) { - return dataSource().update(entitys); - } - - /** - * 更新记录
- * 等价SQL:
- * UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id1}
- * UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id2}
- * ···
- * - * @param entitys Entity对象 - * @return 影响的记录条数CompletableFuture - */ - default CompletableFuture updateAsync(T... entitys) { - return dataSource().updateAsync(entitys); - } - - /** - * 更新记录
- * 等价SQL:
- * UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id1}
- * UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id2}
- * ···
- * - * @param entitys Entity对象 - * @return 影响的记录条数CompletableFuture - */ - default CompletableFuture updateAsync(Collection entitys) { - return dataSource().updateAsync(entitys); - } - - /** - * 更新记录
- * 等价SQL:
- * UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id1}
- * UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id2}
- * ···
- * - * @param entitys Entity对象 - * @return 影响的记录条数CompletableFuture - */ - default CompletableFuture updateAsync(Stream entitys) { - return dataSource().updateAsync(entitys); - } - - /** - * 更新单个记录的单个字段
- * 注意:即使字段标记为@Column(updatable=false)也会被更新
- * 等价SQL: UPDATE {table} SET {column} = {value} WHERE {primary} = {id}
- * - * @param pk 主键 - * @param column 待更新的字段名 - * @param value 更新值 - * @return 影响的记录条数 - */ - default int updateColumn(Serializable pk, String column, Serializable value) { - return dataSource().updateColumn(entityType(), pk, column, value); - } - - /** - * 更新单个记录的单个字段
- * 注意:即使字段标记为@Column(updatable=false)也会被更新
- * 等价SQL: UPDATE {table} SET {column} = {value} WHERE {primary} = {id}
- * - * @param 更新值泛型 - * @param pk 主键 - * @param func 更新值Lambda - * @return 影响的记录条数 - */ - default int updateColumn(Serializable pk, LambdaSupplier func) { - return dataSource().updateColumn(entityType(), pk, func); - } - - /** - * 更新单个记录的单个字段
- * 注意:即使字段标记为@Column(updatable=false)也会被更新
- * 等价SQL: UPDATE {table} SET {column} = {value} WHERE {primary} = {id}
- * - * @param pk 主键 - * @param column 待更新的字段名 - * @param value 更新值 - * @return 影响的记录条数CompletableFuture - */ - default CompletableFuture updateColumnAsync(Serializable pk, String column, Serializable value) { - return dataSource().updateColumnAsync(entityType(), pk, column, value); - } - - /** - * 更新单个记录的单个字段
- * 注意:即使字段标记为@Column(updatable=false)也会被更新
- * 等价SQL: UPDATE {table} SET {column} = {value} WHERE {primary} = {id}
- * - * @param 更新值泛型 - * @param pk 主键 - * @param func 更新值Lambda - * @return 影响的记录条数 - */ - default CompletableFuture updateColumnAsync( - Serializable pk, LambdaSupplier func) { - return dataSource().updateColumnAsync(entityType(), pk, func); - } - - /** - * 更新符合过滤条件记录的单个字段
- * 注意:即使字段标记为@Column(updatable=false)也会被更新
- * 等价SQL: UPDATE {table} SET {column} = {value} WHERE {filter node}
- * - * @param column 待更新的字段名 - * @param value 更新值 - * @param node 过滤条件 - * @return 影响的记录条数 - */ - default int updateColumn(String column, Serializable value, FilterNode node) { - return dataSource().updateColumn(entityType(), column, value, node); - } - - /** - * 更新符合过滤条件记录的单个字段
- * 注意:即使字段标记为@Column(updatable=false)也会被更新
- * 等价SQL: UPDATE {table} SET {column} = {value} WHERE {filter node}
- * - * @param 更新值泛型 - * @param func 更新值Lambda - * @param node 过滤条件 - * @return 影响的记录条数 - */ - default int updateColumn(LambdaSupplier func, FilterNode node) { - return dataSource().updateColumn(entityType(), func, node); - } - - /** - * 更新符合过滤条件记录的单个字段
- * 注意:即使字段标记为@Column(updatable=false)也会被更新
- * 等价SQL: UPDATE {table} SET {column} = {value} WHERE {filter node}
- * - * @param column 待更新的字段名 - * @param value 更新值 - * @param node 过滤条件 - * @return 影响的记录条数CompletableFuture - */ - default CompletableFuture updateColumnAsync(String column, Serializable value, FilterNode node) { - return dataSource().updateColumnAsync(entityType(), column, value, node); - } - - /** - * 更新符合过滤条件记录的单个字段
- * 注意:即使字段标记为@Column(updatable=false)也会被更新
- * 等价SQL: UPDATE {table} SET {column} = {value} WHERE {filter node}
- * - * @param 更新值泛型 - * @param func 更新值Lambda - * @param node 过滤条件 - * @return 影响的记录条数 - */ - default CompletableFuture updateColumnAsync( - LambdaSupplier func, FilterNode node) { - return dataSource().updateColumnAsync(entityType(), func, node); - } - - /** - * 更新指定主键值记录的部分字段
- * 字段赋值操作选项见 ColumnExpress
- * 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} += {value2}, {column3} *= {value3}, ··· - * WHERE {filter node}
- * - * @param pk 主键 - * @param values 更新字段 - * @return 影响的记录条数 - */ - default int updateColumn(Serializable pk, ColumnValue... values) { - return dataSource().updateColumn(entityType(), pk, values); - } - - /** - * 更新指定主键值记录的部分字段
- * 字段赋值操作选项见 ColumnExpress
- * 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} += {value2}, {column3} *= {value3}, ··· - * WHERE {filter node}
- * - * @param pk 主键 - * @param func 更新字段 - * @param value 更新字段值 - * @return 影响的记录条数 - */ - default int updateColumn(Serializable pk, LambdaFunction func, Serializable value) { - return dataSource().updateColumn(entityType(), pk, func, value); - } - - /** - * 更新指定主键值记录的部分字段
- * 字段赋值操作选项见 ColumnExpress
- * 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} += {value2}, {column3} *= {value3}, ··· - * WHERE {filter node}
- * - * @param pk 主键 - * @param values 更新字段 - * @return 影响的记录条数CompletableFuture - */ - default CompletableFuture updateColumnAsync(Serializable pk, ColumnValue... values) { - return dataSource().updateColumnAsync(entityType(), pk, values); - } - - /** - * 更新指定主键值记录的部分字段
- * 字段赋值操作选项见 ColumnExpress
- * 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} += {value2}, {column3} *= {value3}, ··· - * WHERE {filter node}
- * - * @param pk 主键 - * @param func 更新字段 - * @param value 更新字段值 - * @return 影响的记录条数CompletableFuture - */ - default CompletableFuture updateColumnAsync( - Serializable pk, LambdaFunction func, Serializable value) { - return dataSource().updateColumnAsync(entityType(), pk, func, value); - } - - /** - * 更新符合过滤条件记录的部分字段
- * 字段赋值操作选项见 ColumnExpress
- * 注意:Entity类中标记为@Column(updatable=false)不会被更新
- * 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} += {value2}, {column3} *= {value3}, ··· - * WHERE {filter node}
- * - * @param node 过滤条件 - * @param values 更新字段 - * @return 影响的记录条数 - */ - default int updateColumn(FilterNode node, ColumnValue... values) { - return dataSource().updateColumn(entityType(), node, values); - } - - /** - * 更新符合过滤条件记录的部分字段
- * 字段赋值操作选项见 ColumnExpress
- * 注意:Entity类中标记为@Column(updatable=false)不会被更新
- * 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} += {value2}, {column3} *= {value3}, ··· - * WHERE {filter node}
- * - * @param node 过滤条件 - * @param values 更新字段 - * @return 影响的记录条数CompletableFuture - */ - default CompletableFuture updateColumnAsync(FilterNode node, ColumnValue... values) { - return dataSource().updateColumnAsync(entityType(), node, values); - } - - /** - * 更新符合过滤条件的记录的指定字段
- * Flipper中offset字段将被忽略
- * 注意:Entity类中标记为@Column(updatable=false)不会被更新
- * 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} += {value2}, {column3} *= {value3}, ··· - * WHERE {filter node} ORDER BY {flipper.sort}
- * - * @param node 过滤条件 - * @param flipper 翻页对象 - * @param values 更新字段 - * @return 影响的记录条数 - */ - default int updateColumn(FilterNode node, Flipper flipper, ColumnValue... values) { - return dataSource().updateColumn(entityType(), node, flipper, values); - } - - /** - * 更新符合过滤条件的记录的指定字段
- * Flipper中offset字段将被忽略
- * 注意:Entity类中标记为@Column(updatable=false)不会被更新
- * 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} += {value2}, {column3} *= {value3}, ··· - * WHERE {filter node} ORDER BY {flipper.sort}
- * - * @param node 过滤条件 - * @param flipper 翻页对象 - * @param values 更新字段 - * @return 影响的记录条数CompletableFuture - */ - default CompletableFuture updateColumnAsync(FilterNode node, Flipper flipper, ColumnValue... values) { - return dataSource().updateColumnAsync(entityType(), node, flipper, values); - } - - /** - * 更新单个记录的指定字段
- * 注意:Entity类中标记为@Column(updatable=false)不会被更新
- * 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· - * WHERE {primary} = {bean.id}
- * - * @param entity 待更新的Entity对象 - * @param columns 需更新的字段名 - * @return 影响的记录条数 - */ - default int updateColumn(T entity, String... columns) { - return dataSource().updateColumn(entityType(), columns); - } - - /** - * 更新单个记录的指定字段
- * 注意:Entity类中标记为@Column(updatable=false)不会被更新
- * 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· - * WHERE {primary} = {bean.id}
- * - * @param entity 待更新的Entity对象 - * @param funcs 需更新的字段名Lambda集合 - * @return 影响的记录条数 - */ - default int updateColumn(T entity, LambdaFunction... funcs) { - return dataSource().updateColumn(entityType(), funcs); - } - - /** - * 更新单个记录的指定字段
- * 注意:Entity类中标记为@Column(updatable=false)不会被更新
- * 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· - * WHERE {primary} = {bean.id}
- * - * @param entity 待更新的Entity对象 - * @param columns 需更新的字段名 - * @return 影响的记录条数CompletableFuture - */ - default CompletableFuture updateColumnAsync(T entity, String... columns) { - return dataSource().updateColumnAsync(entityType(), columns); - } - - /** - * 更新单个记录的指定字段
- * 注意:Entity类中标记为@Column(updatable=false)不会被更新
- * 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· - * WHERE {primary} = {bean.id}
- * - * @param entity 待更新的Entity对象 - * @param funcs 需更新的字段名Lambda集合 - * @return 影响的记录条数CompletableFuture - */ - default CompletableFuture updateColumnAsync(T entity, LambdaFunction... funcs) { - return dataSource().updateColumnAsync(entityType(), funcs); - } - - /** - * 更新符合过滤条件记录的指定字段
- * 注意:Entity类中标记为@Column(updatable=false)不会被更新
- * 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· - * WHERE {filter node}
- * - * @param entity 待更新的Entity对象 - * @param node 过滤条件 - * @param columns 需更新的字段名 - * @return 影响的记录条数 - */ - default int updateColumn(T entity, FilterNode node, String... columns) { - return dataSource().updateColumn(entity, node, columns); - } - - /** - * 更新符合过滤条件记录的指定字段
- * 注意:Entity类中标记为@Column(updatable=false)不会被更新
- * 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· - * WHERE {filter node}
- * - * @param entity 待更新的Entity对象 - * @param node 过滤条件 - * @param funcs 需更新的字段名Lambda集合 - * @return 影响的记录条数 - */ - default int updateColumn(T entity, FilterNode node, LambdaFunction... funcs) { - return dataSource().updateColumn(entity, node, funcs); - } - - /** - * 更新符合过滤条件记录的指定字段
- * 注意:Entity类中标记为@Column(updatable=false)不会被更新
- * 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· - * WHERE {filter node}
- * - * @param entity 待更新的Entity对象 - * @param node 过滤条件 - * @param columns 需更新的字段名 - * @return 影响的记录条数CompletableFuture - */ - default CompletableFuture updateColumnAsync(T entity, FilterNode node, String... columns) { - return dataSource().updateColumnAsync(entity, node, columns); - } - - /** - * 更新符合过滤条件记录的指定字段
- * 注意:Entity类中标记为@Column(updatable=false)不会被更新
- * 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· - * WHERE {filter node}
- * - * @param entity 待更新的Entity对象 - * @param node 过滤条件 - * @param funcs 需更新的字段名Lambda集合 - * @return 影响的记录条数 - */ - default CompletableFuture updateColumnAsync(T entity, FilterNode node, LambdaFunction... funcs) { - return dataSource().updateColumnAsync(entity, node, funcs); - } - - /** - * 更新单个记录的指定字段
- * 注意:Entity类中标记为@Column(updatable=false)不会被更新
- * 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· - * WHERE {primary} = {bean.id}
- * - * @param entity 待更新的Entity对象 - * @param selects 指定字段 - * @return 影响的记录条数 - */ - default int updateColumn(T entity, SelectColumn selects) { - return dataSource().updateColumn(entity, selects); - } - - /** - * 更新单个记录的指定字段
- * 注意:Entity类中标记为@Column(updatable=false)不会被更新
- * 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· - * WHERE {primary} = {bean.id}
- * - * @param entity 待更新的Entity对象 - * @param selects 指定字段 - * @return 影响的记录条数CompletableFuture - */ - default CompletableFuture updateColumnAsync(T entity, SelectColumn selects) { - return dataSource().updateColumnAsync(entity, selects); - } - - /** - * 更新符合过滤条件记录的指定字段
- * 注意:Entity类中标记为@Column(updatable=false)不会被更新
- * 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· - * WHERE {filter node}
- * - * @param entity 待更新的Entity对象 - * @param node 过滤条件 - * @param selects 指定字段 - * @return 影响的记录条数 - */ - default int updateColumn(T entity, FilterNode node, SelectColumn selects) { - return dataSource().updateColumn(entity, node, selects); - } - - /** - * 更新符合过滤条件记录的指定字段
- * 注意:Entity类中标记为@Column(updatable=false)不会被更新
- * 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· - * WHERE {filter node}
- * - * @param entity 待更新的Entity对象 - * @param node 过滤条件 - * @param selects 指定字段 - * @return 影响的记录条数CompletableFuture - */ - default CompletableFuture updateColumnAsync(T entity, FilterNode node, SelectColumn selects) { - return dataSource().updateColumnAsync(entity, node, selects); - } - - // -----------------------getXXXXResult----------------------------- - default Number getNumberResult(FilterFunc func, String column) { - return dataSource().getNumberResult(entityType(), func, column); - } - - /** - * 获取符合过滤条件记录的聚合结果, 无结果返回null
- * 等价SQL: SELECT FUNC{column} FROM {table}
- * 如 getNumberResultAsync(User.class, FilterFunc.COUNT, null) 等价于: SELECT COUNT(*) FROM {table}
- * - * @param func 聚合函数 - * @param column 指定字段 - * @return 聚合结果CompletableFuture - */ - default CompletableFuture getNumberResultAsync(FilterFunc func, String column) { - return dataSource().getNumberResultAsync(entityType(), func, column); - } - - /** - * 获取符合过滤条件记录的聚合结果, 无结果返回null
- * 等价SQL: SELECT FUNC{column} FROM {table} WHERE {filter bean}
- * 如 getNumberResultAsync(User.class, FilterFunc.COUNT, null, (FilterBean)null) 等价于: SELECT COUNT(*) FROM {table} - *
- * - * @param func 聚合函数 - * @param column 指定字段 - * @param bean 过滤条件 - * @return 聚合结果 - */ - default Number getNumberResult(FilterFunc func, String column, FilterBean bean) { - return dataSource().getNumberResult(entityType(), func, column, bean); - } - - /** - * 获取符合过滤条件记录的聚合结果, 无结果返回null
- * 等价SQL: SELECT FUNC{column} FROM {table} WHERE {filter bean}
- * 如 getNumberResultAsync(User.class, FilterFunc.COUNT, null, (FilterBean)null) 等价于: SELECT COUNT(*) FROM {table} - *
- * - * @param func 聚合函数 - * @param column 指定字段 - * @param bean 过滤条件 - * @return 聚合结果CompletableFuture - */ - default CompletableFuture getNumberResultAsync(FilterFunc func, String column, FilterBean bean) { - return dataSource().getNumberResultAsync(entityType(), func, column, bean); - } - - /** - * 获取符合过滤条件记录的聚合结果, 无结果返回null
- * 等价SQL: SELECT FUNC{column} FROM {table} WHERE {filter node}
- * 如 getNumberResultAsync(User.class, FilterFunc.MAX, "createtime", (FilterNode)null) 等价于: SELECT MAX(createtime) - * FROM {table}
- * - * @param func 聚合函数 - * @param column 指定字段 - * @param node 过滤条件 - * @return 聚合结果 - */ - default Number getNumberResult(FilterFunc func, String column, FilterNode node) { - return dataSource().getNumberResult(entityType(), func, column, node); - } - - /** - * 获取符合过滤条件记录的聚合结果, 无结果返回null
- * 等价SQL: SELECT FUNC{column} FROM {table} WHERE {filter node}
- * 如 getNumberResultAsync(User.class, FilterFunc.MAX, "createtime", (FilterNode)null) 等价于: SELECT MAX(createtime) - * FROM {table}
- * - * @param func 聚合函数 - * @param column 指定字段 - * @param node 过滤条件 - * @return 聚合结果 - */ - default CompletableFuture getNumberResultAsync(FilterFunc func, String column, FilterNode node) { - return dataSource().getNumberResultAsync(entityType(), func, column, node); - } - - /** - * 获取符合过滤条件记录的聚合结果, 无结果返回默认值
- * 等价SQL: SELECT FUNC{column} FROM {table}
- * 如 getNumberResultAsync(User.class, FilterFunc.MAX, "createtime") 等价于: SELECT MAX(createtime) FROM {table}
- * - * @param func 聚合函数 - * @param defVal 默认值 - * @param column 指定字段 - * @return 聚合结果 - */ - default Number getNumberResult(FilterFunc func, Number defVal, String column) { - return dataSource().getNumberResult(entityType(), func, defVal, column); - } - - /** - * 获取符合过滤条件记录的聚合结果, 无结果返回默认值
- * 等价SQL: SELECT FUNC{column} FROM {table}
- * 如 getNumberResultAsync(User.class, FilterFunc.MAX, "createtime") 等价于: SELECT MAX(createtime) FROM {table}
- * - * @param func 聚合函数 - * @param defVal 默认值 - * @param column 指定字段 - * @return 聚合结果CompletableFuture - */ - default CompletableFuture getNumberResultAsync(FilterFunc func, Number defVal, String column) { - return dataSource().getNumberResultAsync(entityType(), func, defVal, column); - } - - /** - * 获取符合过滤条件记录的聚合结果, 无结果返回默认值
- * 等价SQL: SELECT FUNC{column} FROM {table} WHERE {filter bean}
- * 如 getNumberResultAsync(User.class, FilterFunc.MAX, "createtime", (FilterNode)null) 等价于: SELECT MAX(createtime) - * FROM {table}
- * - * @param func 聚合函数 - * @param defVal 默认值 - * @param column 指定字段 - * @param bean 过滤条件 - * @return 聚合结果 - */ - default Number getNumberResult(FilterFunc func, Number defVal, String column, FilterBean bean) { - return dataSource().getNumberResult(entityType(), func, defVal, column, bean); - } - - /** - * 获取符合过滤条件记录的聚合结果, 无结果返回默认值
- * 等价SQL: SELECT FUNC{column} FROM {table} WHERE {filter bean}
- * 如 getNumberResultAsync(User.class, FilterFunc.MAX, "createtime", (FilterNode)null) 等价于: SELECT MAX(createtime) - * FROM {table}
- * - * @param func 聚合函数 - * @param defVal 默认值 - * @param column 指定字段 - * @param bean 过滤条件 - * @return 聚合结果CompletableFuture - */ - default CompletableFuture getNumberResultAsync( - FilterFunc func, Number defVal, String column, FilterBean bean) { - return dataSource().getNumberResultAsync(entityType(), func, defVal, column, bean); - } - - /** - * 获取符合过滤条件记录的聚合结果, 无结果返回默认值
- * 等价SQL: SELECT FUNC{column} FROM {table} WHERE {filter node}
- * 如 getNumberResultAsync(User.class, FilterFunc.MAX, "createtime", (FilterNode)null) 等价于: SELECT MAX(createtime) - * FROM {table}
- * - * @param func 聚合函数 - * @param defVal 默认值 - * @param column 指定字段 - * @param node 过滤条件 - * @return 聚合结果 - */ - default Number getNumberResult(FilterFunc func, Number defVal, String column, FilterNode node) { - return dataSource().getNumberResult(entityType(), func, defVal, column, node); - } - - /** - * 获取符合过滤条件记录的聚合结果, 无结果返回默认值
- * 等价SQL: SELECT FUNC{column} FROM {table} WHERE {filter node}
- * 如 getNumberResultAsync(User.class, FilterFunc.MAX, "createtime", (FilterNode)null) 等价于: SELECT MAX(createtime) - * FROM {table}
- * - * @param func 聚合函数 - * @param defVal 默认值 - * @param column 指定字段 - * @param node 过滤条件 - * @return 聚合结果CompletableFuture - */ - default CompletableFuture getNumberResultAsync( - FilterFunc func, Number defVal, String column, FilterNode node) { - return dataSource().getNumberResultAsync(entityType(), func, defVal, column, node); - } - - /** - * 获取符合过滤条件记录的聚合结果Map
- * 等价SQL: SELECT FUNC1{column1}, FUNC2{column2}, ··· FROM {table}
- * 如 getNumberMapAsync(User.class, new FilterFuncColumn(FilterFunc.MAX, "createtime")) 等价于: SELECT MAX(createtime) - * FROM {table}
- * - * @param Number - * @param columns 聚合字段 - * @return 聚合结果Map - */ - default Map getNumberMap(FilterFuncColumn... columns) { - return dataSource().getNumberMap(entityType(), columns); - } - - /** - * 获取符合过滤条件记录的聚合结果Map
- * 等价SQL: SELECT FUNC1{column1}, FUNC2{column2}, ··· FROM {table}
- * 如 getNumberMapAsync(User.class, new FilterFuncColumn(FilterFunc.MAX, "createtime")) 等价于: SELECT MAX(createtime) - * FROM {table}
- * - * @param Number - * @param columns 聚合字段 - * @return 聚合结果Map CompletableFuture - */ - default CompletableFuture> getNumberMapAsync(FilterFuncColumn... columns) { - return dataSource().getNumberMapAsync(entityType(), columns); - } - - /** - * 获取符合过滤条件记录的聚合结果Map
- * 等价SQL: SELECT FUNC1{column1}, FUNC2{column2}, ··· FROM {table} WHERE {filter bean}
- * 如 getNumberMapAsync(User.class, (FilterBean)null, new FilterFuncColumn(FilterFunc.MAX, "createtime")) 等价于: SELECT - * MAX(createtime) FROM {table}
- * - * @param Number - * @param bean 过滤条件 - * @param columns 聚合字段 - * @return 聚合结果Map - */ - default Map getNumberMap(FilterBean bean, FilterFuncColumn... columns) { - return dataSource().getNumberMap(entityType(), bean, columns); - } - - /** - * 获取符合过滤条件记录的聚合结果Map
- * 等价SQL: SELECT FUNC1{column1}, FUNC2{column2}, ··· FROM {table} WHERE {filter bean}
- * 如 getNumberMapAsync(User.class, (FilterBean)null, new FilterFuncColumn(FilterFunc.MAX, "createtime")) 等价于: SELECT - * MAX(createtime) FROM {table}
- * - * @param Number - * @param bean 过滤条件 - * @param columns 聚合字段 - * @return 聚合结果Map CompletableFuture - */ - default CompletableFuture> getNumberMapAsync( - FilterBean bean, FilterFuncColumn... columns) { - return dataSource().getNumberMapAsync(entityType(), bean, columns); - } - - /** - * 获取符合过滤条件记录的聚合结果Map
- * 等价SQL: SELECT FUNC1{column1}, FUNC2{column2}, ··· FROM {table} WHERE {filter node}
- * 如 getNumberMapAsync(User.class, (FilterNode)null, new FilterFuncColumn(FilterFunc.MAX, "createtime")) 等价于: SELECT - * MAX(createtime) FROM {table}
- * - * @param Number - * @param node 过滤条件 - * @param columns 聚合字段 - * @return 聚合结果Map - */ - default Map getNumberMap(FilterNode node, FilterFuncColumn... columns) { - return dataSource().getNumberMap(entityType(), node, columns); - } - - /** - * 获取符合过滤条件记录的聚合结果Map
- * 等价SQL: SELECT FUNC1{column1}, FUNC2{column2}, ··· FROM {table} WHERE {filter node}
- * 如 getNumberMapAsync(User.class, (FilterNode)null, new FilterFuncColumn(FilterFunc.MAX, "createtime")) 等价于: SELECT - * MAX(createtime) FROM {table}
- * - * @param Number - * @param node 过滤条件 - * @param columns 聚合字段 - * @return 聚合结果Map - */ - default CompletableFuture> getNumberMapAsync( - FilterNode node, FilterFuncColumn... columns) { - return dataSource().getNumberMapAsync(entityType(), node, columns); - } - - /** - * 查询符合过滤条件记录的GROUP BY聚合结果Map
- * 等价SQL: SELECT keyColumn, FUNC{funcColumn} FROM {table} GROUP BY {keyColumn}
- * 如 queryColumnMapAsync(User.class, "name", FilterFunc.MAX, "createtime") 等价于: SELECT name, MAX(createtime) FROM - * user GROUP BY name
- * - * @param Key字段的数据类型 - * @param Number - * @param keyColumn Key字段 - * @param func 聚合函数 - * @param funcColumn 聚合字段 - * @return 聚合结果Map - */ - default Map queryColumnMap( - String keyColumn, FilterFunc func, String funcColumn) { - return dataSource().queryColumnMap(entityType(), keyColumn, func, funcColumn); - } - - /** - * 查询符合过滤条件记录的GROUP BY聚合结果Map
- * 等价SQL: SELECT keyColumn, FUNC{funcColumn} FROM {table} GROUP BY {keyColumn}
- * 如 queryColumnMapAsync(User.class, "name", FilterFunc.MAX, "createtime") 等价于: SELECT name, MAX(createtime) FROM - * user GROUP BY name
- * - * @param Key字段的数据类型 - * @param Number - * @param keyColumn Key字段 - * @param func 聚合函数 - * @param funcColumn 聚合字段 - * @return 聚合结果Map CompletableFuture - */ - default CompletableFuture> queryColumnMapAsync( - String keyColumn, FilterFunc func, String funcColumn) { - return dataSource().queryColumnMapAsync(entityType(), keyColumn, func, funcColumn); - } - - /** - * 查询符合过滤条件记录的GROUP BY聚合结果Map
- * 等价SQL: SELECT keyColumn, FUNC{funcColumn} FROM {table} WHERE {filter bean} GROUP BY {keyColumn}
- * 如 queryColumnMapAsync(User.class, "name", FilterFunc.MAX, "createtime", (FilterBean)null) 等价于: SELECT name, - * MAX(createtime) FROM user GROUP BY name
- * - * @param Key字段的数据类型 - * @param Number - * @param keyColumn Key字段 - * @param func 聚合函数 - * @param funcColumn 聚合字段 - * @param bean 过滤条件 - * @return 聚合结果Map - */ - default Map queryColumnMap( - String keyColumn, FilterFunc func, String funcColumn, FilterBean bean) { - return dataSource().queryColumnMap(entityType(), keyColumn, func, funcColumn, bean); - } - - /** - * 查询符合过滤条件记录的GROUP BY聚合结果Map
- * 等价SQL: SELECT keyColumn, FUNC{funcColumn} FROM {table} WHERE {filter bean} GROUP BY {keyColumn}
- * 如 queryColumnMapAsync(User.class, "name", FilterFunc.MAX, "createtime", (FilterBean)null) 等价于: SELECT name, - * MAX(createtime) FROM user GROUP BY name
- * - * @param Key字段的数据类型 - * @param Number - * @param keyColumn Key字段 - * @param func 聚合函数 - * @param funcColumn 聚合字段 - * @param bean 过滤条件 - * @return 聚合结果Map CompletableFuture - */ - default CompletableFuture> queryColumnMapAsync( - String keyColumn, FilterFunc func, String funcColumn, FilterBean bean) { - return dataSource().queryColumnMapAsync(entityType(), keyColumn, func, funcColumn, bean); - } - - /** - * 查询符合过滤条件记录的GROUP BY聚合结果Map
- * 等价SQL: SELECT keyColumn, FUNC{funcColumn} FROM {table} WHERE {filter node} GROUP BY {keyColumn}
- * 如 queryColumnMapAsync(User.class, "name", FilterFunc.MAX, "createtime", (FilterNode)null) 等价于: SELECT name, - * MAX(createtime) FROM user GROUP BY name
- * - * @param Key字段的数据类型 - * @param Number - * @param keyColumn Key字段 - * @param func 聚合函数 - * @param funcColumn 聚合字段 - * @param node 过滤条件 - * @return 聚合结果Map - */ - default Map queryColumnMap( - String keyColumn, FilterFunc func, String funcColumn, FilterNode node) { - return dataSource().queryColumnMap(entityType(), keyColumn, func, funcColumn, node); - } - - /** - * 查询符合过滤条件记录的GROUP BY聚合结果Map
- * 等价SQL: SELECT keyColumn, FUNC{funcColumn} FROM {table} WHERE {filter node} GROUP BY {keyColumn}
- * 如 queryColumnMapAsync(User.class, "name", FilterFunc.MAX, "createtime", (FilterNode)null) 等价于: SELECT name, - * MAX(createtime) FROM user GROUP BY name
- * - * @param Key字段的数据类型 - * @param Number - * @param keyColumn Key字段 - * @param func 聚合函数 - * @param funcColumn 聚合字段 - * @param node 过滤条件 - * @return 聚合结果Map CompletableFuture - */ - default CompletableFuture> queryColumnMapAsync( - String keyColumn, FilterFunc func, String funcColumn, FilterNode node) { - return dataSource().queryColumnMapAsync(entityType(), keyColumn, func, funcColumn, node); - } - - /** - * 查询符合过滤条件记录的GROUP BY聚合结果Map
- * 等价SQL: SELECT col1, FUNC{funcColumn1}, FUNC{funcColumn2} FROM {table} WHERE GROUP BY {col1}
- * 如 queryColumnMapAsync(OrderRecord.class, Utility.ofArray(ColumnExpNode.div(ColumnFuncNode.sum("money"), 100), - * ColumnFuncNode.avg(ColumnExpNode.dec("money", 20)))), "targetid") 等价于: SELECT targetid, SUM(money) / 100, - * AVG(money - 20) FROM orderrecord GROUP BY targetid
- * - * @param Key字段的数据类型 - * @param Number - * @param funcNodes ColumnNode[] - * @param groupByColumn GROUP BY字段 - * @return 聚合结果Map CompletableFuture - */ - default Map queryColumnMap( - ColumnNode[] funcNodes, String groupByColumn) { - return dataSource().queryColumnMap(entityType(), funcNodes, groupByColumn); - } - - /** - * 查询符合过滤条件记录的GROUP BY聚合结果Map
- * 等价SQL: SELECT col1, FUNC{funcColumn1}, FUNC{funcColumn2} FROM {table} GROUP BY {col1}
- * 如 queryColumnMapAsync(OrderRecord.class, Utility.ofArray(ColumnExpNode.div(ColumnFuncNode.sum("money"), 100), - * ColumnFuncNode.avg(ColumnExpNode.dec("money", 20)))), "targetid") 等价于: SELECT targetid, SUM(money) / 100, - * AVG(money - 20) FROM orderrecord GROUP BY targetid
- * - * @param Key字段的数据类型 - * @param Number - * @param funcNodes ColumnNode[] - * @param groupByColumn GROUP BY字段 - * @return 聚合结果Map CompletableFuture - */ - default CompletableFuture> queryColumnMapAsync( - ColumnNode[] funcNodes, String groupByColumn) { - return dataSource().queryColumnMapAsync(entityType(), funcNodes, groupByColumn); - } - - /** - * 查询符合过滤条件记录的GROUP BY聚合结果Map
- * 等价SQL: SELECT col1, FUNC{funcColumn1}, FUNC{funcColumn2} FROM {table} WHERE {filter bean} GROUP BY {col1}
- * 如 queryColumnMapAsync(OrderRecord.class, Utility.ofArray(ColumnExpNode.div(ColumnFuncNode.sum("money"), 100), - * ColumnFuncNode.avg(ColumnExpNode.dec("money", 20)))), "targetid", (FilterBean)null) 等价于: SELECT targetid, - * SUM(money) / 100, AVG(money - 20) FROM orderrecord GROUP BY targetid
- * - * @param Key字段的数据类型 - * @param Number - * @param funcNodes ColumnNode[] - * @param groupByColumn GROUP BY字段 - * @param bean 过滤条件 - * @return 聚合结果Map CompletableFuture - */ - default Map queryColumnMap( - ColumnNode[] funcNodes, String groupByColumn, FilterBean bean) { - return dataSource().queryColumnMap(entityType(), funcNodes, groupByColumn, bean); - } - - /** - * 查询符合过滤条件记录的GROUP BY聚合结果Map
- * 等价SQL: SELECT col1, FUNC{funcColumn1}, FUNC{funcColumn2} FROM {table} WHERE {filter bean} GROUP BY {col1}
- * 如 queryColumnMapAsync(OrderRecord.class, Utility.ofArray(ColumnExpNode.div(ColumnFuncNode.sum("money"), 100), - * ColumnFuncNode.avg(ColumnExpNode.dec("money", 20)))), "targetid", (FilterBean)null) 等价于: SELECT targetid, - * SUM(money) / 100, AVG(money - 20) FROM orderrecord GROUP BY targetid
- * - * @param Key字段的数据类型 - * @param Number - * @param funcNodes ColumnNode[] - * @param groupByColumn GROUP BY字段 - * @param bean 过滤条件 - * @return 聚合结果Map CompletableFuture - */ - default CompletableFuture> queryColumnMapAsync( - ColumnNode[] funcNodes, String groupByColumn, FilterBean bean) { - return dataSource().queryColumnMapAsync(entityType(), funcNodes, groupByColumn, bean); - } - - /** - * 查询符合过滤条件记录的GROUP BY聚合结果Map
- * 等价SQL: SELECT col1, FUNC{funcColumn1}, FUNC{funcColumn2} FROM {table} WHERE {filter node} GROUP BY {col1}
- * 如 queryColumnMapAsync(OrderRecord.class, Utility.ofArray(ColumnExpNode.div(ColumnFuncNode.sum("money"), 100), - * ColumnFuncNode.avg(ColumnExpNode.dec("money", 20)))), "targetid", (FilterNode)null) 等价于: SELECT targetid, - * SUM(money) / 100, AVG(money - 20) FROM orderrecord GROUP BY targetid
- * - * @param Key字段的数据类型 - * @param Number - * @param funcNodes ColumnNode[] - * @param groupByColumn GROUP BY字段 - * @param node 过滤条件 - * @return 聚合结果Map CompletableFuture - */ - default Map queryColumnMap( - ColumnNode[] funcNodes, String groupByColumn, FilterNode node) { - return dataSource().queryColumnMap(entityType(), funcNodes, groupByColumn, node); - } - - /** - * 查询符合过滤条件记录的GROUP BY聚合结果Map
- * 等价SQL: SELECT col1, FUNC{funcColumn1}, FUNC{funcColumn2} FROM {table} WHERE {filter node} GROUP BY {col1}
- * 如 queryColumnMapAsync(OrderRecord.class, Utility.ofArray(ColumnExpNode.div(ColumnFuncNode.sum("money"), 100), - * ColumnFuncNode.avg(ColumnExpNode.dec("money", 20)))), "targetid", (FilterNode)null) 等价于: SELECT targetid, - * SUM(money) / 100, AVG(money - 20) FROM orderrecord GROUP BY targetid
- * - * @param Key字段的数据类型 - * @param Number - * @param funcNodes ColumnNode[] - * @param groupByColumn GROUP BY字段 - * @param node 过滤条件 - * @return 聚合结果Map CompletableFuture - */ - default CompletableFuture> queryColumnMapAsync( - ColumnNode[] funcNodes, String groupByColumn, FilterNode node) { - return dataSource().queryColumnMapAsync(entityType(), funcNodes, groupByColumn, node); - } - - /** - * 查询符合过滤条件记录的GROUP BY聚合结果Map
- * 等价SQL: SELECT col1, col2, FUNC{funcColumn1}, FUNC{funcColumn2} FROM {table} GROUP BY {col1}, {col2}
- * 如 queryColumnMapAsync(OrderRecord.class, Utility.ofArray(ColumnExpNode.div(ColumnFuncNode.sum("money"), 100), - * ColumnFuncNode.avg(ColumnExpNode.dec("money", 20)))), Utility.ofArray("fromid", "targetid")) 等价于: SELECT fromid, - * targetid, SUM(money) / 100, AVG(money - 20) FROM orderrecord GROUP BY fromid, targetid
- * - * @param Key字段的数据类型 - * @param Number - * @param funcNodes ColumnNode[] - * @param groupByColumns GROUP BY字段 - * @return 聚合结果Map CompletableFuture - */ - default Map queryColumnMap( - ColumnNode[] funcNodes, String[] groupByColumns) { - return dataSource().queryColumnMap(entityType(), funcNodes, groupByColumns); - } - - /** - * 查询符合过滤条件记录的GROUP BY聚合结果Map
- * 等价SQL: SELECT col1, col2, FUNC{funcColumn1}, FUNC{funcColumn2} FROM {table} GROUP BY {col1}, {col2}
- * 如 queryColumnMapAsync(OrderRecord.class, Utility.ofArray(ColumnExpNode.div(ColumnFuncNode.sum("money"), 100), - * ColumnFuncNode.avg(ColumnExpNode.dec("money", 20)))), Utility.ofArray("fromid", "targetid")) 等价于: SELECT fromid, - * targetid, SUM(money) / 100, AVG(money - 20) FROM orderrecord GROUP BY fromid, targetid
- * - * @param Key字段的数据类型 - * @param Number - * @param funcNodes ColumnNode[] - * @param groupByColumns GROUP BY字段 - * @return 聚合结果Map CompletableFuture - */ - default CompletableFuture> queryColumnMapAsync( - ColumnNode[] funcNodes, String[] groupByColumns) { - return dataSource().queryColumnMapAsync(entityType(), funcNodes, groupByColumns); - } - - /** - * 查询符合过滤条件记录的GROUP BY聚合结果Map
- * 等价SQL: SELECT col1, col2, FUNC{funcColumn1}, FUNC{funcColumn2} FROM {table} WHERE {filter bean} GROUP BY {col1}, - * {col2}
- * 如 queryColumnMapAsync(OrderRecord.class, Utility.ofArray(ColumnExpNode.div(ColumnFuncNode.sum("money"), 100), - * ColumnFuncNode.avg(ColumnExpNode.dec("money", 20)))), Utility.ofArray("fromid", "targetid"), (FilterBean)null) - * 等价于: SELECT fromid, targetid, SUM(money) / 100, AVG(money - 20) FROM orderrecord GROUP BY fromid, targetid
- * - * @param Key字段的数据类型 - * @param Number - * @param funcNodes ColumnNode[] - * @param groupByColumns GROUP BY字段 - * @param bean 过滤条件 - * @return 聚合结果Map CompletableFuture - */ - default Map queryColumnMap( - ColumnNode[] funcNodes, String[] groupByColumns, FilterBean bean) { - return dataSource().queryColumnMap(entityType(), funcNodes, groupByColumns, bean); - } - - /** - * 查询符合过滤条件记录的GROUP BY聚合结果Map
- * 等价SQL: SELECT col1, col2, FUNC{funcColumn1}, FUNC{funcColumn2} FROM {table} WHERE {filter bean} GROUP BY {col1}, - * {col2}
- * 如 queryColumnMapAsync(OrderRecord.class, Utility.ofArray(ColumnExpNode.div(ColumnFuncNode.sum("money"), 100), - * ColumnFuncNode.avg(ColumnExpNode.dec("money", 20)))), Utility.ofArray("fromid", "targetid"), (FilterBean)null) - * 等价于: SELECT fromid, targetid, SUM(money) / 100, AVG(money - 20) FROM orderrecord GROUP BY fromid, targetid
- * - * @param Key字段的数据类型 - * @param Number - * @param funcNodes ColumnNode[] - * @param groupByColumns GROUP BY字段 - * @param bean 过滤条件 - * @return 聚合结果Map CompletableFuture - */ - default CompletableFuture> queryColumnMapAsync( - ColumnNode[] funcNodes, String[] groupByColumns, FilterBean bean) { - return dataSource().queryColumnMapAsync(entityType(), funcNodes, groupByColumns, bean); - } - - /** - * 查询符合过滤条件记录的GROUP BY聚合结果Map
- * 等价SQL: SELECT col1, col2, FUNC{funcColumn1}, FUNC{funcColumn2} FROM {table} WHERE {filter node} GROUP BY {col1}, - * {col2}
- * 如 queryColumnMapAsync(OrderRecord.class, Utility.ofArray(ColumnExpNode.div(ColumnFuncNode.sum("money"), 100), - * ColumnFuncNode.avg(ColumnExpNode.dec("money", 20)))), Utility.ofArray("fromid", "targetid"), (FilterNode)null) - * 等价于: SELECT fromid, targetid, SUM(money) / 100, AVG(money - 20) FROM orderrecord GROUP BY fromid, targetid
- * - * @param Key字段的数据类型 - * @param Number - * @param funcNodes ColumnNode[] - * @param groupByColumns GROUP BY字段 - * @param node 过滤条件 - * @return 聚合结果Map - */ - default Map queryColumnMap( - ColumnNode[] funcNodes, String[] groupByColumns, FilterNode node) { - return dataSource().queryColumnMap(entityType(), funcNodes, groupByColumns, node); - } - - /** - * 查询符合过滤条件记录的GROUP BY聚合结果Map
- * 等价SQL: SELECT col1, col2, FUNC{funcColumn1}, FUNC{funcColumn2} FROM {table} WHERE {filter node} GROUP BY {col1}, - * {col2}
- * 如 queryColumnMapAsync(OrderRecord.class, Utility.ofArray(ColumnExpNode.div(ColumnFuncNode.sum("money"), 100), - * ColumnFuncNode.avg(ColumnExpNode.dec("money", 20)))), Utility.ofArray("fromid", "targetid"), (FilterNode)null) - * 等价于: SELECT fromid, targetid, SUM(money) / 100, AVG(money - 20) FROM orderrecord GROUP BY fromid, targetid
- * - * @param Key字段的数据类型 - * @param Number - * @param funcNodes ColumnNode[] - * @param groupByColumns GROUP BY字段 - * @param node 过滤条件 - * @return 聚合结果Map CompletableFuture - */ - default CompletableFuture> queryColumnMapAsync( - ColumnNode[] funcNodes, String[] groupByColumns, FilterNode node) { - return dataSource().queryColumnMapAsync(entityType(), funcNodes, groupByColumns, node); - } - - // -----------------------findAsync---------------------------- - /** - * 获取指定主键值的单个记录, 返回null表示不存在值
- * 等价SQL: SELECT * FROM {table} WHERE {primary} = {id}
- * - * @param pk 主键值 - * @return Entity对象 - */ - default T find(Serializable pk) { - return dataSource().find(entityType(), pk); - } - - /** - * 获取指定主键值的单个记录, 返回null表示不存在值
- * 等价SQL: SELECT * FROM {table} WHERE {primary} = {id}
- * - * @param pk 主键值 - * @return Entity对象 CompletableFuture - */ - default CompletableFuture findAsync(Serializable pk) { - return dataSource().findAsync(entityType(), pk); - } - - /** - * 获取指定主键值的单个记录, 返回null表示不存在值
- * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {primary} = {id}
- * - * @param selects 指定字段 - * @param pk 主键值 - * @return Entity对象 - */ - default T find(SelectColumn selects, Serializable pk) { - return dataSource().find(entityType(), selects, pk); - } - - /** - * 获取指定主键值的单个记录, 返回null表示不存在值
- * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {primary} = {id}
- * - * @param selects 指定字段 - * @param pk 主键值 - * @return Entity对象CompletableFuture - */ - default CompletableFuture findAsync(SelectColumn selects, Serializable pk) { - return dataSource().findAsync(entityType(), selects, pk); - } - - /** - * 获取指定主键值的多个记录, 返回数组,数组长度与pks一样
- * 等价SQL: SELECT * FROM {table} WHERE {primary} = {id1,id2, ···}
- * - * @param pks 主键值集合 - * @return Entity对象 - */ - default T[] finds(Serializable... pks) { - return dataSource().finds(entityType(), pks); - } - - /** - * 获取指定主键值的多个记录, 返回数组,数组长度与pks一样
- * 等价SQL: SELECT * FROM {table} WHERE {primary} = {id1,id2, ···}
- * - * @param 主键泛型 - * @param pks 主键值集合 - * @return Entity对象 - */ - default T[] finds(Stream pks) { - return dataSource().finds(entityType(), pks); - } - - /** - * 获取指定主键值的多个记录, 返回数组,数组长度与pks一样
- * 等价SQL: SELECT * FROM {table} WHERE {primary} = {id1,id2, ···}
- * - * @param pks 主键值集合 - * @return Entity对象 CompletableFuture - */ - default CompletableFuture findsAsync(Serializable... pks) { - return dataSource().findsAsync(entityType(), pks); - } - - /** - * 获取指定主键值的多个记录, 返回数组,数组长度与pks一样
- * 等价SQL: SELECT * FROM {table} WHERE {primary} = {id1,id2, ···}
- * - * @param 主键泛型 - * @param pks 主键值集合 - * @return Entity对象 CompletableFuture - */ - default CompletableFuture findsAsync(Stream pks) { - return dataSource().findsAsync(entityType(), pks); - } - - /** - * 获取指定主键值的多个记录, 返回数组,数组长度与pks一样
- * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {primary} = {id1,id2, - * ···}
- * - * @param selects 指定字段 - * @param pks 主键值集合 - * @return Entity对象 - */ - default T[] finds(SelectColumn selects, Serializable... pks) { - return dataSource().finds(entityType(), selects, pks); - } - - /** - * 获取指定主键值的多个记录, 返回数组,数组长度与pks一样
- * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {primary} = {id1,id2, - * ···}
- * - * @param 主键泛型 - * @param selects 指定字段 - * @param pks 主键值集合 - * @return Entity对象 - */ - default T[] finds(SelectColumn selects, Stream pks) { - return dataSource().finds(entityType(), selects, pks); - } - - /** - * 获取指定主键值的多个记录, 返回数组,数组长度与pks一样
- * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {primary} = {id1,id2, - * ···}
- * - * @param selects 指定字段 - * @param pks 主键值集合 - * @return Entity对象CompletableFuture - */ - default CompletableFuture findsAsync(SelectColumn selects, Serializable... pks) { - return dataSource().findsAsync(entityType(), selects, pks); - } - - /** - * 获取指定主键值的多个记录, 返回数组,数组长度与pks一样
- * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {primary} = {id1,id2, - * ···}
- * - * @param 主键泛型 - * @param selects 指定字段 - * @param pks 主键值集合 - * @return Entity对象 - */ - default CompletableFuture findsAsync(SelectColumn selects, Stream pks) { - return dataSource().findsAsync(entityType(), selects, pks); - } - - /** - * 获取指定主键值的多个记录, 返回列表
- * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {primary} = {id1,id2, - * ···}
- * - * @param 主键泛型 - * @param pks 主键值集合 - * @return Entity对象 - */ - default List findsList(Stream pks) { - return dataSource().findsList(entityType(), pks); - } - - /** - * 获取指定主键值的多个记录, 返回列表
- * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {primary} = {id1,id2, - * ···}
- * - * @param 主键泛型 - * @param pks 主键值集合 - * @return Entity对象 - */ - default CompletableFuture> findsListAsync(Stream pks) { - return dataSource().findsListAsync(entityType(), pks); - } - - /** - * 获取符合过滤条件单个记录, 返回null表示不存在值
- * 等价SQL: SELECT * FROM {table} WHERE {column} = {key}
- * - * @param column 过滤字段名 - * @param colval 过滤字段值 - * @return Entity对象 - */ - default T find(String column, Serializable colval) { - return dataSource().find(entityType(), column, colval); - } - - /** - * 获取符合过滤条件单个记录, 返回null表示不存在值
- * 等价SQL: SELECT * FROM {table} WHERE {column} = {key}
- * - * @param column 过滤字段名 - * @param colval 过滤字段值 - * @return Entity对象CompletableFuture - */ - default CompletableFuture findAsync(String column, Serializable colval) { - return dataSource().findAsync(entityType(), column, colval); - } - - /** - * 获取符合过滤条件单个记录, 返回null表示不存在值
- * 等价SQL: SELECT * FROM {table} WHERE {column} = {key}
- * - * @param func 更新值Lambda - * @return Entity对象 - */ - default T find(LambdaSupplier func) { - return dataSource().find(entityType(), func); - } - - /** - * 获取符合过滤条件单个记录, 返回null表示不存在值
- * 等价SQL: SELECT * FROM {table} WHERE {column} = {key}
- * - * @param func 更新值Lambda - * @return Entity对象 - */ - default CompletableFuture findAsync(LambdaSupplier func) { - return dataSource().findAsync(entityType(), func); - } - - /** - * 获取符合过滤条件单个记录, 返回null表示不存在值
- * 等价SQL: SELECT * FROM {table} WHERE {filter bean}
- * - * @param bean 过滤条件 - * @return Entity对象 - */ - default T find(FilterBean bean) { - return dataSource().find(entityType(), bean); - } - - /** - * 获取符合过滤条件单个记录, 返回null表示不存在值
- * 等价SQL: SELECT * FROM {table} WHERE {filter bean}
- * - * @param bean 过滤条件 - * @return Entity对象CompletableFuture - */ - default CompletableFuture findAsync(FilterBean bean) { - return dataSource().findAsync(entityType(), bean); - } - - /** - * 获取符合过滤条件单个记录, 返回null表示不存在值
- * 等价SQL: SELECT * FROM {table} WHERE {filter node}
- * - * @param node 过滤条件 - * @return Entity对象 - */ - default T find(FilterNode node) { - return dataSource().find(entityType(), node); - } - - /** - * 获取符合过滤条件单个记录, 返回null表示不存在值
- * 等价SQL: SELECT * FROM {table} WHERE {filter node}
- * - * @param node 过滤条件 - * @return Entity对象CompletableFuture - */ - default CompletableFuture findAsync(FilterNode node) { - return dataSource().findAsync(entityType(), node); - } - - /** - * 获取符合过滤条件单个记录, 返回null表示不存在值
- * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter bean}
- * - * @param selects 指定字段 - * @param bean 过滤条件 - * @return Entity对象 - */ - default T find(SelectColumn selects, FilterBean bean) { - return dataSource().find(entityType(), selects, bean); - } - - /** - * 获取符合过滤条件单个记录, 返回null表示不存在值
- * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter bean}
- * - * @param selects 指定字段 - * @param bean 过滤条件 - * @return Entity对象 CompletableFuture - */ - default CompletableFuture findAsync(SelectColumn selects, FilterBean bean) { - return dataSource().findAsync(entityType(), selects, bean); - } - - /** - * 获取符合过滤条件单个记录, 返回null表示不存在值
- * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter node}
- * - * @param selects 指定字段 - * @param node 过滤条件 - * @return Entity对象 - */ - default T find(SelectColumn selects, FilterNode node) { - return dataSource().find(entityType(), selects, node); - } - - /** - * 获取符合过滤条件单个记录, 返回null表示不存在值
- * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter node}
- * - * @param selects 指定字段 - * @param node 过滤条件 - * @return Entity对象 CompletableFuture - */ - default CompletableFuture findAsync(SelectColumn selects, FilterNode node) { - return dataSource().findAsync(entityType(), selects, node); - } - - /** - * 获取符合过滤条件单个记录的单个字段值, 返回null表示不存在值
- * 等价SQL: SELECT {column} FROM {table} WHERE {primary} = {id}
- * - * @param column 字段名 - * @param pk 主键值 - * @return Entity对象 - */ - default Serializable findColumn(String column, Serializable pk) { - return dataSource().findColumn(entityType(), column, pk); - } - - /** - * 获取符合过滤条件单个记录的单个字段值, 返回null表示不存在值
- * 等价SQL: SELECT {column} FROM {table} WHERE {primary} = {id}
- * - * @param column 字段名 - * @param pk 主键值 - * @return Entity对象 CompletableFuture - */ - default CompletableFuture findColumnAsync(String column, Serializable pk) { - return dataSource().findColumnAsync(entityType(), column, pk); - } - - /** - * 获取符合过滤条件单个记录的单个字段值, 返回null表示不存在值
- * 等价SQL: SELECT {column} FROM {table} WHERE {filter bean}
- * - * @param column 字段名 - * @param bean 过滤条件 - * @return 字段值 - */ - default Serializable findColumn(String column, FilterBean bean) { - return dataSource().findColumn(entityType(), column, bean); - } - - /** - * 获取符合过滤条件单个记录的单个字段值, 返回null表示不存在值
- * 等价SQL: SELECT {column} FROM {table} WHERE {filter bean}
- * - * @param column 字段名 - * @param bean 过滤条件 - * @return 字段值 CompletableFuture - */ - default CompletableFuture findColumnAsync(String column, FilterBean bean) { - return dataSource().findColumnAsync(entityType(), column, bean); - } - - /** - * 获取符合过滤条件单个记录的单个字段值, 返回null表示不存在值
- * 等价SQL: SELECT {column} FROM {table} WHERE {filter node}
- * - * @param column 字段名 - * @param node 过滤条件 - * @return 字段值 - */ - default Serializable findColumn(String column, FilterNode node) { - return dataSource().findColumn(entityType(), column, node); - } - - /** - * 获取符合过滤条件单个记录的单个字段值, 返回null表示不存在值
- * 等价SQL: SELECT {column} FROM {table} WHERE {filter node}
- * - * @param column 字段名 - * @param node 过滤条件 - * @return 字段值 CompletableFuture - */ - default CompletableFuture findColumnAsync(String column, FilterNode node) { - return dataSource().findColumnAsync(entityType(), column, node); - } - - /** - * 获取符合过滤条件单个记录的单个字段值, 不存在值则返回默认值
- * 等价SQL: SELECT {column} FROM {table} WHERE {primary} = {id}
- * - * @param column 字段名 - * @param defValue 默认值 - * @param pk 主键值 - * @return 字段值 - */ - default Serializable findColumn(String column, Serializable defValue, Serializable pk) { - return dataSource().findColumn(entityType(), column, defValue, pk); - } - - /** - * 获取符合过滤条件单个记录的单个字段值, 不存在值则返回默认值
- * 等价SQL: SELECT {column} FROM {table} WHERE {primary} = {id}
- * - * @param column 字段名 - * @param defValue 默认值 - * @param pk 主键值 - * @return 字段值 CompletableFuture - */ - default CompletableFuture findColumnAsync(String column, Serializable defValue, Serializable pk) { - return dataSource().findColumnAsync(entityType(), column, defValue, pk); - } - - /** - * 获取符合过滤条件单个记录的单个字段值, 不存在值则返回默认值
- * 等价SQL: SELECT {column} FROM {table} WHERE {filter bean}
- * - * @param column 字段名 - * @param defValue 默认值 - * @param bean 过滤条件 - * @return 字段值 - */ - default Serializable findColumn(String column, Serializable defValue, FilterBean bean) { - return dataSource().findColumn(entityType(), column, defValue, bean); - } - - /** - * 获取符合过滤条件单个记录的单个字段值, 不存在值则返回默认值
- * 等价SQL: SELECT {column} FROM {table} WHERE {filter bean}
- * - * @param column 字段名 - * @param defValue 默认值 - * @param bean 过滤条件 - * @return 字段值 CompletableFuture - */ - default CompletableFuture findColumnAsync(String column, Serializable defValue, FilterBean bean) { - return dataSource().findColumnAsync(entityType(), column, defValue, bean); - } - - /** - * 获取符合过滤条件单个记录的单个字段值, 不存在值则返回默认值
- * 等价SQL: SELECT {column} FROM {table} WHERE {filter node}
- * - * @param column 字段名 - * @param defValue 默认值 - * @param node 过滤条件 - * @return 字段值 - */ - default Serializable findColumn(String column, Serializable defValue, FilterNode node) { - return dataSource().findColumn(entityType(), column, defValue, node); - } - - /** - * 获取符合过滤条件单个记录的单个字段值, 不存在值则返回默认值
- * 等价SQL: SELECT {column} FROM {table} WHERE {filter node}
- * - * @param column 字段名 - * @param defValue 默认值 - * @param node 过滤条件 - * @return 字段值 CompletableFuture - */ - default CompletableFuture findColumnAsync(String column, Serializable defValue, FilterNode node) { - return dataSource().findColumnAsync(entityType(), column, defValue, node); - } - - /** - * 判断是否存在主键值的记录
- * 等价SQL: SELECT COUNT(*) FROM {table} WHERE {primary} = {id}
- * - * @param pk 主键值 - * @return 是否存在 - */ - default boolean exists(Serializable pk) { - return dataSource().exists(entityType(), pk); - } - - /** - * 判断是否存在主键值的记录
- * 等价SQL: SELECT COUNT(*) FROM {table} WHERE {primary} = {id}
- * - * @param pk 主键值 - * @return 是否存在CompletableFuture - */ - default CompletableFuture existsAsync(Serializable pk) { - return dataSource().existsAsync(entityType(), pk); - } - - /** - * 判断是否存在符合过滤条件的记录
- * 等价SQL: SELECT COUNT(*) FROM {table} WHERE {filter bean}
- * - * @param bean 过滤条件 - * @return 是否存在 - */ - default boolean exists(FilterBean bean) { - return dataSource().exists(entityType(), bean); - } - - /** - * 判断是否存在符合过滤条件的记录
- * 等价SQL: SELECT COUNT(*) FROM {table} WHERE {filter bean}
- * - * @param bean 过滤条件 - * @return 是否存在CompletableFuture - */ - default CompletableFuture existsAsync(FilterBean bean) { - return dataSource().existsAsync(entityType(), bean); - } - - /** - * 判断是否存在符合过滤条件的记录
- * 等价SQL: SELECT COUNT(*) FROM {table} WHERE {filter node}
- * - * @param node 过滤条件 - * @return 是否存在 - */ - default boolean exists(FilterNode node) { - return dataSource().exists(entityType(), node); - } - - /** - * 判断是否存在符合过滤条件的记录
- * 等价SQL: SELECT COUNT(*) FROM {table} WHERE {filter node}
- * - * @param node 过滤条件 - * @return 是否存在CompletableFuture - */ - default CompletableFuture existsAsync(FilterNode node) { - return dataSource().existsAsync(entityType(), node); - } - - // -----------------------list set---------------------------- - /** - * 查询符合过滤条件记录的某个字段Set集合
- * 等价SQL: SELECT DISTINCT {selectedColumn} FROM {table} WHERE {column} = {key}
- * - * @param 字段类型 - * @param selectedColumn 指定字段 - * @param column 过滤字段名 - * @param colval 过滤字段值 - * @return 字段值的集合 - */ - default Set queryColumnSet(String selectedColumn, String column, Serializable colval) { - return dataSource().queryColumnSet(selectedColumn, entityType(), column, colval); - } - - /** - * 查询符合过滤条件记录的某个字段Set集合
- * 等价SQL: SELECT DISTINCT {selectedColumn} FROM {table} WHERE {column} = {key}
- * - * @param 字段类型 - * @param selectedColumn 指定字段 - * @param column 过滤字段名 - * @param colval 过滤字段值 - * @return 字段值的集合CompletableFuture - */ - default CompletableFuture> queryColumnSetAsync( - String selectedColumn, String column, Serializable colval) { - return dataSource().queryColumnSetAsync(selectedColumn, entityType(), column, colval); - } - - /** - * 查询符合过滤条件记录的某个字段Set集合
- * 等价SQL: SELECT DISTINCT {selectedColumn} FROM {table} WHERE {filter bean}
- * - * @param 字段类型 - * @param selectedColumn 指定字段 - * @param bean 过滤条件 - * @return 字段值的集合 - */ - default Set queryColumnSet(String selectedColumn, FilterBean bean) { - return dataSource().queryColumnSet(selectedColumn, entityType(), bean); - } - - /** - * 查询符合过滤条件记录的某个字段Set集合
- * 等价SQL: SELECT DISTINCT {selectedColumn} FROM {table} WHERE {filter bean}
- * - * @param 字段类型 - * @param selectedColumn 指定字段 - * @param bean 过滤条件 - * @return 字段值的集合CompletableFuture - */ - default CompletableFuture> queryColumnSetAsync( - String selectedColumn, FilterBean bean) { - return dataSource().queryColumnSetAsync(selectedColumn, entityType(), bean); - } - - /** - * 查询符合过滤条件记录的某个字段Set集合
- * 等价SQL: SELECT DISTINCT {selectedColumn} FROM {table} WHERE {filter node}
- * - * @param 字段类型 - * @param selectedColumn 指定字段 - * @param node 过滤条件 - * @return 字段值的集合 - */ - default Set queryColumnSet(String selectedColumn, FilterNode node) { - return dataSource().queryColumnSet(selectedColumn, entityType(), node); - } - - /** - * 查询符合过滤条件记录的某个字段Set集合
- * 等价SQL: SELECT DISTINCT {selectedColumn} FROM {table} WHERE {filter node}
- * - * @param 字段类型 - * @param selectedColumn 指定字段 - * @param node 过滤条件 - * @return 字段值的集合CompletableFuture - */ - default CompletableFuture> queryColumnSetAsync( - String selectedColumn, FilterNode node) { - return dataSource().queryColumnSetAsync(selectedColumn, entityType(), node); - } - - /** - * 查询符合过滤条件记录的某个字段Set集合
- * 等价SQL: SELECT DISTINCT {selectedColumn} FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT - * {flipper.limit}
- * - * @param 字段类型 - * @param selectedColumn 指定字段 - * @param flipper 翻页对象 - * @param bean 过滤条件 - * @return 字段值的集合 - */ - default Set queryColumnSet(String selectedColumn, Flipper flipper, FilterBean bean) { - return dataSource().queryColumnSet(selectedColumn, entityType(), flipper, bean); - } - - /** - * 查询符合过滤条件记录的某个字段Set集合
- * 等价SQL: SELECT DISTINCT {selectedColumn} FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT - * {flipper.limit}
- * - * @param 字段类型 - * @param selectedColumn 指定字段 - * @param flipper 翻页对象 - * @param bean 过滤条件 - * @return 字段值的集合CompletableFuture - */ - default CompletableFuture> queryColumnSetAsync( - String selectedColumn, Flipper flipper, FilterBean bean) { - return dataSource().queryColumnSetAsync(selectedColumn, entityType(), flipper, bean); - } - - /** - * 查询符合过滤条件记录的某个字段Set集合
- * 等价SQL: SELECT DISTINCT {selectedColumn} FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT - * {flipper.limit}
- * - * @param 字段类型 - * @param selectedColumn 指定字段 - * @param flipper 翻页对象 - * @param node 过滤条件 - * @return 字段值的集合 - */ - default Set queryColumnSet(String selectedColumn, Flipper flipper, FilterNode node) { - return dataSource().queryColumnSet(selectedColumn, entityType(), flipper, node); - } - - /** - * 查询符合过滤条件记录的某个字段Set集合
- * 等价SQL: SELECT DISTINCT {selectedColumn} FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT - * {flipper.limit}
- * - * @param 字段类型 - * @param selectedColumn 指定字段 - * @param flipper 翻页对象 - * @param node 过滤条件 - * @return 字段值的集合CompletableFuture - */ - default CompletableFuture> queryColumnSetAsync( - String selectedColumn, Flipper flipper, FilterNode node) { - return dataSource().queryColumnSetAsync(selectedColumn, entityType(), flipper, node); - } - - /** - * 查询符合过滤条件记录的某个字段List集合
- * 等价SQL: SELECT {selectedColumn} FROM {table} WHERE {column} = {key}
- * - * @param 字段类型 - * @param selectedColumn 指定字段 - * @param column 过滤字段名 - * @param colval 过滤字段值 - * @return 字段值的集合 - */ - default List queryColumnList( - String selectedColumn, String column, Serializable colval) { - return dataSource().queryColumnList(selectedColumn, entityType(), column, colval); - } - - /** - * 查询符合过滤条件记录的某个字段List集合
- * 等价SQL: SELECT {selectedColumn} FROM {table} WHERE {column} = {key}
- * - * @param 字段类型 - * @param selectedColumn 指定字段 - * @param column 过滤字段名 - * @param colval 过滤字段值 - * @return 字段值的集合CompletableFuture - */ - default CompletableFuture> queryColumnListAsync( - String selectedColumn, String column, Serializable colval) { - return dataSource().queryColumnListAsync(selectedColumn, entityType(), column, colval); - } - - /** - * 查询符合过滤条件记录的某个字段List集合
- * 等价SQL: SELECT {selectedColumn} FROM {table} WHERE {filter bean}
- * - * @param 字段类型 - * @param selectedColumn 指定字段 - * @param bean 过滤条件 - * @return 字段值的集合 - */ - default List queryColumnList(String selectedColumn, FilterBean bean) { - return dataSource().queryColumnList(selectedColumn, entityType(), bean); - } - - /** - * 查询符合过滤条件记录的某个字段List集合
- * 等价SQL: SELECT {selectedColumn} FROM {table} WHERE {filter bean}
- * - * @param 字段类型 - * @param selectedColumn 指定字段 - * @param bean 过滤条件 - * @return 字段值的集合CompletableFuture - */ - default CompletableFuture> queryColumnListAsync( - String selectedColumn, FilterBean bean) { - return dataSource().queryColumnListAsync(selectedColumn, entityType(), bean); - } - - /** - * 查询符合过滤条件记录的某个字段List集合
- * 等价SQL: SELECT {selectedColumn} FROM {table} WHERE {filter node}
- * - * @param 字段类型 - * @param selectedColumn 指定字段 - * @param node 过滤条件 - * @return 字段值的集合 - */ - default List queryColumnList(String selectedColumn, FilterNode node) { - return dataSource().queryColumnList(selectedColumn, entityType(), node); - } - - /** - * 查询符合过滤条件记录的某个字段List集合
- * 等价SQL: SELECT {selectedColumn} FROM {table} WHERE {filter node}
- * - * @param 字段类型 - * @param selectedColumn 指定字段 - * @param node 过滤条件 - * @return 字段值的集合CompletableFuture - */ - default CompletableFuture> queryColumnListAsync( - String selectedColumn, FilterNode node) { - return dataSource().queryColumnListAsync(selectedColumn, entityType(), node); - } - - /** - * 查询符合过滤条件记录的某个字段List集合
- * 等价SQL: SELECT {selectedColumn} FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit} - *
- * - * @param 字段类型 - * @param selectedColumn 指定字段 - * @param flipper 翻页对象 - * @param bean 过滤条件 - * @return 字段值的集合 - */ - default List queryColumnList(String selectedColumn, Flipper flipper, FilterBean bean) { - return dataSource().queryColumnList(selectedColumn, entityType(), flipper, bean); - } - - /** - * 查询符合过滤条件记录的某个字段List集合
- * 等价SQL: SELECT {selectedColumn} FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit} - *
- * - * @param 字段类型 - * @param selectedColumn 指定字段 - * @param flipper 翻页对象 - * @param bean 过滤条件 - * @return 字段值的集合CompletableFuture - */ - default CompletableFuture> queryColumnListAsync( - String selectedColumn, Flipper flipper, FilterBean bean) { - return dataSource().queryColumnListAsync(selectedColumn, entityType(), flipper, bean); - } - - /** - * 查询符合过滤条件记录的某个字段List集合
- * 等价SQL: SELECT {selectedColumn} FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit} - *
- * - * @param 字段类型 - * @param selectedColumn 指定字段 - * @param flipper 翻页对象 - * @param node 过滤条件 - * @return 字段值的集合 - */ - default List queryColumnList(String selectedColumn, Flipper flipper, FilterNode node) { - return dataSource().queryColumnList(selectedColumn, entityType(), flipper, node); - } - - /** - * 查询符合过滤条件记录的某个字段List集合
- * 等价SQL: SELECT {selectedColumn} FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit} - *
- * - * @param 字段类型 - * @param selectedColumn 指定字段 - * @param flipper 翻页对象 - * @param node 过滤条件 - * @return 字段值的集合CompletableFuture - */ - default CompletableFuture> queryColumnListAsync( - String selectedColumn, Flipper flipper, FilterNode node) { - return dataSource().queryColumnListAsync(selectedColumn, entityType(), flipper, node); - } - - /** - * 查询符合过滤条件记录的某个字段Sheet集合
- * 等价SQL: SELECT {selectedColumn} FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit} - *
- * - * @param 字段类型 - * @param selectedColumn 指定字段 - * @param flipper 翻页对象 - * @param bean 过滤条件 - * @return 字段值的集合 - */ - default Sheet queryColumnSheet( - String selectedColumn, Flipper flipper, FilterBean bean) { - return dataSource().queryColumnSheet(selectedColumn, entityType(), flipper, bean); - } - - /** - * 查询符合过滤条件记录的某个字段Sheet集合
- * 等价SQL: SELECT {selectedColumn} FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit} - *
- * - * @param 字段类型 - * @param selectedColumn 指定字段 - * @param flipper 翻页对象 - * @param bean 过滤条件 - * @return 字段值的集合CompletableFuture - */ - default CompletableFuture> queryColumnSheetAsync( - String selectedColumn, Flipper flipper, FilterBean bean) { - return dataSource().queryColumnSheetAsync(selectedColumn, entityType(), flipper, bean); - } - - /** - * 查询符合过滤条件记录的某个字段Sheet集合
- * 等价SQL: SELECT {selectedColumn} FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit} - *
- * - * @param 字段类型 - * @param selectedColumn 指定字段 - * @param flipper 翻页对象 - * @param node 过滤条件 - * @return 字段值的集合 - */ - default Sheet queryColumnSheet( - String selectedColumn, Flipper flipper, FilterNode node) { - return dataSource().queryColumnSheet(selectedColumn, entityType(), flipper, node); - } - - /** - * 查询符合过滤条件记录的某个字段Sheet集合
- * 等价SQL: SELECT {selectedColumn} FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit} - *
- * - * @param 字段类型 - * @param selectedColumn 指定字段 - * @param flipper 翻页对象 - * @param node 过滤条件 - * @return 字段值的集合CompletableFuture - */ - default CompletableFuture> queryColumnSheetAsync( - String selectedColumn, Flipper flipper, FilterNode node) { - return dataSource().queryColumnSheetAsync(selectedColumn, entityType(), flipper, node); - } - - /** - * 查询符合过滤条件记录的List转Map集合, key=主键值, value=Entity对象
- * 等价SQL: SELECT * FROM {table} WHERE id IN {ids}
- * - * @param 主键泛型 - * @param keyStream 主键Stream - * @return Entity的集合 - */ - default Map queryMap(Stream keyStream) { - return dataSource().queryMap(entityType(), keyStream); - } - - /** - * 查询符合过滤条件记录的List转Map集合, key=主键值, value=Entity对象
- * 等价SQL: SELECT * FROM {table} WHERE id IN {ids}
- * - * @param 主键泛型 - * @param keyStream 主键Stream - * @return Entity的集合CompletableFuture - */ - default CompletableFuture> queryMapAsync(Stream keyStream) { - return dataSource().queryMapAsync(entityType(), keyStream); - } - - /** - * 查询符合过滤条件记录的List转Map集合, key=主键值, value=Entity对象
- * 等价SQL: SELECT * FROM {table} WHERE {filter node}
- * - * @param 主键泛型 - * @param bean FilterBean - * @return Entity的集合 - */ - default Map queryMap(FilterBean bean) { - return dataSource().queryMap(entityType(), bean); - } - - /** - * 查询符合过滤条件记录的List转Map集合, key=主键值, value=Entity对象
- * 等价SQL: SELECT * FROM {table} WHERE {filter node}
- * - * @param 主键泛型 - * @param bean FilterBean - * @return Entity的集合CompletableFuture - */ - default CompletableFuture> queryMapAsync(FilterBean bean) { - return dataSource().queryMapAsync(entityType(), bean); - } - - /** - * 查询符合过滤条件记录的List转Map集合, key=主键值, value=Entity对象
- * 等价SQL: SELECT * FROM {table} WHERE {filter node}
- * - * @param 主键泛型 - * @param node FilterNode - * @return Entity的集合 - */ - default Map queryMap(FilterNode node) { - return dataSource().queryMap(entityType(), node); - } - - /** - * 查询符合过滤条件记录的List转Map集合, key=主键值, value=Entity对象
- * 等价SQL: SELECT * FROM {table} WHERE {filter node}
- * - * @param 主键泛型 - * @param node FilterNode - * @return Entity的集合CompletableFuture - */ - default CompletableFuture> queryMapAsync(FilterNode node) { - return dataSource().queryMapAsync(entityType(), node); - } - - /** - * 查询符合过滤条件记录的List转Map集合, key=主键值, value=Entity对象
- * 等价SQL: SELECT * FROM {table} WHERE id IN {ids}
- * - * @param 主键泛型 - * @param selects 指定字段 - * @param keyStream 主键Stream - * @return Entity的集合 - */ - default Map queryMap(SelectColumn selects, Stream keyStream) { - return dataSource().queryMap(entityType(), selects, keyStream); - } - - /** - * 查询符合过滤条件记录的List转Map集合, key=主键值, value=Entity对象
- * 等价SQL: SELECT * FROM {table} WHERE id IN {ids}
- * - * @param 主键泛型 - * @param selects 指定字段 - * @param keyStream 主键Stream - * @return Entity的集合CompletableFuture - */ - default CompletableFuture> queryMapAsync( - SelectColumn selects, Stream keyStream) { - return dataSource().queryMapAsync(entityType(), selects, keyStream); - } - - /** - * 查询符合过滤条件记录的List转Map集合, key=主键值, value=Entity对象
- * 等价SQL: SELECT * FROM {table} WHERE {filter node}
- * - * @param 主键泛型 - * @param selects 指定字段 - * @param bean FilterBean - * @return Entity的集合 - */ - default Map queryMap(SelectColumn selects, FilterBean bean) { - return dataSource().queryMap(entityType(), selects, bean); - } - - /** - * 查询符合过滤条件记录的List转Map集合, key=主键值, value=Entity对象
- * 等价SQL: SELECT * FROM {table} WHERE {filter node}
- * - * @param 主键泛型 - * @param selects 指定字段 - * @param bean FilterBean - * @return Entity的集合CompletableFuture - */ - default CompletableFuture> queryMapAsync(SelectColumn selects, FilterBean bean) { - return dataSource().queryMapAsync(entityType(), selects, bean); - } - - /** - * 查询符合过滤条件记录的List转Map集合, key=主键值, value=Entity对象
- * 等价SQL: SELECT * FROM {table} WHERE {filter node}
- * - * @param 主键泛型 - * @param selects 指定字段 - * @param node FilterNode - * @return Entity的集合 - */ - default Map queryMap(SelectColumn selects, FilterNode node) { - return dataSource().queryMap(entityType(), selects, node); - } - - /** - * 查询符合过滤条件记录的List转Map集合, key=主键值, value=Entity对象
- * 等价SQL: SELECT * FROM {table} WHERE {filter node}
- * - * @param 主键泛型 - * @param selects 指定字段 - * @param node FilterNode - * @return Entity的集合CompletableFuture - */ - default CompletableFuture> queryMapAsync(SelectColumn selects, FilterNode node) { - return dataSource().queryMapAsync(entityType(), selects, node); - } - - /** - * 查询符合过滤条件记录的Set集合
- * 等价SQL: SELECT DISTINCT * FROM {table} WHERE {column} = {key} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param column 过滤字段名 - * @param colval 过滤字段值 - * @return Entity的集合 - */ - default Set querySet(String column, Serializable colval) { - return dataSource().querySet(entityType(), column, colval); - } - - /** - * 查询符合过滤条件记录的Set集合
- * 等价SQL: SELECT DISTINCT * FROM {table} WHERE {column} = {key} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param column 过滤字段名 - * @param colval 过滤字段值 - * @return Entity的集合CompletableFuture - */ - default CompletableFuture> querySetAsync(String column, Serializable colval) { - return dataSource().querySetAsync(entityType(), column, colval); - } - - /** - * 查询符合过滤条件记录的Set集合
- * 等价SQL: SELECT DISTINCT * FROM {table} WHERE {filter bean}
- * - * @param bean 过滤条件 - * @return Entity的集合 - */ - default Set querySet(FilterBean bean) { - return dataSource().querySet(entityType(), bean); - } - - /** - * 查询符合过滤条件记录的Set集合
- * 等价SQL: SELECT DISTINCT * FROM {table} WHERE {filter bean}
- * - * @param bean 过滤条件 - * @return Entity的集合CompletableFuture - */ - default CompletableFuture> querySetAsync(FilterBean bean) { - return dataSource().querySetAsync(entityType(), bean); - } - - /** - * 查询记录的Set集合
- * 等价SQL: SELECT DISTINCT * FROM {table}
- * - * @return Entity的集合 - */ - default Set querySet() { - return dataSource().querySet(entityType()); - } - - /** - * 查询符合过滤条件记录的Set集合
- * 等价SQL: SELECT DISTINCT * FROM {table} WHERE {filter node}
- * - * @param node 过滤条件 - * @return Entity的集合 - */ - default Set querySet(FilterNode node) { - return dataSource().querySet(entityType(), node); - } - - /** - * 查询记录的Set集合
- * 等价SQL: SELECT DISTINCT * FROM {table}
- * - * @return Entity的集合CompletableFuture - */ - default CompletableFuture> querySetAsync() { - return dataSource().querySetAsync(entityType()); - } - - /** - * 查询符合过滤条件记录的Set集合
- * 等价SQL: SELECT DISTINCT * FROM {table} WHERE {filter node}
- * - * @param node 过滤条件 - * @return Entity的集合CompletableFuture - */ - default CompletableFuture> querySetAsync(FilterNode node) { - return dataSource().querySetAsync(entityType(), node); - } - - /** - * 查询符合过滤条件记录的Set集合
- * 等价SQL: SELECT DISTINCT {column1},{column2}, ··· FROM {table} WHERE {filter bean}
- * - * @param selects 指定字段 - * @param bean 过滤条件 - * @return Entity的集合 - */ - default Set querySet(SelectColumn selects, FilterBean bean) { - return dataSource().querySet(entityType(), selects, bean); - } - - /** - * 查询符合过滤条件记录的Set集合
- * 等价SQL: SELECT DISTINCT {column1},{column2}, ··· FROM {table} WHERE {filter bean}
- * - * @param selects 指定字段 - * @param bean 过滤条件 - * @return Entity的集合CompletableFuture - */ - default CompletableFuture> querySetAsync(SelectColumn selects, FilterBean bean) { - return dataSource().querySetAsync(entityType(), selects, bean); - } - - /** - * 查询符合过滤条件记录的Set集合
- * 等价SQL: SELECT DISTINCT {column1},{column2}, ··· FROM {table} WHERE {filter node}
- * - * @param selects 指定字段 - * @param node 过滤条件 - * @return Entity的集合 - */ - default Set querySet(SelectColumn selects, FilterNode node) { - return dataSource().querySet(entityType(), selects, node); - } - - /** - * 查询符合过滤条件记录的Set集合
- * 等价SQL: SELECT DISTINCT {column1},{column2}, ··· FROM {table} WHERE {filter node}
- * - * @param selects 指定字段 - * @param node 过滤条件 - * @return Entity的集合CompletableFuture - */ - default CompletableFuture> querySetAsync(SelectColumn selects, FilterNode node) { - return dataSource().querySetAsync(entityType(), selects, node); - } - - /** - * 查询符合过滤条件记录的Set集合
- * 等价SQL: SELECT DISTINCT * FROM {table} WHERE {column} = {key} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param flipper 翻页对象 - * @param column 过滤字段名 - * @param colval 过滤字段值 - * @return Entity的集合 - */ - default Set querySet(Flipper flipper, String column, Serializable colval) { - return dataSource().querySet(entityType(), flipper, column, colval); - } - - /** - * 查询符合过滤条件记录的Set集合
- * 等价SQL: SELECT DISTINCT * FROM {table} WHERE {column} = {key} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param flipper 翻页对象 - * @param column 过滤字段名 - * @param colval 过滤字段值 - * @return Entity的集合CompletableFuture - */ - default CompletableFuture> querySetAsync(Flipper flipper, String column, Serializable colval) { - return dataSource().querySetAsync(entityType(), flipper, column, colval); - } - - /** - * 查询符合过滤条件记录的Set集合
- * 等价SQL: SELECT DISTINCT * FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param flipper 翻页对象 - * @param bean 过滤条件 - * @return Entity的集合 - */ - default Set querySet(Flipper flipper, FilterBean bean) { - return dataSource().querySet(entityType(), flipper, bean); - } - - /** - * 查询符合过滤条件记录的Set集合
- * 等价SQL: SELECT DISTINCT * FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param flipper 翻页对象 - * @param bean 过滤条件 - * @return Entity的集合CompletableFuture - */ - default CompletableFuture> querySetAsync(Flipper flipper, FilterBean bean) { - return dataSource().querySetAsync(entityType(), flipper, bean); - } - - /** - * 查询符合过滤条件记录的Set集合
- * 等价SQL: SELECT DISTINCT * FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param flipper 翻页对象 - * @param node 过滤条件 - * @return Entity的集合 - */ - default Set querySet(Flipper flipper, FilterNode node) { - return dataSource().querySet(entityType(), flipper, node); - } - - /** - * 查询符合过滤条件记录的Set集合
- * 等价SQL: SELECT DISTINCT * FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param flipper 翻页对象 - * @param node 过滤条件 - * @return Entity的集合 - */ - default CompletableFuture> querySetAsync(Flipper flipper, FilterNode node) { - return dataSource().querySetAsync(entityType(), flipper, node); - } - - /** - * 查询符合过滤条件记录的Set集合
- * 等价SQL: SELECT DISTINCT {column1},{column2}, ··· FROM {table} WHERE {filter bean} ORDER BY - * {flipper.sort} LIMIT {flipper.limit}
- * - * @param selects 指定字段 - * @param flipper 翻页对象 - * @param bean 过滤条件 - * @return Entity的集合 - */ - default Set querySet(SelectColumn selects, Flipper flipper, FilterBean bean) { - return dataSource().querySet(entityType(), selects, flipper, bean); - } - - /** - * 查询符合过滤条件记录的Set集合
- * 等价SQL: SELECT DISTINCT {column1},{column2}, ··· FROM {table} WHERE {filter bean} ORDER BY - * {flipper.sort} LIMIT {flipper.limit}
- * - * @param selects 指定字段 - * @param flipper 翻页对象 - * @param bean 过滤条件 - * @return Entity的集合CompletableFuture - */ - default CompletableFuture> querySetAsync(SelectColumn selects, Flipper flipper, FilterBean bean) { - return dataSource().querySetAsync(entityType(), selects, flipper, bean); - } - - /** - * 查询符合过滤条件记录的Set集合
- * 等价SQL: SELECT DISTINCT {column1},{column2}, ··· FROM {table} WHERE {filter node} ORDER BY - * {flipper.sort} LIMIT {flipper.limit}
- * - * @param selects 指定字段 - * @param flipper 翻页对象 - * @param node 过滤条件 - * @return Entity的集合 - */ - default Set querySet(SelectColumn selects, Flipper flipper, FilterNode node) { - return dataSource().querySet(entityType(), selects, flipper, node); - } - - /** - * 查询符合过滤条件记录的Set集合
- * 等价SQL: SELECT DISTINCT {column1},{column2}, ··· FROM {table} WHERE {filter node} ORDER BY - * {flipper.sort} LIMIT {flipper.limit}
- * - * @param selects 指定字段 - * @param flipper 翻页对象 - * @param node 过滤条件 - * @return Entity的集合CompletableFuture - */ - default CompletableFuture> querySetAsync(SelectColumn selects, Flipper flipper, FilterNode node) { - return dataSource().querySetAsync(entityType(), selects, flipper, node); - } - - /** - * 查询符合过滤条件记录的List集合
- * 等价SQL: SELECT * FROM {table} WHERE {column} = {key} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param column 过滤字段名 - * @param colval 过滤字段值 - * @return Entity的集合 - */ - default List queryList(String column, Serializable colval) { - return dataSource().queryList(entityType(), column, colval); - } - - /** - * 查询符合过滤条件记录的List集合
- * 等价SQL: SELECT * FROM {table} WHERE {column} = {key} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param column 过滤字段名 - * @param colval 过滤字段值 - * @return Entity的集合CompletableFuture - */ - default CompletableFuture> queryListAsync(String column, Serializable colval) { - return dataSource().queryListAsync(entityType(), column, colval); - } - - /** - * 查询符合过滤条件记录的List集合
- * 等价SQL: SELECT * FROM {table} WHERE {filter bean}
- * - * @param bean 过滤条件 - * @return Entity的集合 - */ - default List queryList(FilterBean bean) { - return dataSource().queryList(entityType(), bean); - } - - /** - * 查询符合过滤条件记录的List集合
- * 等价SQL: SELECT * FROM {table} WHERE {filter bean}
- * - * @param bean 过滤条件 - * @return Entity的集合CompletableFuture - */ - default CompletableFuture> queryListAsync(FilterBean bean) { - return dataSource().queryListAsync(entityType(), bean); - } - - /** - * 查询记录的List集合
- * 等价SQL: SELECT * FROM {table}
- * - * @return Entity的集合 - */ - default List queryList() { - return dataSource().queryList(entityType()); - } - - /** - * 查询符合过滤条件记录的List集合
- * 等价SQL: SELECT * FROM {table} WHERE {filter node}
- * - * @param node 过滤条件 - * @return Entity的集合 - */ - default List queryList(FilterNode node) { - return dataSource().queryList(entityType(), node); - } - - /** - * 查询记录的List集合
- * 等价SQL: SELECT * FROM {table}
- * - * @return Entity的集合CompletableFuture - */ - default CompletableFuture> queryListAsync() { - return dataSource().queryListAsync(entityType()); - } - - /** - * 查询符合过滤条件记录的List集合
- * 等价SQL: SELECT * FROM {table} WHERE {filter node}
- * - * @param node 过滤条件 - * @return Entity的集合CompletableFuture - */ - default CompletableFuture> queryListAsync(FilterNode node) { - return dataSource().queryListAsync(entityType(), node); - } - - /** - * 查询符合过滤条件记录的List集合
- * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter bean}
- * - * @param selects 指定字段 - * @param bean 过滤条件 - * @return Entity的集合 - */ - default List queryList(SelectColumn selects, FilterBean bean) { - return dataSource().queryList(entityType(), selects, bean); - } - - /** - * 查询符合过滤条件记录的List集合
- * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter bean}
- * - * @param selects 指定字段 - * @param bean 过滤条件 - * @return Entity的集合CompletableFuture - */ - default CompletableFuture> queryListAsync(SelectColumn selects, FilterBean bean) { - return dataSource().queryListAsync(entityType(), selects, bean); - } - - /** - * 查询符合过滤条件记录的List集合
- * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter node}
- * - * @param selects 指定字段 - * @param node 过滤条件 - * @return Entity的集合 - */ - default List queryList(SelectColumn selects, FilterNode node) { - return dataSource().queryList(entityType(), selects, node); - } - - /** - * 查询符合过滤条件记录的List集合
- * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter node}
- * - * @param selects 指定字段 - * @param node 过滤条件 - * @return Entity的集合CompletableFuture - */ - default CompletableFuture> queryListAsync(SelectColumn selects, FilterNode node) { - return dataSource().queryListAsync(entityType(), selects, node); - } - - /** - * 查询符合过滤条件记录的List集合
- * 等价SQL: SELECT * FROM {table} WHERE {column} = {key} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param flipper 翻页对象 - * @param column 过滤字段名 - * @param colval 过滤字段值 - * @return Entity的集合 - */ - default List queryList(Flipper flipper, String column, Serializable colval) { - return dataSource().queryList(entityType(), flipper, column, colval); - } - - /** - * 查询符合过滤条件记录的List集合
- * 等价SQL: SELECT * FROM {table} WHERE {column} = {key} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param flipper 翻页对象 - * @param column 过滤字段名 - * @param colval 过滤字段值 - * @return Entity的集合CompletableFuture - */ - default CompletableFuture> queryListAsync(Flipper flipper, String column, Serializable colval) { - return dataSource().queryListAsync(entityType(), flipper, column, colval); - } - - /** - * 查询符合过滤条件记录的List集合
- * 等价SQL: SELECT * FROM {table} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param flipper 翻页对象 - * @return Entity的集合 - */ - default List queryList(Flipper flipper) { - return dataSource().queryList(entityType(), flipper); - } - - /** - * 查询符合过滤条件记录的List集合
- * 等价SQL: SELECT * FROM {table} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param flipper 翻页对象 - * @return Entity的集合CompletableFuture - */ - default CompletableFuture> queryListAsync(Flipper flipper) { - return dataSource().queryListAsync(entityType(), flipper); - } - - /** - * 查询符合过滤条件记录的List集合
- * 等价SQL: SELECT * FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param flipper 翻页对象 - * @param bean 过滤条件 - * @return Entity的集合 - */ - default List queryList(Flipper flipper, FilterBean bean) { - return dataSource().queryList(entityType(), flipper, bean); - } - - /** - * 查询符合过滤条件记录的List集合
- * 等价SQL: SELECT * FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param flipper 翻页对象 - * @param bean 过滤条件 - * @return Entity的集合CompletableFuture - */ - default CompletableFuture> queryListAsync(Flipper flipper, FilterBean bean) { - return dataSource().queryListAsync(entityType(), flipper, bean); - } - - /** - * 查询符合过滤条件记录的List集合
- * 等价SQL: SELECT * FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param flipper 翻页对象 - * @param node 过滤条件 - * @return Entity的集合 - */ - default List queryList(Flipper flipper, FilterNode node) { - return dataSource().queryList(entityType(), flipper, node); - } - - /** - * 查询符合过滤条件记录的List集合
- * 等价SQL: SELECT * FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param flipper 翻页对象 - * @param node 过滤条件 - * @return Entity的集合 - */ - default CompletableFuture> queryListAsync(Flipper flipper, FilterNode node) { - return dataSource().queryListAsync(entityType(), flipper, node); - } - - /** - * 查询符合过滤条件记录的List集合
- * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} ORDER BY {flipper.sort} LIMIT {flipper.limit} - *
- * - * @param selects 指定字段 - * @param flipper 翻页对象 - * @return Entity的集合 - */ - default List queryList(SelectColumn selects, Flipper flipper) { - return dataSource().queryList(entityType(), selects, flipper); - } - - /** - * 查询符合过滤条件记录的List集合
- * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} ORDER BY {flipper.sort} LIMIT {flipper.limit} - *
- * - * @param selects 指定字段 - * @param flipper 翻页对象 - * @return Entity的集合CompletableFuture - */ - default CompletableFuture> queryListAsync(SelectColumn selects, Flipper flipper) { - return dataSource().queryListAsync(entityType(), selects, flipper); - } - - /** - * 查询符合过滤条件记录的List集合
- * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} - * LIMIT {flipper.limit}
- * - * @param selects 指定字段 - * @param flipper 翻页对象 - * @param bean 过滤条件 - * @return Entity的集合 - */ - default List queryList(SelectColumn selects, Flipper flipper, FilterBean bean) { - return dataSource().queryList(entityType(), selects, flipper, bean); - } - - /** - * 查询符合过滤条件记录的List集合
- * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} - * LIMIT {flipper.limit}
- * - * @param selects 指定字段 - * @param flipper 翻页对象 - * @param bean 过滤条件 - * @return Entity的集合CompletableFuture - */ - default CompletableFuture> queryListAsync(SelectColumn selects, Flipper flipper, FilterBean bean) { - return dataSource().queryListAsync(entityType(), selects, flipper, bean); - } - - /** - * 查询符合过滤条件记录的List集合
- * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter node} ORDER BY {flipper.sort} - * LIMIT {flipper.limit}
- * - * @param selects 指定字段 - * @param flipper 翻页对象 - * @param node 过滤条件 - * @return Entity的集合 - */ - default List queryList(SelectColumn selects, Flipper flipper, FilterNode node) { - return dataSource().queryList(entityType(), selects, flipper, node); - } - - /** - * 查询符合过滤条件记录的List集合
- * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter node} ORDER BY {flipper.sort} - * LIMIT {flipper.limit}
- * - * @param selects 指定字段 - * @param flipper 翻页对象 - * @param node 过滤条件 - * @return Entity的集合CompletableFuture - */ - default CompletableFuture> queryListAsync(SelectColumn selects, Flipper flipper, FilterNode node) { - return dataSource().queryListAsync(entityType(), selects, flipper, node); - } - - // -----------------------sheet---------------------------- - /** - * 查询符合过滤条件记录的Sheet集合
- * 等价SQL: SELECT * FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param flipper 翻页对象 - * @param bean 过滤条件 - * @return Entity的集合 - */ - default Sheet querySheet(Flipper flipper, FilterBean bean) { - return dataSource().querySheet(entityType(), flipper, bean); - } - - /** - * 查询符合过滤条件记录的Sheet集合
- * 等价SQL: SELECT * FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param 过滤类型 - * @param pageBean 过滤翻页条件 - * @return Entity的集合 - */ - default Sheet querySheet(PageBean pageBean) { - return dataSource().querySheet(entityType(), pageBean); - } - - /** - * 查询符合过滤条件记录的Sheet集合
- * 等价SQL: SELECT * FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param flipper 翻页对象 - * @param bean 过滤条件 - * @return Entity的集合CompletableFuture - */ - default CompletableFuture> querySheetAsync(Flipper flipper, FilterBean bean) { - return dataSource().querySheetAsync(entityType(), flipper, bean); - } - - /** - * 查询符合过滤条件记录的Sheet集合
- * 等价SQL: SELECT * FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param 过滤类型 - * @param pageBean 过滤翻页条件 - * @return Entity的集合 - */ - default CompletableFuture> querySheetAsync(PageBean pageBean) { - return dataSource().querySheetAsync(entityType(), pageBean); - } - - /** - * 查询符合过滤条件记录的Sheet集合
- * 等价SQL: SELECT * FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param flipper 翻页对象 - * @param node 过滤条件 - * @return Entity的集合 - */ - default Sheet querySheet(Flipper flipper, FilterNode node) { - return dataSource().querySheet(entityType(), flipper, node); - } - - /** - * 查询符合过滤条件记录的Sheet集合
- * 等价SQL: SELECT * FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param flipper 翻页对象 - * @param node 过滤条件 - * @return Entity的集合CompletableFuture - */ - default CompletableFuture> querySheetAsync(Flipper flipper, FilterNode node) { - return dataSource().querySheetAsync(entityType(), flipper, node); - } - - /** - * 查询符合过滤条件记录的Sheet集合
- * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} - * LIMIT {flipper.limit}
- * - * @param selects 指定字段 - * @param flipper 翻页对象 - * @param bean 过滤条件 - * @return Entity的集合 - */ - default Sheet querySheet(SelectColumn selects, Flipper flipper, FilterBean bean) { - return dataSource().querySheet(entityType(), selects, flipper, bean); - } - - /** - * 查询符合过滤条件记录的Sheet集合
- * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} - * LIMIT {flipper.limit}
- * - * @param 过滤类型 - * @param selects 指定字段 - * @param pageBean 过滤翻页条件 - * @return Entity的集合 - */ - default Sheet querySheet(SelectColumn selects, PageBean pageBean) { - return dataSource().querySheet(entityType(), selects, pageBean); - } - - /** - * 查询符合过滤条件记录的Sheet集合
- * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} - * LIMIT {flipper.limit}
- * - * @param selects 指定字段 - * @param flipper 翻页对象 - * @param bean 过滤条件 - * @return Entity的集合CompletableFuture - */ - default CompletableFuture> querySheetAsync(SelectColumn selects, Flipper flipper, FilterBean bean) { - return dataSource().querySheetAsync(entityType(), selects, flipper, bean); - } - - /** - * 查询符合过滤条件记录的Sheet集合
- * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} - * LIMIT {flipper.limit}
- * - * @param 过滤类型 - * @param selects 指定字段 - * @param pageBean 过滤翻页条件 - * @return Entity的集合 - */ - default CompletableFuture> querySheetAsync( - SelectColumn selects, PageBean pageBean) { - return dataSource().querySheetAsync(entityType(), selects, pageBean); - } - - /** - * 查询符合过滤条件记录的Sheet集合
- * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter node} ORDER BY {flipper.sort} - * LIMIT {flipper.limit}
- * - * @param selects 指定字段 - * @param flipper 翻页对象 - * @param node 过滤条件 - * @return Entity的集合 - */ - default Sheet querySheet(SelectColumn selects, Flipper flipper, FilterNode node) { - return dataSource().querySheet(entityType(), selects, flipper, node); - } - - /** - * 查询符合过滤条件记录的Sheet集合
- * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter node} ORDER BY {flipper.sort} - * LIMIT {flipper.limit}
- * - * @param selects 指定字段 - * @param flipper 翻页对象 - * @param node 过滤条件 - * @return Entity的集合CompletableFuture - */ - default CompletableFuture> querySheetAsync(SelectColumn selects, Flipper flipper, FilterNode node) { - return dataSource().querySheetAsync(entityType(), selects, flipper, node); - } -} +/* + * + */ +package org.redkale.source; + +import java.io.Serializable; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Stream; +import org.redkale.annotation.ClassDepends; +import org.redkale.util.LambdaFunction; +import org.redkale.util.LambdaSupplier; +import org.redkale.util.SelectColumn; +import org.redkale.util.Sheet; + +/** + * 类似Mybatis的Mapper接口类, 接口系列和DataSource相似度高
+ * 自定义的sql接口的返回结果类型只能是: void/基本数据类型/JavaBean/Map/List/Sheet
+ * 异步接口返回的是泛型为以上类型的CompletableFuture + * + *

+ * + *
+ * public interface ForumInfoMapper extends BaseMapper<ForumInfo> {
+ *
+ *   @Sql("SELECT f.forum_groupid, s.forum_section_color "
+ *      + "FROM forum_info f, forum_section s "
+ *      + " WHERE f.forumid = s.forumid AND "
+ *      + "s.forum_sectionid = #{bean.forumSectionid} AND "
+ *      + "f.forumid = #{bean.forumid} AND s.forum_section_color = #{bean.forumSectionColor}")
+ *   public ForumResult findForumResult(ForumBean bean);
+ *
+ *   @Sql("SELECT f.forum_groupid, s.forum_section_color "
+ *      + "FROM forum_info f, forum_section s "
+ *      + " WHERE f.forumid = s.forumid AND "
+ *      + "s.forum_sectionid = #{bean.forumSectionid} AND "
+ *      + "f.forumid = #{bean.forumid} AND s.forum_section_color = #{bean.forumSectionColor}")
+ *   public CompletableFuture<ForumResult> findForumResultAsync(ForumBean bean);
+ *
+ *   @Sql("SELECT f.forum_groupid, s.forum_section_color "
+ *      + "FROM forum_info f, forum_section s "
+ *      + " WHERE f.forumid = s.forumid AND "
+ *      + "s.forum_sectionid = #{bean.forumSectionid} AND "
+ *      + "f.forumid = #{bean.forumid} AND s.forum_section_color = #{bean.forumSectionColor}")
+ *   public List<ForumResult> queryForumResult(@Param("bean") ForumBean bean0);
+ *
+ *   @Sql("SELECT f.forum_groupid, s.forum_section_color "
+ *      + "FROM forum_info f, forum_section s "
+ *      + " WHERE f.forumid = s.forumid AND "
+ *      + "s.forum_sectionid = #{bean.forumSectionid} AND "
+ *      + "f.forumid = #{bean.forumid} AND s.forum_section_color = #{bean.forumSectionColor}")
+ *   public CompletableFuture<List<ForumResult>> queryForumResultAsync(ForumBean bean);
+ * }
+ * 
+ * + *
+ * + *

详情见: https://redkale.org + * + * @see org.redkale.source.spi.DataSqlMapperBuilder + * @see org.redkale.persistence.Sql + * @author zhangjx + * @param T + * @since 2.8.0 + */ +public interface DataSqlMapper { + + /** + * 获取当前数据源 + * + * @return DataSqlSource + */ + @ClassDepends + DataSqlSource dataSource(); + + /** + * 获取当前实体类型 + * + * @return Class + */ + @ClassDepends + Class entityType(); + + /** + * 新增记录
+ * + * @param entitys Entity对象 + * @return CompletableFuture + */ + default int insert(T... entitys) { + return dataSource().insert(entitys); + } + + /** + * 新增记录
+ * + * @param entitys Entity对象 + * @return CompletableFuture + */ + default int insert(Collection entitys) { + return dataSource().insert(entitys); + } + + /** + * 新增记录
+ * + * @param entitys Entity对象 + * @return CompletableFuture + */ + default int insert(Stream entitys) { + return dataSource().insert(entitys); + } + + /** + * 新增记录
+ * + * @param entitys Entity对象 + * @return CompletableFuture + */ + default CompletableFuture insertAsync(T... entitys) { + return dataSource().insertAsync(entitys); + } + + /** + * 新增记录
+ * + * @param entitys Entity对象 + * @return CompletableFuture + */ + default CompletableFuture insertAsync(Collection entitys) { + return dataSource().insertAsync(entitys); + } + + /** + * 新增记录
+ * + * @param entitys Entity对象 + * @return CompletableFuture + */ + default CompletableFuture insertAsync(Stream entitys) { + return dataSource().insertAsync(entitys); + } + + /** + * 删除指定主键值的记录
+ * 等价SQL: DELETE FROM {table} WHERE {primary} IN {values.id}
+ * + * @param entitys Entity对象 + * @return 影响的记录条数CompletableFuture + */ + default int delete(T... entitys) { + return dataSource().delete(entitys); + } + + /** + * 删除指定主键值的记录
+ * 等价SQL: DELETE FROM {table} WHERE {primary} IN {values.id}
+ * + * @param entitys Entity对象 + * @return 影响的记录条数CompletableFuture + */ + default int delete(Collection entitys) { + return dataSource().delete(entitys); + } + + /** + * 删除指定主键值的记录
+ * 等价SQL: DELETE FROM {table} WHERE {primary} IN {values.id}
+ * + * @param entitys Entity对象 + * @return 影响的记录条数CompletableFuture + */ + default int delete(Stream entitys) { + return dataSource().delete(entitys); + } + + /** + * 删除指定主键值的记录
+ * 等价SQL: DELETE FROM {table} WHERE {primary} IN {values.id}
+ * + * @param entitys Entity对象 + * @return 影响的记录条数CompletableFuture + */ + default CompletableFuture deleteAsync(T... entitys) { + return dataSource().deleteAsync(entitys); + } + + /** + * 删除指定主键值的记录
+ * 等价SQL: DELETE FROM {table} WHERE {primary} IN {values.id}
+ * + * @param entitys Entity对象 + * @return 影响的记录条数CompletableFuture + */ + default CompletableFuture deleteAsync(Collection entitys) { + return dataSource().deleteAsync(entitys); + } + + /** + * 删除指定主键值的记录
+ * 等价SQL: DELETE FROM {table} WHERE {primary} IN {values.id}
+ * + * @param entitys Entity对象 + * @return 影响的记录条数CompletableFuture + */ + default CompletableFuture deleteAsync(Stream entitys) { + return dataSource().deleteAsync(entitys); + } + + /** + * 删除指定主键值的记录,多主键值必须在同一张表中
+ * 等价SQL: DELETE FROM {table} WHERE {primary} IN {ids}
+ * + * @param pks 主键值 + * @return 影响的记录条数 + */ + default int deleteById(Serializable... pks) { + return dataSource().delete(entityType(), pks); + } + + /** + * 删除指定主键值的记录,多主键值必须在同一张表中
+ * 等价SQL: DELETE FROM {table} WHERE {primary} IN {ids}
+ * + * @param pks 主键值 + * @return 影响的记录条数CompletableFuture + */ + default CompletableFuture deleteByIdAsync(Serializable... pks) { + return dataSource().deleteAsync(entityType(), pks); + } + + // ------------------------update--------------------------- + /** + * 更新记录
+ * 等价SQL:
+ * UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id1}
+ * UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id2}
+ * ···
+ * + * @param entitys Entity对象 + * @return 影响的记录条数 + */ + default int update(T... entitys) { + return dataSource().update(entitys); + } + + /** + * 更新记录
+ * 等价SQL:
+ * UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id1}
+ * UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id2}
+ * ···
+ * + * @param entitys Entity对象 + * @return 影响的记录条数 + */ + default int update(Collection entitys) { + return dataSource().update(entitys); + } + + /** + * 更新记录
+ * 等价SQL:
+ * UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id1}
+ * UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id2}
+ * ···
+ * + * @param entitys Entity对象 + * @return 影响的记录条数 + */ + default int update(Stream entitys) { + return dataSource().update(entitys); + } + + /** + * 更新记录
+ * 等价SQL:
+ * UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id1}
+ * UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id2}
+ * ···
+ * + * @param entitys Entity对象 + * @return 影响的记录条数CompletableFuture + */ + default CompletableFuture updateAsync(T... entitys) { + return dataSource().updateAsync(entitys); + } + + /** + * 更新记录
+ * 等价SQL:
+ * UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id1}
+ * UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id2}
+ * ···
+ * + * @param entitys Entity对象 + * @return 影响的记录条数CompletableFuture + */ + default CompletableFuture updateAsync(Collection entitys) { + return dataSource().updateAsync(entitys); + } + + /** + * 更新记录
+ * 等价SQL:
+ * UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id1}
+ * UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id2}
+ * ···
+ * + * @param entitys Entity对象 + * @return 影响的记录条数CompletableFuture + */ + default CompletableFuture updateAsync(Stream entitys) { + return dataSource().updateAsync(entitys); + } + + /** + * 更新单个记录的单个字段
+ * 注意:即使字段标记为@Column(updatable=false)也会被更新
+ * 等价SQL: UPDATE {table} SET {column} = {value} WHERE {primary} = {id}
+ * + * @param pk 主键 + * @param column 待更新的字段名 + * @param value 更新值 + * @return 影响的记录条数 + */ + default int updateColumn(Serializable pk, String column, Serializable value) { + return dataSource().updateColumn(entityType(), pk, column, value); + } + + /** + * 更新单个记录的单个字段
+ * 注意:即使字段标记为@Column(updatable=false)也会被更新
+ * 等价SQL: UPDATE {table} SET {column} = {value} WHERE {primary} = {id}
+ * + * @param 更新值泛型 + * @param pk 主键 + * @param func 更新值Lambda + * @return 影响的记录条数 + */ + default int updateColumn(Serializable pk, LambdaSupplier func) { + return dataSource().updateColumn(entityType(), pk, func); + } + + /** + * 更新单个记录的单个字段
+ * 注意:即使字段标记为@Column(updatable=false)也会被更新
+ * 等价SQL: UPDATE {table} SET {column} = {value} WHERE {primary} = {id}
+ * + * @param pk 主键 + * @param column 待更新的字段名 + * @param value 更新值 + * @return 影响的记录条数CompletableFuture + */ + default CompletableFuture updateColumnAsync(Serializable pk, String column, Serializable value) { + return dataSource().updateColumnAsync(entityType(), pk, column, value); + } + + /** + * 更新单个记录的单个字段
+ * 注意:即使字段标记为@Column(updatable=false)也会被更新
+ * 等价SQL: UPDATE {table} SET {column} = {value} WHERE {primary} = {id}
+ * + * @param 更新值泛型 + * @param pk 主键 + * @param func 更新值Lambda + * @return 影响的记录条数 + */ + default CompletableFuture updateColumnAsync( + Serializable pk, LambdaSupplier func) { + return dataSource().updateColumnAsync(entityType(), pk, func); + } + + /** + * 更新符合过滤条件记录的单个字段
+ * 注意:即使字段标记为@Column(updatable=false)也会被更新
+ * 等价SQL: UPDATE {table} SET {column} = {value} WHERE {filter node}
+ * + * @param column 待更新的字段名 + * @param value 更新值 + * @param node 过滤条件 + * @return 影响的记录条数 + */ + default int updateColumn(String column, Serializable value, FilterNode node) { + return dataSource().updateColumn(entityType(), column, value, node); + } + + /** + * 更新符合过滤条件记录的单个字段
+ * 注意:即使字段标记为@Column(updatable=false)也会被更新
+ * 等价SQL: UPDATE {table} SET {column} = {value} WHERE {filter node}
+ * + * @param 更新值泛型 + * @param func 更新值Lambda + * @param node 过滤条件 + * @return 影响的记录条数 + */ + default int updateColumn(LambdaSupplier func, FilterNode node) { + return dataSource().updateColumn(entityType(), func, node); + } + + /** + * 更新符合过滤条件记录的单个字段
+ * 注意:即使字段标记为@Column(updatable=false)也会被更新
+ * 等价SQL: UPDATE {table} SET {column} = {value} WHERE {filter node}
+ * + * @param column 待更新的字段名 + * @param value 更新值 + * @param node 过滤条件 + * @return 影响的记录条数CompletableFuture + */ + default CompletableFuture updateColumnAsync(String column, Serializable value, FilterNode node) { + return dataSource().updateColumnAsync(entityType(), column, value, node); + } + + /** + * 更新符合过滤条件记录的单个字段
+ * 注意:即使字段标记为@Column(updatable=false)也会被更新
+ * 等价SQL: UPDATE {table} SET {column} = {value} WHERE {filter node}
+ * + * @param 更新值泛型 + * @param func 更新值Lambda + * @param node 过滤条件 + * @return 影响的记录条数 + */ + default CompletableFuture updateColumnAsync( + LambdaSupplier func, FilterNode node) { + return dataSource().updateColumnAsync(entityType(), func, node); + } + + /** + * 更新指定主键值记录的部分字段
+ * 字段赋值操作选项见 ColumnExpress
+ * 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} += {value2}, {column3} *= {value3}, ··· + * WHERE {filter node}
+ * + * @param pk 主键 + * @param values 更新字段 + * @return 影响的记录条数 + */ + default int updateColumn(Serializable pk, ColumnValue... values) { + return dataSource().updateColumn(entityType(), pk, values); + } + + /** + * 更新指定主键值记录的部分字段
+ * 字段赋值操作选项见 ColumnExpress
+ * 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} += {value2}, {column3} *= {value3}, ··· + * WHERE {filter node}
+ * + * @param pk 主键 + * @param func 更新字段 + * @param value 更新字段值 + * @return 影响的记录条数 + */ + default int updateColumn(Serializable pk, LambdaFunction func, Serializable value) { + return dataSource().updateColumn(entityType(), pk, func, value); + } + + /** + * 更新指定主键值记录的部分字段
+ * 字段赋值操作选项见 ColumnExpress
+ * 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} += {value2}, {column3} *= {value3}, ··· + * WHERE {filter node}
+ * + * @param pk 主键 + * @param values 更新字段 + * @return 影响的记录条数CompletableFuture + */ + default CompletableFuture updateColumnAsync(Serializable pk, ColumnValue... values) { + return dataSource().updateColumnAsync(entityType(), pk, values); + } + + /** + * 更新指定主键值记录的部分字段
+ * 字段赋值操作选项见 ColumnExpress
+ * 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} += {value2}, {column3} *= {value3}, ··· + * WHERE {filter node}
+ * + * @param pk 主键 + * @param func 更新字段 + * @param value 更新字段值 + * @return 影响的记录条数CompletableFuture + */ + default CompletableFuture updateColumnAsync( + Serializable pk, LambdaFunction func, Serializable value) { + return dataSource().updateColumnAsync(entityType(), pk, func, value); + } + + /** + * 更新符合过滤条件记录的部分字段
+ * 字段赋值操作选项见 ColumnExpress
+ * 注意:Entity类中标记为@Column(updatable=false)不会被更新
+ * 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} += {value2}, {column3} *= {value3}, ··· + * WHERE {filter node}
+ * + * @param node 过滤条件 + * @param values 更新字段 + * @return 影响的记录条数 + */ + default int updateColumn(FilterNode node, ColumnValue... values) { + return dataSource().updateColumn(entityType(), node, values); + } + + /** + * 更新符合过滤条件记录的部分字段
+ * 字段赋值操作选项见 ColumnExpress
+ * 注意:Entity类中标记为@Column(updatable=false)不会被更新
+ * 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} += {value2}, {column3} *= {value3}, ··· + * WHERE {filter node}
+ * + * @param node 过滤条件 + * @param values 更新字段 + * @return 影响的记录条数CompletableFuture + */ + default CompletableFuture updateColumnAsync(FilterNode node, ColumnValue... values) { + return dataSource().updateColumnAsync(entityType(), node, values); + } + + /** + * 更新符合过滤条件的记录的指定字段
+ * Flipper中offset字段将被忽略
+ * 注意:Entity类中标记为@Column(updatable=false)不会被更新
+ * 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} += {value2}, {column3} *= {value3}, ··· + * WHERE {filter node} ORDER BY {flipper.sort}
+ * + * @param node 过滤条件 + * @param flipper 翻页对象 + * @param values 更新字段 + * @return 影响的记录条数 + */ + default int updateColumn(FilterNode node, Flipper flipper, ColumnValue... values) { + return dataSource().updateColumn(entityType(), node, flipper, values); + } + + /** + * 更新符合过滤条件的记录的指定字段
+ * Flipper中offset字段将被忽略
+ * 注意:Entity类中标记为@Column(updatable=false)不会被更新
+ * 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} += {value2}, {column3} *= {value3}, ··· + * WHERE {filter node} ORDER BY {flipper.sort}
+ * + * @param node 过滤条件 + * @param flipper 翻页对象 + * @param values 更新字段 + * @return 影响的记录条数CompletableFuture + */ + default CompletableFuture updateColumnAsync(FilterNode node, Flipper flipper, ColumnValue... values) { + return dataSource().updateColumnAsync(entityType(), node, flipper, values); + } + + /** + * 更新单个记录的指定字段
+ * 注意:Entity类中标记为@Column(updatable=false)不会被更新
+ * 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· + * WHERE {primary} = {bean.id}
+ * + * @param entity 待更新的Entity对象 + * @param columns 需更新的字段名 + * @return 影响的记录条数 + */ + default int updateColumn(T entity, String... columns) { + return dataSource().updateColumn(entityType(), columns); + } + + /** + * 更新单个记录的指定字段
+ * 注意:Entity类中标记为@Column(updatable=false)不会被更新
+ * 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· + * WHERE {primary} = {bean.id}
+ * + * @param entity 待更新的Entity对象 + * @param funcs 需更新的字段名Lambda集合 + * @return 影响的记录条数 + */ + default int updateColumn(T entity, LambdaFunction... funcs) { + return dataSource().updateColumn(entityType(), funcs); + } + + /** + * 更新单个记录的指定字段
+ * 注意:Entity类中标记为@Column(updatable=false)不会被更新
+ * 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· + * WHERE {primary} = {bean.id}
+ * + * @param entity 待更新的Entity对象 + * @param columns 需更新的字段名 + * @return 影响的记录条数CompletableFuture + */ + default CompletableFuture updateColumnAsync(T entity, String... columns) { + return dataSource().updateColumnAsync(entityType(), columns); + } + + /** + * 更新单个记录的指定字段
+ * 注意:Entity类中标记为@Column(updatable=false)不会被更新
+ * 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· + * WHERE {primary} = {bean.id}
+ * + * @param entity 待更新的Entity对象 + * @param funcs 需更新的字段名Lambda集合 + * @return 影响的记录条数CompletableFuture + */ + default CompletableFuture updateColumnAsync(T entity, LambdaFunction... funcs) { + return dataSource().updateColumnAsync(entityType(), funcs); + } + + /** + * 更新符合过滤条件记录的指定字段
+ * 注意:Entity类中标记为@Column(updatable=false)不会被更新
+ * 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· + * WHERE {filter node}
+ * + * @param entity 待更新的Entity对象 + * @param node 过滤条件 + * @param columns 需更新的字段名 + * @return 影响的记录条数 + */ + default int updateColumn(T entity, FilterNode node, String... columns) { + return dataSource().updateColumn(entity, node, columns); + } + + /** + * 更新符合过滤条件记录的指定字段
+ * 注意:Entity类中标记为@Column(updatable=false)不会被更新
+ * 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· + * WHERE {filter node}
+ * + * @param entity 待更新的Entity对象 + * @param node 过滤条件 + * @param funcs 需更新的字段名Lambda集合 + * @return 影响的记录条数 + */ + default int updateColumn(T entity, FilterNode node, LambdaFunction... funcs) { + return dataSource().updateColumn(entity, node, funcs); + } + + /** + * 更新符合过滤条件记录的指定字段
+ * 注意:Entity类中标记为@Column(updatable=false)不会被更新
+ * 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· + * WHERE {filter node}
+ * + * @param entity 待更新的Entity对象 + * @param node 过滤条件 + * @param columns 需更新的字段名 + * @return 影响的记录条数CompletableFuture + */ + default CompletableFuture updateColumnAsync(T entity, FilterNode node, String... columns) { + return dataSource().updateColumnAsync(entity, node, columns); + } + + /** + * 更新符合过滤条件记录的指定字段
+ * 注意:Entity类中标记为@Column(updatable=false)不会被更新
+ * 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· + * WHERE {filter node}
+ * + * @param entity 待更新的Entity对象 + * @param node 过滤条件 + * @param funcs 需更新的字段名Lambda集合 + * @return 影响的记录条数 + */ + default CompletableFuture updateColumnAsync(T entity, FilterNode node, LambdaFunction... funcs) { + return dataSource().updateColumnAsync(entity, node, funcs); + } + + /** + * 更新单个记录的指定字段
+ * 注意:Entity类中标记为@Column(updatable=false)不会被更新
+ * 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· + * WHERE {primary} = {bean.id}
+ * + * @param entity 待更新的Entity对象 + * @param selects 指定字段 + * @return 影响的记录条数 + */ + default int updateColumn(T entity, SelectColumn selects) { + return dataSource().updateColumn(entity, selects); + } + + /** + * 更新单个记录的指定字段
+ * 注意:Entity类中标记为@Column(updatable=false)不会被更新
+ * 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· + * WHERE {primary} = {bean.id}
+ * + * @param entity 待更新的Entity对象 + * @param selects 指定字段 + * @return 影响的记录条数CompletableFuture + */ + default CompletableFuture updateColumnAsync(T entity, SelectColumn selects) { + return dataSource().updateColumnAsync(entity, selects); + } + + /** + * 更新符合过滤条件记录的指定字段
+ * 注意:Entity类中标记为@Column(updatable=false)不会被更新
+ * 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· + * WHERE {filter node}
+ * + * @param entity 待更新的Entity对象 + * @param node 过滤条件 + * @param selects 指定字段 + * @return 影响的记录条数 + */ + default int updateColumn(T entity, FilterNode node, SelectColumn selects) { + return dataSource().updateColumn(entity, node, selects); + } + + /** + * 更新符合过滤条件记录的指定字段
+ * 注意:Entity类中标记为@Column(updatable=false)不会被更新
+ * 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· + * WHERE {filter node}
+ * + * @param entity 待更新的Entity对象 + * @param node 过滤条件 + * @param selects 指定字段 + * @return 影响的记录条数CompletableFuture + */ + default CompletableFuture updateColumnAsync(T entity, FilterNode node, SelectColumn selects) { + return dataSource().updateColumnAsync(entity, node, selects); + } + + // -----------------------getXXXXResult----------------------------- + default Number getNumberResult(FilterFunc func, String column) { + return dataSource().getNumberResult(entityType(), func, column); + } + + /** + * 获取符合过滤条件记录的聚合结果, 无结果返回null
+ * 等价SQL: SELECT FUNC{column} FROM {table}
+ * 如 getNumberResultAsync(User.class, FilterFunc.COUNT, null) 等价于: SELECT COUNT(*) FROM {table}
+ * + * @param func 聚合函数 + * @param column 指定字段 + * @return 聚合结果CompletableFuture + */ + default CompletableFuture getNumberResultAsync(FilterFunc func, String column) { + return dataSource().getNumberResultAsync(entityType(), func, column); + } + + /** + * 获取符合过滤条件记录的聚合结果, 无结果返回null
+ * 等价SQL: SELECT FUNC{column} FROM {table} WHERE {filter bean}
+ * 如 getNumberResultAsync(User.class, FilterFunc.COUNT, null, (FilterBean)null) 等价于: SELECT COUNT(*) FROM {table} + *
+ * + * @param func 聚合函数 + * @param column 指定字段 + * @param bean 过滤条件 + * @return 聚合结果 + */ + default Number getNumberResult(FilterFunc func, String column, FilterBean bean) { + return dataSource().getNumberResult(entityType(), func, column, bean); + } + + /** + * 获取符合过滤条件记录的聚合结果, 无结果返回null
+ * 等价SQL: SELECT FUNC{column} FROM {table} WHERE {filter bean}
+ * 如 getNumberResultAsync(User.class, FilterFunc.COUNT, null, (FilterBean)null) 等价于: SELECT COUNT(*) FROM {table} + *
+ * + * @param func 聚合函数 + * @param column 指定字段 + * @param bean 过滤条件 + * @return 聚合结果CompletableFuture + */ + default CompletableFuture getNumberResultAsync(FilterFunc func, String column, FilterBean bean) { + return dataSource().getNumberResultAsync(entityType(), func, column, bean); + } + + /** + * 获取符合过滤条件记录的聚合结果, 无结果返回null
+ * 等价SQL: SELECT FUNC{column} FROM {table} WHERE {filter node}
+ * 如 getNumberResultAsync(User.class, FilterFunc.MAX, "createtime", (FilterNode)null) 等价于: SELECT MAX(createtime) + * FROM {table}
+ * + * @param func 聚合函数 + * @param column 指定字段 + * @param node 过滤条件 + * @return 聚合结果 + */ + default Number getNumberResult(FilterFunc func, String column, FilterNode node) { + return dataSource().getNumberResult(entityType(), func, column, node); + } + + /** + * 获取符合过滤条件记录的聚合结果, 无结果返回null
+ * 等价SQL: SELECT FUNC{column} FROM {table} WHERE {filter node}
+ * 如 getNumberResultAsync(User.class, FilterFunc.MAX, "createtime", (FilterNode)null) 等价于: SELECT MAX(createtime) + * FROM {table}
+ * + * @param func 聚合函数 + * @param column 指定字段 + * @param node 过滤条件 + * @return 聚合结果 + */ + default CompletableFuture getNumberResultAsync(FilterFunc func, String column, FilterNode node) { + return dataSource().getNumberResultAsync(entityType(), func, column, node); + } + + /** + * 获取符合过滤条件记录的聚合结果, 无结果返回默认值
+ * 等价SQL: SELECT FUNC{column} FROM {table}
+ * 如 getNumberResultAsync(User.class, FilterFunc.MAX, "createtime") 等价于: SELECT MAX(createtime) FROM {table}
+ * + * @param func 聚合函数 + * @param defVal 默认值 + * @param column 指定字段 + * @return 聚合结果 + */ + default Number getNumberResult(FilterFunc func, Number defVal, String column) { + return dataSource().getNumberResult(entityType(), func, defVal, column); + } + + /** + * 获取符合过滤条件记录的聚合结果, 无结果返回默认值
+ * 等价SQL: SELECT FUNC{column} FROM {table}
+ * 如 getNumberResultAsync(User.class, FilterFunc.MAX, "createtime") 等价于: SELECT MAX(createtime) FROM {table}
+ * + * @param func 聚合函数 + * @param defVal 默认值 + * @param column 指定字段 + * @return 聚合结果CompletableFuture + */ + default CompletableFuture getNumberResultAsync(FilterFunc func, Number defVal, String column) { + return dataSource().getNumberResultAsync(entityType(), func, defVal, column); + } + + /** + * 获取符合过滤条件记录的聚合结果, 无结果返回默认值
+ * 等价SQL: SELECT FUNC{column} FROM {table} WHERE {filter bean}
+ * 如 getNumberResultAsync(User.class, FilterFunc.MAX, "createtime", (FilterNode)null) 等价于: SELECT MAX(createtime) + * FROM {table}
+ * + * @param func 聚合函数 + * @param defVal 默认值 + * @param column 指定字段 + * @param bean 过滤条件 + * @return 聚合结果 + */ + default Number getNumberResult(FilterFunc func, Number defVal, String column, FilterBean bean) { + return dataSource().getNumberResult(entityType(), func, defVal, column, bean); + } + + /** + * 获取符合过滤条件记录的聚合结果, 无结果返回默认值
+ * 等价SQL: SELECT FUNC{column} FROM {table} WHERE {filter bean}
+ * 如 getNumberResultAsync(User.class, FilterFunc.MAX, "createtime", (FilterNode)null) 等价于: SELECT MAX(createtime) + * FROM {table}
+ * + * @param func 聚合函数 + * @param defVal 默认值 + * @param column 指定字段 + * @param bean 过滤条件 + * @return 聚合结果CompletableFuture + */ + default CompletableFuture getNumberResultAsync( + FilterFunc func, Number defVal, String column, FilterBean bean) { + return dataSource().getNumberResultAsync(entityType(), func, defVal, column, bean); + } + + /** + * 获取符合过滤条件记录的聚合结果, 无结果返回默认值
+ * 等价SQL: SELECT FUNC{column} FROM {table} WHERE {filter node}
+ * 如 getNumberResultAsync(User.class, FilterFunc.MAX, "createtime", (FilterNode)null) 等价于: SELECT MAX(createtime) + * FROM {table}
+ * + * @param func 聚合函数 + * @param defVal 默认值 + * @param column 指定字段 + * @param node 过滤条件 + * @return 聚合结果 + */ + default Number getNumberResult(FilterFunc func, Number defVal, String column, FilterNode node) { + return dataSource().getNumberResult(entityType(), func, defVal, column, node); + } + + /** + * 获取符合过滤条件记录的聚合结果, 无结果返回默认值
+ * 等价SQL: SELECT FUNC{column} FROM {table} WHERE {filter node}
+ * 如 getNumberResultAsync(User.class, FilterFunc.MAX, "createtime", (FilterNode)null) 等价于: SELECT MAX(createtime) + * FROM {table}
+ * + * @param func 聚合函数 + * @param defVal 默认值 + * @param column 指定字段 + * @param node 过滤条件 + * @return 聚合结果CompletableFuture + */ + default CompletableFuture getNumberResultAsync( + FilterFunc func, Number defVal, String column, FilterNode node) { + return dataSource().getNumberResultAsync(entityType(), func, defVal, column, node); + } + + /** + * 获取符合过滤条件记录的聚合结果Map
+ * 等价SQL: SELECT FUNC1{column1}, FUNC2{column2}, ··· FROM {table}
+ * 如 getNumberMapAsync(User.class, new FilterFuncColumn(FilterFunc.MAX, "createtime")) 等价于: SELECT MAX(createtime) + * FROM {table}
+ * + * @param Number + * @param columns 聚合字段 + * @return 聚合结果Map + */ + default Map getNumberMap(FilterFuncColumn... columns) { + return dataSource().getNumberMap(entityType(), columns); + } + + /** + * 获取符合过滤条件记录的聚合结果Map
+ * 等价SQL: SELECT FUNC1{column1}, FUNC2{column2}, ··· FROM {table}
+ * 如 getNumberMapAsync(User.class, new FilterFuncColumn(FilterFunc.MAX, "createtime")) 等价于: SELECT MAX(createtime) + * FROM {table}
+ * + * @param Number + * @param columns 聚合字段 + * @return 聚合结果Map CompletableFuture + */ + default CompletableFuture> getNumberMapAsync(FilterFuncColumn... columns) { + return dataSource().getNumberMapAsync(entityType(), columns); + } + + /** + * 获取符合过滤条件记录的聚合结果Map
+ * 等价SQL: SELECT FUNC1{column1}, FUNC2{column2}, ··· FROM {table} WHERE {filter bean}
+ * 如 getNumberMapAsync(User.class, (FilterBean)null, new FilterFuncColumn(FilterFunc.MAX, "createtime")) 等价于: SELECT + * MAX(createtime) FROM {table}
+ * + * @param Number + * @param bean 过滤条件 + * @param columns 聚合字段 + * @return 聚合结果Map + */ + default Map getNumberMap(FilterBean bean, FilterFuncColumn... columns) { + return dataSource().getNumberMap(entityType(), bean, columns); + } + + /** + * 获取符合过滤条件记录的聚合结果Map
+ * 等价SQL: SELECT FUNC1{column1}, FUNC2{column2}, ··· FROM {table} WHERE {filter bean}
+ * 如 getNumberMapAsync(User.class, (FilterBean)null, new FilterFuncColumn(FilterFunc.MAX, "createtime")) 等价于: SELECT + * MAX(createtime) FROM {table}
+ * + * @param Number + * @param bean 过滤条件 + * @param columns 聚合字段 + * @return 聚合结果Map CompletableFuture + */ + default CompletableFuture> getNumberMapAsync( + FilterBean bean, FilterFuncColumn... columns) { + return dataSource().getNumberMapAsync(entityType(), bean, columns); + } + + /** + * 获取符合过滤条件记录的聚合结果Map
+ * 等价SQL: SELECT FUNC1{column1}, FUNC2{column2}, ··· FROM {table} WHERE {filter node}
+ * 如 getNumberMapAsync(User.class, (FilterNode)null, new FilterFuncColumn(FilterFunc.MAX, "createtime")) 等价于: SELECT + * MAX(createtime) FROM {table}
+ * + * @param Number + * @param node 过滤条件 + * @param columns 聚合字段 + * @return 聚合结果Map + */ + default Map getNumberMap(FilterNode node, FilterFuncColumn... columns) { + return dataSource().getNumberMap(entityType(), node, columns); + } + + /** + * 获取符合过滤条件记录的聚合结果Map
+ * 等价SQL: SELECT FUNC1{column1}, FUNC2{column2}, ··· FROM {table} WHERE {filter node}
+ * 如 getNumberMapAsync(User.class, (FilterNode)null, new FilterFuncColumn(FilterFunc.MAX, "createtime")) 等价于: SELECT + * MAX(createtime) FROM {table}
+ * + * @param Number + * @param node 过滤条件 + * @param columns 聚合字段 + * @return 聚合结果Map + */ + default CompletableFuture> getNumberMapAsync( + FilterNode node, FilterFuncColumn... columns) { + return dataSource().getNumberMapAsync(entityType(), node, columns); + } + + /** + * 查询符合过滤条件记录的GROUP BY聚合结果Map
+ * 等价SQL: SELECT keyColumn, FUNC{funcColumn} FROM {table} GROUP BY {keyColumn}
+ * 如 queryColumnMapAsync(User.class, "name", FilterFunc.MAX, "createtime") 等价于: SELECT name, MAX(createtime) FROM + * user GROUP BY name
+ * + * @param Key字段的数据类型 + * @param Number + * @param keyColumn Key字段 + * @param func 聚合函数 + * @param funcColumn 聚合字段 + * @return 聚合结果Map + */ + default Map queryColumnMap( + String keyColumn, FilterFunc func, String funcColumn) { + return dataSource().queryColumnMap(entityType(), keyColumn, func, funcColumn); + } + + /** + * 查询符合过滤条件记录的GROUP BY聚合结果Map
+ * 等价SQL: SELECT keyColumn, FUNC{funcColumn} FROM {table} GROUP BY {keyColumn}
+ * 如 queryColumnMapAsync(User.class, "name", FilterFunc.MAX, "createtime") 等价于: SELECT name, MAX(createtime) FROM + * user GROUP BY name
+ * + * @param Key字段的数据类型 + * @param Number + * @param keyColumn Key字段 + * @param func 聚合函数 + * @param funcColumn 聚合字段 + * @return 聚合结果Map CompletableFuture + */ + default CompletableFuture> queryColumnMapAsync( + String keyColumn, FilterFunc func, String funcColumn) { + return dataSource().queryColumnMapAsync(entityType(), keyColumn, func, funcColumn); + } + + /** + * 查询符合过滤条件记录的GROUP BY聚合结果Map
+ * 等价SQL: SELECT keyColumn, FUNC{funcColumn} FROM {table} WHERE {filter bean} GROUP BY {keyColumn}
+ * 如 queryColumnMapAsync(User.class, "name", FilterFunc.MAX, "createtime", (FilterBean)null) 等价于: SELECT name, + * MAX(createtime) FROM user GROUP BY name
+ * + * @param Key字段的数据类型 + * @param Number + * @param keyColumn Key字段 + * @param func 聚合函数 + * @param funcColumn 聚合字段 + * @param bean 过滤条件 + * @return 聚合结果Map + */ + default Map queryColumnMap( + String keyColumn, FilterFunc func, String funcColumn, FilterBean bean) { + return dataSource().queryColumnMap(entityType(), keyColumn, func, funcColumn, bean); + } + + /** + * 查询符合过滤条件记录的GROUP BY聚合结果Map
+ * 等价SQL: SELECT keyColumn, FUNC{funcColumn} FROM {table} WHERE {filter bean} GROUP BY {keyColumn}
+ * 如 queryColumnMapAsync(User.class, "name", FilterFunc.MAX, "createtime", (FilterBean)null) 等价于: SELECT name, + * MAX(createtime) FROM user GROUP BY name
+ * + * @param Key字段的数据类型 + * @param Number + * @param keyColumn Key字段 + * @param func 聚合函数 + * @param funcColumn 聚合字段 + * @param bean 过滤条件 + * @return 聚合结果Map CompletableFuture + */ + default CompletableFuture> queryColumnMapAsync( + String keyColumn, FilterFunc func, String funcColumn, FilterBean bean) { + return dataSource().queryColumnMapAsync(entityType(), keyColumn, func, funcColumn, bean); + } + + /** + * 查询符合过滤条件记录的GROUP BY聚合结果Map
+ * 等价SQL: SELECT keyColumn, FUNC{funcColumn} FROM {table} WHERE {filter node} GROUP BY {keyColumn}
+ * 如 queryColumnMapAsync(User.class, "name", FilterFunc.MAX, "createtime", (FilterNode)null) 等价于: SELECT name, + * MAX(createtime) FROM user GROUP BY name
+ * + * @param Key字段的数据类型 + * @param Number + * @param keyColumn Key字段 + * @param func 聚合函数 + * @param funcColumn 聚合字段 + * @param node 过滤条件 + * @return 聚合结果Map + */ + default Map queryColumnMap( + String keyColumn, FilterFunc func, String funcColumn, FilterNode node) { + return dataSource().queryColumnMap(entityType(), keyColumn, func, funcColumn, node); + } + + /** + * 查询符合过滤条件记录的GROUP BY聚合结果Map
+ * 等价SQL: SELECT keyColumn, FUNC{funcColumn} FROM {table} WHERE {filter node} GROUP BY {keyColumn}
+ * 如 queryColumnMapAsync(User.class, "name", FilterFunc.MAX, "createtime", (FilterNode)null) 等价于: SELECT name, + * MAX(createtime) FROM user GROUP BY name
+ * + * @param Key字段的数据类型 + * @param Number + * @param keyColumn Key字段 + * @param func 聚合函数 + * @param funcColumn 聚合字段 + * @param node 过滤条件 + * @return 聚合结果Map CompletableFuture + */ + default CompletableFuture> queryColumnMapAsync( + String keyColumn, FilterFunc func, String funcColumn, FilterNode node) { + return dataSource().queryColumnMapAsync(entityType(), keyColumn, func, funcColumn, node); + } + + /** + * 查询符合过滤条件记录的GROUP BY聚合结果Map
+ * 等价SQL: SELECT col1, FUNC{funcColumn1}, FUNC{funcColumn2} FROM {table} WHERE GROUP BY {col1}
+ * 如 queryColumnMapAsync(OrderRecord.class, Utility.ofArray(ColumnExpNode.div(ColumnFuncNode.sum("money"), 100), + * ColumnFuncNode.avg(ColumnExpNode.dec("money", 20)))), "targetid") 等价于: SELECT targetid, SUM(money) / 100, + * AVG(money - 20) FROM orderrecord GROUP BY targetid
+ * + * @param Key字段的数据类型 + * @param Number + * @param funcNodes ColumnNode[] + * @param groupByColumn GROUP BY字段 + * @return 聚合结果Map CompletableFuture + */ + default Map queryColumnMap( + ColumnNode[] funcNodes, String groupByColumn) { + return dataSource().queryColumnMap(entityType(), funcNodes, groupByColumn); + } + + /** + * 查询符合过滤条件记录的GROUP BY聚合结果Map
+ * 等价SQL: SELECT col1, FUNC{funcColumn1}, FUNC{funcColumn2} FROM {table} GROUP BY {col1}
+ * 如 queryColumnMapAsync(OrderRecord.class, Utility.ofArray(ColumnExpNode.div(ColumnFuncNode.sum("money"), 100), + * ColumnFuncNode.avg(ColumnExpNode.dec("money", 20)))), "targetid") 等价于: SELECT targetid, SUM(money) / 100, + * AVG(money - 20) FROM orderrecord GROUP BY targetid
+ * + * @param Key字段的数据类型 + * @param Number + * @param funcNodes ColumnNode[] + * @param groupByColumn GROUP BY字段 + * @return 聚合结果Map CompletableFuture + */ + default CompletableFuture> queryColumnMapAsync( + ColumnNode[] funcNodes, String groupByColumn) { + return dataSource().queryColumnMapAsync(entityType(), funcNodes, groupByColumn); + } + + /** + * 查询符合过滤条件记录的GROUP BY聚合结果Map
+ * 等价SQL: SELECT col1, FUNC{funcColumn1}, FUNC{funcColumn2} FROM {table} WHERE {filter bean} GROUP BY {col1}
+ * 如 queryColumnMapAsync(OrderRecord.class, Utility.ofArray(ColumnExpNode.div(ColumnFuncNode.sum("money"), 100), + * ColumnFuncNode.avg(ColumnExpNode.dec("money", 20)))), "targetid", (FilterBean)null) 等价于: SELECT targetid, + * SUM(money) / 100, AVG(money - 20) FROM orderrecord GROUP BY targetid
+ * + * @param Key字段的数据类型 + * @param Number + * @param funcNodes ColumnNode[] + * @param groupByColumn GROUP BY字段 + * @param bean 过滤条件 + * @return 聚合结果Map CompletableFuture + */ + default Map queryColumnMap( + ColumnNode[] funcNodes, String groupByColumn, FilterBean bean) { + return dataSource().queryColumnMap(entityType(), funcNodes, groupByColumn, bean); + } + + /** + * 查询符合过滤条件记录的GROUP BY聚合结果Map
+ * 等价SQL: SELECT col1, FUNC{funcColumn1}, FUNC{funcColumn2} FROM {table} WHERE {filter bean} GROUP BY {col1}
+ * 如 queryColumnMapAsync(OrderRecord.class, Utility.ofArray(ColumnExpNode.div(ColumnFuncNode.sum("money"), 100), + * ColumnFuncNode.avg(ColumnExpNode.dec("money", 20)))), "targetid", (FilterBean)null) 等价于: SELECT targetid, + * SUM(money) / 100, AVG(money - 20) FROM orderrecord GROUP BY targetid
+ * + * @param Key字段的数据类型 + * @param Number + * @param funcNodes ColumnNode[] + * @param groupByColumn GROUP BY字段 + * @param bean 过滤条件 + * @return 聚合结果Map CompletableFuture + */ + default CompletableFuture> queryColumnMapAsync( + ColumnNode[] funcNodes, String groupByColumn, FilterBean bean) { + return dataSource().queryColumnMapAsync(entityType(), funcNodes, groupByColumn, bean); + } + + /** + * 查询符合过滤条件记录的GROUP BY聚合结果Map
+ * 等价SQL: SELECT col1, FUNC{funcColumn1}, FUNC{funcColumn2} FROM {table} WHERE {filter node} GROUP BY {col1}
+ * 如 queryColumnMapAsync(OrderRecord.class, Utility.ofArray(ColumnExpNode.div(ColumnFuncNode.sum("money"), 100), + * ColumnFuncNode.avg(ColumnExpNode.dec("money", 20)))), "targetid", (FilterNode)null) 等价于: SELECT targetid, + * SUM(money) / 100, AVG(money - 20) FROM orderrecord GROUP BY targetid
+ * + * @param Key字段的数据类型 + * @param Number + * @param funcNodes ColumnNode[] + * @param groupByColumn GROUP BY字段 + * @param node 过滤条件 + * @return 聚合结果Map CompletableFuture + */ + default Map queryColumnMap( + ColumnNode[] funcNodes, String groupByColumn, FilterNode node) { + return dataSource().queryColumnMap(entityType(), funcNodes, groupByColumn, node); + } + + /** + * 查询符合过滤条件记录的GROUP BY聚合结果Map
+ * 等价SQL: SELECT col1, FUNC{funcColumn1}, FUNC{funcColumn2} FROM {table} WHERE {filter node} GROUP BY {col1}
+ * 如 queryColumnMapAsync(OrderRecord.class, Utility.ofArray(ColumnExpNode.div(ColumnFuncNode.sum("money"), 100), + * ColumnFuncNode.avg(ColumnExpNode.dec("money", 20)))), "targetid", (FilterNode)null) 等价于: SELECT targetid, + * SUM(money) / 100, AVG(money - 20) FROM orderrecord GROUP BY targetid
+ * + * @param Key字段的数据类型 + * @param Number + * @param funcNodes ColumnNode[] + * @param groupByColumn GROUP BY字段 + * @param node 过滤条件 + * @return 聚合结果Map CompletableFuture + */ + default CompletableFuture> queryColumnMapAsync( + ColumnNode[] funcNodes, String groupByColumn, FilterNode node) { + return dataSource().queryColumnMapAsync(entityType(), funcNodes, groupByColumn, node); + } + + /** + * 查询符合过滤条件记录的GROUP BY聚合结果Map
+ * 等价SQL: SELECT col1, col2, FUNC{funcColumn1}, FUNC{funcColumn2} FROM {table} GROUP BY {col1}, {col2}
+ * 如 queryColumnMapAsync(OrderRecord.class, Utility.ofArray(ColumnExpNode.div(ColumnFuncNode.sum("money"), 100), + * ColumnFuncNode.avg(ColumnExpNode.dec("money", 20)))), Utility.ofArray("fromid", "targetid")) 等价于: SELECT fromid, + * targetid, SUM(money) / 100, AVG(money - 20) FROM orderrecord GROUP BY fromid, targetid
+ * + * @param Key字段的数据类型 + * @param Number + * @param funcNodes ColumnNode[] + * @param groupByColumns GROUP BY字段 + * @return 聚合结果Map CompletableFuture + */ + default Map queryColumnMap( + ColumnNode[] funcNodes, String[] groupByColumns) { + return dataSource().queryColumnMap(entityType(), funcNodes, groupByColumns); + } + + /** + * 查询符合过滤条件记录的GROUP BY聚合结果Map
+ * 等价SQL: SELECT col1, col2, FUNC{funcColumn1}, FUNC{funcColumn2} FROM {table} GROUP BY {col1}, {col2}
+ * 如 queryColumnMapAsync(OrderRecord.class, Utility.ofArray(ColumnExpNode.div(ColumnFuncNode.sum("money"), 100), + * ColumnFuncNode.avg(ColumnExpNode.dec("money", 20)))), Utility.ofArray("fromid", "targetid")) 等价于: SELECT fromid, + * targetid, SUM(money) / 100, AVG(money - 20) FROM orderrecord GROUP BY fromid, targetid
+ * + * @param Key字段的数据类型 + * @param Number + * @param funcNodes ColumnNode[] + * @param groupByColumns GROUP BY字段 + * @return 聚合结果Map CompletableFuture + */ + default CompletableFuture> queryColumnMapAsync( + ColumnNode[] funcNodes, String[] groupByColumns) { + return dataSource().queryColumnMapAsync(entityType(), funcNodes, groupByColumns); + } + + /** + * 查询符合过滤条件记录的GROUP BY聚合结果Map
+ * 等价SQL: SELECT col1, col2, FUNC{funcColumn1}, FUNC{funcColumn2} FROM {table} WHERE {filter bean} GROUP BY {col1}, + * {col2}
+ * 如 queryColumnMapAsync(OrderRecord.class, Utility.ofArray(ColumnExpNode.div(ColumnFuncNode.sum("money"), 100), + * ColumnFuncNode.avg(ColumnExpNode.dec("money", 20)))), Utility.ofArray("fromid", "targetid"), (FilterBean)null) + * 等价于: SELECT fromid, targetid, SUM(money) / 100, AVG(money - 20) FROM orderrecord GROUP BY fromid, targetid
+ * + * @param Key字段的数据类型 + * @param Number + * @param funcNodes ColumnNode[] + * @param groupByColumns GROUP BY字段 + * @param bean 过滤条件 + * @return 聚合结果Map CompletableFuture + */ + default Map queryColumnMap( + ColumnNode[] funcNodes, String[] groupByColumns, FilterBean bean) { + return dataSource().queryColumnMap(entityType(), funcNodes, groupByColumns, bean); + } + + /** + * 查询符合过滤条件记录的GROUP BY聚合结果Map
+ * 等价SQL: SELECT col1, col2, FUNC{funcColumn1}, FUNC{funcColumn2} FROM {table} WHERE {filter bean} GROUP BY {col1}, + * {col2}
+ * 如 queryColumnMapAsync(OrderRecord.class, Utility.ofArray(ColumnExpNode.div(ColumnFuncNode.sum("money"), 100), + * ColumnFuncNode.avg(ColumnExpNode.dec("money", 20)))), Utility.ofArray("fromid", "targetid"), (FilterBean)null) + * 等价于: SELECT fromid, targetid, SUM(money) / 100, AVG(money - 20) FROM orderrecord GROUP BY fromid, targetid
+ * + * @param Key字段的数据类型 + * @param Number + * @param funcNodes ColumnNode[] + * @param groupByColumns GROUP BY字段 + * @param bean 过滤条件 + * @return 聚合结果Map CompletableFuture + */ + default CompletableFuture> queryColumnMapAsync( + ColumnNode[] funcNodes, String[] groupByColumns, FilterBean bean) { + return dataSource().queryColumnMapAsync(entityType(), funcNodes, groupByColumns, bean); + } + + /** + * 查询符合过滤条件记录的GROUP BY聚合结果Map
+ * 等价SQL: SELECT col1, col2, FUNC{funcColumn1}, FUNC{funcColumn2} FROM {table} WHERE {filter node} GROUP BY {col1}, + * {col2}
+ * 如 queryColumnMapAsync(OrderRecord.class, Utility.ofArray(ColumnExpNode.div(ColumnFuncNode.sum("money"), 100), + * ColumnFuncNode.avg(ColumnExpNode.dec("money", 20)))), Utility.ofArray("fromid", "targetid"), (FilterNode)null) + * 等价于: SELECT fromid, targetid, SUM(money) / 100, AVG(money - 20) FROM orderrecord GROUP BY fromid, targetid
+ * + * @param Key字段的数据类型 + * @param Number + * @param funcNodes ColumnNode[] + * @param groupByColumns GROUP BY字段 + * @param node 过滤条件 + * @return 聚合结果Map + */ + default Map queryColumnMap( + ColumnNode[] funcNodes, String[] groupByColumns, FilterNode node) { + return dataSource().queryColumnMap(entityType(), funcNodes, groupByColumns, node); + } + + /** + * 查询符合过滤条件记录的GROUP BY聚合结果Map
+ * 等价SQL: SELECT col1, col2, FUNC{funcColumn1}, FUNC{funcColumn2} FROM {table} WHERE {filter node} GROUP BY {col1}, + * {col2}
+ * 如 queryColumnMapAsync(OrderRecord.class, Utility.ofArray(ColumnExpNode.div(ColumnFuncNode.sum("money"), 100), + * ColumnFuncNode.avg(ColumnExpNode.dec("money", 20)))), Utility.ofArray("fromid", "targetid"), (FilterNode)null) + * 等价于: SELECT fromid, targetid, SUM(money) / 100, AVG(money - 20) FROM orderrecord GROUP BY fromid, targetid
+ * + * @param Key字段的数据类型 + * @param Number + * @param funcNodes ColumnNode[] + * @param groupByColumns GROUP BY字段 + * @param node 过滤条件 + * @return 聚合结果Map CompletableFuture + */ + default CompletableFuture> queryColumnMapAsync( + ColumnNode[] funcNodes, String[] groupByColumns, FilterNode node) { + return dataSource().queryColumnMapAsync(entityType(), funcNodes, groupByColumns, node); + } + + // -----------------------findAsync---------------------------- + /** + * 获取指定主键值的单个记录, 返回null表示不存在值
+ * 等价SQL: SELECT * FROM {table} WHERE {primary} = {id}
+ * + * @param pk 主键值 + * @return Entity对象 + */ + default T find(Serializable pk) { + return dataSource().find(entityType(), pk); + } + + /** + * 获取指定主键值的单个记录, 返回null表示不存在值
+ * 等价SQL: SELECT * FROM {table} WHERE {primary} = {id}
+ * + * @param pk 主键值 + * @return Entity对象 CompletableFuture + */ + default CompletableFuture findAsync(Serializable pk) { + return dataSource().findAsync(entityType(), pk); + } + + /** + * 获取指定主键值的单个记录, 返回null表示不存在值
+ * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {primary} = {id}
+ * + * @param selects 指定字段 + * @param pk 主键值 + * @return Entity对象 + */ + default T find(SelectColumn selects, Serializable pk) { + return dataSource().find(entityType(), selects, pk); + } + + /** + * 获取指定主键值的单个记录, 返回null表示不存在值
+ * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {primary} = {id}
+ * + * @param selects 指定字段 + * @param pk 主键值 + * @return Entity对象CompletableFuture + */ + default CompletableFuture findAsync(SelectColumn selects, Serializable pk) { + return dataSource().findAsync(entityType(), selects, pk); + } + + /** + * 获取指定主键值的多个记录, 返回数组,数组长度与pks一样
+ * 等价SQL: SELECT * FROM {table} WHERE {primary} = {id1,id2, ···}
+ * + * @param pks 主键值集合 + * @return Entity对象 + */ + default T[] finds(Serializable... pks) { + return dataSource().finds(entityType(), pks); + } + + /** + * 获取指定主键值的多个记录, 返回数组,数组长度与pks一样
+ * 等价SQL: SELECT * FROM {table} WHERE {primary} = {id1,id2, ···}
+ * + * @param 主键泛型 + * @param pks 主键值集合 + * @return Entity对象 + */ + default T[] finds(Stream pks) { + return dataSource().finds(entityType(), pks); + } + + /** + * 获取指定主键值的多个记录, 返回数组,数组长度与pks一样
+ * 等价SQL: SELECT * FROM {table} WHERE {primary} = {id1,id2, ···}
+ * + * @param pks 主键值集合 + * @return Entity对象 CompletableFuture + */ + default CompletableFuture findsAsync(Serializable... pks) { + return dataSource().findsAsync(entityType(), pks); + } + + /** + * 获取指定主键值的多个记录, 返回数组,数组长度与pks一样
+ * 等价SQL: SELECT * FROM {table} WHERE {primary} = {id1,id2, ···}
+ * + * @param 主键泛型 + * @param pks 主键值集合 + * @return Entity对象 CompletableFuture + */ + default CompletableFuture findsAsync(Stream pks) { + return dataSource().findsAsync(entityType(), pks); + } + + /** + * 获取指定主键值的多个记录, 返回数组,数组长度与pks一样
+ * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {primary} = {id1,id2, + * ···}
+ * + * @param selects 指定字段 + * @param pks 主键值集合 + * @return Entity对象 + */ + default T[] finds(SelectColumn selects, Serializable... pks) { + return dataSource().finds(entityType(), selects, pks); + } + + /** + * 获取指定主键值的多个记录, 返回数组,数组长度与pks一样
+ * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {primary} = {id1,id2, + * ···}
+ * + * @param 主键泛型 + * @param selects 指定字段 + * @param pks 主键值集合 + * @return Entity对象 + */ + default T[] finds(SelectColumn selects, Stream pks) { + return dataSource().finds(entityType(), selects, pks); + } + + /** + * 获取指定主键值的多个记录, 返回数组,数组长度与pks一样
+ * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {primary} = {id1,id2, + * ···}
+ * + * @param selects 指定字段 + * @param pks 主键值集合 + * @return Entity对象CompletableFuture + */ + default CompletableFuture findsAsync(SelectColumn selects, Serializable... pks) { + return dataSource().findsAsync(entityType(), selects, pks); + } + + /** + * 获取指定主键值的多个记录, 返回数组,数组长度与pks一样
+ * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {primary} = {id1,id2, + * ···}
+ * + * @param 主键泛型 + * @param selects 指定字段 + * @param pks 主键值集合 + * @return Entity对象 + */ + default CompletableFuture findsAsync(SelectColumn selects, Stream pks) { + return dataSource().findsAsync(entityType(), selects, pks); + } + + /** + * 获取指定主键值的多个记录, 返回列表
+ * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {primary} = {id1,id2, + * ···}
+ * + * @param 主键泛型 + * @param pks 主键值集合 + * @return Entity对象 + */ + default List findsList(Stream pks) { + return dataSource().findsList(entityType(), pks); + } + + /** + * 获取指定主键值的多个记录, 返回列表
+ * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {primary} = {id1,id2, + * ···}
+ * + * @param 主键泛型 + * @param pks 主键值集合 + * @return Entity对象 + */ + default CompletableFuture> findsListAsync(Stream pks) { + return dataSource().findsListAsync(entityType(), pks); + } + + /** + * 获取符合过滤条件单个记录, 返回null表示不存在值
+ * 等价SQL: SELECT * FROM {table} WHERE {column} = {key}
+ * + * @param column 过滤字段名 + * @param colval 过滤字段值 + * @return Entity对象 + */ + default T find(String column, Serializable colval) { + return dataSource().find(entityType(), column, colval); + } + + /** + * 获取符合过滤条件单个记录, 返回null表示不存在值
+ * 等价SQL: SELECT * FROM {table} WHERE {column} = {key}
+ * + * @param column 过滤字段名 + * @param colval 过滤字段值 + * @return Entity对象CompletableFuture + */ + default CompletableFuture findAsync(String column, Serializable colval) { + return dataSource().findAsync(entityType(), column, colval); + } + + /** + * 获取符合过滤条件单个记录, 返回null表示不存在值
+ * 等价SQL: SELECT * FROM {table} WHERE {column} = {key}
+ * + * @param func 更新值Lambda + * @return Entity对象 + */ + default T find(LambdaSupplier func) { + return dataSource().find(entityType(), func); + } + + /** + * 获取符合过滤条件单个记录, 返回null表示不存在值
+ * 等价SQL: SELECT * FROM {table} WHERE {column} = {key}
+ * + * @param func 更新值Lambda + * @return Entity对象 + */ + default CompletableFuture findAsync(LambdaSupplier func) { + return dataSource().findAsync(entityType(), func); + } + + /** + * 获取符合过滤条件单个记录, 返回null表示不存在值
+ * 等价SQL: SELECT * FROM {table} WHERE {filter bean}
+ * + * @param bean 过滤条件 + * @return Entity对象 + */ + default T find(FilterBean bean) { + return dataSource().find(entityType(), bean); + } + + /** + * 获取符合过滤条件单个记录, 返回null表示不存在值
+ * 等价SQL: SELECT * FROM {table} WHERE {filter bean}
+ * + * @param bean 过滤条件 + * @return Entity对象CompletableFuture + */ + default CompletableFuture findAsync(FilterBean bean) { + return dataSource().findAsync(entityType(), bean); + } + + /** + * 获取符合过滤条件单个记录, 返回null表示不存在值
+ * 等价SQL: SELECT * FROM {table} WHERE {filter node}
+ * + * @param node 过滤条件 + * @return Entity对象 + */ + default T find(FilterNode node) { + return dataSource().find(entityType(), node); + } + + /** + * 获取符合过滤条件单个记录, 返回null表示不存在值
+ * 等价SQL: SELECT * FROM {table} WHERE {filter node}
+ * + * @param node 过滤条件 + * @return Entity对象CompletableFuture + */ + default CompletableFuture findAsync(FilterNode node) { + return dataSource().findAsync(entityType(), node); + } + + /** + * 获取符合过滤条件单个记录, 返回null表示不存在值
+ * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter bean}
+ * + * @param selects 指定字段 + * @param bean 过滤条件 + * @return Entity对象 + */ + default T find(SelectColumn selects, FilterBean bean) { + return dataSource().find(entityType(), selects, bean); + } + + /** + * 获取符合过滤条件单个记录, 返回null表示不存在值
+ * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter bean}
+ * + * @param selects 指定字段 + * @param bean 过滤条件 + * @return Entity对象 CompletableFuture + */ + default CompletableFuture findAsync(SelectColumn selects, FilterBean bean) { + return dataSource().findAsync(entityType(), selects, bean); + } + + /** + * 获取符合过滤条件单个记录, 返回null表示不存在值
+ * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter node}
+ * + * @param selects 指定字段 + * @param node 过滤条件 + * @return Entity对象 + */ + default T find(SelectColumn selects, FilterNode node) { + return dataSource().find(entityType(), selects, node); + } + + /** + * 获取符合过滤条件单个记录, 返回null表示不存在值
+ * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter node}
+ * + * @param selects 指定字段 + * @param node 过滤条件 + * @return Entity对象 CompletableFuture + */ + default CompletableFuture findAsync(SelectColumn selects, FilterNode node) { + return dataSource().findAsync(entityType(), selects, node); + } + + /** + * 获取符合过滤条件单个记录的单个字段值, 返回null表示不存在值
+ * 等价SQL: SELECT {column} FROM {table} WHERE {primary} = {id}
+ * + * @param column 字段名 + * @param pk 主键值 + * @return Entity对象 + */ + default Serializable findColumn(String column, Serializable pk) { + return dataSource().findColumn(entityType(), column, pk); + } + + /** + * 获取符合过滤条件单个记录的单个字段值, 返回null表示不存在值
+ * 等价SQL: SELECT {column} FROM {table} WHERE {primary} = {id}
+ * + * @param column 字段名 + * @param pk 主键值 + * @return Entity对象 CompletableFuture + */ + default CompletableFuture findColumnAsync(String column, Serializable pk) { + return dataSource().findColumnAsync(entityType(), column, pk); + } + + /** + * 获取符合过滤条件单个记录的单个字段值, 返回null表示不存在值
+ * 等价SQL: SELECT {column} FROM {table} WHERE {filter bean}
+ * + * @param column 字段名 + * @param bean 过滤条件 + * @return 字段值 + */ + default Serializable findColumn(String column, FilterBean bean) { + return dataSource().findColumn(entityType(), column, bean); + } + + /** + * 获取符合过滤条件单个记录的单个字段值, 返回null表示不存在值
+ * 等价SQL: SELECT {column} FROM {table} WHERE {filter bean}
+ * + * @param column 字段名 + * @param bean 过滤条件 + * @return 字段值 CompletableFuture + */ + default CompletableFuture findColumnAsync(String column, FilterBean bean) { + return dataSource().findColumnAsync(entityType(), column, bean); + } + + /** + * 获取符合过滤条件单个记录的单个字段值, 返回null表示不存在值
+ * 等价SQL: SELECT {column} FROM {table} WHERE {filter node}
+ * + * @param column 字段名 + * @param node 过滤条件 + * @return 字段值 + */ + default Serializable findColumn(String column, FilterNode node) { + return dataSource().findColumn(entityType(), column, node); + } + + /** + * 获取符合过滤条件单个记录的单个字段值, 返回null表示不存在值
+ * 等价SQL: SELECT {column} FROM {table} WHERE {filter node}
+ * + * @param column 字段名 + * @param node 过滤条件 + * @return 字段值 CompletableFuture + */ + default CompletableFuture findColumnAsync(String column, FilterNode node) { + return dataSource().findColumnAsync(entityType(), column, node); + } + + /** + * 获取符合过滤条件单个记录的单个字段值, 不存在值则返回默认值
+ * 等价SQL: SELECT {column} FROM {table} WHERE {primary} = {id}
+ * + * @param column 字段名 + * @param defValue 默认值 + * @param pk 主键值 + * @return 字段值 + */ + default Serializable findColumn(String column, Serializable defValue, Serializable pk) { + return dataSource().findColumn(entityType(), column, defValue, pk); + } + + /** + * 获取符合过滤条件单个记录的单个字段值, 不存在值则返回默认值
+ * 等价SQL: SELECT {column} FROM {table} WHERE {primary} = {id}
+ * + * @param column 字段名 + * @param defValue 默认值 + * @param pk 主键值 + * @return 字段值 CompletableFuture + */ + default CompletableFuture findColumnAsync(String column, Serializable defValue, Serializable pk) { + return dataSource().findColumnAsync(entityType(), column, defValue, pk); + } + + /** + * 获取符合过滤条件单个记录的单个字段值, 不存在值则返回默认值
+ * 等价SQL: SELECT {column} FROM {table} WHERE {filter bean}
+ * + * @param column 字段名 + * @param defValue 默认值 + * @param bean 过滤条件 + * @return 字段值 + */ + default Serializable findColumn(String column, Serializable defValue, FilterBean bean) { + return dataSource().findColumn(entityType(), column, defValue, bean); + } + + /** + * 获取符合过滤条件单个记录的单个字段值, 不存在值则返回默认值
+ * 等价SQL: SELECT {column} FROM {table} WHERE {filter bean}
+ * + * @param column 字段名 + * @param defValue 默认值 + * @param bean 过滤条件 + * @return 字段值 CompletableFuture + */ + default CompletableFuture findColumnAsync(String column, Serializable defValue, FilterBean bean) { + return dataSource().findColumnAsync(entityType(), column, defValue, bean); + } + + /** + * 获取符合过滤条件单个记录的单个字段值, 不存在值则返回默认值
+ * 等价SQL: SELECT {column} FROM {table} WHERE {filter node}
+ * + * @param column 字段名 + * @param defValue 默认值 + * @param node 过滤条件 + * @return 字段值 + */ + default Serializable findColumn(String column, Serializable defValue, FilterNode node) { + return dataSource().findColumn(entityType(), column, defValue, node); + } + + /** + * 获取符合过滤条件单个记录的单个字段值, 不存在值则返回默认值
+ * 等价SQL: SELECT {column} FROM {table} WHERE {filter node}
+ * + * @param column 字段名 + * @param defValue 默认值 + * @param node 过滤条件 + * @return 字段值 CompletableFuture + */ + default CompletableFuture findColumnAsync(String column, Serializable defValue, FilterNode node) { + return dataSource().findColumnAsync(entityType(), column, defValue, node); + } + + /** + * 判断是否存在主键值的记录
+ * 等价SQL: SELECT COUNT(*) FROM {table} WHERE {primary} = {id}
+ * + * @param pk 主键值 + * @return 是否存在 + */ + default boolean exists(Serializable pk) { + return dataSource().exists(entityType(), pk); + } + + /** + * 判断是否存在主键值的记录
+ * 等价SQL: SELECT COUNT(*) FROM {table} WHERE {primary} = {id}
+ * + * @param pk 主键值 + * @return 是否存在CompletableFuture + */ + default CompletableFuture existsAsync(Serializable pk) { + return dataSource().existsAsync(entityType(), pk); + } + + /** + * 判断是否存在符合过滤条件的记录
+ * 等价SQL: SELECT COUNT(*) FROM {table} WHERE {filter bean}
+ * + * @param bean 过滤条件 + * @return 是否存在 + */ + default boolean exists(FilterBean bean) { + return dataSource().exists(entityType(), bean); + } + + /** + * 判断是否存在符合过滤条件的记录
+ * 等价SQL: SELECT COUNT(*) FROM {table} WHERE {filter bean}
+ * + * @param bean 过滤条件 + * @return 是否存在CompletableFuture + */ + default CompletableFuture existsAsync(FilterBean bean) { + return dataSource().existsAsync(entityType(), bean); + } + + /** + * 判断是否存在符合过滤条件的记录
+ * 等价SQL: SELECT COUNT(*) FROM {table} WHERE {filter node}
+ * + * @param node 过滤条件 + * @return 是否存在 + */ + default boolean exists(FilterNode node) { + return dataSource().exists(entityType(), node); + } + + /** + * 判断是否存在符合过滤条件的记录
+ * 等价SQL: SELECT COUNT(*) FROM {table} WHERE {filter node}
+ * + * @param node 过滤条件 + * @return 是否存在CompletableFuture + */ + default CompletableFuture existsAsync(FilterNode node) { + return dataSource().existsAsync(entityType(), node); + } + + // -----------------------list set---------------------------- + /** + * 查询符合过滤条件记录的某个字段Set集合
+ * 等价SQL: SELECT DISTINCT {selectedColumn} FROM {table} WHERE {column} = {key}
+ * + * @param 字段类型 + * @param selectedColumn 指定字段 + * @param column 过滤字段名 + * @param colval 过滤字段值 + * @return 字段值的集合 + */ + default Set queryColumnSet(String selectedColumn, String column, Serializable colval) { + return dataSource().queryColumnSet(selectedColumn, entityType(), column, colval); + } + + /** + * 查询符合过滤条件记录的某个字段Set集合
+ * 等价SQL: SELECT DISTINCT {selectedColumn} FROM {table} WHERE {column} = {key}
+ * + * @param 字段类型 + * @param selectedColumn 指定字段 + * @param column 过滤字段名 + * @param colval 过滤字段值 + * @return 字段值的集合CompletableFuture + */ + default CompletableFuture> queryColumnSetAsync( + String selectedColumn, String column, Serializable colval) { + return dataSource().queryColumnSetAsync(selectedColumn, entityType(), column, colval); + } + + /** + * 查询符合过滤条件记录的某个字段Set集合
+ * 等价SQL: SELECT DISTINCT {selectedColumn} FROM {table} WHERE {filter bean}
+ * + * @param 字段类型 + * @param selectedColumn 指定字段 + * @param bean 过滤条件 + * @return 字段值的集合 + */ + default Set queryColumnSet(String selectedColumn, FilterBean bean) { + return dataSource().queryColumnSet(selectedColumn, entityType(), bean); + } + + /** + * 查询符合过滤条件记录的某个字段Set集合
+ * 等价SQL: SELECT DISTINCT {selectedColumn} FROM {table} WHERE {filter bean}
+ * + * @param 字段类型 + * @param selectedColumn 指定字段 + * @param bean 过滤条件 + * @return 字段值的集合CompletableFuture + */ + default CompletableFuture> queryColumnSetAsync( + String selectedColumn, FilterBean bean) { + return dataSource().queryColumnSetAsync(selectedColumn, entityType(), bean); + } + + /** + * 查询符合过滤条件记录的某个字段Set集合
+ * 等价SQL: SELECT DISTINCT {selectedColumn} FROM {table} WHERE {filter node}
+ * + * @param 字段类型 + * @param selectedColumn 指定字段 + * @param node 过滤条件 + * @return 字段值的集合 + */ + default Set queryColumnSet(String selectedColumn, FilterNode node) { + return dataSource().queryColumnSet(selectedColumn, entityType(), node); + } + + /** + * 查询符合过滤条件记录的某个字段Set集合
+ * 等价SQL: SELECT DISTINCT {selectedColumn} FROM {table} WHERE {filter node}
+ * + * @param 字段类型 + * @param selectedColumn 指定字段 + * @param node 过滤条件 + * @return 字段值的集合CompletableFuture + */ + default CompletableFuture> queryColumnSetAsync( + String selectedColumn, FilterNode node) { + return dataSource().queryColumnSetAsync(selectedColumn, entityType(), node); + } + + /** + * 查询符合过滤条件记录的某个字段Set集合
+ * 等价SQL: SELECT DISTINCT {selectedColumn} FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT + * {flipper.limit}
+ * + * @param 字段类型 + * @param selectedColumn 指定字段 + * @param flipper 翻页对象 + * @param bean 过滤条件 + * @return 字段值的集合 + */ + default Set queryColumnSet(String selectedColumn, Flipper flipper, FilterBean bean) { + return dataSource().queryColumnSet(selectedColumn, entityType(), flipper, bean); + } + + /** + * 查询符合过滤条件记录的某个字段Set集合
+ * 等价SQL: SELECT DISTINCT {selectedColumn} FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT + * {flipper.limit}
+ * + * @param 字段类型 + * @param selectedColumn 指定字段 + * @param flipper 翻页对象 + * @param bean 过滤条件 + * @return 字段值的集合CompletableFuture + */ + default CompletableFuture> queryColumnSetAsync( + String selectedColumn, Flipper flipper, FilterBean bean) { + return dataSource().queryColumnSetAsync(selectedColumn, entityType(), flipper, bean); + } + + /** + * 查询符合过滤条件记录的某个字段Set集合
+ * 等价SQL: SELECT DISTINCT {selectedColumn} FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT + * {flipper.limit}
+ * + * @param 字段类型 + * @param selectedColumn 指定字段 + * @param flipper 翻页对象 + * @param node 过滤条件 + * @return 字段值的集合 + */ + default Set queryColumnSet(String selectedColumn, Flipper flipper, FilterNode node) { + return dataSource().queryColumnSet(selectedColumn, entityType(), flipper, node); + } + + /** + * 查询符合过滤条件记录的某个字段Set集合
+ * 等价SQL: SELECT DISTINCT {selectedColumn} FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT + * {flipper.limit}
+ * + * @param 字段类型 + * @param selectedColumn 指定字段 + * @param flipper 翻页对象 + * @param node 过滤条件 + * @return 字段值的集合CompletableFuture + */ + default CompletableFuture> queryColumnSetAsync( + String selectedColumn, Flipper flipper, FilterNode node) { + return dataSource().queryColumnSetAsync(selectedColumn, entityType(), flipper, node); + } + + /** + * 查询符合过滤条件记录的某个字段List集合
+ * 等价SQL: SELECT {selectedColumn} FROM {table} WHERE {column} = {key}
+ * + * @param 字段类型 + * @param selectedColumn 指定字段 + * @param column 过滤字段名 + * @param colval 过滤字段值 + * @return 字段值的集合 + */ + default List queryColumnList( + String selectedColumn, String column, Serializable colval) { + return dataSource().queryColumnList(selectedColumn, entityType(), column, colval); + } + + /** + * 查询符合过滤条件记录的某个字段List集合
+ * 等价SQL: SELECT {selectedColumn} FROM {table} WHERE {column} = {key}
+ * + * @param 字段类型 + * @param selectedColumn 指定字段 + * @param column 过滤字段名 + * @param colval 过滤字段值 + * @return 字段值的集合CompletableFuture + */ + default CompletableFuture> queryColumnListAsync( + String selectedColumn, String column, Serializable colval) { + return dataSource().queryColumnListAsync(selectedColumn, entityType(), column, colval); + } + + /** + * 查询符合过滤条件记录的某个字段List集合
+ * 等价SQL: SELECT {selectedColumn} FROM {table} WHERE {filter bean}
+ * + * @param 字段类型 + * @param selectedColumn 指定字段 + * @param bean 过滤条件 + * @return 字段值的集合 + */ + default List queryColumnList(String selectedColumn, FilterBean bean) { + return dataSource().queryColumnList(selectedColumn, entityType(), bean); + } + + /** + * 查询符合过滤条件记录的某个字段List集合
+ * 等价SQL: SELECT {selectedColumn} FROM {table} WHERE {filter bean}
+ * + * @param 字段类型 + * @param selectedColumn 指定字段 + * @param bean 过滤条件 + * @return 字段值的集合CompletableFuture + */ + default CompletableFuture> queryColumnListAsync( + String selectedColumn, FilterBean bean) { + return dataSource().queryColumnListAsync(selectedColumn, entityType(), bean); + } + + /** + * 查询符合过滤条件记录的某个字段List集合
+ * 等价SQL: SELECT {selectedColumn} FROM {table} WHERE {filter node}
+ * + * @param 字段类型 + * @param selectedColumn 指定字段 + * @param node 过滤条件 + * @return 字段值的集合 + */ + default List queryColumnList(String selectedColumn, FilterNode node) { + return dataSource().queryColumnList(selectedColumn, entityType(), node); + } + + /** + * 查询符合过滤条件记录的某个字段List集合
+ * 等价SQL: SELECT {selectedColumn} FROM {table} WHERE {filter node}
+ * + * @param 字段类型 + * @param selectedColumn 指定字段 + * @param node 过滤条件 + * @return 字段值的集合CompletableFuture + */ + default CompletableFuture> queryColumnListAsync( + String selectedColumn, FilterNode node) { + return dataSource().queryColumnListAsync(selectedColumn, entityType(), node); + } + + /** + * 查询符合过滤条件记录的某个字段List集合
+ * 等价SQL: SELECT {selectedColumn} FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit} + *
+ * + * @param 字段类型 + * @param selectedColumn 指定字段 + * @param flipper 翻页对象 + * @param bean 过滤条件 + * @return 字段值的集合 + */ + default List queryColumnList(String selectedColumn, Flipper flipper, FilterBean bean) { + return dataSource().queryColumnList(selectedColumn, entityType(), flipper, bean); + } + + /** + * 查询符合过滤条件记录的某个字段List集合
+ * 等价SQL: SELECT {selectedColumn} FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit} + *
+ * + * @param 字段类型 + * @param selectedColumn 指定字段 + * @param flipper 翻页对象 + * @param bean 过滤条件 + * @return 字段值的集合CompletableFuture + */ + default CompletableFuture> queryColumnListAsync( + String selectedColumn, Flipper flipper, FilterBean bean) { + return dataSource().queryColumnListAsync(selectedColumn, entityType(), flipper, bean); + } + + /** + * 查询符合过滤条件记录的某个字段List集合
+ * 等价SQL: SELECT {selectedColumn} FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit} + *
+ * + * @param 字段类型 + * @param selectedColumn 指定字段 + * @param flipper 翻页对象 + * @param node 过滤条件 + * @return 字段值的集合 + */ + default List queryColumnList(String selectedColumn, Flipper flipper, FilterNode node) { + return dataSource().queryColumnList(selectedColumn, entityType(), flipper, node); + } + + /** + * 查询符合过滤条件记录的某个字段List集合
+ * 等价SQL: SELECT {selectedColumn} FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit} + *
+ * + * @param 字段类型 + * @param selectedColumn 指定字段 + * @param flipper 翻页对象 + * @param node 过滤条件 + * @return 字段值的集合CompletableFuture + */ + default CompletableFuture> queryColumnListAsync( + String selectedColumn, Flipper flipper, FilterNode node) { + return dataSource().queryColumnListAsync(selectedColumn, entityType(), flipper, node); + } + + /** + * 查询符合过滤条件记录的某个字段Sheet集合
+ * 等价SQL: SELECT {selectedColumn} FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit} + *
+ * + * @param 字段类型 + * @param selectedColumn 指定字段 + * @param flipper 翻页对象 + * @param bean 过滤条件 + * @return 字段值的集合 + */ + default Sheet queryColumnSheet( + String selectedColumn, Flipper flipper, FilterBean bean) { + return dataSource().queryColumnSheet(selectedColumn, entityType(), flipper, bean); + } + + /** + * 查询符合过滤条件记录的某个字段Sheet集合
+ * 等价SQL: SELECT {selectedColumn} FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit} + *
+ * + * @param 字段类型 + * @param selectedColumn 指定字段 + * @param flipper 翻页对象 + * @param bean 过滤条件 + * @return 字段值的集合CompletableFuture + */ + default CompletableFuture> queryColumnSheetAsync( + String selectedColumn, Flipper flipper, FilterBean bean) { + return dataSource().queryColumnSheetAsync(selectedColumn, entityType(), flipper, bean); + } + + /** + * 查询符合过滤条件记录的某个字段Sheet集合
+ * 等价SQL: SELECT {selectedColumn} FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit} + *
+ * + * @param 字段类型 + * @param selectedColumn 指定字段 + * @param flipper 翻页对象 + * @param node 过滤条件 + * @return 字段值的集合 + */ + default Sheet queryColumnSheet( + String selectedColumn, Flipper flipper, FilterNode node) { + return dataSource().queryColumnSheet(selectedColumn, entityType(), flipper, node); + } + + /** + * 查询符合过滤条件记录的某个字段Sheet集合
+ * 等价SQL: SELECT {selectedColumn} FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit} + *
+ * + * @param 字段类型 + * @param selectedColumn 指定字段 + * @param flipper 翻页对象 + * @param node 过滤条件 + * @return 字段值的集合CompletableFuture + */ + default CompletableFuture> queryColumnSheetAsync( + String selectedColumn, Flipper flipper, FilterNode node) { + return dataSource().queryColumnSheetAsync(selectedColumn, entityType(), flipper, node); + } + + /** + * 查询符合过滤条件记录的List转Map集合, key=主键值, value=Entity对象
+ * 等价SQL: SELECT * FROM {table} WHERE id IN {ids}
+ * + * @param 主键泛型 + * @param keyStream 主键Stream + * @return Entity的集合 + */ + default Map queryMap(Stream keyStream) { + return dataSource().queryMap(entityType(), keyStream); + } + + /** + * 查询符合过滤条件记录的List转Map集合, key=主键值, value=Entity对象
+ * 等价SQL: SELECT * FROM {table} WHERE id IN {ids}
+ * + * @param 主键泛型 + * @param keyStream 主键Stream + * @return Entity的集合CompletableFuture + */ + default CompletableFuture> queryMapAsync(Stream keyStream) { + return dataSource().queryMapAsync(entityType(), keyStream); + } + + /** + * 查询符合过滤条件记录的List转Map集合, key=主键值, value=Entity对象
+ * 等价SQL: SELECT * FROM {table} WHERE {filter node}
+ * + * @param 主键泛型 + * @param bean FilterBean + * @return Entity的集合 + */ + default Map queryMap(FilterBean bean) { + return dataSource().queryMap(entityType(), bean); + } + + /** + * 查询符合过滤条件记录的List转Map集合, key=主键值, value=Entity对象
+ * 等价SQL: SELECT * FROM {table} WHERE {filter node}
+ * + * @param 主键泛型 + * @param bean FilterBean + * @return Entity的集合CompletableFuture + */ + default CompletableFuture> queryMapAsync(FilterBean bean) { + return dataSource().queryMapAsync(entityType(), bean); + } + + /** + * 查询符合过滤条件记录的List转Map集合, key=主键值, value=Entity对象
+ * 等价SQL: SELECT * FROM {table} WHERE {filter node}
+ * + * @param 主键泛型 + * @param node FilterNode + * @return Entity的集合 + */ + default Map queryMap(FilterNode node) { + return dataSource().queryMap(entityType(), node); + } + + /** + * 查询符合过滤条件记录的List转Map集合, key=主键值, value=Entity对象
+ * 等价SQL: SELECT * FROM {table} WHERE {filter node}
+ * + * @param 主键泛型 + * @param node FilterNode + * @return Entity的集合CompletableFuture + */ + default CompletableFuture> queryMapAsync(FilterNode node) { + return dataSource().queryMapAsync(entityType(), node); + } + + /** + * 查询符合过滤条件记录的List转Map集合, key=主键值, value=Entity对象
+ * 等价SQL: SELECT * FROM {table} WHERE id IN {ids}
+ * + * @param 主键泛型 + * @param selects 指定字段 + * @param keyStream 主键Stream + * @return Entity的集合 + */ + default Map queryMap(SelectColumn selects, Stream keyStream) { + return dataSource().queryMap(entityType(), selects, keyStream); + } + + /** + * 查询符合过滤条件记录的List转Map集合, key=主键值, value=Entity对象
+ * 等价SQL: SELECT * FROM {table} WHERE id IN {ids}
+ * + * @param 主键泛型 + * @param selects 指定字段 + * @param keyStream 主键Stream + * @return Entity的集合CompletableFuture + */ + default CompletableFuture> queryMapAsync( + SelectColumn selects, Stream keyStream) { + return dataSource().queryMapAsync(entityType(), selects, keyStream); + } + + /** + * 查询符合过滤条件记录的List转Map集合, key=主键值, value=Entity对象
+ * 等价SQL: SELECT * FROM {table} WHERE {filter node}
+ * + * @param 主键泛型 + * @param selects 指定字段 + * @param bean FilterBean + * @return Entity的集合 + */ + default Map queryMap(SelectColumn selects, FilterBean bean) { + return dataSource().queryMap(entityType(), selects, bean); + } + + /** + * 查询符合过滤条件记录的List转Map集合, key=主键值, value=Entity对象
+ * 等价SQL: SELECT * FROM {table} WHERE {filter node}
+ * + * @param 主键泛型 + * @param selects 指定字段 + * @param bean FilterBean + * @return Entity的集合CompletableFuture + */ + default CompletableFuture> queryMapAsync(SelectColumn selects, FilterBean bean) { + return dataSource().queryMapAsync(entityType(), selects, bean); + } + + /** + * 查询符合过滤条件记录的List转Map集合, key=主键值, value=Entity对象
+ * 等价SQL: SELECT * FROM {table} WHERE {filter node}
+ * + * @param 主键泛型 + * @param selects 指定字段 + * @param node FilterNode + * @return Entity的集合 + */ + default Map queryMap(SelectColumn selects, FilterNode node) { + return dataSource().queryMap(entityType(), selects, node); + } + + /** + * 查询符合过滤条件记录的List转Map集合, key=主键值, value=Entity对象
+ * 等价SQL: SELECT * FROM {table} WHERE {filter node}
+ * + * @param 主键泛型 + * @param selects 指定字段 + * @param node FilterNode + * @return Entity的集合CompletableFuture + */ + default CompletableFuture> queryMapAsync(SelectColumn selects, FilterNode node) { + return dataSource().queryMapAsync(entityType(), selects, node); + } + + /** + * 查询符合过滤条件记录的Set集合
+ * 等价SQL: SELECT DISTINCT * FROM {table} WHERE {column} = {key} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param column 过滤字段名 + * @param colval 过滤字段值 + * @return Entity的集合 + */ + default Set querySet(String column, Serializable colval) { + return dataSource().querySet(entityType(), column, colval); + } + + /** + * 查询符合过滤条件记录的Set集合
+ * 等价SQL: SELECT DISTINCT * FROM {table} WHERE {column} = {key} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param column 过滤字段名 + * @param colval 过滤字段值 + * @return Entity的集合CompletableFuture + */ + default CompletableFuture> querySetAsync(String column, Serializable colval) { + return dataSource().querySetAsync(entityType(), column, colval); + } + + /** + * 查询符合过滤条件记录的Set集合
+ * 等价SQL: SELECT DISTINCT * FROM {table} WHERE {filter bean}
+ * + * @param bean 过滤条件 + * @return Entity的集合 + */ + default Set querySet(FilterBean bean) { + return dataSource().querySet(entityType(), bean); + } + + /** + * 查询符合过滤条件记录的Set集合
+ * 等价SQL: SELECT DISTINCT * FROM {table} WHERE {filter bean}
+ * + * @param bean 过滤条件 + * @return Entity的集合CompletableFuture + */ + default CompletableFuture> querySetAsync(FilterBean bean) { + return dataSource().querySetAsync(entityType(), bean); + } + + /** + * 查询记录的Set集合
+ * 等价SQL: SELECT DISTINCT * FROM {table}
+ * + * @return Entity的集合 + */ + default Set querySet() { + return dataSource().querySet(entityType()); + } + + /** + * 查询符合过滤条件记录的Set集合
+ * 等价SQL: SELECT DISTINCT * FROM {table} WHERE {filter node}
+ * + * @param node 过滤条件 + * @return Entity的集合 + */ + default Set querySet(FilterNode node) { + return dataSource().querySet(entityType(), node); + } + + /** + * 查询记录的Set集合
+ * 等价SQL: SELECT DISTINCT * FROM {table}
+ * + * @return Entity的集合CompletableFuture + */ + default CompletableFuture> querySetAsync() { + return dataSource().querySetAsync(entityType()); + } + + /** + * 查询符合过滤条件记录的Set集合
+ * 等价SQL: SELECT DISTINCT * FROM {table} WHERE {filter node}
+ * + * @param node 过滤条件 + * @return Entity的集合CompletableFuture + */ + default CompletableFuture> querySetAsync(FilterNode node) { + return dataSource().querySetAsync(entityType(), node); + } + + /** + * 查询符合过滤条件记录的Set集合
+ * 等价SQL: SELECT DISTINCT {column1},{column2}, ··· FROM {table} WHERE {filter bean}
+ * + * @param selects 指定字段 + * @param bean 过滤条件 + * @return Entity的集合 + */ + default Set querySet(SelectColumn selects, FilterBean bean) { + return dataSource().querySet(entityType(), selects, bean); + } + + /** + * 查询符合过滤条件记录的Set集合
+ * 等价SQL: SELECT DISTINCT {column1},{column2}, ··· FROM {table} WHERE {filter bean}
+ * + * @param selects 指定字段 + * @param bean 过滤条件 + * @return Entity的集合CompletableFuture + */ + default CompletableFuture> querySetAsync(SelectColumn selects, FilterBean bean) { + return dataSource().querySetAsync(entityType(), selects, bean); + } + + /** + * 查询符合过滤条件记录的Set集合
+ * 等价SQL: SELECT DISTINCT {column1},{column2}, ··· FROM {table} WHERE {filter node}
+ * + * @param selects 指定字段 + * @param node 过滤条件 + * @return Entity的集合 + */ + default Set querySet(SelectColumn selects, FilterNode node) { + return dataSource().querySet(entityType(), selects, node); + } + + /** + * 查询符合过滤条件记录的Set集合
+ * 等价SQL: SELECT DISTINCT {column1},{column2}, ··· FROM {table} WHERE {filter node}
+ * + * @param selects 指定字段 + * @param node 过滤条件 + * @return Entity的集合CompletableFuture + */ + default CompletableFuture> querySetAsync(SelectColumn selects, FilterNode node) { + return dataSource().querySetAsync(entityType(), selects, node); + } + + /** + * 查询符合过滤条件记录的Set集合
+ * 等价SQL: SELECT DISTINCT * FROM {table} WHERE {column} = {key} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param flipper 翻页对象 + * @param column 过滤字段名 + * @param colval 过滤字段值 + * @return Entity的集合 + */ + default Set querySet(Flipper flipper, String column, Serializable colval) { + return dataSource().querySet(entityType(), flipper, column, colval); + } + + /** + * 查询符合过滤条件记录的Set集合
+ * 等价SQL: SELECT DISTINCT * FROM {table} WHERE {column} = {key} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param flipper 翻页对象 + * @param column 过滤字段名 + * @param colval 过滤字段值 + * @return Entity的集合CompletableFuture + */ + default CompletableFuture> querySetAsync(Flipper flipper, String column, Serializable colval) { + return dataSource().querySetAsync(entityType(), flipper, column, colval); + } + + /** + * 查询符合过滤条件记录的Set集合
+ * 等价SQL: SELECT DISTINCT * FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param flipper 翻页对象 + * @param bean 过滤条件 + * @return Entity的集合 + */ + default Set querySet(Flipper flipper, FilterBean bean) { + return dataSource().querySet(entityType(), flipper, bean); + } + + /** + * 查询符合过滤条件记录的Set集合
+ * 等价SQL: SELECT DISTINCT * FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param flipper 翻页对象 + * @param bean 过滤条件 + * @return Entity的集合CompletableFuture + */ + default CompletableFuture> querySetAsync(Flipper flipper, FilterBean bean) { + return dataSource().querySetAsync(entityType(), flipper, bean); + } + + /** + * 查询符合过滤条件记录的Set集合
+ * 等价SQL: SELECT DISTINCT * FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param flipper 翻页对象 + * @param node 过滤条件 + * @return Entity的集合 + */ + default Set querySet(Flipper flipper, FilterNode node) { + return dataSource().querySet(entityType(), flipper, node); + } + + /** + * 查询符合过滤条件记录的Set集合
+ * 等价SQL: SELECT DISTINCT * FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param flipper 翻页对象 + * @param node 过滤条件 + * @return Entity的集合 + */ + default CompletableFuture> querySetAsync(Flipper flipper, FilterNode node) { + return dataSource().querySetAsync(entityType(), flipper, node); + } + + /** + * 查询符合过滤条件记录的Set集合
+ * 等价SQL: SELECT DISTINCT {column1},{column2}, ··· FROM {table} WHERE {filter bean} ORDER BY + * {flipper.sort} LIMIT {flipper.limit}
+ * + * @param selects 指定字段 + * @param flipper 翻页对象 + * @param bean 过滤条件 + * @return Entity的集合 + */ + default Set querySet(SelectColumn selects, Flipper flipper, FilterBean bean) { + return dataSource().querySet(entityType(), selects, flipper, bean); + } + + /** + * 查询符合过滤条件记录的Set集合
+ * 等价SQL: SELECT DISTINCT {column1},{column2}, ··· FROM {table} WHERE {filter bean} ORDER BY + * {flipper.sort} LIMIT {flipper.limit}
+ * + * @param selects 指定字段 + * @param flipper 翻页对象 + * @param bean 过滤条件 + * @return Entity的集合CompletableFuture + */ + default CompletableFuture> querySetAsync(SelectColumn selects, Flipper flipper, FilterBean bean) { + return dataSource().querySetAsync(entityType(), selects, flipper, bean); + } + + /** + * 查询符合过滤条件记录的Set集合
+ * 等价SQL: SELECT DISTINCT {column1},{column2}, ··· FROM {table} WHERE {filter node} ORDER BY + * {flipper.sort} LIMIT {flipper.limit}
+ * + * @param selects 指定字段 + * @param flipper 翻页对象 + * @param node 过滤条件 + * @return Entity的集合 + */ + default Set querySet(SelectColumn selects, Flipper flipper, FilterNode node) { + return dataSource().querySet(entityType(), selects, flipper, node); + } + + /** + * 查询符合过滤条件记录的Set集合
+ * 等价SQL: SELECT DISTINCT {column1},{column2}, ··· FROM {table} WHERE {filter node} ORDER BY + * {flipper.sort} LIMIT {flipper.limit}
+ * + * @param selects 指定字段 + * @param flipper 翻页对象 + * @param node 过滤条件 + * @return Entity的集合CompletableFuture + */ + default CompletableFuture> querySetAsync(SelectColumn selects, Flipper flipper, FilterNode node) { + return dataSource().querySetAsync(entityType(), selects, flipper, node); + } + + /** + * 查询符合过滤条件记录的List集合
+ * 等价SQL: SELECT * FROM {table} WHERE {column} = {key} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param column 过滤字段名 + * @param colval 过滤字段值 + * @return Entity的集合 + */ + default List queryList(String column, Serializable colval) { + return dataSource().queryList(entityType(), column, colval); + } + + /** + * 查询符合过滤条件记录的List集合
+ * 等价SQL: SELECT * FROM {table} WHERE {column} = {key} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param column 过滤字段名 + * @param colval 过滤字段值 + * @return Entity的集合CompletableFuture + */ + default CompletableFuture> queryListAsync(String column, Serializable colval) { + return dataSource().queryListAsync(entityType(), column, colval); + } + + /** + * 查询符合过滤条件记录的List集合
+ * 等价SQL: SELECT * FROM {table} WHERE {filter bean}
+ * + * @param bean 过滤条件 + * @return Entity的集合 + */ + default List queryList(FilterBean bean) { + return dataSource().queryList(entityType(), bean); + } + + /** + * 查询符合过滤条件记录的List集合
+ * 等价SQL: SELECT * FROM {table} WHERE {filter bean}
+ * + * @param bean 过滤条件 + * @return Entity的集合CompletableFuture + */ + default CompletableFuture> queryListAsync(FilterBean bean) { + return dataSource().queryListAsync(entityType(), bean); + } + + /** + * 查询记录的List集合
+ * 等价SQL: SELECT * FROM {table}
+ * + * @return Entity的集合 + */ + default List queryList() { + return dataSource().queryList(entityType()); + } + + /** + * 查询符合过滤条件记录的List集合
+ * 等价SQL: SELECT * FROM {table} WHERE {filter node}
+ * + * @param node 过滤条件 + * @return Entity的集合 + */ + default List queryList(FilterNode node) { + return dataSource().queryList(entityType(), node); + } + + /** + * 查询记录的List集合
+ * 等价SQL: SELECT * FROM {table}
+ * + * @return Entity的集合CompletableFuture + */ + default CompletableFuture> queryListAsync() { + return dataSource().queryListAsync(entityType()); + } + + /** + * 查询符合过滤条件记录的List集合
+ * 等价SQL: SELECT * FROM {table} WHERE {filter node}
+ * + * @param node 过滤条件 + * @return Entity的集合CompletableFuture + */ + default CompletableFuture> queryListAsync(FilterNode node) { + return dataSource().queryListAsync(entityType(), node); + } + + /** + * 查询符合过滤条件记录的List集合
+ * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter bean}
+ * + * @param selects 指定字段 + * @param bean 过滤条件 + * @return Entity的集合 + */ + default List queryList(SelectColumn selects, FilterBean bean) { + return dataSource().queryList(entityType(), selects, bean); + } + + /** + * 查询符合过滤条件记录的List集合
+ * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter bean}
+ * + * @param selects 指定字段 + * @param bean 过滤条件 + * @return Entity的集合CompletableFuture + */ + default CompletableFuture> queryListAsync(SelectColumn selects, FilterBean bean) { + return dataSource().queryListAsync(entityType(), selects, bean); + } + + /** + * 查询符合过滤条件记录的List集合
+ * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter node}
+ * + * @param selects 指定字段 + * @param node 过滤条件 + * @return Entity的集合 + */ + default List queryList(SelectColumn selects, FilterNode node) { + return dataSource().queryList(entityType(), selects, node); + } + + /** + * 查询符合过滤条件记录的List集合
+ * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter node}
+ * + * @param selects 指定字段 + * @param node 过滤条件 + * @return Entity的集合CompletableFuture + */ + default CompletableFuture> queryListAsync(SelectColumn selects, FilterNode node) { + return dataSource().queryListAsync(entityType(), selects, node); + } + + /** + * 查询符合过滤条件记录的List集合
+ * 等价SQL: SELECT * FROM {table} WHERE {column} = {key} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param flipper 翻页对象 + * @param column 过滤字段名 + * @param colval 过滤字段值 + * @return Entity的集合 + */ + default List queryList(Flipper flipper, String column, Serializable colval) { + return dataSource().queryList(entityType(), flipper, column, colval); + } + + /** + * 查询符合过滤条件记录的List集合
+ * 等价SQL: SELECT * FROM {table} WHERE {column} = {key} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param flipper 翻页对象 + * @param column 过滤字段名 + * @param colval 过滤字段值 + * @return Entity的集合CompletableFuture + */ + default CompletableFuture> queryListAsync(Flipper flipper, String column, Serializable colval) { + return dataSource().queryListAsync(entityType(), flipper, column, colval); + } + + /** + * 查询符合过滤条件记录的List集合
+ * 等价SQL: SELECT * FROM {table} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param flipper 翻页对象 + * @return Entity的集合 + */ + default List queryList(Flipper flipper) { + return dataSource().queryList(entityType(), flipper); + } + + /** + * 查询符合过滤条件记录的List集合
+ * 等价SQL: SELECT * FROM {table} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param flipper 翻页对象 + * @return Entity的集合CompletableFuture + */ + default CompletableFuture> queryListAsync(Flipper flipper) { + return dataSource().queryListAsync(entityType(), flipper); + } + + /** + * 查询符合过滤条件记录的List集合
+ * 等价SQL: SELECT * FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param flipper 翻页对象 + * @param bean 过滤条件 + * @return Entity的集合 + */ + default List queryList(Flipper flipper, FilterBean bean) { + return dataSource().queryList(entityType(), flipper, bean); + } + + /** + * 查询符合过滤条件记录的List集合
+ * 等价SQL: SELECT * FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param flipper 翻页对象 + * @param bean 过滤条件 + * @return Entity的集合CompletableFuture + */ + default CompletableFuture> queryListAsync(Flipper flipper, FilterBean bean) { + return dataSource().queryListAsync(entityType(), flipper, bean); + } + + /** + * 查询符合过滤条件记录的List集合
+ * 等价SQL: SELECT * FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param flipper 翻页对象 + * @param node 过滤条件 + * @return Entity的集合 + */ + default List queryList(Flipper flipper, FilterNode node) { + return dataSource().queryList(entityType(), flipper, node); + } + + /** + * 查询符合过滤条件记录的List集合
+ * 等价SQL: SELECT * FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param flipper 翻页对象 + * @param node 过滤条件 + * @return Entity的集合 + */ + default CompletableFuture> queryListAsync(Flipper flipper, FilterNode node) { + return dataSource().queryListAsync(entityType(), flipper, node); + } + + /** + * 查询符合过滤条件记录的List集合
+ * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} ORDER BY {flipper.sort} LIMIT {flipper.limit} + *
+ * + * @param selects 指定字段 + * @param flipper 翻页对象 + * @return Entity的集合 + */ + default List queryList(SelectColumn selects, Flipper flipper) { + return dataSource().queryList(entityType(), selects, flipper); + } + + /** + * 查询符合过滤条件记录的List集合
+ * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} ORDER BY {flipper.sort} LIMIT {flipper.limit} + *
+ * + * @param selects 指定字段 + * @param flipper 翻页对象 + * @return Entity的集合CompletableFuture + */ + default CompletableFuture> queryListAsync(SelectColumn selects, Flipper flipper) { + return dataSource().queryListAsync(entityType(), selects, flipper); + } + + /** + * 查询符合过滤条件记录的List集合
+ * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} + * LIMIT {flipper.limit}
+ * + * @param selects 指定字段 + * @param flipper 翻页对象 + * @param bean 过滤条件 + * @return Entity的集合 + */ + default List queryList(SelectColumn selects, Flipper flipper, FilterBean bean) { + return dataSource().queryList(entityType(), selects, flipper, bean); + } + + /** + * 查询符合过滤条件记录的List集合
+ * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} + * LIMIT {flipper.limit}
+ * + * @param selects 指定字段 + * @param flipper 翻页对象 + * @param bean 过滤条件 + * @return Entity的集合CompletableFuture + */ + default CompletableFuture> queryListAsync(SelectColumn selects, Flipper flipper, FilterBean bean) { + return dataSource().queryListAsync(entityType(), selects, flipper, bean); + } + + /** + * 查询符合过滤条件记录的List集合
+ * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter node} ORDER BY {flipper.sort} + * LIMIT {flipper.limit}
+ * + * @param selects 指定字段 + * @param flipper 翻页对象 + * @param node 过滤条件 + * @return Entity的集合 + */ + default List queryList(SelectColumn selects, Flipper flipper, FilterNode node) { + return dataSource().queryList(entityType(), selects, flipper, node); + } + + /** + * 查询符合过滤条件记录的List集合
+ * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter node} ORDER BY {flipper.sort} + * LIMIT {flipper.limit}
+ * + * @param selects 指定字段 + * @param flipper 翻页对象 + * @param node 过滤条件 + * @return Entity的集合CompletableFuture + */ + default CompletableFuture> queryListAsync(SelectColumn selects, Flipper flipper, FilterNode node) { + return dataSource().queryListAsync(entityType(), selects, flipper, node); + } + + // -----------------------sheet---------------------------- + /** + * 查询符合过滤条件记录的Sheet集合
+ * 等价SQL: SELECT * FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param flipper 翻页对象 + * @param bean 过滤条件 + * @return Entity的集合 + */ + default Sheet querySheet(Flipper flipper, FilterBean bean) { + return dataSource().querySheet(entityType(), flipper, bean); + } + + /** + * 查询符合过滤条件记录的Sheet集合
+ * 等价SQL: SELECT * FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param 过滤类型 + * @param pageBean 过滤翻页条件 + * @return Entity的集合 + */ + default Sheet querySheet(PageBean pageBean) { + return dataSource().querySheet(entityType(), pageBean); + } + + /** + * 查询符合过滤条件记录的Sheet集合
+ * 等价SQL: SELECT * FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param flipper 翻页对象 + * @param bean 过滤条件 + * @return Entity的集合CompletableFuture + */ + default CompletableFuture> querySheetAsync(Flipper flipper, FilterBean bean) { + return dataSource().querySheetAsync(entityType(), flipper, bean); + } + + /** + * 查询符合过滤条件记录的Sheet集合
+ * 等价SQL: SELECT * FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param 过滤类型 + * @param pageBean 过滤翻页条件 + * @return Entity的集合 + */ + default CompletableFuture> querySheetAsync(PageBean pageBean) { + return dataSource().querySheetAsync(entityType(), pageBean); + } + + /** + * 查询符合过滤条件记录的Sheet集合
+ * 等价SQL: SELECT * FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param flipper 翻页对象 + * @param node 过滤条件 + * @return Entity的集合 + */ + default Sheet querySheet(Flipper flipper, FilterNode node) { + return dataSource().querySheet(entityType(), flipper, node); + } + + /** + * 查询符合过滤条件记录的Sheet集合
+ * 等价SQL: SELECT * FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param flipper 翻页对象 + * @param node 过滤条件 + * @return Entity的集合CompletableFuture + */ + default CompletableFuture> querySheetAsync(Flipper flipper, FilterNode node) { + return dataSource().querySheetAsync(entityType(), flipper, node); + } + + /** + * 查询符合过滤条件记录的Sheet集合
+ * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} + * LIMIT {flipper.limit}
+ * + * @param selects 指定字段 + * @param flipper 翻页对象 + * @param bean 过滤条件 + * @return Entity的集合 + */ + default Sheet querySheet(SelectColumn selects, Flipper flipper, FilterBean bean) { + return dataSource().querySheet(entityType(), selects, flipper, bean); + } + + /** + * 查询符合过滤条件记录的Sheet集合
+ * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} + * LIMIT {flipper.limit}
+ * + * @param 过滤类型 + * @param selects 指定字段 + * @param pageBean 过滤翻页条件 + * @return Entity的集合 + */ + default Sheet querySheet(SelectColumn selects, PageBean pageBean) { + return dataSource().querySheet(entityType(), selects, pageBean); + } + + /** + * 查询符合过滤条件记录的Sheet集合
+ * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} + * LIMIT {flipper.limit}
+ * + * @param selects 指定字段 + * @param flipper 翻页对象 + * @param bean 过滤条件 + * @return Entity的集合CompletableFuture + */ + default CompletableFuture> querySheetAsync(SelectColumn selects, Flipper flipper, FilterBean bean) { + return dataSource().querySheetAsync(entityType(), selects, flipper, bean); + } + + /** + * 查询符合过滤条件记录的Sheet集合
+ * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} + * LIMIT {flipper.limit}
+ * + * @param 过滤类型 + * @param selects 指定字段 + * @param pageBean 过滤翻页条件 + * @return Entity的集合 + */ + default CompletableFuture> querySheetAsync( + SelectColumn selects, PageBean pageBean) { + return dataSource().querySheetAsync(entityType(), selects, pageBean); + } + + /** + * 查询符合过滤条件记录的Sheet集合
+ * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter node} ORDER BY {flipper.sort} + * LIMIT {flipper.limit}
+ * + * @param selects 指定字段 + * @param flipper 翻页对象 + * @param node 过滤条件 + * @return Entity的集合 + */ + default Sheet querySheet(SelectColumn selects, Flipper flipper, FilterNode node) { + return dataSource().querySheet(entityType(), selects, flipper, node); + } + + /** + * 查询符合过滤条件记录的Sheet集合
+ * 等价SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter node} ORDER BY {flipper.sort} + * LIMIT {flipper.limit}
+ * + * @param selects 指定字段 + * @param flipper 翻页对象 + * @param node 过滤条件 + * @return Entity的集合CompletableFuture + */ + default CompletableFuture> querySheetAsync(SelectColumn selects, Flipper flipper, FilterNode node) { + return dataSource().querySheetAsync(entityType(), selects, flipper, node); + } +} diff --git a/src/main/java/org/redkale/source/DataSqlSource.java b/src/main/java/org/redkale/source/DataSqlSource.java index df81730bd..7852632cc 100644 --- a/src/main/java/org/redkale/source/DataSqlSource.java +++ b/src/main/java/org/redkale/source/DataSqlSource.java @@ -1,451 +1,451 @@ -/* - * - */ -package org.redkale.source; - -import static org.redkale.source.DataResultSet.formatColumnValue; - -import java.io.Serializable; -import java.util.*; -import java.util.concurrent.CompletableFuture; -import java.util.function.*; -import org.redkale.annotation.ClassDepends; -import org.redkale.util.*; - -/** - * 关系型sql数据库的数据源, 比DataSource多了操作sql语句的接口。
- * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -@ClassDepends -public interface DataSqlSource extends DataSource { - - /** - * 执行多条原生无参数的sql - * - * @param sqls 无参数的sql语句 - * @return 执行条数 - */ - public int[] nativeUpdates(String... sqls); - - /** - * 执行多条原生无参数的sql - * - * @param sqls 无参数的sql语句 - * @return 执行条数 - */ - public CompletableFuture nativeUpdatesAsync(String... sqls); - - /** - * 执行原生无参数的sql - * - * @param sql 无参数的sql语句 - * @return 执行条数 - */ - public int nativeUpdate(String sql); - - /** - * 执行原生无参数的sql - * - * @param sql 无参数的sql语句 - * @return 执行条数 - */ - public CompletableFuture nativeUpdateAsync(String sql); - - /** - * 执行原生带参数的sql - * - * @param sql 带参数的sql语句 - * @param params 参数值集合 - * @return 执行条数 - */ - @ClassDepends - public int nativeUpdate(String sql, Map params); - - /** - * 执行原生带参数的sql - * - * @param sql 带参数的sql语句 - * @param params 参数值集合 - * @return 执行条数 - */ - @ClassDepends - public CompletableFuture nativeUpdateAsync(String sql, Map params); - - /** - * 通过原生的sql查询结果 - * - * @param 泛型 - * @param sql 无参数的sql语句 - * @param consumer BiConsumer 参数1: connection, 参数2: statement - * @param handler DataResultSet的回调函数 - * @return 结果对象 - */ - public V nativeQuery(String sql, BiConsumer consumer, Function handler); - - /** - * 通过原生的sql查询结果 - * - * @param 泛型 - * @param sql 无参数的sql语句 - * @param consumer BiConsumer 参数1: connection, 参数2: statement - * @param handler DataResultSet的回调函数 - * @return 结果对象 - */ - public CompletableFuture nativeQueryAsync( - String sql, BiConsumer consumer, Function handler); - - /** - * 通过原生带参数的sql查询结果 - * - * @param 泛型 - * @param sql 带参数的sql语句 - * @param consumer BiConsumer 参数1: connection, 参数2: statement - * @param handler DataResultSet的回调函数 - * @param params 参数值集合 - * @return 结果对象 - */ - public V nativeQuery( - String sql, - BiConsumer consumer, - Function handler, - Map params); - - /** - * 通过原生带参数的sql查询结果 - * - * @param 泛型 - * @param sql 带参数的sql语句 - * @param consumer BiConsumer 参数1: connection, 参数2: statement - * @param handler DataResultSet的回调函数 - * @param params 参数值集合 - * @return 结果对象 - */ - public CompletableFuture nativeQueryAsync( - String sql, - BiConsumer consumer, - Function handler, - Map params); - - @ClassDepends - public Sheet nativeQuerySheet(Class type, String sql, Flipper flipper, Map params); - - @ClassDepends - public CompletableFuture> nativeQuerySheetAsync( - Class type, String sql, Flipper flipper, Map params); - - // ----------------------------- 无参数 ----------------------------- - default V nativeQuery(String sql, Function handler) { - return nativeQuery(sql, null, handler); - } - - default CompletableFuture nativeQueryAsync(String sql, Function handler) { - return nativeQueryAsync(sql, null, handler); - } - - @ClassDepends - default V nativeQueryOne(Class type, String sql) { - return nativeQuery(sql, rset -> EntityBuilder.getOneValue(type, rset)); - } - - @ClassDepends - default CompletableFuture nativeQueryOneAsync(Class type, String sql) { - return nativeQueryAsync(sql, rset -> EntityBuilder.getOneValue(type, rset)); - } - - @ClassDepends - default List nativeQueryList(Class type, String sql) { - return nativeQuery(sql, rset -> EntityBuilder.getListValue(type, rset)); - } - - @ClassDepends - default CompletableFuture> nativeQueryListAsync(Class type, String sql) { - return nativeQueryAsync(sql, rset -> EntityBuilder.getListValue(type, rset)); - } - - @ClassDepends - default Sheet nativeQuerySheet(Class type, String sql, Flipper flipper) { - return nativeQuerySheet(type, sql, flipper, Collections.emptyMap()); - } - - @ClassDepends - default CompletableFuture> nativeQuerySheetAsync(Class type, String sql, Flipper flipper) { - return nativeQuerySheetAsync(type, sql, flipper, Collections.emptyMap()); - } - - @ClassDepends - default Map nativeQueryMap(Class keyType, Class valType, String sql) { - return nativeQuery(sql, rset -> { - Map map = new LinkedHashMap<>(); - while (rset.next()) { - if (!rset.wasNull()) { - map.put((K) formatColumnValue(keyType, rset.getObject(1)), (V) - formatColumnValue(valType, rset.getObject(2))); - } - } - return map; - }); - } - - @ClassDepends - default CompletableFuture> nativeQueryMapAsync(Class keyType, Class valType, String sql) { - return nativeQueryAsync(sql, rset -> { - Map map = new LinkedHashMap<>(); - while (rset.next()) { - if (!rset.wasNull()) { - map.put((K) formatColumnValue(keyType, rset.getObject(1)), (V) - formatColumnValue(valType, rset.getObject(2))); - } - } - return map; - }); - } - - default Map nativeQueryToStrStrMap(String sql) { - return nativeQueryMap(String.class, String.class, sql); - } - - default CompletableFuture> nativeQueryStrStrMapAsync(String sql) { - return nativeQueryMapAsync(String.class, String.class, sql); - } - - default Map nativeQueryToIntStrMap(String sql) { - return nativeQueryMap(Integer.class, String.class, sql); - } - - default CompletableFuture> nativeQueryToIntStrMapAsync(String sql) { - return nativeQueryMapAsync(Integer.class, String.class, sql); - } - - // ----------------------------- Map ----------------------------- - default V nativeQuery(String sql, Function handler, Map params) { - return nativeQuery(sql, null, handler, params); - } - - default CompletableFuture nativeQueryAsync( - String sql, Function handler, Map params) { - return nativeQueryAsync(sql, null, handler, params); - } - - @ClassDepends - default V nativeQueryOne(Class type, String sql, Map params) { - return nativeQuery( - sql, - rset -> { - if (!rset.next()) { - return null; - } - if (EntityBuilder.isSimpleType(type)) { - return (V) formatColumnValue(type, rset.getObject(1)); - } - return EntityBuilder.load(type).getObjectValue(rset); - }, - params); - } - - @ClassDepends - default CompletableFuture nativeQueryOneAsync(Class type, String sql, Map params) { - return nativeQueryAsync( - sql, - rset -> { - if (!rset.next()) { - return null; - } - if (EntityBuilder.isSimpleType(type)) { - return (V) formatColumnValue(type, rset.getObject(1)); - } - return EntityBuilder.load(type).getObjectValue(rset); - }, - params); - } - - @ClassDepends - default List nativeQueryList(Class type, String sql, Map params) { - return nativeQuery( - sql, - rset -> { - if (EntityBuilder.isSimpleType(type)) { - List list = new ArrayList<>(); - while (rset.next()) { - list.add(rset.wasNull() ? null : (V) formatColumnValue(type, rset.getObject(1))); - } - return list; - } - return EntityBuilder.load(type).getObjectList(rset); - }, - params); - } - - @ClassDepends - default CompletableFuture> nativeQueryListAsync(Class type, String sql, Map params) { - return nativeQueryAsync( - sql, - rset -> { - if (EntityBuilder.isSimpleType(type)) { - List list = new ArrayList<>(); - while (rset.next()) { - list.add(rset.wasNull() ? null : (V) formatColumnValue(type, rset.getObject(1))); - } - return list; - } - return EntityBuilder.load(type).getObjectList(rset); - }, - params); - } - - @ClassDepends - default Map nativeQueryMap( - Class keyType, Class valType, String sql, Map params) { - return nativeQuery( - sql, - rset -> { - Map map = new LinkedHashMap<>(); - while (rset.next()) { - if (!rset.wasNull()) { - map.put((K) formatColumnValue(keyType, rset.getObject(1)), (V) - formatColumnValue(valType, rset.getObject(2))); - } - } - return map; - }, - params); - } - - @ClassDepends - default CompletableFuture> nativeQueryMapAsync( - Class keyType, Class valType, String sql, Map params) { - return nativeQueryAsync( - sql, - rset -> { - Map map = new LinkedHashMap<>(); - while (rset.next()) { - if (!rset.wasNull()) { - map.put((K) formatColumnValue(keyType, rset.getObject(1)), (V) - formatColumnValue(valType, rset.getObject(2))); - } - } - return map; - }, - params); - } - - default Map nativeQueryToStrStrMap(String sql, Map params) { - return nativeQueryMap(String.class, String.class, sql, params); - } - - default CompletableFuture> nativeQueryToStrStrMapAsync(String sql, Map params) { - return nativeQueryMapAsync(String.class, String.class, sql, params); - } - - default Map nativeQueryToIntStrMap(String sql, Map params) { - return nativeQueryMap(Integer.class, String.class, sql, params); - } - - default CompletableFuture> nativeQueryToIntStrMapAsync( - String sql, Map params) { - return nativeQueryMapAsync(Integer.class, String.class, sql, params); - } - - // ----------------------------- JavaBean ----------------------------- - default int nativeUpdate(String sql, Serializable bean) { - return nativeUpdate(sql, (Map) Copier.copyToMap(bean, Copier.OPTION_SKIP_NULL_VALUE)); - } - - default CompletableFuture nativeUpdateAsync(String sql, Serializable bean) { - return nativeUpdateAsync(sql, (Map) Copier.copyToMap(bean, Copier.OPTION_SKIP_NULL_VALUE)); - } - - default V nativeQuery(String sql, Function handler, Serializable bean) { - return nativeQuery( - sql, null, handler, (Map) Copier.copyToMap(bean, Copier.OPTION_SKIP_NULL_VALUE)); - } - - default CompletableFuture nativeQueryAsync( - String sql, Function handler, Serializable bean) { - return nativeQueryAsync( - sql, null, handler, (Map) Copier.copyToMap(bean, Copier.OPTION_SKIP_NULL_VALUE)); - } - - default V nativeQueryOne(Class type, String sql, Serializable bean) { - return nativeQueryOne(type, sql, (Map) Copier.copyToMap(bean, Copier.OPTION_SKIP_NULL_VALUE)); - } - - default CompletableFuture nativeQueryOneAsync(Class type, String sql, Serializable bean) { - return nativeQueryOneAsync( - type, sql, (Map) Copier.copyToMap(bean, Copier.OPTION_SKIP_NULL_VALUE)); - } - - default List nativeQueryList(Class type, String sql, Serializable bean) { - return nativeQueryList(type, sql, (Map) Copier.copyToMap(bean, Copier.OPTION_SKIP_NULL_VALUE)); - } - - default CompletableFuture> nativeQueryListAsync(Class type, String sql, Serializable bean) { - return nativeQueryListAsync( - type, sql, (Map) Copier.copyToMap(bean, Copier.OPTION_SKIP_NULL_VALUE)); - } - - default Map nativeQueryMap(Class keyType, Class valType, String sql, Serializable bean) { - return nativeQueryMap( - keyType, valType, sql, (Map) Copier.copyToMap(bean, Copier.OPTION_SKIP_NULL_VALUE)); - } - - default CompletableFuture> nativeQueryMapAsync( - Class keyType, Class valType, String sql, Serializable bean) { - return nativeQueryMapAsync( - keyType, valType, sql, (Map) Copier.copyToMap(bean, Copier.OPTION_SKIP_NULL_VALUE)); - } - - default Map nativeQueryToStrStrMap(String sql, Serializable bean) { - return nativeQueryMap(String.class, String.class, sql, (Map) - Copier.copyToMap(bean, Copier.OPTION_SKIP_NULL_VALUE)); - } - - default CompletableFuture> nativeQueryToStrStrMapAsync(String sql, Serializable bean) { - return nativeQueryMapAsync(String.class, String.class, sql, (Map) - Copier.copyToMap(bean, Copier.OPTION_SKIP_NULL_VALUE)); - } - - default Map nativeQueryToIntStrMap(String sql, Serializable bean) { - return nativeQueryMap(Integer.class, String.class, sql, (Map) - Copier.copyToMap(bean, Copier.OPTION_SKIP_NULL_VALUE)); - } - - default CompletableFuture> nativeQueryToIntStrMapAsync(String sql, Serializable bean) { - return nativeQueryMapAsync(Integer.class, String.class, sql, (Map) - Copier.copyToMap(bean, Copier.OPTION_SKIP_NULL_VALUE)); - } - - default Sheet nativeQuerySheet(Class type, String sql, Flipper flipper, Serializable bean) { - return nativeQuerySheet( - type, sql, flipper, (Map) Copier.copyToMap(bean, Copier.OPTION_SKIP_NULL_VALUE)); - } - - default CompletableFuture> nativeQuerySheetAsync( - Class type, String sql, Flipper flipper, Serializable bean) { - return nativeQuerySheetAsync( - type, sql, flipper, (Map) Copier.copyToMap(bean, Copier.OPTION_SKIP_NULL_VALUE)); - } - - default Sheet nativeQuerySheet(Class type, String sql, PageBean pageBean) { - return nativeQuerySheet( - type, - sql, - pageBean == null ? null : pageBean.getFlipper(), - pageBean == null - ? null - : (Map) Copier.copyToMap(pageBean.getBean(), Copier.OPTION_SKIP_NULL_VALUE)); - } - - default CompletableFuture> nativeQuerySheetAsync(Class type, String sql, PageBean pageBean) { - return nativeQuerySheetAsync( - type, - sql, - pageBean == null ? null : pageBean.getFlipper(), - pageBean == null - ? null - : (Map) Copier.copyToMap(pageBean.getBean(), Copier.OPTION_SKIP_NULL_VALUE)); - } -} +/* + * + */ +package org.redkale.source; + +import static org.redkale.source.DataResultSet.formatColumnValue; + +import java.io.Serializable; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.function.*; +import org.redkale.annotation.ClassDepends; +import org.redkale.util.*; + +/** + * 关系型sql数据库的数据源, 比DataSource多了操作sql语句的接口。
+ * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +@ClassDepends +public interface DataSqlSource extends DataSource { + + /** + * 执行多条原生无参数的sql + * + * @param sqls 无参数的sql语句 + * @return 执行条数 + */ + public int[] nativeUpdates(String... sqls); + + /** + * 执行多条原生无参数的sql + * + * @param sqls 无参数的sql语句 + * @return 执行条数 + */ + public CompletableFuture nativeUpdatesAsync(String... sqls); + + /** + * 执行原生无参数的sql + * + * @param sql 无参数的sql语句 + * @return 执行条数 + */ + public int nativeUpdate(String sql); + + /** + * 执行原生无参数的sql + * + * @param sql 无参数的sql语句 + * @return 执行条数 + */ + public CompletableFuture nativeUpdateAsync(String sql); + + /** + * 执行原生带参数的sql + * + * @param sql 带参数的sql语句 + * @param params 参数值集合 + * @return 执行条数 + */ + @ClassDepends + public int nativeUpdate(String sql, Map params); + + /** + * 执行原生带参数的sql + * + * @param sql 带参数的sql语句 + * @param params 参数值集合 + * @return 执行条数 + */ + @ClassDepends + public CompletableFuture nativeUpdateAsync(String sql, Map params); + + /** + * 通过原生的sql查询结果 + * + * @param 泛型 + * @param sql 无参数的sql语句 + * @param consumer BiConsumer 参数1: connection, 参数2: statement + * @param handler DataResultSet的回调函数 + * @return 结果对象 + */ + public V nativeQuery(String sql, BiConsumer consumer, Function handler); + + /** + * 通过原生的sql查询结果 + * + * @param 泛型 + * @param sql 无参数的sql语句 + * @param consumer BiConsumer 参数1: connection, 参数2: statement + * @param handler DataResultSet的回调函数 + * @return 结果对象 + */ + public CompletableFuture nativeQueryAsync( + String sql, BiConsumer consumer, Function handler); + + /** + * 通过原生带参数的sql查询结果 + * + * @param 泛型 + * @param sql 带参数的sql语句 + * @param consumer BiConsumer 参数1: connection, 参数2: statement + * @param handler DataResultSet的回调函数 + * @param params 参数值集合 + * @return 结果对象 + */ + public V nativeQuery( + String sql, + BiConsumer consumer, + Function handler, + Map params); + + /** + * 通过原生带参数的sql查询结果 + * + * @param 泛型 + * @param sql 带参数的sql语句 + * @param consumer BiConsumer 参数1: connection, 参数2: statement + * @param handler DataResultSet的回调函数 + * @param params 参数值集合 + * @return 结果对象 + */ + public CompletableFuture nativeQueryAsync( + String sql, + BiConsumer consumer, + Function handler, + Map params); + + @ClassDepends + public Sheet nativeQuerySheet(Class type, String sql, Flipper flipper, Map params); + + @ClassDepends + public CompletableFuture> nativeQuerySheetAsync( + Class type, String sql, Flipper flipper, Map params); + + // ----------------------------- 无参数 ----------------------------- + default V nativeQuery(String sql, Function handler) { + return nativeQuery(sql, null, handler); + } + + default CompletableFuture nativeQueryAsync(String sql, Function handler) { + return nativeQueryAsync(sql, null, handler); + } + + @ClassDepends + default V nativeQueryOne(Class type, String sql) { + return nativeQuery(sql, rset -> EntityBuilder.getOneValue(type, rset)); + } + + @ClassDepends + default CompletableFuture nativeQueryOneAsync(Class type, String sql) { + return nativeQueryAsync(sql, rset -> EntityBuilder.getOneValue(type, rset)); + } + + @ClassDepends + default List nativeQueryList(Class type, String sql) { + return nativeQuery(sql, rset -> EntityBuilder.getListValue(type, rset)); + } + + @ClassDepends + default CompletableFuture> nativeQueryListAsync(Class type, String sql) { + return nativeQueryAsync(sql, rset -> EntityBuilder.getListValue(type, rset)); + } + + @ClassDepends + default Sheet nativeQuerySheet(Class type, String sql, Flipper flipper) { + return nativeQuerySheet(type, sql, flipper, Collections.emptyMap()); + } + + @ClassDepends + default CompletableFuture> nativeQuerySheetAsync(Class type, String sql, Flipper flipper) { + return nativeQuerySheetAsync(type, sql, flipper, Collections.emptyMap()); + } + + @ClassDepends + default Map nativeQueryMap(Class keyType, Class valType, String sql) { + return nativeQuery(sql, rset -> { + Map map = new LinkedHashMap<>(); + while (rset.next()) { + if (!rset.wasNull()) { + map.put((K) formatColumnValue(keyType, rset.getObject(1)), (V) + formatColumnValue(valType, rset.getObject(2))); + } + } + return map; + }); + } + + @ClassDepends + default CompletableFuture> nativeQueryMapAsync(Class keyType, Class valType, String sql) { + return nativeQueryAsync(sql, rset -> { + Map map = new LinkedHashMap<>(); + while (rset.next()) { + if (!rset.wasNull()) { + map.put((K) formatColumnValue(keyType, rset.getObject(1)), (V) + formatColumnValue(valType, rset.getObject(2))); + } + } + return map; + }); + } + + default Map nativeQueryToStrStrMap(String sql) { + return nativeQueryMap(String.class, String.class, sql); + } + + default CompletableFuture> nativeQueryStrStrMapAsync(String sql) { + return nativeQueryMapAsync(String.class, String.class, sql); + } + + default Map nativeQueryToIntStrMap(String sql) { + return nativeQueryMap(Integer.class, String.class, sql); + } + + default CompletableFuture> nativeQueryToIntStrMapAsync(String sql) { + return nativeQueryMapAsync(Integer.class, String.class, sql); + } + + // ----------------------------- Map ----------------------------- + default V nativeQuery(String sql, Function handler, Map params) { + return nativeQuery(sql, null, handler, params); + } + + default CompletableFuture nativeQueryAsync( + String sql, Function handler, Map params) { + return nativeQueryAsync(sql, null, handler, params); + } + + @ClassDepends + default V nativeQueryOne(Class type, String sql, Map params) { + return nativeQuery( + sql, + rset -> { + if (!rset.next()) { + return null; + } + if (EntityBuilder.isSimpleType(type)) { + return (V) formatColumnValue(type, rset.getObject(1)); + } + return EntityBuilder.load(type).getObjectValue(rset); + }, + params); + } + + @ClassDepends + default CompletableFuture nativeQueryOneAsync(Class type, String sql, Map params) { + return nativeQueryAsync( + sql, + rset -> { + if (!rset.next()) { + return null; + } + if (EntityBuilder.isSimpleType(type)) { + return (V) formatColumnValue(type, rset.getObject(1)); + } + return EntityBuilder.load(type).getObjectValue(rset); + }, + params); + } + + @ClassDepends + default List nativeQueryList(Class type, String sql, Map params) { + return nativeQuery( + sql, + rset -> { + if (EntityBuilder.isSimpleType(type)) { + List list = new ArrayList<>(); + while (rset.next()) { + list.add(rset.wasNull() ? null : (V) formatColumnValue(type, rset.getObject(1))); + } + return list; + } + return EntityBuilder.load(type).getObjectList(rset); + }, + params); + } + + @ClassDepends + default CompletableFuture> nativeQueryListAsync(Class type, String sql, Map params) { + return nativeQueryAsync( + sql, + rset -> { + if (EntityBuilder.isSimpleType(type)) { + List list = new ArrayList<>(); + while (rset.next()) { + list.add(rset.wasNull() ? null : (V) formatColumnValue(type, rset.getObject(1))); + } + return list; + } + return EntityBuilder.load(type).getObjectList(rset); + }, + params); + } + + @ClassDepends + default Map nativeQueryMap( + Class keyType, Class valType, String sql, Map params) { + return nativeQuery( + sql, + rset -> { + Map map = new LinkedHashMap<>(); + while (rset.next()) { + if (!rset.wasNull()) { + map.put((K) formatColumnValue(keyType, rset.getObject(1)), (V) + formatColumnValue(valType, rset.getObject(2))); + } + } + return map; + }, + params); + } + + @ClassDepends + default CompletableFuture> nativeQueryMapAsync( + Class keyType, Class valType, String sql, Map params) { + return nativeQueryAsync( + sql, + rset -> { + Map map = new LinkedHashMap<>(); + while (rset.next()) { + if (!rset.wasNull()) { + map.put((K) formatColumnValue(keyType, rset.getObject(1)), (V) + formatColumnValue(valType, rset.getObject(2))); + } + } + return map; + }, + params); + } + + default Map nativeQueryToStrStrMap(String sql, Map params) { + return nativeQueryMap(String.class, String.class, sql, params); + } + + default CompletableFuture> nativeQueryToStrStrMapAsync(String sql, Map params) { + return nativeQueryMapAsync(String.class, String.class, sql, params); + } + + default Map nativeQueryToIntStrMap(String sql, Map params) { + return nativeQueryMap(Integer.class, String.class, sql, params); + } + + default CompletableFuture> nativeQueryToIntStrMapAsync( + String sql, Map params) { + return nativeQueryMapAsync(Integer.class, String.class, sql, params); + } + + // ----------------------------- JavaBean ----------------------------- + default int nativeUpdate(String sql, Serializable bean) { + return nativeUpdate(sql, (Map) Copier.copyToMap(bean, Copier.OPTION_SKIP_NULL_VALUE)); + } + + default CompletableFuture nativeUpdateAsync(String sql, Serializable bean) { + return nativeUpdateAsync(sql, (Map) Copier.copyToMap(bean, Copier.OPTION_SKIP_NULL_VALUE)); + } + + default V nativeQuery(String sql, Function handler, Serializable bean) { + return nativeQuery( + sql, null, handler, (Map) Copier.copyToMap(bean, Copier.OPTION_SKIP_NULL_VALUE)); + } + + default CompletableFuture nativeQueryAsync( + String sql, Function handler, Serializable bean) { + return nativeQueryAsync( + sql, null, handler, (Map) Copier.copyToMap(bean, Copier.OPTION_SKIP_NULL_VALUE)); + } + + default V nativeQueryOne(Class type, String sql, Serializable bean) { + return nativeQueryOne(type, sql, (Map) Copier.copyToMap(bean, Copier.OPTION_SKIP_NULL_VALUE)); + } + + default CompletableFuture nativeQueryOneAsync(Class type, String sql, Serializable bean) { + return nativeQueryOneAsync( + type, sql, (Map) Copier.copyToMap(bean, Copier.OPTION_SKIP_NULL_VALUE)); + } + + default List nativeQueryList(Class type, String sql, Serializable bean) { + return nativeQueryList(type, sql, (Map) Copier.copyToMap(bean, Copier.OPTION_SKIP_NULL_VALUE)); + } + + default CompletableFuture> nativeQueryListAsync(Class type, String sql, Serializable bean) { + return nativeQueryListAsync( + type, sql, (Map) Copier.copyToMap(bean, Copier.OPTION_SKIP_NULL_VALUE)); + } + + default Map nativeQueryMap(Class keyType, Class valType, String sql, Serializable bean) { + return nativeQueryMap( + keyType, valType, sql, (Map) Copier.copyToMap(bean, Copier.OPTION_SKIP_NULL_VALUE)); + } + + default CompletableFuture> nativeQueryMapAsync( + Class keyType, Class valType, String sql, Serializable bean) { + return nativeQueryMapAsync( + keyType, valType, sql, (Map) Copier.copyToMap(bean, Copier.OPTION_SKIP_NULL_VALUE)); + } + + default Map nativeQueryToStrStrMap(String sql, Serializable bean) { + return nativeQueryMap(String.class, String.class, sql, (Map) + Copier.copyToMap(bean, Copier.OPTION_SKIP_NULL_VALUE)); + } + + default CompletableFuture> nativeQueryToStrStrMapAsync(String sql, Serializable bean) { + return nativeQueryMapAsync(String.class, String.class, sql, (Map) + Copier.copyToMap(bean, Copier.OPTION_SKIP_NULL_VALUE)); + } + + default Map nativeQueryToIntStrMap(String sql, Serializable bean) { + return nativeQueryMap(Integer.class, String.class, sql, (Map) + Copier.copyToMap(bean, Copier.OPTION_SKIP_NULL_VALUE)); + } + + default CompletableFuture> nativeQueryToIntStrMapAsync(String sql, Serializable bean) { + return nativeQueryMapAsync(Integer.class, String.class, sql, (Map) + Copier.copyToMap(bean, Copier.OPTION_SKIP_NULL_VALUE)); + } + + default Sheet nativeQuerySheet(Class type, String sql, Flipper flipper, Serializable bean) { + return nativeQuerySheet( + type, sql, flipper, (Map) Copier.copyToMap(bean, Copier.OPTION_SKIP_NULL_VALUE)); + } + + default CompletableFuture> nativeQuerySheetAsync( + Class type, String sql, Flipper flipper, Serializable bean) { + return nativeQuerySheetAsync( + type, sql, flipper, (Map) Copier.copyToMap(bean, Copier.OPTION_SKIP_NULL_VALUE)); + } + + default Sheet nativeQuerySheet(Class type, String sql, PageBean pageBean) { + return nativeQuerySheet( + type, + sql, + pageBean == null ? null : pageBean.getFlipper(), + pageBean == null + ? null + : (Map) Copier.copyToMap(pageBean.getBean(), Copier.OPTION_SKIP_NULL_VALUE)); + } + + default CompletableFuture> nativeQuerySheetAsync(Class type, String sql, PageBean pageBean) { + return nativeQuerySheetAsync( + type, + sql, + pageBean == null ? null : pageBean.getFlipper(), + pageBean == null + ? null + : (Map) Copier.copyToMap(pageBean.getBean(), Copier.OPTION_SKIP_NULL_VALUE)); + } +} diff --git a/src/main/java/org/redkale/source/DataTransaction.java b/src/main/java/org/redkale/source/DataTransaction.java index aed84aa33..88bf2f5ec 100644 --- a/src/main/java/org/redkale/source/DataTransaction.java +++ b/src/main/java/org/redkale/source/DataTransaction.java @@ -1,49 +1,49 @@ -/* - * - */ -package org.redkale.source; - -import java.util.concurrent.CompletableFuture; - -/** - * DataSource的事务类
- * 示例:
- * - *

- * - *
- * DataSource source = ...;
- * DataTransaction tran = source.createTransaction();
- * try {
- *    tran.source().insert(record1); //必须使用tran.source(),不能使用source
- *    tran.source().update(record2); //必须使用tran.source(),不能使用source
- *    tran.commit(); //事务提交
- * } catch(Exception e){
- *    tran.rollback(); //回滚
- * }
- * 
- * - *
- * - * 详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public interface DataTransaction { - - // 事务版的DataSource - DataSource source(); - - // 同步模式提交 - public void commit(); - - // 同步模式回滚 - public void rollback(); - - // 异步模式提交 - public CompletableFuture commitAsync(); - - // 异步模式回滚 - public CompletableFuture rollbackAsync(); -} +/* + * + */ +package org.redkale.source; + +import java.util.concurrent.CompletableFuture; + +/** + * DataSource的事务类
+ * 示例:
+ * + *
+ * + *
+ * DataSource source = ...;
+ * DataTransaction tran = source.createTransaction();
+ * try {
+ *    tran.source().insert(record1); //必须使用tran.source(),不能使用source
+ *    tran.source().update(record2); //必须使用tran.source(),不能使用source
+ *    tran.commit(); //事务提交
+ * } catch(Exception e){
+ *    tran.rollback(); //回滚
+ * }
+ * 
+ * + *
+ * + * 详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public interface DataTransaction { + + // 事务版的DataSource + DataSource source(); + + // 同步模式提交 + public void commit(); + + // 同步模式回滚 + public void rollback(); + + // 异步模式提交 + public CompletableFuture commitAsync(); + + // 异步模式回滚 + public CompletableFuture rollbackAsync(); +} diff --git a/src/main/java/org/redkale/source/EntityBuilder.java b/src/main/java/org/redkale/source/EntityBuilder.java index b8ddc0bd6..407b57f01 100644 --- a/src/main/java/org/redkale/source/EntityBuilder.java +++ b/src/main/java/org/redkale/source/EntityBuilder.java @@ -1,602 +1,602 @@ -/* - * - */ -package org.redkale.source; - -import java.io.Serializable; -import java.lang.reflect.*; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import org.redkale.annotation.Nullable; -import org.redkale.convert.ConvertDisabled; -import org.redkale.persistence.*; -import org.redkale.source.EntityInfo.DataResultSetRow; -import org.redkale.util.*; - -/** - * 可以是实体类,也可以是查询结果的JavaBean类 - * - * @author zhangjx - * @param T - * @since 2.8.0 - */ -public class EntityBuilder { - - private static final ConcurrentHashMap cacheMap = new ConcurrentHashMap<>(); - - private static final ConcurrentHashMap lowerMap = new ConcurrentHashMap<>(); - - private static final ConcurrentHashMap snakeMap = new ConcurrentHashMap<>(); - - private static final ConcurrentHashMap camelMap = new ConcurrentHashMap<>(); - - // 实体类名 - private final Class type; - - // 是否Map类型的虚拟实体类 - private final boolean entityIsMap; - - // Entity构建器 - private final Creator creator; - - // Entity构建器参数 - @Nullable - private final String[] constructorParameters; - - // key:类字段名, value:数据库字段名 - // 只有field.name 与 Column.name不同才存放在aliasmap里. - @Nullable - private final Map aliasmap; - - // Entity构建器参数Attribute, 数组个数与constructorParameters相同 - @Nullable - private final Attribute[] constructorAttributes; - - // Entity构建器参数Attribute - @Nullable - private final Attribute[] unconstructorAttributes; - - // key:类字段名 - final Map> attributeMap; - - // key:数据库字段名 - private final Map> sqlAttrMap; - - // key:数据库字段名去掉下划线并小写 - private final Map> sqlLowerAttrMap; - - // 数据库中所有字段, 顺序必须与querySqlColumns、querySqlColumnSequence一致 - private final Attribute[] attributes; - - EntityBuilder( - Class type, - Creator creator, - Map aliasmap, - String[] constructorParameters, - Attribute[] constructorAttributes, - Attribute[] unconstructorAttributes, - Map> attributeMap, - Attribute[] queryAttributes) { - this.type = type; - this.creator = creator; - this.aliasmap = aliasmap; - this.constructorParameters = constructorParameters; - this.constructorAttributes = constructorAttributes; - this.unconstructorAttributes = unconstructorAttributes; - this.attributeMap = attributeMap; - this.attributes = queryAttributes; - this.sqlAttrMap = new HashMap<>(); - this.sqlLowerAttrMap = new HashMap<>(); - this.entityIsMap = Map.class.isAssignableFrom(type); - attributeMap.forEach((k, v) -> { - String col = getSQLColumn(null, k); - sqlAttrMap.put(col, v); - sqlLowerAttrMap.put(lowerCaseColumn(col), v); - }); - } - - public static boolean isSimpleType(Class type) { - return type == byte[].class - || type == String.class - || type.isPrimitive() - || Number.class.isAssignableFrom(type) - || (!Map.class.isAssignableFrom(type) && type.getName().startsWith("java.")); - } - - public static EntityBuilder load(Class type) { - return cacheMap.computeIfAbsent(type, EntityBuilder::create); - } - - private static EntityBuilder create(Class type) { - Creator creator = Creator.create(type); - String[] constructorParameters = null; - if (!Map.class.isAssignableFrom(type)) { - try { - Method cm = creator.getClass().getMethod("create", Object[].class); - RedkaleClassLoader.putReflectionPublicMethods(creator.getClass().getName()); - RedkaleClassLoader.putReflectionMethod(creator.getClass().getName(), cm); - org.redkale.annotation.ConstructorParameters cp = - cm.getAnnotation(org.redkale.annotation.ConstructorParameters.class); - if (cp != null && cp.value().length > 0) { - constructorParameters = cp.value(); - } else { - org.redkale.util.ConstructorParameters cp2 = - cm.getAnnotation(org.redkale.util.ConstructorParameters.class); - if (cp2 != null && cp2.value().length > 0) { - constructorParameters = cp2.value(); - } - } - } catch (Exception e) { - throw new SourceException(type + " cannot find ConstructorParameters Creator"); - } - } - Class cltmp = type; - Map aliasmap = null; - Set fields = new HashSet<>(); - List> queryAttrs = new ArrayList<>(); - HashMap> attributeMap = new HashMap<>(); - if (!Map.class.isAssignableFrom(type)) { - do { - RedkaleClassLoader.putReflectionDeclaredFields(cltmp.getName()); - for (Field field : cltmp.getDeclaredFields()) { - if (Modifier.isStatic(field.getModifiers())) { - continue; - } - if (Modifier.isFinal(field.getModifiers())) { - continue; - } - if (field.getAnnotation(Transient.class) != null) { - continue; - } - if (field.getAnnotation(javax.persistence.Transient.class) != null) { - continue; - } - if (fields.contains(field.getName())) { - continue; - } - final String fieldName = field.getName(); - final Column col = field.getAnnotation(Column.class); - final String sqlField = col == null || col.name().isEmpty() ? fieldName : col.name(); - if (!fieldName.equals(sqlField)) { - if (aliasmap == null) { - aliasmap = new HashMap<>(); - } - aliasmap.put(fieldName, sqlField); - } - Attribute attr; - try { - attr = Attribute.create(type, cltmp, field); - } catch (RuntimeException e) { - continue; - } - RedkaleClassLoader.putReflectionField(cltmp.getName(), field); - queryAttrs.add(attr); - fields.add(fieldName); - attributeMap.put(fieldName, attr); - } - } while ((cltmp = cltmp.getSuperclass()) != Object.class); - } - Attribute[] constructorAttributes; - Attribute[] unconstructorAttributes; - if (constructorParameters == null) { - constructorAttributes = null; - unconstructorAttributes = null; - } else { - constructorAttributes = new Attribute[constructorParameters.length]; - List> unconstructorAttrs = new ArrayList<>(); - List newQueryCols1 = new ArrayList<>(); - List newQueryCols2 = new ArrayList<>(); - for (Attribute attr : new ArrayList<>(queryAttrs)) { - int pos = -1; - for (int i = 0; i < constructorParameters.length; i++) { - if (attr.field().equals(constructorParameters[i])) { - pos = i; - break; - } - } - if (pos >= 0) { - constructorAttributes[pos] = attr; - } else { - unconstructorAttrs.add(attr); - } - } - unconstructorAttributes = unconstructorAttrs.toArray(new Attribute[unconstructorAttrs.size()]); - newQueryCols1.addAll(newQueryCols2); - List> newQueryAttrs = new ArrayList<>(); - newQueryAttrs.addAll(List.of(constructorAttributes)); - newQueryAttrs.addAll(unconstructorAttrs); - queryAttrs = newQueryAttrs; - } - return new EntityBuilder<>( - type, - creator, - aliasmap, - constructorParameters, - constructorAttributes, - unconstructorAttributes, - attributeMap, - queryAttrs.toArray(new Attribute[queryAttrs.size()])); - } - - /** - * 将数据ResultSet转成对象集合 - * - * @param 泛型 - * @param type 实体类或JavaBean - * @param rset 数据ResultSet - * @return 对象集合 - */ - public static List getListValue(Class type, final DataResultSet rset) { - if (type == byte[].class - || type == String.class - || type.isPrimitive() - || Number.class.isAssignableFrom(type) - || (!Map.class.isAssignableFrom(type) && type.getName().startsWith("java."))) { - List list = new ArrayList<>(); - while (rset.next()) { - list.add(rset.wasNull() ? null : (T) DataResultSet.formatColumnValue(type, rset.getObject(1))); - } - return list; - } - return EntityBuilder.load(type).getObjectList(rset); - } - - /** - * 将数据ResultSet转成单个对象 - * - * @param 泛型 - * @param type 实体类或JavaBean - * @param rset 数据ResultSet - * @return 单个对象 - */ - public static T getOneValue(Class type, final DataResultSet rset) { - if (!rset.next()) { - return null; - } - if (type == byte[].class - || type == String.class - || type.isPrimitive() - || Number.class.isAssignableFrom(type) - || (!Map.class.isAssignableFrom(type) && type.getName().startsWith("java."))) { - return (T) DataResultSet.formatColumnValue(type, rset.getObject(1)); - } - return EntityBuilder.load(type).getObjectValue(rset); - } - - public List getObjectList(final DataResultSet rset) { - List list = new ArrayList<>(); - List sqlColumns = rset.getColumnLabels(); - while (rset.next()) { - list.add(getObjectValue(sqlColumns, rset)); - } - return list; - } - - public T getObjectValue(final DataResultSetRow row) { - return getObjectValue(null, row); - } - - // 去掉字段名中的下划线并转出小写 - protected String lowerCaseColumn(String sqlCol) { - return lowerMap.computeIfAbsent(sqlCol, col -> { - char ch; - char[] chs = col.toCharArray(); - StringBuilder sb = new StringBuilder(chs.length); - for (int i = 0; i < chs.length; i++) { - ch = chs[i]; - if ((ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9')) { - sb.append(ch); - } else if (ch >= 'A' && ch <= 'Z') { - sb.append(Character.toLowerCase(ch)); - } - } - return sb.toString(); - }); - } - - // 带下划线的字段名替换成驼峰式 - protected String snakeCaseColumn(String sqlCol) { - return snakeMap.computeIfAbsent(sqlCol, col -> { - char ch; - char[] chs = col.toCharArray(); - StringBuilder sb = new StringBuilder(chs.length - 1); - for (int i = 0; i < chs.length; i++) { - ch = chs[i]; - if (ch != '_') { - sb.append(i > 0 && chs[i - 1] == '_' ? Character.toUpperCase(ch) : ch); - } - } - return sb.toString(); - }); - } - - // 驼峰式字段名替换成带下划线的 - protected String camelCaseColumn(String column) { - return camelMap.computeIfAbsent(column, col -> { - char ch; - char[] chs = col.toCharArray(); - StringBuilder sb = new StringBuilder(chs.length + 3); - for (int i = 0; i < chs.length; i++) { - ch = chs[i]; - if (Character.isUpperCase(ch)) { - sb.append('_').append(Character.toLowerCase(ch)); - } else { - sb.append(ch); - } - } - return sb.toString(); - }); - } - - protected T getObjectValue(List sqlColumns, final DataResultSetRow row) { - if (row.wasNull()) { - return null; - } - T obj; - if (sqlColumns == null) { - sqlColumns = row.getColumnLabels(); - } - if (entityIsMap) { - final Map map = (Map) creator.create(); - obj = (T) map; - for (String sqlCol : sqlColumns) { - map.put(sqlCol, getFieldValue(row, sqlCol)); - } - return obj; - } - Map> attrs = this.sqlAttrMap; - if (this.constructorParameters == null) { - obj = creator.create(); - for (String sqlCol : sqlColumns) { - Attribute attr = attrs.get(sqlCol); - boolean sqlFlag = false; - if (attr == null && sqlCol.indexOf('_') > -1) { - attr = attrs.get(snakeCaseColumn(sqlCol)); - sqlFlag = true; - } - if (attr == null) { - attr = sqlLowerAttrMap.get(lowerCaseColumn(sqlCol)); - sqlFlag = true; - } - if (attr != null) { // 兼容返回的字段不存在类中 - if (sqlFlag) { - attr.set(obj, getFieldValue(row, sqlCol)); - } else { - attr.set(obj, getFieldValue(attr, row, 0)); - } - } - } - } else { - Object[] cps = new Object[this.constructorParameters.length]; - for (int i = 0; i < this.constructorAttributes.length; i++) { - Attribute attr = this.constructorAttributes[i]; - String sqlCol = getSQLColumn(null, attr.field()); - if (sqlColumns.contains(sqlCol)) { - cps[i] = getFieldValue(attr, row, 0); - } else { - sqlCol = camelCaseColumn(sqlCol); - if (sqlColumns.contains(sqlCol)) { - cps[i] = getFieldValue(attr, row, 0); - } - } - } - obj = creator.create(cps); - for (Attribute attr : this.unconstructorAttributes) { - String sqlCol = getSQLColumn(null, attr.field()); - if (sqlColumns.contains(sqlCol)) { - attr.set(obj, getFieldValue(attr, row, 0)); - } else { - sqlCol = camelCaseColumn(sqlCol); - if (sqlColumns.contains(sqlCol)) { - attr.set(obj, getFieldValue(attr, row, 0)); - } - } - } - } - return obj; - } - - public List getEntityList(final SelectColumn sels, final DataResultSet rset) { - List list = new ArrayList<>(); - while (rset.next()) { - list.add(getEntityValue(sels, rset)); - } - return list; - } - - /** - * 将一行的ResultSet组装成一个Entity对象 - * - * @param sels 指定字段 - * @param row ResultSet - * @return Entity对象 - */ - public T getEntityValue(final SelectColumn sels, final DataResultSetRow row) { - if (sels == null) { - return getFullEntityValue(row); - } - if (row.wasNull()) { - return null; - } - if (entityIsMap) { - final Map map = (Map) creator.create(); - for (String sqlCol : row.getColumnLabels()) { - map.put(sqlCol, getFieldValue(row, sqlCol)); - } - return (T) map; - } - T obj; - Attribute[] attrs = this.attributes; - if (this.constructorParameters == null) { - obj = creator.create(); - } else { - Object[] cps = new Object[this.constructorParameters.length]; - for (int i = 0; i < this.constructorAttributes.length; i++) { - Attribute attr = this.constructorAttributes[i]; - if (sels == null || sels.test(attr.field())) { - cps[i] = getFieldValue(attr, row, 0); - } - } - obj = creator.create(cps); - attrs = this.unconstructorAttributes; - } - for (Attribute attr : attrs) { - if (sels == null || sels.test(attr.field())) { - attr.set(obj, getFieldValue(attr, row, 0)); - } - } - return obj; - } - - public List getFullEntityList(final DataResultSet rset) { - List list = new ArrayList<>(); - while (rset.next()) { - list.add(getFullEntityValue(rset)); - } - return list; - } - - public T getFullEntityValue(final DataResultSetRow row) { - return getEntityValue( - constructorAttributes, constructorAttributes == null ? attributes : unconstructorAttributes, row); - } - - public T getFullEntityValue(final Serializable... values) { - return getEntityValue( - constructorAttributes, constructorAttributes == null ? attributes : unconstructorAttributes, values); - } - - /** - * 将一行的ResultSet组装成一个Entity对象 - * - * @param constructorAttrs 构建函数的Attribute数组, 大小必须与this.constructorAttributes相同 - * @param unconstructorAttrs 非构建函数的Attribute数组 - * @param row ResultSet - * @return Entity对象 - */ - protected T getEntityValue( - final Attribute[] constructorAttrs, - final Attribute[] unconstructorAttrs, - final DataResultSetRow row) { - if (row.wasNull()) { - return null; - } - if (entityIsMap) { - final Map map = (Map) creator.create(); - for (String sqlCol : row.getColumnLabels()) { - map.put(sqlCol, getFieldValue(row, sqlCol)); - } - return (T) map; - } - T obj; - int index = 0; - if (this.constructorParameters == null) { - obj = creator.create(); - } else { - Object[] cps = new Object[this.constructorParameters.length]; - for (int i = 0; i < constructorAttrs.length; i++) { - Attribute attr = constructorAttrs[i]; - if (attr == null) { - continue; - } - cps[i] = getFieldValue(attr, row, ++index); - } - obj = creator.create(cps); - } - if (unconstructorAttrs != null) { - for (Attribute attr : unconstructorAttrs) { - if (attr == null) { - continue; - } - attr.set(obj, getFieldValue(attr, row, ++index)); - } - } - return obj; - } - - /** - * 将一行的ResultSet组装成一个Entity对象 - * - * @param constructorAttrs 构建函数的Attribute数组, 大小必须与this.constructorAttributes相同 - * @param unconstructorAttrs 非构建函数的Attribute数组 - * @param values 字段值集合 - * @return Entity对象 - */ - protected T getEntityValue( - final Attribute[] constructorAttrs, - final Attribute[] unconstructorAttrs, - final Serializable... values) { - if (values == null) { - return null; - } - T obj; - int index = -1; - if (this.constructorParameters == null) { - obj = creator.create(); - } else { - Object[] cps = new Object[this.constructorParameters.length]; - for (int i = 0; i < constructorAttrs.length; i++) { - Attribute attr = constructorAttrs[i]; - if (attr != null) { - cps[i] = values[++index]; - } - } - obj = creator.create(cps); - } - if (unconstructorAttrs != null) { - for (Attribute attr : unconstructorAttrs) { - if (attr != null) { - attr.set(obj, values[++index]); - } - } - } - return obj; - } - - protected Serializable getFieldValue(final DataResultSetRow row, String sqlColumn) { - return (Serializable) row.getObject(sqlColumn); - } - - protected Serializable getFieldValue(Attribute attr, final DataResultSetRow row, int index) { - return row.getObject(attr, index, index > 0 ? null : this.getSQLColumn(null, attr.field())); - } - - /** - * 根据field字段名获取数据库对应的字段名 - * - * @param tabalis 表别名 - * @param fieldname 字段名 - * @return String - */ - public String getSQLColumn(String tabalis, String fieldname) { - return this.aliasmap == null - ? (tabalis == null ? fieldname : (tabalis + '.' + fieldname)) - : (tabalis == null - ? aliasmap.getOrDefault(fieldname, fieldname) - : (tabalis + '.' + aliasmap.getOrDefault(fieldname, fieldname))); - } - - public boolean hasConstructorAttribute() { - return constructorAttributes != null; - } - - /** - * 判断Entity类的字段名与表字段名s是否存在不一致的值 - * - * @return boolean - */ - @ConvertDisabled - public boolean isNoAlias() { - return this.aliasmap == null; - } - - @ConvertDisabled - public Creator getCreator() { - return creator; - } - - @ConvertDisabled - public Class getType() { - return type; - } -} +/* + * + */ +package org.redkale.source; + +import java.io.Serializable; +import java.lang.reflect.*; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import org.redkale.annotation.Nullable; +import org.redkale.convert.ConvertDisabled; +import org.redkale.persistence.*; +import org.redkale.source.EntityInfo.DataResultSetRow; +import org.redkale.util.*; + +/** + * 可以是实体类,也可以是查询结果的JavaBean类 + * + * @author zhangjx + * @param T + * @since 2.8.0 + */ +public class EntityBuilder { + + private static final ConcurrentHashMap cacheMap = new ConcurrentHashMap<>(); + + private static final ConcurrentHashMap lowerMap = new ConcurrentHashMap<>(); + + private static final ConcurrentHashMap snakeMap = new ConcurrentHashMap<>(); + + private static final ConcurrentHashMap camelMap = new ConcurrentHashMap<>(); + + // 实体类名 + private final Class type; + + // 是否Map类型的虚拟实体类 + private final boolean entityIsMap; + + // Entity构建器 + private final Creator creator; + + // Entity构建器参数 + @Nullable + private final String[] constructorParameters; + + // key:类字段名, value:数据库字段名 + // 只有field.name 与 Column.name不同才存放在aliasmap里. + @Nullable + private final Map aliasmap; + + // Entity构建器参数Attribute, 数组个数与constructorParameters相同 + @Nullable + private final Attribute[] constructorAttributes; + + // Entity构建器参数Attribute + @Nullable + private final Attribute[] unconstructorAttributes; + + // key:类字段名 + final Map> attributeMap; + + // key:数据库字段名 + private final Map> sqlAttrMap; + + // key:数据库字段名去掉下划线并小写 + private final Map> sqlLowerAttrMap; + + // 数据库中所有字段, 顺序必须与querySqlColumns、querySqlColumnSequence一致 + private final Attribute[] attributes; + + EntityBuilder( + Class type, + Creator creator, + Map aliasmap, + String[] constructorParameters, + Attribute[] constructorAttributes, + Attribute[] unconstructorAttributes, + Map> attributeMap, + Attribute[] queryAttributes) { + this.type = type; + this.creator = creator; + this.aliasmap = aliasmap; + this.constructorParameters = constructorParameters; + this.constructorAttributes = constructorAttributes; + this.unconstructorAttributes = unconstructorAttributes; + this.attributeMap = attributeMap; + this.attributes = queryAttributes; + this.sqlAttrMap = new HashMap<>(); + this.sqlLowerAttrMap = new HashMap<>(); + this.entityIsMap = Map.class.isAssignableFrom(type); + attributeMap.forEach((k, v) -> { + String col = getSQLColumn(null, k); + sqlAttrMap.put(col, v); + sqlLowerAttrMap.put(lowerCaseColumn(col), v); + }); + } + + public static boolean isSimpleType(Class type) { + return type == byte[].class + || type == String.class + || type.isPrimitive() + || Number.class.isAssignableFrom(type) + || (!Map.class.isAssignableFrom(type) && type.getName().startsWith("java.")); + } + + public static EntityBuilder load(Class type) { + return cacheMap.computeIfAbsent(type, EntityBuilder::create); + } + + private static EntityBuilder create(Class type) { + Creator creator = Creator.create(type); + String[] constructorParameters = null; + if (!Map.class.isAssignableFrom(type)) { + try { + Method cm = creator.getClass().getMethod("create", Object[].class); + RedkaleClassLoader.putReflectionPublicMethods(creator.getClass().getName()); + RedkaleClassLoader.putReflectionMethod(creator.getClass().getName(), cm); + org.redkale.annotation.ConstructorParameters cp = + cm.getAnnotation(org.redkale.annotation.ConstructorParameters.class); + if (cp != null && cp.value().length > 0) { + constructorParameters = cp.value(); + } else { + org.redkale.util.ConstructorParameters cp2 = + cm.getAnnotation(org.redkale.util.ConstructorParameters.class); + if (cp2 != null && cp2.value().length > 0) { + constructorParameters = cp2.value(); + } + } + } catch (Exception e) { + throw new SourceException(type + " cannot find ConstructorParameters Creator"); + } + } + Class cltmp = type; + Map aliasmap = null; + Set fields = new HashSet<>(); + List> queryAttrs = new ArrayList<>(); + HashMap> attributeMap = new HashMap<>(); + if (!Map.class.isAssignableFrom(type)) { + do { + RedkaleClassLoader.putReflectionDeclaredFields(cltmp.getName()); + for (Field field : cltmp.getDeclaredFields()) { + if (Modifier.isStatic(field.getModifiers())) { + continue; + } + if (Modifier.isFinal(field.getModifiers())) { + continue; + } + if (field.getAnnotation(Transient.class) != null) { + continue; + } + if (field.getAnnotation(javax.persistence.Transient.class) != null) { + continue; + } + if (fields.contains(field.getName())) { + continue; + } + final String fieldName = field.getName(); + final Column col = field.getAnnotation(Column.class); + final String sqlField = col == null || col.name().isEmpty() ? fieldName : col.name(); + if (!fieldName.equals(sqlField)) { + if (aliasmap == null) { + aliasmap = new HashMap<>(); + } + aliasmap.put(fieldName, sqlField); + } + Attribute attr; + try { + attr = Attribute.create(type, cltmp, field); + } catch (RuntimeException e) { + continue; + } + RedkaleClassLoader.putReflectionField(cltmp.getName(), field); + queryAttrs.add(attr); + fields.add(fieldName); + attributeMap.put(fieldName, attr); + } + } while ((cltmp = cltmp.getSuperclass()) != Object.class); + } + Attribute[] constructorAttributes; + Attribute[] unconstructorAttributes; + if (constructorParameters == null) { + constructorAttributes = null; + unconstructorAttributes = null; + } else { + constructorAttributes = new Attribute[constructorParameters.length]; + List> unconstructorAttrs = new ArrayList<>(); + List newQueryCols1 = new ArrayList<>(); + List newQueryCols2 = new ArrayList<>(); + for (Attribute attr : new ArrayList<>(queryAttrs)) { + int pos = -1; + for (int i = 0; i < constructorParameters.length; i++) { + if (attr.field().equals(constructorParameters[i])) { + pos = i; + break; + } + } + if (pos >= 0) { + constructorAttributes[pos] = attr; + } else { + unconstructorAttrs.add(attr); + } + } + unconstructorAttributes = unconstructorAttrs.toArray(new Attribute[unconstructorAttrs.size()]); + newQueryCols1.addAll(newQueryCols2); + List> newQueryAttrs = new ArrayList<>(); + newQueryAttrs.addAll(List.of(constructorAttributes)); + newQueryAttrs.addAll(unconstructorAttrs); + queryAttrs = newQueryAttrs; + } + return new EntityBuilder<>( + type, + creator, + aliasmap, + constructorParameters, + constructorAttributes, + unconstructorAttributes, + attributeMap, + queryAttrs.toArray(new Attribute[queryAttrs.size()])); + } + + /** + * 将数据ResultSet转成对象集合 + * + * @param 泛型 + * @param type 实体类或JavaBean + * @param rset 数据ResultSet + * @return 对象集合 + */ + public static List getListValue(Class type, final DataResultSet rset) { + if (type == byte[].class + || type == String.class + || type.isPrimitive() + || Number.class.isAssignableFrom(type) + || (!Map.class.isAssignableFrom(type) && type.getName().startsWith("java."))) { + List list = new ArrayList<>(); + while (rset.next()) { + list.add(rset.wasNull() ? null : (T) DataResultSet.formatColumnValue(type, rset.getObject(1))); + } + return list; + } + return EntityBuilder.load(type).getObjectList(rset); + } + + /** + * 将数据ResultSet转成单个对象 + * + * @param 泛型 + * @param type 实体类或JavaBean + * @param rset 数据ResultSet + * @return 单个对象 + */ + public static T getOneValue(Class type, final DataResultSet rset) { + if (!rset.next()) { + return null; + } + if (type == byte[].class + || type == String.class + || type.isPrimitive() + || Number.class.isAssignableFrom(type) + || (!Map.class.isAssignableFrom(type) && type.getName().startsWith("java."))) { + return (T) DataResultSet.formatColumnValue(type, rset.getObject(1)); + } + return EntityBuilder.load(type).getObjectValue(rset); + } + + public List getObjectList(final DataResultSet rset) { + List list = new ArrayList<>(); + List sqlColumns = rset.getColumnLabels(); + while (rset.next()) { + list.add(getObjectValue(sqlColumns, rset)); + } + return list; + } + + public T getObjectValue(final DataResultSetRow row) { + return getObjectValue(null, row); + } + + // 去掉字段名中的下划线并转出小写 + protected String lowerCaseColumn(String sqlCol) { + return lowerMap.computeIfAbsent(sqlCol, col -> { + char ch; + char[] chs = col.toCharArray(); + StringBuilder sb = new StringBuilder(chs.length); + for (int i = 0; i < chs.length; i++) { + ch = chs[i]; + if ((ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9')) { + sb.append(ch); + } else if (ch >= 'A' && ch <= 'Z') { + sb.append(Character.toLowerCase(ch)); + } + } + return sb.toString(); + }); + } + + // 带下划线的字段名替换成驼峰式 + protected String snakeCaseColumn(String sqlCol) { + return snakeMap.computeIfAbsent(sqlCol, col -> { + char ch; + char[] chs = col.toCharArray(); + StringBuilder sb = new StringBuilder(chs.length - 1); + for (int i = 0; i < chs.length; i++) { + ch = chs[i]; + if (ch != '_') { + sb.append(i > 0 && chs[i - 1] == '_' ? Character.toUpperCase(ch) : ch); + } + } + return sb.toString(); + }); + } + + // 驼峰式字段名替换成带下划线的 + protected String camelCaseColumn(String column) { + return camelMap.computeIfAbsent(column, col -> { + char ch; + char[] chs = col.toCharArray(); + StringBuilder sb = new StringBuilder(chs.length + 3); + for (int i = 0; i < chs.length; i++) { + ch = chs[i]; + if (Character.isUpperCase(ch)) { + sb.append('_').append(Character.toLowerCase(ch)); + } else { + sb.append(ch); + } + } + return sb.toString(); + }); + } + + protected T getObjectValue(List sqlColumns, final DataResultSetRow row) { + if (row.wasNull()) { + return null; + } + T obj; + if (sqlColumns == null) { + sqlColumns = row.getColumnLabels(); + } + if (entityIsMap) { + final Map map = (Map) creator.create(); + obj = (T) map; + for (String sqlCol : sqlColumns) { + map.put(sqlCol, getFieldValue(row, sqlCol)); + } + return obj; + } + Map> attrs = this.sqlAttrMap; + if (this.constructorParameters == null) { + obj = creator.create(); + for (String sqlCol : sqlColumns) { + Attribute attr = attrs.get(sqlCol); + boolean sqlFlag = false; + if (attr == null && sqlCol.indexOf('_') > -1) { + attr = attrs.get(snakeCaseColumn(sqlCol)); + sqlFlag = true; + } + if (attr == null) { + attr = sqlLowerAttrMap.get(lowerCaseColumn(sqlCol)); + sqlFlag = true; + } + if (attr != null) { // 兼容返回的字段不存在类中 + if (sqlFlag) { + attr.set(obj, getFieldValue(row, sqlCol)); + } else { + attr.set(obj, getFieldValue(attr, row, 0)); + } + } + } + } else { + Object[] cps = new Object[this.constructorParameters.length]; + for (int i = 0; i < this.constructorAttributes.length; i++) { + Attribute attr = this.constructorAttributes[i]; + String sqlCol = getSQLColumn(null, attr.field()); + if (sqlColumns.contains(sqlCol)) { + cps[i] = getFieldValue(attr, row, 0); + } else { + sqlCol = camelCaseColumn(sqlCol); + if (sqlColumns.contains(sqlCol)) { + cps[i] = getFieldValue(attr, row, 0); + } + } + } + obj = creator.create(cps); + for (Attribute attr : this.unconstructorAttributes) { + String sqlCol = getSQLColumn(null, attr.field()); + if (sqlColumns.contains(sqlCol)) { + attr.set(obj, getFieldValue(attr, row, 0)); + } else { + sqlCol = camelCaseColumn(sqlCol); + if (sqlColumns.contains(sqlCol)) { + attr.set(obj, getFieldValue(attr, row, 0)); + } + } + } + } + return obj; + } + + public List getEntityList(final SelectColumn sels, final DataResultSet rset) { + List list = new ArrayList<>(); + while (rset.next()) { + list.add(getEntityValue(sels, rset)); + } + return list; + } + + /** + * 将一行的ResultSet组装成一个Entity对象 + * + * @param sels 指定字段 + * @param row ResultSet + * @return Entity对象 + */ + public T getEntityValue(final SelectColumn sels, final DataResultSetRow row) { + if (sels == null) { + return getFullEntityValue(row); + } + if (row.wasNull()) { + return null; + } + if (entityIsMap) { + final Map map = (Map) creator.create(); + for (String sqlCol : row.getColumnLabels()) { + map.put(sqlCol, getFieldValue(row, sqlCol)); + } + return (T) map; + } + T obj; + Attribute[] attrs = this.attributes; + if (this.constructorParameters == null) { + obj = creator.create(); + } else { + Object[] cps = new Object[this.constructorParameters.length]; + for (int i = 0; i < this.constructorAttributes.length; i++) { + Attribute attr = this.constructorAttributes[i]; + if (sels == null || sels.test(attr.field())) { + cps[i] = getFieldValue(attr, row, 0); + } + } + obj = creator.create(cps); + attrs = this.unconstructorAttributes; + } + for (Attribute attr : attrs) { + if (sels == null || sels.test(attr.field())) { + attr.set(obj, getFieldValue(attr, row, 0)); + } + } + return obj; + } + + public List getFullEntityList(final DataResultSet rset) { + List list = new ArrayList<>(); + while (rset.next()) { + list.add(getFullEntityValue(rset)); + } + return list; + } + + public T getFullEntityValue(final DataResultSetRow row) { + return getEntityValue( + constructorAttributes, constructorAttributes == null ? attributes : unconstructorAttributes, row); + } + + public T getFullEntityValue(final Serializable... values) { + return getEntityValue( + constructorAttributes, constructorAttributes == null ? attributes : unconstructorAttributes, values); + } + + /** + * 将一行的ResultSet组装成一个Entity对象 + * + * @param constructorAttrs 构建函数的Attribute数组, 大小必须与this.constructorAttributes相同 + * @param unconstructorAttrs 非构建函数的Attribute数组 + * @param row ResultSet + * @return Entity对象 + */ + protected T getEntityValue( + final Attribute[] constructorAttrs, + final Attribute[] unconstructorAttrs, + final DataResultSetRow row) { + if (row.wasNull()) { + return null; + } + if (entityIsMap) { + final Map map = (Map) creator.create(); + for (String sqlCol : row.getColumnLabels()) { + map.put(sqlCol, getFieldValue(row, sqlCol)); + } + return (T) map; + } + T obj; + int index = 0; + if (this.constructorParameters == null) { + obj = creator.create(); + } else { + Object[] cps = new Object[this.constructorParameters.length]; + for (int i = 0; i < constructorAttrs.length; i++) { + Attribute attr = constructorAttrs[i]; + if (attr == null) { + continue; + } + cps[i] = getFieldValue(attr, row, ++index); + } + obj = creator.create(cps); + } + if (unconstructorAttrs != null) { + for (Attribute attr : unconstructorAttrs) { + if (attr == null) { + continue; + } + attr.set(obj, getFieldValue(attr, row, ++index)); + } + } + return obj; + } + + /** + * 将一行的ResultSet组装成一个Entity对象 + * + * @param constructorAttrs 构建函数的Attribute数组, 大小必须与this.constructorAttributes相同 + * @param unconstructorAttrs 非构建函数的Attribute数组 + * @param values 字段值集合 + * @return Entity对象 + */ + protected T getEntityValue( + final Attribute[] constructorAttrs, + final Attribute[] unconstructorAttrs, + final Serializable... values) { + if (values == null) { + return null; + } + T obj; + int index = -1; + if (this.constructorParameters == null) { + obj = creator.create(); + } else { + Object[] cps = new Object[this.constructorParameters.length]; + for (int i = 0; i < constructorAttrs.length; i++) { + Attribute attr = constructorAttrs[i]; + if (attr != null) { + cps[i] = values[++index]; + } + } + obj = creator.create(cps); + } + if (unconstructorAttrs != null) { + for (Attribute attr : unconstructorAttrs) { + if (attr != null) { + attr.set(obj, values[++index]); + } + } + } + return obj; + } + + protected Serializable getFieldValue(final DataResultSetRow row, String sqlColumn) { + return (Serializable) row.getObject(sqlColumn); + } + + protected Serializable getFieldValue(Attribute attr, final DataResultSetRow row, int index) { + return row.getObject(attr, index, index > 0 ? null : this.getSQLColumn(null, attr.field())); + } + + /** + * 根据field字段名获取数据库对应的字段名 + * + * @param tabalis 表别名 + * @param fieldname 字段名 + * @return String + */ + public String getSQLColumn(String tabalis, String fieldname) { + return this.aliasmap == null + ? (tabalis == null ? fieldname : (tabalis + '.' + fieldname)) + : (tabalis == null + ? aliasmap.getOrDefault(fieldname, fieldname) + : (tabalis + '.' + aliasmap.getOrDefault(fieldname, fieldname))); + } + + public boolean hasConstructorAttribute() { + return constructorAttributes != null; + } + + /** + * 判断Entity类的字段名与表字段名s是否存在不一致的值 + * + * @return boolean + */ + @ConvertDisabled + public boolean isNoAlias() { + return this.aliasmap == null; + } + + @ConvertDisabled + public Creator getCreator() { + return creator; + } + + @ConvertDisabled + public Class getType() { + return type; + } +} diff --git a/src/main/java/org/redkale/source/FilterJoinType.java b/src/main/java/org/redkale/source/FilterJoinType.java index 7b62168fc..f7b4c4e8b 100644 --- a/src/main/java/org/redkale/source/FilterJoinType.java +++ b/src/main/java/org/redkale/source/FilterJoinType.java @@ -1,16 +1,16 @@ -/* - * - */ -package org.redkale.source; - -/** - * JOIN表的类别 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public enum FilterJoinType { - INNER; -} +/* + * + */ +package org.redkale.source; + +/** + * JOIN表的类别 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public enum FilterJoinType { + INNER; +} diff --git a/src/main/java/org/redkale/source/FilterNodes.java b/src/main/java/org/redkale/source/FilterNodes.java index 71f792e78..46efe3ebb 100644 --- a/src/main/java/org/redkale/source/FilterNodes.java +++ b/src/main/java/org/redkale/source/FilterNodes.java @@ -1,609 +1,609 @@ -/* - * - */ -package org.redkale.source; - -import static org.redkale.source.FilterExpress.*; - -import java.io.Serializable; -import java.util.Collection; -import java.util.stream.Stream; -import org.redkale.util.LambdaFunction; -import org.redkale.util.LambdaSupplier; - -/** - * FilterNode的工具类 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public final class FilterNodes { - - private FilterNodes() { - // do nothing - } - - public static FilterNode create(String column, Serializable value) { - return new FilterNode(column, null, value); - } - - public static FilterNode create(String column, FilterExpress express, Serializable value) { - return new FilterNode(column, express, value); - } - - public static FilterNode create(LambdaSupplier func) { - return new FilterNode(LambdaSupplier.readColumn(func), null, func.get()); - } - - public static FilterNode create(LambdaSupplier func, FilterExpress express) { - return new FilterNode(LambdaSupplier.readColumn(func), express, func.get()); - } - - public static FilterNode create(LambdaFunction func, F value) { - return new FilterNode(LambdaFunction.readColumn(func), null, value); - } - - public static FilterNode create( - LambdaFunction func, FilterExpress express, F value) { - return new FilterNode(LambdaFunction.readColumn(func), express, value); - } - - public static FilterNode eq(String column, Serializable value) { - return new FilterNode(column, EQ, value); - } - - public static FilterNode eq(LambdaSupplier func) { - return new FilterNode(LambdaSupplier.readColumn(func), EQ, func.get()); - } - - public static FilterNode eq(LambdaFunction func, F value) { - return new FilterNode(LambdaFunction.readColumn(func), EQ, value); - } - - public static FilterNode igEq(String column, Serializable value) { - return new FilterNode(column, IG_EQ, value); - } - - public static FilterNode igEq(LambdaSupplier func) { - return new FilterNode(LambdaSupplier.readColumn(func), IG_EQ, func.get()); - } - - public static FilterNode igEq(LambdaFunction func, F value) { - return new FilterNode(LambdaFunction.readColumn(func), IG_EQ, value); - } - - public static FilterNode ne(String column, Serializable value) { - return new FilterNode(column, NE, value); - } - - public static FilterNode ne(LambdaSupplier func) { - return new FilterNode(LambdaSupplier.readColumn(func), NE, func.get()); - } - - public static FilterNode ne(LambdaFunction func, F value) { - return new FilterNode(LambdaFunction.readColumn(func), NE, value); - } - - public static FilterNode igNe(String column, Serializable value) { - return new FilterNode(column, IG_NE, value); - } - - public static FilterNode igNe(LambdaSupplier func) { - return new FilterNode(LambdaSupplier.readColumn(func), IG_NE, func.get()); - } - - public static FilterNode igNe(LambdaFunction func, F value) { - return new FilterNode(LambdaFunction.readColumn(func), IG_NE, value); - } - - public static FilterNode gt(String column, Number value) { - return new FilterNode(column, GT, value); - } - - public static FilterNode gt(LambdaSupplier func) { - return new FilterNode(LambdaSupplier.readColumn(func), GT, func.get()); - } - - public static FilterNode gt(LambdaFunction func, F value) { - return new FilterNode(LambdaFunction.readColumn(func), GT, value); - } - - public static FilterNode lt(String column, Number value) { - return new FilterNode(column, LT, value); - } - - public static FilterNode lt(LambdaSupplier func) { - return new FilterNode(LambdaSupplier.readColumn(func), LT, func.get()); - } - - public static FilterNode lt(LambdaFunction func, F value) { - return new FilterNode(LambdaFunction.readColumn(func), LT, value); - } - - public static FilterNode ge(String column, Number value) { - return new FilterNode(column, GE, value); - } - - public static FilterNode ge(LambdaSupplier func) { - return new FilterNode(LambdaSupplier.readColumn(func), GE, func.get()); - } - - public static FilterNode ge(LambdaFunction func, F value) { - return new FilterNode(LambdaFunction.readColumn(func), GE, value); - } - - public static FilterNode le(String column, Number value) { - return new FilterNode(column, LE, value); - } - - public static FilterNode le(LambdaSupplier func) { - return new FilterNode(LambdaSupplier.readColumn(func), LE, func.get()); - } - - public static FilterNode le(LambdaFunction func, F value) { - return new FilterNode(LambdaFunction.readColumn(func), LE, value); - } - - public static FilterNode like(String column, String value) { - return new FilterNode(column, LIKE, value); - } - - public static FilterNode like(LambdaSupplier func) { - return new FilterNode(LambdaSupplier.readColumn(func), LIKE, func.get()); - } - - public static FilterNode like(LambdaFunction func, String value) { - return new FilterNode(LambdaFunction.readColumn(func), LIKE, value); - } - - public static FilterNode notLike(String column, String value) { - return new FilterNode(column, NOT_LIKE, value); - } - - public static FilterNode notLike(LambdaSupplier func) { - return new FilterNode(LambdaSupplier.readColumn(func), NOT_LIKE, func.get()); - } - - public static FilterNode notLike(LambdaFunction func, String value) { - return new FilterNode(LambdaFunction.readColumn(func), NOT_LIKE, value); - } - - public static FilterNode igLike(String column, String value) { - return new FilterNode(column, IG_LIKE, value); - } - - public static FilterNode igLike(LambdaSupplier func) { - return new FilterNode(LambdaSupplier.readColumn(func), IG_LIKE, func.get()); - } - - public static FilterNode igLike(LambdaFunction func, String value) { - return new FilterNode(LambdaFunction.readColumn(func), IG_LIKE, value); - } - - public static FilterNode igNotLike(String column, String value) { - return new FilterNode(column, IG_NOT_LIKE, value); - } - - public static FilterNode igNotLike(LambdaSupplier func) { - return new FilterNode(LambdaSupplier.readColumn(func), IG_NOT_LIKE, func.get()); - } - - public static FilterNode igNotLike(LambdaFunction func, String value) { - return new FilterNode(LambdaFunction.readColumn(func), IG_NOT_LIKE, value); - } - - public static FilterNode starts(String column, String value) { - return new FilterNode(column, STARTS, value); - } - - public static FilterNode starts(LambdaSupplier func) { - return new FilterNode(LambdaSupplier.readColumn(func), STARTS, func.get()); - } - - public static FilterNode starts(LambdaFunction func, String value) { - return new FilterNode(LambdaFunction.readColumn(func), STARTS, value); - } - - public static FilterNode ends(String column, String value) { - return new FilterNode(column, ENDS, value); - } - - public static FilterNode ends(LambdaSupplier func) { - return new FilterNode(LambdaSupplier.readColumn(func), ENDS, func.get()); - } - - public static FilterNode ends(LambdaFunction func, String value) { - return new FilterNode(LambdaFunction.readColumn(func), ENDS, value); - } - - public static FilterNode notStarts(String column, String value) { - return new FilterNode(column, NOT_STARTS, value); - } - - public static FilterNode notStarts(LambdaSupplier func) { - return new FilterNode(LambdaSupplier.readColumn(func), NOT_STARTS, func.get()); - } - - public static FilterNode notStarts(LambdaFunction func, String value) { - return new FilterNode(LambdaFunction.readColumn(func), NOT_STARTS, value); - } - - public static FilterNode notEnds(String column, String value) { - return new FilterNode(column, NOT_ENDS, value); - } - - public static FilterNode notEnds(LambdaSupplier func) { - return new FilterNode(LambdaSupplier.readColumn(func), NOT_ENDS, func.get()); - } - - public static FilterNode notEnds(LambdaFunction func, String value) { - return new FilterNode(LambdaFunction.readColumn(func), NOT_ENDS, value); - } - - public static FilterNode lenEq(String column, Number value) { - return new FilterNode(column, LEN_EQ, value); - } - - public static FilterNode lenEq(LambdaSupplier func) { - return new FilterNode(LambdaSupplier.readColumn(func), LEN_EQ, func.get()); - } - - public static FilterNode lenEq(LambdaFunction func, F value) { - return new FilterNode(LambdaFunction.readColumn(func), LEN_EQ, value); - } - - public static FilterNode lenGt(String column, Number value) { - return new FilterNode(column, LEN_GT, value); - } - - public static FilterNode lenGt(LambdaSupplier func) { - return new FilterNode(LambdaSupplier.readColumn(func), LEN_GT, func.get()); - } - - public static FilterNode lenGt(LambdaFunction func, F value) { - return new FilterNode(LambdaFunction.readColumn(func), LEN_GT, value); - } - - public static FilterNode lenLt(String column, Number value) { - return new FilterNode(column, LEN_LT, value); - } - - public static FilterNode lenLt(LambdaSupplier func) { - return new FilterNode(LambdaSupplier.readColumn(func), LEN_LT, func.get()); - } - - public static FilterNode lenLt(LambdaFunction func, F value) { - return new FilterNode(LambdaFunction.readColumn(func), LEN_LT, value); - } - - public static FilterNode lenGe(String column, Number value) { - return new FilterNode(column, LEN_GE, value); - } - - public static FilterNode lenGe(LambdaSupplier func) { - return new FilterNode(LambdaSupplier.readColumn(func), LEN_GE, func.get()); - } - - public static FilterNode lenGe(LambdaFunction func, F value) { - return new FilterNode(LambdaFunction.readColumn(func), LEN_GE, value); - } - - public static FilterNode lenLe(String column, Number value) { - return new FilterNode(column, LEN_LE, value); - } - - public static FilterNode lenLe(LambdaSupplier func) { - return new FilterNode(LambdaSupplier.readColumn(func), LEN_LE, func.get()); - } - - public static FilterNode lenLe(LambdaFunction func, F value) { - return new FilterNode(LambdaFunction.readColumn(func), LEN_LE, value); - } - - public static FilterNode contain(String column, Serializable value) { - return new FilterNode(column, CONTAIN, value); - } - - public static FilterNode contain(LambdaSupplier func) { - return new FilterNode(LambdaSupplier.readColumn(func), CONTAIN, func.get()); - } - - public static FilterNode contain(LambdaFunction func, F value) { - return new FilterNode(LambdaFunction.readColumn(func), CONTAIN, value); - } - - public static FilterNode notContain(String column, Serializable value) { - return new FilterNode(column, NOT_CONTAIN, value); - } - - public static FilterNode notContain(LambdaSupplier func) { - return new FilterNode(LambdaSupplier.readColumn(func), NOT_CONTAIN, func.get()); - } - - public static FilterNode notContain(LambdaFunction func, F value) { - return new FilterNode(LambdaFunction.readColumn(func), NOT_CONTAIN, value); - } - - public static FilterNode igContain(String column, Serializable value) { - return new FilterNode(column, IG_CONTAIN, value); - } - - public static FilterNode igContain(LambdaSupplier func) { - return new FilterNode(LambdaSupplier.readColumn(func), IG_CONTAIN, func.get()); - } - - public static FilterNode igContain(LambdaFunction func, F value) { - return new FilterNode(LambdaFunction.readColumn(func), IG_CONTAIN, value); - } - - public static FilterNode igNotContain(String column, Serializable value) { - return new FilterNode(column, IG_NOT_CONTAIN, value); - } - - public static FilterNode igNotContain(LambdaSupplier func) { - return new FilterNode(LambdaSupplier.readColumn(func), IG_NOT_CONTAIN, func.get()); - } - - public static FilterNode igNotContain(LambdaFunction func, F value) { - return new FilterNode(LambdaFunction.readColumn(func), IG_NOT_CONTAIN, value); - } - - public static FilterNode between(String column, Range value) { - return new FilterNode(column, BETWEEN, value); - } - - public static FilterNode between(LambdaSupplier func) { - return new FilterNode(LambdaSupplier.readColumn(func), BETWEEN, func.get()); - } - - public static FilterNode between(LambdaFunction func, F value) { - return new FilterNode(LambdaFunction.readColumn(func), BETWEEN, value); - } - - public static FilterNode notBetween(String column, Range value) { - return new FilterNode(column, NOT_BETWEEN, value); - } - - public static FilterNode notBetween(LambdaSupplier func) { - return new FilterNode(LambdaSupplier.readColumn(func), NOT_BETWEEN, func.get()); - } - - public static FilterNode notBetween(LambdaFunction func, F value) { - return new FilterNode(LambdaFunction.readColumn(func), NOT_BETWEEN, value); - } - - public static FilterNode in(String column, Serializable value) { - return new FilterNode(column, IN, value); - } - - public static FilterNode in(String column, Stream stream) { - return new FilterNode(column, IN, stream == null ? null : (Serializable) stream.toArray()); - } - - public static FilterNode in(String column, Collection collection) { - return new FilterNode(column, IN, (Serializable) collection); - } - - public static FilterNode in(LambdaSupplier func) { - return new FilterNode(LambdaSupplier.readColumn(func), IN, (Serializable) func.get()); - } - - public static FilterNode in(LambdaFunction func, F value) { - return new FilterNode(LambdaFunction.readColumn(func), IN, (Serializable) value); - } - - public static FilterNode notIn(String column, Serializable value) { - return new FilterNode(column, NOT_IN, value); - } - - public static FilterNode notIn(String column, Stream stream) { - return new FilterNode(column, NOT_IN, stream == null ? null : (Serializable) stream.toArray()); - } - - public static FilterNode notIn(String column, Collection collection) { - return new FilterNode(column, NOT_IN, (Serializable) collection); - } - - public static FilterNode notIn(LambdaSupplier func) { - return new FilterNode(LambdaSupplier.readColumn(func), NOT_IN, (Serializable) func.get()); - } - - public static FilterNode notIn(LambdaFunction func, F value) { - return new FilterNode(LambdaFunction.readColumn(func), NOT_IN, (Serializable) value); - } - - public static FilterNode isNull(String column) { - return new FilterNode(column, IS_NULL, null); - } - - public static FilterNode isNull(LambdaSupplier func) { - return new FilterNode(LambdaSupplier.readColumn(func), IS_NULL, null); - } - - public static FilterNode isNull(LambdaFunction func) { - return new FilterNode(LambdaFunction.readColumn(func), IS_NULL, null); - } - - public static FilterNode notNull(String column) { - return new FilterNode(column, NOT_NULL, null); - } - - public static FilterNode notNull(LambdaSupplier func) { - return new FilterNode(LambdaSupplier.readColumn(func), NOT_NULL, null); - } - - public static FilterNode notNull(LambdaFunction func) { - return new FilterNode(LambdaFunction.readColumn(func), NOT_NULL, null); - } - - public static FilterNode isEmpty(String column) { - return new FilterNode(column, IS_EMPTY, null); - } - - public static FilterNode isEmpty(LambdaSupplier func) { - return new FilterNode(LambdaSupplier.readColumn(func), IS_EMPTY, null); - } - - public static FilterNode isEmpty(LambdaFunction func) { - return new FilterNode(LambdaFunction.readColumn(func), IS_EMPTY, null); - } - - public static FilterNode notEmpty(String column) { - return new FilterNode(column, NOT_EMPTY, null); - } - - public static FilterNode notEmpty(LambdaSupplier func) { - return new FilterNode(LambdaSupplier.readColumn(func), NOT_EMPTY, null); - } - - public static FilterNode notEmpty(LambdaFunction func) { - return new FilterNode(LambdaFunction.readColumn(func), NOT_EMPTY, null); - } - - public static FilterNode opand(String column, Number value) { - return new FilterNode(column, OPAND, value); - } - - public static FilterNode opand(LambdaSupplier func) { - return new FilterNode(LambdaSupplier.readColumn(func), OPAND, func.get()); - } - - public static FilterNode opand(LambdaFunction func, F value) { - return new FilterNode(LambdaFunction.readColumn(func), OPAND, value); - } - - public static FilterNode opor(String column, Number value) { - return new FilterNode(column, OPOR, value); - } - - public static FilterNode opor(LambdaSupplier func) { - return new FilterNode(LambdaSupplier.readColumn(func), OPOR, func.get()); - } - - public FilterNode opor(LambdaFunction func, F value) { - return new FilterNode(LambdaFunction.readColumn(func), OPOR, value); - } - - public static FilterNode notOpand(String column, Number value) { - return new FilterNode(column, NOT_OPAND, value); - } - - public static FilterNode notOpand(LambdaSupplier func) { - return new FilterNode(LambdaSupplier.readColumn(func), NOT_OPAND, func.get()); - } - - public static FilterNode notOpand(LambdaFunction func, F value) { - return new FilterNode(LambdaFunction.readColumn(func), NOT_OPAND, value); - } - - public static FilterNode fvmode(String column, FilterExpValue value) { - return new FilterNode(column, FV_MOD, value); - } - - public static FilterNode fvmode(LambdaSupplier func) { - return new FilterNode(LambdaSupplier.readColumn(func), FV_MOD, func.get()); - } - - public static FilterNode fvmode(LambdaFunction func, F value) { - return new FilterNode(LambdaFunction.readColumn(func), FV_MOD, value); - } - - public static FilterNode fvdiv(String column, FilterExpValue value) { - return new FilterNode(column, FV_DIV, value); - } - - public static FilterNode fvdiv(LambdaSupplier func) { - return new FilterNode(LambdaSupplier.readColumn(func), FV_DIV, func.get()); - } - - public static FilterNode fvdiv(LambdaFunction func, F value) { - return new FilterNode(LambdaFunction.readColumn(func), FV_DIV, value); - } - - // ---------------------------------------------------------------------------------------------------- - public static FilterJoinNode joinInner(Class joinClass, String joinColumn, String column, Serializable value) { - return joinInner(joinClass, new String[] {joinColumn}, column, value); - } - - public static FilterJoinNode joinInner( - Class joinClass, String joinColumn, String column, FilterExpress express, Serializable value) { - return joinInner(joinClass, new String[] {joinColumn}, column, express, value); - } - - public static FilterJoinNode joinInner(Class joinClass, String[] joinColumns, String column, Serializable value) { - return joinInner(joinClass, joinColumns, column, null, value); - } - - public static FilterJoinNode joinInner( - Class joinClass, String[] joinColumns, String column, FilterExpress express, Serializable value) { - return new FilterJoinNode(FilterJoinType.INNER, joinClass, joinColumns, column, express, value); - } - - // ---------------------------------------------------------------------------------------------------- - static FilterExpress oldExpress(FilterExpress express) { - switch (express) { - case EQUAL: - return EQ; - case IGNORECASEEQUAL: - return IG_EQ; - case NOTEQUAL: - return NE; - case IGNORECASENOTEQUAL: - return IG_NE; - case GREATERTHAN: - return GT; - case LESSTHAN: - return LT; - case GREATERTHANOREQUALTO: - return GE; - case LESSTHANOREQUALTO: - return LE; - case NOTLIKE: - return NOT_LIKE; - case IGNORECASELIKE: - return IG_LIKE; - case IGNORECASENOTLIKE: - return IG_NOT_LIKE; - case STARTSWITH: - return STARTS; - case ENDSWITH: - return ENDS; - case NOTSTARTSWITH: - return NOT_STARTS; - case NOTENDSWITH: - return NOT_ENDS; - case LENGTH_EQUAL: - return LEN_EQ; - case LENGTH_GREATERTHAN: - return LEN_GT; - case LENGTH_LESSTHAN: - return LEN_LT; - case LENGTH_GREATERTHANOREQUALTO: - return LEN_GE; - case LENGTH_LESSTHANOREQUALTO: - return LEN_LE; - case NOTCONTAIN: - return NOT_CONTAIN; - case IGNORECASECONTAIN: - return IG_CONTAIN; - case IGNORECASENOTCONTAIN: - return IG_NOT_CONTAIN; - case NOTBETWEEN: - return NOT_BETWEEN; - case NOTIN: - return NOT_IN; - case ISNULL: - return IS_NULL; - case ISNOTNULL: - return NOT_NULL; - case ISEMPTY: - return IS_EMPTY; - case ISNOTEMPTY: - return NOT_EMPTY; - default: - return express; - } - } -} +/* + * + */ +package org.redkale.source; + +import static org.redkale.source.FilterExpress.*; + +import java.io.Serializable; +import java.util.Collection; +import java.util.stream.Stream; +import org.redkale.util.LambdaFunction; +import org.redkale.util.LambdaSupplier; + +/** + * FilterNode的工具类 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public final class FilterNodes { + + private FilterNodes() { + // do nothing + } + + public static FilterNode create(String column, Serializable value) { + return new FilterNode(column, null, value); + } + + public static FilterNode create(String column, FilterExpress express, Serializable value) { + return new FilterNode(column, express, value); + } + + public static FilterNode create(LambdaSupplier func) { + return new FilterNode(LambdaSupplier.readColumn(func), null, func.get()); + } + + public static FilterNode create(LambdaSupplier func, FilterExpress express) { + return new FilterNode(LambdaSupplier.readColumn(func), express, func.get()); + } + + public static FilterNode create(LambdaFunction func, F value) { + return new FilterNode(LambdaFunction.readColumn(func), null, value); + } + + public static FilterNode create( + LambdaFunction func, FilterExpress express, F value) { + return new FilterNode(LambdaFunction.readColumn(func), express, value); + } + + public static FilterNode eq(String column, Serializable value) { + return new FilterNode(column, EQ, value); + } + + public static FilterNode eq(LambdaSupplier func) { + return new FilterNode(LambdaSupplier.readColumn(func), EQ, func.get()); + } + + public static FilterNode eq(LambdaFunction func, F value) { + return new FilterNode(LambdaFunction.readColumn(func), EQ, value); + } + + public static FilterNode igEq(String column, Serializable value) { + return new FilterNode(column, IG_EQ, value); + } + + public static FilterNode igEq(LambdaSupplier func) { + return new FilterNode(LambdaSupplier.readColumn(func), IG_EQ, func.get()); + } + + public static FilterNode igEq(LambdaFunction func, F value) { + return new FilterNode(LambdaFunction.readColumn(func), IG_EQ, value); + } + + public static FilterNode ne(String column, Serializable value) { + return new FilterNode(column, NE, value); + } + + public static FilterNode ne(LambdaSupplier func) { + return new FilterNode(LambdaSupplier.readColumn(func), NE, func.get()); + } + + public static FilterNode ne(LambdaFunction func, F value) { + return new FilterNode(LambdaFunction.readColumn(func), NE, value); + } + + public static FilterNode igNe(String column, Serializable value) { + return new FilterNode(column, IG_NE, value); + } + + public static FilterNode igNe(LambdaSupplier func) { + return new FilterNode(LambdaSupplier.readColumn(func), IG_NE, func.get()); + } + + public static FilterNode igNe(LambdaFunction func, F value) { + return new FilterNode(LambdaFunction.readColumn(func), IG_NE, value); + } + + public static FilterNode gt(String column, Number value) { + return new FilterNode(column, GT, value); + } + + public static FilterNode gt(LambdaSupplier func) { + return new FilterNode(LambdaSupplier.readColumn(func), GT, func.get()); + } + + public static FilterNode gt(LambdaFunction func, F value) { + return new FilterNode(LambdaFunction.readColumn(func), GT, value); + } + + public static FilterNode lt(String column, Number value) { + return new FilterNode(column, LT, value); + } + + public static FilterNode lt(LambdaSupplier func) { + return new FilterNode(LambdaSupplier.readColumn(func), LT, func.get()); + } + + public static FilterNode lt(LambdaFunction func, F value) { + return new FilterNode(LambdaFunction.readColumn(func), LT, value); + } + + public static FilterNode ge(String column, Number value) { + return new FilterNode(column, GE, value); + } + + public static FilterNode ge(LambdaSupplier func) { + return new FilterNode(LambdaSupplier.readColumn(func), GE, func.get()); + } + + public static FilterNode ge(LambdaFunction func, F value) { + return new FilterNode(LambdaFunction.readColumn(func), GE, value); + } + + public static FilterNode le(String column, Number value) { + return new FilterNode(column, LE, value); + } + + public static FilterNode le(LambdaSupplier func) { + return new FilterNode(LambdaSupplier.readColumn(func), LE, func.get()); + } + + public static FilterNode le(LambdaFunction func, F value) { + return new FilterNode(LambdaFunction.readColumn(func), LE, value); + } + + public static FilterNode like(String column, String value) { + return new FilterNode(column, LIKE, value); + } + + public static FilterNode like(LambdaSupplier func) { + return new FilterNode(LambdaSupplier.readColumn(func), LIKE, func.get()); + } + + public static FilterNode like(LambdaFunction func, String value) { + return new FilterNode(LambdaFunction.readColumn(func), LIKE, value); + } + + public static FilterNode notLike(String column, String value) { + return new FilterNode(column, NOT_LIKE, value); + } + + public static FilterNode notLike(LambdaSupplier func) { + return new FilterNode(LambdaSupplier.readColumn(func), NOT_LIKE, func.get()); + } + + public static FilterNode notLike(LambdaFunction func, String value) { + return new FilterNode(LambdaFunction.readColumn(func), NOT_LIKE, value); + } + + public static FilterNode igLike(String column, String value) { + return new FilterNode(column, IG_LIKE, value); + } + + public static FilterNode igLike(LambdaSupplier func) { + return new FilterNode(LambdaSupplier.readColumn(func), IG_LIKE, func.get()); + } + + public static FilterNode igLike(LambdaFunction func, String value) { + return new FilterNode(LambdaFunction.readColumn(func), IG_LIKE, value); + } + + public static FilterNode igNotLike(String column, String value) { + return new FilterNode(column, IG_NOT_LIKE, value); + } + + public static FilterNode igNotLike(LambdaSupplier func) { + return new FilterNode(LambdaSupplier.readColumn(func), IG_NOT_LIKE, func.get()); + } + + public static FilterNode igNotLike(LambdaFunction func, String value) { + return new FilterNode(LambdaFunction.readColumn(func), IG_NOT_LIKE, value); + } + + public static FilterNode starts(String column, String value) { + return new FilterNode(column, STARTS, value); + } + + public static FilterNode starts(LambdaSupplier func) { + return new FilterNode(LambdaSupplier.readColumn(func), STARTS, func.get()); + } + + public static FilterNode starts(LambdaFunction func, String value) { + return new FilterNode(LambdaFunction.readColumn(func), STARTS, value); + } + + public static FilterNode ends(String column, String value) { + return new FilterNode(column, ENDS, value); + } + + public static FilterNode ends(LambdaSupplier func) { + return new FilterNode(LambdaSupplier.readColumn(func), ENDS, func.get()); + } + + public static FilterNode ends(LambdaFunction func, String value) { + return new FilterNode(LambdaFunction.readColumn(func), ENDS, value); + } + + public static FilterNode notStarts(String column, String value) { + return new FilterNode(column, NOT_STARTS, value); + } + + public static FilterNode notStarts(LambdaSupplier func) { + return new FilterNode(LambdaSupplier.readColumn(func), NOT_STARTS, func.get()); + } + + public static FilterNode notStarts(LambdaFunction func, String value) { + return new FilterNode(LambdaFunction.readColumn(func), NOT_STARTS, value); + } + + public static FilterNode notEnds(String column, String value) { + return new FilterNode(column, NOT_ENDS, value); + } + + public static FilterNode notEnds(LambdaSupplier func) { + return new FilterNode(LambdaSupplier.readColumn(func), NOT_ENDS, func.get()); + } + + public static FilterNode notEnds(LambdaFunction func, String value) { + return new FilterNode(LambdaFunction.readColumn(func), NOT_ENDS, value); + } + + public static FilterNode lenEq(String column, Number value) { + return new FilterNode(column, LEN_EQ, value); + } + + public static FilterNode lenEq(LambdaSupplier func) { + return new FilterNode(LambdaSupplier.readColumn(func), LEN_EQ, func.get()); + } + + public static FilterNode lenEq(LambdaFunction func, F value) { + return new FilterNode(LambdaFunction.readColumn(func), LEN_EQ, value); + } + + public static FilterNode lenGt(String column, Number value) { + return new FilterNode(column, LEN_GT, value); + } + + public static FilterNode lenGt(LambdaSupplier func) { + return new FilterNode(LambdaSupplier.readColumn(func), LEN_GT, func.get()); + } + + public static FilterNode lenGt(LambdaFunction func, F value) { + return new FilterNode(LambdaFunction.readColumn(func), LEN_GT, value); + } + + public static FilterNode lenLt(String column, Number value) { + return new FilterNode(column, LEN_LT, value); + } + + public static FilterNode lenLt(LambdaSupplier func) { + return new FilterNode(LambdaSupplier.readColumn(func), LEN_LT, func.get()); + } + + public static FilterNode lenLt(LambdaFunction func, F value) { + return new FilterNode(LambdaFunction.readColumn(func), LEN_LT, value); + } + + public static FilterNode lenGe(String column, Number value) { + return new FilterNode(column, LEN_GE, value); + } + + public static FilterNode lenGe(LambdaSupplier func) { + return new FilterNode(LambdaSupplier.readColumn(func), LEN_GE, func.get()); + } + + public static FilterNode lenGe(LambdaFunction func, F value) { + return new FilterNode(LambdaFunction.readColumn(func), LEN_GE, value); + } + + public static FilterNode lenLe(String column, Number value) { + return new FilterNode(column, LEN_LE, value); + } + + public static FilterNode lenLe(LambdaSupplier func) { + return new FilterNode(LambdaSupplier.readColumn(func), LEN_LE, func.get()); + } + + public static FilterNode lenLe(LambdaFunction func, F value) { + return new FilterNode(LambdaFunction.readColumn(func), LEN_LE, value); + } + + public static FilterNode contain(String column, Serializable value) { + return new FilterNode(column, CONTAIN, value); + } + + public static FilterNode contain(LambdaSupplier func) { + return new FilterNode(LambdaSupplier.readColumn(func), CONTAIN, func.get()); + } + + public static FilterNode contain(LambdaFunction func, F value) { + return new FilterNode(LambdaFunction.readColumn(func), CONTAIN, value); + } + + public static FilterNode notContain(String column, Serializable value) { + return new FilterNode(column, NOT_CONTAIN, value); + } + + public static FilterNode notContain(LambdaSupplier func) { + return new FilterNode(LambdaSupplier.readColumn(func), NOT_CONTAIN, func.get()); + } + + public static FilterNode notContain(LambdaFunction func, F value) { + return new FilterNode(LambdaFunction.readColumn(func), NOT_CONTAIN, value); + } + + public static FilterNode igContain(String column, Serializable value) { + return new FilterNode(column, IG_CONTAIN, value); + } + + public static FilterNode igContain(LambdaSupplier func) { + return new FilterNode(LambdaSupplier.readColumn(func), IG_CONTAIN, func.get()); + } + + public static FilterNode igContain(LambdaFunction func, F value) { + return new FilterNode(LambdaFunction.readColumn(func), IG_CONTAIN, value); + } + + public static FilterNode igNotContain(String column, Serializable value) { + return new FilterNode(column, IG_NOT_CONTAIN, value); + } + + public static FilterNode igNotContain(LambdaSupplier func) { + return new FilterNode(LambdaSupplier.readColumn(func), IG_NOT_CONTAIN, func.get()); + } + + public static FilterNode igNotContain(LambdaFunction func, F value) { + return new FilterNode(LambdaFunction.readColumn(func), IG_NOT_CONTAIN, value); + } + + public static FilterNode between(String column, Range value) { + return new FilterNode(column, BETWEEN, value); + } + + public static FilterNode between(LambdaSupplier func) { + return new FilterNode(LambdaSupplier.readColumn(func), BETWEEN, func.get()); + } + + public static FilterNode between(LambdaFunction func, F value) { + return new FilterNode(LambdaFunction.readColumn(func), BETWEEN, value); + } + + public static FilterNode notBetween(String column, Range value) { + return new FilterNode(column, NOT_BETWEEN, value); + } + + public static FilterNode notBetween(LambdaSupplier func) { + return new FilterNode(LambdaSupplier.readColumn(func), NOT_BETWEEN, func.get()); + } + + public static FilterNode notBetween(LambdaFunction func, F value) { + return new FilterNode(LambdaFunction.readColumn(func), NOT_BETWEEN, value); + } + + public static FilterNode in(String column, Serializable value) { + return new FilterNode(column, IN, value); + } + + public static FilterNode in(String column, Stream stream) { + return new FilterNode(column, IN, stream == null ? null : (Serializable) stream.toArray()); + } + + public static FilterNode in(String column, Collection collection) { + return new FilterNode(column, IN, (Serializable) collection); + } + + public static FilterNode in(LambdaSupplier func) { + return new FilterNode(LambdaSupplier.readColumn(func), IN, (Serializable) func.get()); + } + + public static FilterNode in(LambdaFunction func, F value) { + return new FilterNode(LambdaFunction.readColumn(func), IN, (Serializable) value); + } + + public static FilterNode notIn(String column, Serializable value) { + return new FilterNode(column, NOT_IN, value); + } + + public static FilterNode notIn(String column, Stream stream) { + return new FilterNode(column, NOT_IN, stream == null ? null : (Serializable) stream.toArray()); + } + + public static FilterNode notIn(String column, Collection collection) { + return new FilterNode(column, NOT_IN, (Serializable) collection); + } + + public static FilterNode notIn(LambdaSupplier func) { + return new FilterNode(LambdaSupplier.readColumn(func), NOT_IN, (Serializable) func.get()); + } + + public static FilterNode notIn(LambdaFunction func, F value) { + return new FilterNode(LambdaFunction.readColumn(func), NOT_IN, (Serializable) value); + } + + public static FilterNode isNull(String column) { + return new FilterNode(column, IS_NULL, null); + } + + public static FilterNode isNull(LambdaSupplier func) { + return new FilterNode(LambdaSupplier.readColumn(func), IS_NULL, null); + } + + public static FilterNode isNull(LambdaFunction func) { + return new FilterNode(LambdaFunction.readColumn(func), IS_NULL, null); + } + + public static FilterNode notNull(String column) { + return new FilterNode(column, NOT_NULL, null); + } + + public static FilterNode notNull(LambdaSupplier func) { + return new FilterNode(LambdaSupplier.readColumn(func), NOT_NULL, null); + } + + public static FilterNode notNull(LambdaFunction func) { + return new FilterNode(LambdaFunction.readColumn(func), NOT_NULL, null); + } + + public static FilterNode isEmpty(String column) { + return new FilterNode(column, IS_EMPTY, null); + } + + public static FilterNode isEmpty(LambdaSupplier func) { + return new FilterNode(LambdaSupplier.readColumn(func), IS_EMPTY, null); + } + + public static FilterNode isEmpty(LambdaFunction func) { + return new FilterNode(LambdaFunction.readColumn(func), IS_EMPTY, null); + } + + public static FilterNode notEmpty(String column) { + return new FilterNode(column, NOT_EMPTY, null); + } + + public static FilterNode notEmpty(LambdaSupplier func) { + return new FilterNode(LambdaSupplier.readColumn(func), NOT_EMPTY, null); + } + + public static FilterNode notEmpty(LambdaFunction func) { + return new FilterNode(LambdaFunction.readColumn(func), NOT_EMPTY, null); + } + + public static FilterNode opand(String column, Number value) { + return new FilterNode(column, OPAND, value); + } + + public static FilterNode opand(LambdaSupplier func) { + return new FilterNode(LambdaSupplier.readColumn(func), OPAND, func.get()); + } + + public static FilterNode opand(LambdaFunction func, F value) { + return new FilterNode(LambdaFunction.readColumn(func), OPAND, value); + } + + public static FilterNode opor(String column, Number value) { + return new FilterNode(column, OPOR, value); + } + + public static FilterNode opor(LambdaSupplier func) { + return new FilterNode(LambdaSupplier.readColumn(func), OPOR, func.get()); + } + + public FilterNode opor(LambdaFunction func, F value) { + return new FilterNode(LambdaFunction.readColumn(func), OPOR, value); + } + + public static FilterNode notOpand(String column, Number value) { + return new FilterNode(column, NOT_OPAND, value); + } + + public static FilterNode notOpand(LambdaSupplier func) { + return new FilterNode(LambdaSupplier.readColumn(func), NOT_OPAND, func.get()); + } + + public static FilterNode notOpand(LambdaFunction func, F value) { + return new FilterNode(LambdaFunction.readColumn(func), NOT_OPAND, value); + } + + public static FilterNode fvmode(String column, FilterExpValue value) { + return new FilterNode(column, FV_MOD, value); + } + + public static FilterNode fvmode(LambdaSupplier func) { + return new FilterNode(LambdaSupplier.readColumn(func), FV_MOD, func.get()); + } + + public static FilterNode fvmode(LambdaFunction func, F value) { + return new FilterNode(LambdaFunction.readColumn(func), FV_MOD, value); + } + + public static FilterNode fvdiv(String column, FilterExpValue value) { + return new FilterNode(column, FV_DIV, value); + } + + public static FilterNode fvdiv(LambdaSupplier func) { + return new FilterNode(LambdaSupplier.readColumn(func), FV_DIV, func.get()); + } + + public static FilterNode fvdiv(LambdaFunction func, F value) { + return new FilterNode(LambdaFunction.readColumn(func), FV_DIV, value); + } + + // ---------------------------------------------------------------------------------------------------- + public static FilterJoinNode joinInner(Class joinClass, String joinColumn, String column, Serializable value) { + return joinInner(joinClass, new String[] {joinColumn}, column, value); + } + + public static FilterJoinNode joinInner( + Class joinClass, String joinColumn, String column, FilterExpress express, Serializable value) { + return joinInner(joinClass, new String[] {joinColumn}, column, express, value); + } + + public static FilterJoinNode joinInner(Class joinClass, String[] joinColumns, String column, Serializable value) { + return joinInner(joinClass, joinColumns, column, null, value); + } + + public static FilterJoinNode joinInner( + Class joinClass, String[] joinColumns, String column, FilterExpress express, Serializable value) { + return new FilterJoinNode(FilterJoinType.INNER, joinClass, joinColumns, column, express, value); + } + + // ---------------------------------------------------------------------------------------------------- + static FilterExpress oldExpress(FilterExpress express) { + switch (express) { + case EQUAL: + return EQ; + case IGNORECASEEQUAL: + return IG_EQ; + case NOTEQUAL: + return NE; + case IGNORECASENOTEQUAL: + return IG_NE; + case GREATERTHAN: + return GT; + case LESSTHAN: + return LT; + case GREATERTHANOREQUALTO: + return GE; + case LESSTHANOREQUALTO: + return LE; + case NOTLIKE: + return NOT_LIKE; + case IGNORECASELIKE: + return IG_LIKE; + case IGNORECASENOTLIKE: + return IG_NOT_LIKE; + case STARTSWITH: + return STARTS; + case ENDSWITH: + return ENDS; + case NOTSTARTSWITH: + return NOT_STARTS; + case NOTENDSWITH: + return NOT_ENDS; + case LENGTH_EQUAL: + return LEN_EQ; + case LENGTH_GREATERTHAN: + return LEN_GT; + case LENGTH_LESSTHAN: + return LEN_LT; + case LENGTH_GREATERTHANOREQUALTO: + return LEN_GE; + case LENGTH_LESSTHANOREQUALTO: + return LEN_LE; + case NOTCONTAIN: + return NOT_CONTAIN; + case IGNORECASECONTAIN: + return IG_CONTAIN; + case IGNORECASENOTCONTAIN: + return IG_NOT_CONTAIN; + case NOTBETWEEN: + return NOT_BETWEEN; + case NOTIN: + return NOT_IN; + case ISNULL: + return IS_NULL; + case ISNOTNULL: + return NOT_NULL; + case ISEMPTY: + return IS_EMPTY; + case ISNOTEMPTY: + return NOT_EMPTY; + default: + return express; + } + } +} diff --git a/src/main/java/org/redkale/source/SourceException.java b/src/main/java/org/redkale/source/SourceException.java index 5fb164c5d..9ea2cca85 100644 --- a/src/main/java/org/redkale/source/SourceException.java +++ b/src/main/java/org/redkale/source/SourceException.java @@ -1,33 +1,33 @@ -/* - * - */ -package org.redkale.source; - -import org.redkale.util.RedkaleException; - -/** - * 数据源自定义异常类 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public class SourceException extends RedkaleException { - - public SourceException() { - super(); - } - - public SourceException(String s) { - super(s); - } - - public SourceException(String message, Throwable cause) { - super(message, cause); - } - - public SourceException(Throwable cause) { - super(cause); - } -} +/* + * + */ +package org.redkale.source; + +import org.redkale.util.RedkaleException; + +/** + * 数据源自定义异常类 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public class SourceException extends RedkaleException { + + public SourceException() { + super(); + } + + public SourceException(String s) { + super(s); + } + + public SourceException(String message, Throwable cause) { + super(message, cause); + } + + public SourceException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/org/redkale/source/SourceManager.java b/src/main/java/org/redkale/source/SourceManager.java index 662b78669..cbe19b4ee 100644 --- a/src/main/java/org/redkale/source/SourceManager.java +++ b/src/main/java/org/redkale/source/SourceManager.java @@ -1,63 +1,63 @@ -/* - * - */ -package org.redkale.source; - -import java.util.Map; - -/** - * source组件的基本管理器 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public interface SourceManager { - - /** - * @param sourceName 资源名 - * @return CacheSource - */ - default CacheSource loadCacheSource(final String sourceName) { - return loadCacheSource(sourceName, false); - } - - /** - * @param sourceName 资源名 - * @param autoMemory 不存在是否自动创建内存版CacheSource - * @return CacheSource - */ - public CacheSource loadCacheSource(final String sourceName, boolean autoMemory); - - /** - * 获取所有CacheSource, 不同资源名可能指向同一个CacheSource - * - * @return CacheSource集合 - */ - public Map getCacheSources(); - - /** - * @param sourceName 资源名 - * @return DataSource - */ - default DataSource loadDataSource(final String sourceName) { - return loadDataSource(sourceName, false); - } - - /** - * 加载DataSource - * - * @param sourceName 资源名 - * @param autoMemory 不存在是否自动创建内存版DataSource - * @return DataSource - */ - public DataSource loadDataSource(final String sourceName, boolean autoMemory); - - /** - * 获取所有DataSource, 不同资源名可能指向同一个DataSource - * - * @return DataSource集合 - */ - public Map getDataSources(); -} +/* + * + */ +package org.redkale.source; + +import java.util.Map; + +/** + * source组件的基本管理器 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public interface SourceManager { + + /** + * @param sourceName 资源名 + * @return CacheSource + */ + default CacheSource loadCacheSource(final String sourceName) { + return loadCacheSource(sourceName, false); + } + + /** + * @param sourceName 资源名 + * @param autoMemory 不存在是否自动创建内存版CacheSource + * @return CacheSource + */ + public CacheSource loadCacheSource(final String sourceName, boolean autoMemory); + + /** + * 获取所有CacheSource, 不同资源名可能指向同一个CacheSource + * + * @return CacheSource集合 + */ + public Map getCacheSources(); + + /** + * @param sourceName 资源名 + * @return DataSource + */ + default DataSource loadDataSource(final String sourceName) { + return loadDataSource(sourceName, false); + } + + /** + * 加载DataSource + * + * @param sourceName 资源名 + * @param autoMemory 不存在是否自动创建内存版DataSource + * @return DataSource + */ + public DataSource loadDataSource(final String sourceName, boolean autoMemory); + + /** + * 获取所有DataSource, 不同资源名可能指向同一个DataSource + * + * @return DataSource集合 + */ + public Map getDataSources(); +} diff --git a/src/main/java/org/redkale/source/spi/DataNativeSqlParserProvider.java b/src/main/java/org/redkale/source/spi/DataNativeSqlParserProvider.java index 7245438e2..9d1fe3c4e 100644 --- a/src/main/java/org/redkale/source/spi/DataNativeSqlParserProvider.java +++ b/src/main/java/org/redkale/source/spi/DataNativeSqlParserProvider.java @@ -1,17 +1,17 @@ -/* - * - */ -package org.redkale.source.spi; - -import org.redkale.source.DataNativeSqlParser; -import org.redkale.util.InstanceProvider; - -/** - * 自定义的DataNativeSqlParser加载器, 如果标记@Priority加载器的优先级需要大于1000, 1000以下预留给官方加载器 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public interface DataNativeSqlParserProvider extends InstanceProvider {} +/* + * + */ +package org.redkale.source.spi; + +import org.redkale.source.DataNativeSqlParser; +import org.redkale.util.InstanceProvider; + +/** + * 自定义的DataNativeSqlParser加载器, 如果标记@Priority加载器的优先级需要大于1000, 1000以下预留给官方加载器 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public interface DataNativeSqlParserProvider extends InstanceProvider {} diff --git a/src/main/java/org/redkale/source/spi/DataSqlMapperBuilder.java b/src/main/java/org/redkale/source/spi/DataSqlMapperBuilder.java index df3f456e1..a496b6f29 100644 --- a/src/main/java/org/redkale/source/spi/DataSqlMapperBuilder.java +++ b/src/main/java/org/redkale/source/spi/DataSqlMapperBuilder.java @@ -1,460 +1,460 @@ -/* - * - */ -package org.redkale.source.spi; - -import static org.redkale.asm.ClassWriter.COMPUTE_FRAMES; -import static org.redkale.asm.Opcodes.*; -import static org.redkale.source.DataNativeSqlInfo.SqlMode.SELECT; - -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.lang.reflect.Parameter; -import java.lang.reflect.ParameterizedType; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CompletableFuture; -import java.util.function.IntFunction; -import org.redkale.annotation.Param; -import org.redkale.asm.AsmMethodBean; -import org.redkale.asm.AsmMethodBoost; -import org.redkale.asm.AsmMethodParam; -import org.redkale.asm.Asms; -import org.redkale.asm.ClassWriter; -import org.redkale.asm.FieldVisitor; -import org.redkale.asm.Label; -import org.redkale.asm.MethodDebugVisitor; -import org.redkale.asm.MethodVisitor; -import org.redkale.asm.Type; -import org.redkale.convert.json.JsonObject; -import org.redkale.persistence.Sql; -import org.redkale.source.AbstractDataSqlSource; -import org.redkale.source.DataNativeSqlInfo; -import org.redkale.source.DataNativeSqlParser; -import org.redkale.source.DataSqlMapper; -import org.redkale.source.DataSqlSource; -import org.redkale.source.EntityBuilder; -import org.redkale.source.Flipper; -import org.redkale.source.SourceException; -import org.redkale.util.RedkaleClassLoader; -import org.redkale.util.Sheet; -import org.redkale.util.TypeToken; -import org.redkale.util.Utility; - -/** - * DataSqlMapper工厂类 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public final class DataSqlMapperBuilder { - - private DataSqlMapperBuilder() {} - - public static > M createMapper( - DataNativeSqlParser nativeSqlParser, DataSqlSource source, Class mapperType) { - if (!mapperType.isInterface()) { - throw new SourceException(mapperType + " is not interface"); - } - final ClassLoader loader = Thread.currentThread().getContextClassLoader(); - final Class entityType = entityType(mapperType); - final String supDynName = mapperType.getName().replace('.', '/'); - final String newDynName = "org/redkaledyn/source/mapper/_DynDataSqlMapper_" - + mapperType.getName().replace('.', '_').replace('$', '_'); - try { - Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.')); - Class newClazz = clz == null ? loader.loadClass(newDynName.replace('/', '.')) : clz; - M mapper = (M) newClazz.getDeclaredConstructor().newInstance(); - { - Field c = newClazz.getDeclaredField("_source"); - c.setAccessible(true); - c.set(mapper, source); - } - { - Field c = newClazz.getDeclaredField("_type"); - c.setAccessible(true); - c.set(mapper, entityType); - } - return mapper; - } catch (ClassNotFoundException e) { - // do nothing - } catch (Throwable t) { - t.printStackTrace(); - } - EntityBuilder.load(entityType); - List items = new ArrayList<>(); - Map selfMethodBeans = AsmMethodBoost.getMethodBeans(mapperType); - for (Method method : mapperType.getMethods()) { - if (Modifier.isStatic(method.getModifiers())) { - continue; - } - if ("dataSource".equals(method.getName()) && method.getParameterCount() == 0) { - continue; - } - if ("entityType".equals(method.getName()) && method.getParameterCount() == 0) { - continue; - } - Sql sql = method.getAnnotation(Sql.class); - if (sql == null) { - if (Modifier.isAbstract(method.getModifiers())) { - throw new SourceException(mapperType.getSimpleName() + "." + method.getName() + " require @" - + Sql.class.getSimpleName()); - } - continue; - } - if (!Modifier.isAbstract(method.getModifiers())) { - throw new SourceException(mapperType.getSimpleName() + "." + method.getName() - + " is not abstract, but contains @" + Sql.class.getSimpleName()); - } - if (method.getExceptionTypes().length > 0) { - throw new SourceException( - "@" + Sql.class.getSimpleName() + " cannot on throw-exception method, but " + method); - } - IntFunction signFunc = null; - if (source instanceof AbstractDataSqlSource) { - signFunc = ((AbstractDataSqlSource) source).getSignFunc(); - } - DataNativeSqlInfo sqlInfo = nativeSqlParser.parse(signFunc, source.getType(), sql.value()); - AsmMethodBean methodBean = selfMethodBeans.get(AsmMethodBoost.getMethodBeanKey(method)); - List fieldNames = methodBean.fieldNameList(); - Class resultClass = resultClass(method); - int flipperIndex = -1; - if (resultClass.isAssignableFrom(Sheet.class)) { - Class[] pts = method.getParameterTypes(); - for (int i = 0; i < pts.length; i++) { - if (pts[i] == Flipper.class) { - flipperIndex = i; - break; - } - } - if (flipperIndex < 0) { - throw new SourceException( - mapperType.getSimpleName() + "." + method.getName() + " need Flipper type parameter on @" - + Sql.class.getSimpleName() + "(" + sql.value() + ")"); - } - fieldNames.remove(flipperIndex); - } - if (!Utility.equalsElement(sqlInfo.getRootParamNames(), fieldNames)) { - throw new SourceException(mapperType.getSimpleName() + "." + method.getName() - + " parameters not match, fieldNames = " + fieldNames + ", sqlParams = " - + sqlInfo.getRootParamNames() + ", methodBean = " + methodBean); - } - if (sqlInfo.getSqlMode() != SELECT) { // 非SELECT语句只能返回int或void - if (resultClass != Integer.class && resultClass != int.class) { - throw new SourceException("Update SQL must on return int method, but " + method); - } - } - items.add(new Item(method, sqlInfo, methodBean, flipperIndex)); - } - // ------------------------------------------------------------------------------ - - final String utilClassName = Utility.class.getName().replace('.', '/'); - final String sheetDesc = Type.getDescriptor(Sheet.class); - final String flipperDesc = Type.getDescriptor(Flipper.class); - final String entityDesc = Type.getDescriptor(entityType); - final String sqlSourceName = DataSqlSource.class.getName().replace('.', '/'); - final String sqlSourceDesc = Type.getDescriptor(DataSqlSource.class); - - ClassWriter cw = new ClassWriter(COMPUTE_FRAMES); - FieldVisitor fv; - MethodVisitor mv; - - cw.visit(V11, ACC_PUBLIC + ACC_SUPER, newDynName, null, "java/lang/Object", new String[] {supDynName}); - { - fv = cw.visitField(ACC_PRIVATE, "_source", sqlSourceDesc, null, null); - fv.visitEnd(); - } - { - fv = cw.visitField(ACC_PRIVATE, "_type", "Ljava/lang/Class;", null, null); - fv.visitEnd(); - } - { - mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); - mv.visitInsn(RETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - { - mv = cw.visitMethod(ACC_PUBLIC, "dataSource", "()" + sqlSourceDesc, null, null); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, "_source", sqlSourceDesc); - mv.visitInsn(ARETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - { - mv = cw.visitMethod( - ACC_PUBLIC, "entityType", "()Ljava/lang/Class;", "()Ljava/lang/Class<" + entityDesc + ">;", null); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, "_type", "Ljava/lang/Class;"); - mv.visitInsn(ARETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - - // sql系列方法 - // int nativeUpdate(String sql) - // CompletableFuture nativeUpdateAsync(String sql) - // int nativeUpdate(String sql, Map params) - // CompletableFuture nativeUpdateAsync(String sql, Map params) - // - // V nativeQueryOne(Class type, String sql) - // CompletableFuture nativeQueryOneAsync(Class type, String sql) - // V nativeQueryOne(Class type, String sql, Map params) - // CompletableFuture nativeQueryOneAsync(Class type, String sql, Map params) - // - // Map nativeQueryMap(Class keyType, Class valType, String sql, Map params) - // CompletableFuture> nativeQueryMapAsync(Class keyType, Class valType, String sql, Map params) - // - // nativeQueryOne、nativeQueryList、nativeQuerySheet - for (Item item : items) { - Method method = item.method; - DataNativeSqlInfo sqlInfo = item.sqlInfo; - AsmMethodBean methodBean = item.methodBean; - int flipperIndex = item.flipperIndex; - Sql sql = method.getAnnotation(Sql.class); - Class resultClass = resultClass(method); - Class[] componentTypes = resultComponentType(method); - final boolean async = method.getReturnType().isAssignableFrom(CompletableFuture.class); - Parameter[] params = method.getParameters(); - Class[] paramTypes = method.getParameterTypes(); - List methodParams = methodBean.getParams(); - List insns = new ArrayList<>(); - if (!EntityBuilder.isSimpleType(componentTypes[0])) { - EntityBuilder.load(componentTypes[0]); - } - - mv = new MethodDebugVisitor(cw.visitMethod( - ACC_PUBLIC, method.getName(), methodBean.getDesc(), methodBean.getSignature(), null)) - .setDebug(false); - Label l0 = new Label(); - mv.visitLabel(l0); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "dataSource", "()" + sqlSourceDesc, false); - if (sqlInfo.getSqlMode() == SELECT) { - // 参数:结果类 - mv.visitLdcInsn(Type.getType(Type.getDescriptor(componentTypes[0]))); - if (resultClass.isAssignableFrom(Map.class)) { - mv.visitLdcInsn(Type.getType(Type.getDescriptor(componentTypes[1]))); - } - } - // 参数:sql - mv.visitLdcInsn(sql.value()); - if (flipperIndex >= 0) { - mv.visitVarInsn(ALOAD, flipperIndex + 1); - } - // 参数: params - Asms.visitInsn(mv, paramTypes.length * 2 - (flipperIndex >= 0 ? 2 : 0)); - mv.visitTypeInsn(ANEWARRAY, "java/lang/Object"); - int insn = 0; - for (int i = 0; i < paramTypes.length; i++) { - insn++; - if (i != flipperIndex) { - Class pt = paramTypes[i]; - // 参数名 - mv.visitInsn(DUP); - Asms.visitInsn(mv, i * 2); - Param p = params[i].getAnnotation(Param.class); - String k = p == null ? methodParams.get(i).getName() : p.value(); - mv.visitLdcInsn(k); - mv.visitInsn(AASTORE); - // 参数值 - mv.visitInsn(DUP); - Asms.visitInsn(mv, i * 2 + 1); - if (pt.isPrimitive()) { - if (pt == long.class) { - mv.visitVarInsn(LLOAD, insn++); - } else if (pt == float.class) { - mv.visitVarInsn(FLOAD, insn++); - } else if (pt == double.class) { - mv.visitVarInsn(DLOAD, insn++); - } else { - mv.visitVarInsn(ILOAD, insn); - } - } else { - mv.visitVarInsn(ALOAD, insn); - } - Asms.visitPrimitiveValueOf(mv, pt); - mv.visitInsn(AASTORE); - } - insns.add(insn); - } - - mv.visitMethodInsn(INVOKESTATIC, utilClassName, "ofMap", "([Ljava/lang/Object;)Ljava/util/HashMap;", false); - - // One: "(Ljava/lang/Class;Ljava/lang/String;Ljava/util/Map;)Ljava/lang/Object;" - // Map: "(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/String;Ljava/util/Map;)Ljava/util/Map;" - // List: "(Ljava/lang/Class;Ljava/lang/String;Ljava/util/Map;)Ljava/util/List;" - // Sheet: - // "(Ljava/lang/Class;Ljava/lang/String;Lorg/redkale/source/Flipper;Ljava/util/Map;)Lorg/redkale/util/Sheet;" - // Async: "(Ljava/lang/Class;Ljava/lang/String;Ljava/util/Map;)Ljava/util/concurrent/CompletableFuture;" - if (sqlInfo.getSqlMode() == SELECT) { - String queryMethodName = "nativeQueryOne"; - String queryMethodDesc = "(Ljava/lang/Class;Ljava/lang/String;Ljava/util/Map;)" - + (async ? "Ljava/util/concurrent/CompletableFuture;" : "Ljava/lang/Object;"); - boolean oneMode = !async; - if (resultClass.isAssignableFrom(Map.class)) { - oneMode = false; - queryMethodName = "nativeQueryMap"; - queryMethodDesc = "(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/String;Ljava/util/Map;)" - + (async ? "Ljava/util/concurrent/CompletableFuture;" : "Ljava/util/Map;"); - } else if (resultClass.isAssignableFrom(List.class)) { - oneMode = false; - queryMethodName = "nativeQueryList"; - queryMethodDesc = "(Ljava/lang/Class;Ljava/lang/String;Ljava/util/Map;)" - + (async ? "Ljava/util/concurrent/CompletableFuture;" : "Ljava/util/List;"); - } else if (resultClass.isAssignableFrom(Sheet.class)) { - oneMode = false; - queryMethodName = "nativeQuerySheet"; - queryMethodDesc = "(Ljava/lang/Class;Ljava/lang/String;" + flipperDesc + "Ljava/util/Map;)" - + (async ? "Ljava/util/concurrent/CompletableFuture;" : sheetDesc); - } - mv.visitMethodInsn( - INVOKEINTERFACE, - sqlSourceName, - queryMethodName + (async ? "Async" : ""), - queryMethodDesc, - true); - if (oneMode) { - mv.visitTypeInsn(CHECKCAST, componentTypes[0].getName().replace('.', '/')); - } - mv.visitInsn(ARETURN); - } else { - String updateMethodName = "nativeUpdate" + (async ? "Async" : ""); - String updateMethodDesc = "(Ljava/lang/String;Ljava/util/Map;)" - + (async ? "Ljava/util/concurrent/CompletableFuture;" : "I"); - mv.visitMethodInsn(INVOKEINTERFACE, sqlSourceName, updateMethodName, updateMethodDesc, true); - if (resultClass == int.class) { - mv.visitInsn(IRETURN); - } else if (!async && resultClass == Integer.class) { - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false); - mv.visitInsn(ARETURN); - } else if (resultClass == void.class) { - mv.visitInsn(POP); - mv.visitInsn(RETURN); - } else { - mv.visitInsn(ARETURN); - } - } - Label l2 = new Label(); - mv.visitLabel(l2); - mv.visitLocalVariable("this", "L" + newDynName + ";", null, l0, l2, 0); - for (int i = 0; i < paramTypes.length; i++) { - AsmMethodParam param = methodParams.get(i); - mv.visitLocalVariable( - param.getName(), - param.description(paramTypes[i]), - param.signature(paramTypes[i]), - l0, - l2, - insns.get(i)); - } - mv.visitMaxs(8, 5); - mv.visitEnd(); - } - - cw.visitEnd(); - - byte[] bytes = cw.toByteArray(); - Class newClazz = new ClassLoader(loader) { - public final Class loadClass(String name, byte[] b) { - return defineClass(name, b, 0, b.length); - } - }.loadClass(newDynName.replace('/', '.'), bytes); - RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, newClazz); - RedkaleClassLoader.putReflectionPublicConstructors(newClazz, newDynName.replace('/', '.')); - RedkaleClassLoader.putReflectionDeclaredConstructors(newClazz, newDynName.replace('/', '.')); - try { - M mapper = (M) newClazz.getDeclaredConstructor().newInstance(); - { - Field c = newClazz.getDeclaredField("_source"); - c.setAccessible(true); - c.set(mapper, source); - } - { - Field c = newClazz.getDeclaredField("_type"); - c.setAccessible(true); - c.set(mapper, entityType); - } - return mapper; - } catch (Exception ex) { - throw new SourceException(ex); - } - } - - private static Class entityType(Class mapperType) { - for (java.lang.reflect.Type t : mapperType.getGenericInterfaces()) { - if (DataSqlMapper.class.isAssignableFrom(TypeToken.typeToClass(t))) { - return TypeToken.typeToClass(((ParameterizedType) t).getActualTypeArguments()[0]); - } - } - throw new SourceException("Not found entity class from " + mapperType.getName()); - } - - private static Class resultClass(Method method) { - Class type = method.getReturnType(); - if (type.isAssignableFrom(CompletableFuture.class)) { - ParameterizedType pt = (ParameterizedType) method.getGenericReturnType(); - return TypeToken.typeToClass(pt.getActualTypeArguments()[0]); - } - return type; - } - - private static Class[] resultComponentType(Method method) { - if (method.getReturnType().isAssignableFrom(CompletableFuture.class)) { - ParameterizedType pt = (ParameterizedType) method.getGenericReturnType(); - return resultComponentType(pt.getActualTypeArguments()[0]); - } - return resultComponentType(method.getGenericReturnType()); - } - - private static Class[] resultComponentType(java.lang.reflect.Type type) { - Class clzz = TypeToken.typeToClass(type); - if (clzz.isAssignableFrom(Map.class)) { - if (type instanceof ParameterizedType) { - java.lang.reflect.Type[] ts = ((ParameterizedType) type).getActualTypeArguments(); - return new Class[] {TypeToken.typeToClass(ts[0]), TypeToken.typeToClass(ts[1])}; - } else { - return new Class[] {String.class, JsonObject.class}; - } - } else if (clzz.isAssignableFrom(List.class)) { - if (type instanceof ParameterizedType) { - clzz = TypeToken.typeToClass(((ParameterizedType) type).getActualTypeArguments()[0]); - } else { - clzz = JsonObject.class; - } - } else if (clzz.isAssignableFrom(Sheet.class)) { - if (type instanceof ParameterizedType) { - clzz = TypeToken.typeToClass(((ParameterizedType) type).getActualTypeArguments()[0]); - } else { - clzz = JsonObject.class; - } - } - return new Class[] {clzz}; - } - - private static class Item { - - public Method method; - - public DataNativeSqlInfo sqlInfo; - - public AsmMethodBean methodBean; - - public int flipperIndex = -1; - - public Item(Method method, DataNativeSqlInfo sqlInfo, AsmMethodBean methodBean, int flipperIndex) { - this.method = method; - this.sqlInfo = sqlInfo; - this.methodBean = methodBean; - this.flipperIndex = flipperIndex; - } - } -} +/* + * + */ +package org.redkale.source.spi; + +import static org.redkale.asm.ClassWriter.COMPUTE_FRAMES; +import static org.redkale.asm.Opcodes.*; +import static org.redkale.source.DataNativeSqlInfo.SqlMode.SELECT; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.Parameter; +import java.lang.reflect.ParameterizedType; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.function.IntFunction; +import org.redkale.annotation.Param; +import org.redkale.asm.AsmMethodBean; +import org.redkale.asm.AsmMethodBoost; +import org.redkale.asm.AsmMethodParam; +import org.redkale.asm.Asms; +import org.redkale.asm.ClassWriter; +import org.redkale.asm.FieldVisitor; +import org.redkale.asm.Label; +import org.redkale.asm.MethodDebugVisitor; +import org.redkale.asm.MethodVisitor; +import org.redkale.asm.Type; +import org.redkale.convert.json.JsonObject; +import org.redkale.persistence.Sql; +import org.redkale.source.AbstractDataSqlSource; +import org.redkale.source.DataNativeSqlInfo; +import org.redkale.source.DataNativeSqlParser; +import org.redkale.source.DataSqlMapper; +import org.redkale.source.DataSqlSource; +import org.redkale.source.EntityBuilder; +import org.redkale.source.Flipper; +import org.redkale.source.SourceException; +import org.redkale.util.RedkaleClassLoader; +import org.redkale.util.Sheet; +import org.redkale.util.TypeToken; +import org.redkale.util.Utility; + +/** + * DataSqlMapper工厂类 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public final class DataSqlMapperBuilder { + + private DataSqlMapperBuilder() {} + + public static > M createMapper( + DataNativeSqlParser nativeSqlParser, DataSqlSource source, Class mapperType) { + if (!mapperType.isInterface()) { + throw new SourceException(mapperType + " is not interface"); + } + final ClassLoader loader = Thread.currentThread().getContextClassLoader(); + final Class entityType = entityType(mapperType); + final String supDynName = mapperType.getName().replace('.', '/'); + final String newDynName = "org/redkaledyn/source/mapper/_DynDataSqlMapper_" + + mapperType.getName().replace('.', '_').replace('$', '_'); + try { + Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.')); + Class newClazz = clz == null ? loader.loadClass(newDynName.replace('/', '.')) : clz; + M mapper = (M) newClazz.getDeclaredConstructor().newInstance(); + { + Field c = newClazz.getDeclaredField("_source"); + c.setAccessible(true); + c.set(mapper, source); + } + { + Field c = newClazz.getDeclaredField("_type"); + c.setAccessible(true); + c.set(mapper, entityType); + } + return mapper; + } catch (ClassNotFoundException e) { + // do nothing + } catch (Throwable t) { + t.printStackTrace(); + } + EntityBuilder.load(entityType); + List items = new ArrayList<>(); + Map selfMethodBeans = AsmMethodBoost.getMethodBeans(mapperType); + for (Method method : mapperType.getMethods()) { + if (Modifier.isStatic(method.getModifiers())) { + continue; + } + if ("dataSource".equals(method.getName()) && method.getParameterCount() == 0) { + continue; + } + if ("entityType".equals(method.getName()) && method.getParameterCount() == 0) { + continue; + } + Sql sql = method.getAnnotation(Sql.class); + if (sql == null) { + if (Modifier.isAbstract(method.getModifiers())) { + throw new SourceException(mapperType.getSimpleName() + "." + method.getName() + " require @" + + Sql.class.getSimpleName()); + } + continue; + } + if (!Modifier.isAbstract(method.getModifiers())) { + throw new SourceException(mapperType.getSimpleName() + "." + method.getName() + + " is not abstract, but contains @" + Sql.class.getSimpleName()); + } + if (method.getExceptionTypes().length > 0) { + throw new SourceException( + "@" + Sql.class.getSimpleName() + " cannot on throw-exception method, but " + method); + } + IntFunction signFunc = null; + if (source instanceof AbstractDataSqlSource) { + signFunc = ((AbstractDataSqlSource) source).getSignFunc(); + } + DataNativeSqlInfo sqlInfo = nativeSqlParser.parse(signFunc, source.getType(), sql.value()); + AsmMethodBean methodBean = selfMethodBeans.get(AsmMethodBoost.getMethodBeanKey(method)); + List fieldNames = methodBean.fieldNameList(); + Class resultClass = resultClass(method); + int flipperIndex = -1; + if (resultClass.isAssignableFrom(Sheet.class)) { + Class[] pts = method.getParameterTypes(); + for (int i = 0; i < pts.length; i++) { + if (pts[i] == Flipper.class) { + flipperIndex = i; + break; + } + } + if (flipperIndex < 0) { + throw new SourceException( + mapperType.getSimpleName() + "." + method.getName() + " need Flipper type parameter on @" + + Sql.class.getSimpleName() + "(" + sql.value() + ")"); + } + fieldNames.remove(flipperIndex); + } + if (!Utility.equalsElement(sqlInfo.getRootParamNames(), fieldNames)) { + throw new SourceException(mapperType.getSimpleName() + "." + method.getName() + + " parameters not match, fieldNames = " + fieldNames + ", sqlParams = " + + sqlInfo.getRootParamNames() + ", methodBean = " + methodBean); + } + if (sqlInfo.getSqlMode() != SELECT) { // 非SELECT语句只能返回int或void + if (resultClass != Integer.class && resultClass != int.class) { + throw new SourceException("Update SQL must on return int method, but " + method); + } + } + items.add(new Item(method, sqlInfo, methodBean, flipperIndex)); + } + // ------------------------------------------------------------------------------ + + final String utilClassName = Utility.class.getName().replace('.', '/'); + final String sheetDesc = Type.getDescriptor(Sheet.class); + final String flipperDesc = Type.getDescriptor(Flipper.class); + final String entityDesc = Type.getDescriptor(entityType); + final String sqlSourceName = DataSqlSource.class.getName().replace('.', '/'); + final String sqlSourceDesc = Type.getDescriptor(DataSqlSource.class); + + ClassWriter cw = new ClassWriter(COMPUTE_FRAMES); + FieldVisitor fv; + MethodVisitor mv; + + cw.visit(V11, ACC_PUBLIC + ACC_SUPER, newDynName, null, "java/lang/Object", new String[] {supDynName}); + { + fv = cw.visitField(ACC_PRIVATE, "_source", sqlSourceDesc, null, null); + fv.visitEnd(); + } + { + fv = cw.visitField(ACC_PRIVATE, "_type", "Ljava/lang/Class;", null, null); + fv.visitEnd(); + } + { + mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + { + mv = cw.visitMethod(ACC_PUBLIC, "dataSource", "()" + sqlSourceDesc, null, null); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, "_source", sqlSourceDesc); + mv.visitInsn(ARETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + { + mv = cw.visitMethod( + ACC_PUBLIC, "entityType", "()Ljava/lang/Class;", "()Ljava/lang/Class<" + entityDesc + ">;", null); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, "_type", "Ljava/lang/Class;"); + mv.visitInsn(ARETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + + // sql系列方法 + // int nativeUpdate(String sql) + // CompletableFuture nativeUpdateAsync(String sql) + // int nativeUpdate(String sql, Map params) + // CompletableFuture nativeUpdateAsync(String sql, Map params) + // + // V nativeQueryOne(Class type, String sql) + // CompletableFuture nativeQueryOneAsync(Class type, String sql) + // V nativeQueryOne(Class type, String sql, Map params) + // CompletableFuture nativeQueryOneAsync(Class type, String sql, Map params) + // + // Map nativeQueryMap(Class keyType, Class valType, String sql, Map params) + // CompletableFuture> nativeQueryMapAsync(Class keyType, Class valType, String sql, Map params) + // + // nativeQueryOne、nativeQueryList、nativeQuerySheet + for (Item item : items) { + Method method = item.method; + DataNativeSqlInfo sqlInfo = item.sqlInfo; + AsmMethodBean methodBean = item.methodBean; + int flipperIndex = item.flipperIndex; + Sql sql = method.getAnnotation(Sql.class); + Class resultClass = resultClass(method); + Class[] componentTypes = resultComponentType(method); + final boolean async = method.getReturnType().isAssignableFrom(CompletableFuture.class); + Parameter[] params = method.getParameters(); + Class[] paramTypes = method.getParameterTypes(); + List methodParams = methodBean.getParams(); + List insns = new ArrayList<>(); + if (!EntityBuilder.isSimpleType(componentTypes[0])) { + EntityBuilder.load(componentTypes[0]); + } + + mv = new MethodDebugVisitor(cw.visitMethod( + ACC_PUBLIC, method.getName(), methodBean.getDesc(), methodBean.getSignature(), null)) + .setDebug(false); + Label l0 = new Label(); + mv.visitLabel(l0); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "dataSource", "()" + sqlSourceDesc, false); + if (sqlInfo.getSqlMode() == SELECT) { + // 参数:结果类 + mv.visitLdcInsn(Type.getType(Type.getDescriptor(componentTypes[0]))); + if (resultClass.isAssignableFrom(Map.class)) { + mv.visitLdcInsn(Type.getType(Type.getDescriptor(componentTypes[1]))); + } + } + // 参数:sql + mv.visitLdcInsn(sql.value()); + if (flipperIndex >= 0) { + mv.visitVarInsn(ALOAD, flipperIndex + 1); + } + // 参数: params + Asms.visitInsn(mv, paramTypes.length * 2 - (flipperIndex >= 0 ? 2 : 0)); + mv.visitTypeInsn(ANEWARRAY, "java/lang/Object"); + int insn = 0; + for (int i = 0; i < paramTypes.length; i++) { + insn++; + if (i != flipperIndex) { + Class pt = paramTypes[i]; + // 参数名 + mv.visitInsn(DUP); + Asms.visitInsn(mv, i * 2); + Param p = params[i].getAnnotation(Param.class); + String k = p == null ? methodParams.get(i).getName() : p.value(); + mv.visitLdcInsn(k); + mv.visitInsn(AASTORE); + // 参数值 + mv.visitInsn(DUP); + Asms.visitInsn(mv, i * 2 + 1); + if (pt.isPrimitive()) { + if (pt == long.class) { + mv.visitVarInsn(LLOAD, insn++); + } else if (pt == float.class) { + mv.visitVarInsn(FLOAD, insn++); + } else if (pt == double.class) { + mv.visitVarInsn(DLOAD, insn++); + } else { + mv.visitVarInsn(ILOAD, insn); + } + } else { + mv.visitVarInsn(ALOAD, insn); + } + Asms.visitPrimitiveValueOf(mv, pt); + mv.visitInsn(AASTORE); + } + insns.add(insn); + } + + mv.visitMethodInsn(INVOKESTATIC, utilClassName, "ofMap", "([Ljava/lang/Object;)Ljava/util/HashMap;", false); + + // One: "(Ljava/lang/Class;Ljava/lang/String;Ljava/util/Map;)Ljava/lang/Object;" + // Map: "(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/String;Ljava/util/Map;)Ljava/util/Map;" + // List: "(Ljava/lang/Class;Ljava/lang/String;Ljava/util/Map;)Ljava/util/List;" + // Sheet: + // "(Ljava/lang/Class;Ljava/lang/String;Lorg/redkale/source/Flipper;Ljava/util/Map;)Lorg/redkale/util/Sheet;" + // Async: "(Ljava/lang/Class;Ljava/lang/String;Ljava/util/Map;)Ljava/util/concurrent/CompletableFuture;" + if (sqlInfo.getSqlMode() == SELECT) { + String queryMethodName = "nativeQueryOne"; + String queryMethodDesc = "(Ljava/lang/Class;Ljava/lang/String;Ljava/util/Map;)" + + (async ? "Ljava/util/concurrent/CompletableFuture;" : "Ljava/lang/Object;"); + boolean oneMode = !async; + if (resultClass.isAssignableFrom(Map.class)) { + oneMode = false; + queryMethodName = "nativeQueryMap"; + queryMethodDesc = "(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/String;Ljava/util/Map;)" + + (async ? "Ljava/util/concurrent/CompletableFuture;" : "Ljava/util/Map;"); + } else if (resultClass.isAssignableFrom(List.class)) { + oneMode = false; + queryMethodName = "nativeQueryList"; + queryMethodDesc = "(Ljava/lang/Class;Ljava/lang/String;Ljava/util/Map;)" + + (async ? "Ljava/util/concurrent/CompletableFuture;" : "Ljava/util/List;"); + } else if (resultClass.isAssignableFrom(Sheet.class)) { + oneMode = false; + queryMethodName = "nativeQuerySheet"; + queryMethodDesc = "(Ljava/lang/Class;Ljava/lang/String;" + flipperDesc + "Ljava/util/Map;)" + + (async ? "Ljava/util/concurrent/CompletableFuture;" : sheetDesc); + } + mv.visitMethodInsn( + INVOKEINTERFACE, + sqlSourceName, + queryMethodName + (async ? "Async" : ""), + queryMethodDesc, + true); + if (oneMode) { + mv.visitTypeInsn(CHECKCAST, componentTypes[0].getName().replace('.', '/')); + } + mv.visitInsn(ARETURN); + } else { + String updateMethodName = "nativeUpdate" + (async ? "Async" : ""); + String updateMethodDesc = "(Ljava/lang/String;Ljava/util/Map;)" + + (async ? "Ljava/util/concurrent/CompletableFuture;" : "I"); + mv.visitMethodInsn(INVOKEINTERFACE, sqlSourceName, updateMethodName, updateMethodDesc, true); + if (resultClass == int.class) { + mv.visitInsn(IRETURN); + } else if (!async && resultClass == Integer.class) { + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false); + mv.visitInsn(ARETURN); + } else if (resultClass == void.class) { + mv.visitInsn(POP); + mv.visitInsn(RETURN); + } else { + mv.visitInsn(ARETURN); + } + } + Label l2 = new Label(); + mv.visitLabel(l2); + mv.visitLocalVariable("this", "L" + newDynName + ";", null, l0, l2, 0); + for (int i = 0; i < paramTypes.length; i++) { + AsmMethodParam param = methodParams.get(i); + mv.visitLocalVariable( + param.getName(), + param.description(paramTypes[i]), + param.signature(paramTypes[i]), + l0, + l2, + insns.get(i)); + } + mv.visitMaxs(8, 5); + mv.visitEnd(); + } + + cw.visitEnd(); + + byte[] bytes = cw.toByteArray(); + Class newClazz = new ClassLoader(loader) { + public final Class loadClass(String name, byte[] b) { + return defineClass(name, b, 0, b.length); + } + }.loadClass(newDynName.replace('/', '.'), bytes); + RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, newClazz); + RedkaleClassLoader.putReflectionPublicConstructors(newClazz, newDynName.replace('/', '.')); + RedkaleClassLoader.putReflectionDeclaredConstructors(newClazz, newDynName.replace('/', '.')); + try { + M mapper = (M) newClazz.getDeclaredConstructor().newInstance(); + { + Field c = newClazz.getDeclaredField("_source"); + c.setAccessible(true); + c.set(mapper, source); + } + { + Field c = newClazz.getDeclaredField("_type"); + c.setAccessible(true); + c.set(mapper, entityType); + } + return mapper; + } catch (Exception ex) { + throw new SourceException(ex); + } + } + + private static Class entityType(Class mapperType) { + for (java.lang.reflect.Type t : mapperType.getGenericInterfaces()) { + if (DataSqlMapper.class.isAssignableFrom(TypeToken.typeToClass(t))) { + return TypeToken.typeToClass(((ParameterizedType) t).getActualTypeArguments()[0]); + } + } + throw new SourceException("Not found entity class from " + mapperType.getName()); + } + + private static Class resultClass(Method method) { + Class type = method.getReturnType(); + if (type.isAssignableFrom(CompletableFuture.class)) { + ParameterizedType pt = (ParameterizedType) method.getGenericReturnType(); + return TypeToken.typeToClass(pt.getActualTypeArguments()[0]); + } + return type; + } + + private static Class[] resultComponentType(Method method) { + if (method.getReturnType().isAssignableFrom(CompletableFuture.class)) { + ParameterizedType pt = (ParameterizedType) method.getGenericReturnType(); + return resultComponentType(pt.getActualTypeArguments()[0]); + } + return resultComponentType(method.getGenericReturnType()); + } + + private static Class[] resultComponentType(java.lang.reflect.Type type) { + Class clzz = TypeToken.typeToClass(type); + if (clzz.isAssignableFrom(Map.class)) { + if (type instanceof ParameterizedType) { + java.lang.reflect.Type[] ts = ((ParameterizedType) type).getActualTypeArguments(); + return new Class[] {TypeToken.typeToClass(ts[0]), TypeToken.typeToClass(ts[1])}; + } else { + return new Class[] {String.class, JsonObject.class}; + } + } else if (clzz.isAssignableFrom(List.class)) { + if (type instanceof ParameterizedType) { + clzz = TypeToken.typeToClass(((ParameterizedType) type).getActualTypeArguments()[0]); + } else { + clzz = JsonObject.class; + } + } else if (clzz.isAssignableFrom(Sheet.class)) { + if (type instanceof ParameterizedType) { + clzz = TypeToken.typeToClass(((ParameterizedType) type).getActualTypeArguments()[0]); + } else { + clzz = JsonObject.class; + } + } + return new Class[] {clzz}; + } + + private static class Item { + + public Method method; + + public DataNativeSqlInfo sqlInfo; + + public AsmMethodBean methodBean; + + public int flipperIndex = -1; + + public Item(Method method, DataNativeSqlInfo sqlInfo, AsmMethodBean methodBean, int flipperIndex) { + this.method = method; + this.sqlInfo = sqlInfo; + this.methodBean = methodBean; + this.flipperIndex = flipperIndex; + } + } +} diff --git a/src/main/java/org/redkale/source/spi/SourceModuleEngine.java b/src/main/java/org/redkale/source/spi/SourceModuleEngine.java index a91413ae9..b788416c1 100644 --- a/src/main/java/org/redkale/source/spi/SourceModuleEngine.java +++ b/src/main/java/org/redkale/source/spi/SourceModuleEngine.java @@ -1,659 +1,659 @@ -/* - * - */ -package org.redkale.source.spi; - -import java.lang.reflect.Field; -import java.lang.reflect.Type; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Properties; -import java.util.ServiceLoader; -import java.util.Set; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.locks.ReentrantLock; -import java.util.logging.Level; -import org.redkale.annotation.Resource; -import org.redkale.boot.Application; -import org.redkale.boot.ModuleEngine; -import org.redkale.inject.Resourcable; -import org.redkale.inject.ResourceEvent; -import org.redkale.inject.ResourceFactory; -import org.redkale.inject.ResourceTypeLoader; -import org.redkale.net.Servlet; -import org.redkale.net.sncp.Sncp; -import org.redkale.service.Service; -import org.redkale.source.AbstractCacheSource; -import org.redkale.source.AbstractDataSource; -import org.redkale.source.CacheMemorySource; -import org.redkale.source.CacheSource; -import org.redkale.source.DataJdbcSource; -import org.redkale.source.DataMemorySource; -import org.redkale.source.DataNativeSqlParser; -import org.redkale.source.DataSource; -import org.redkale.source.DataSources; -import org.redkale.source.DataSqlMapper; -import org.redkale.source.DataSqlSource; -import org.redkale.source.SearchSource; -import org.redkale.source.SourceManager; -import org.redkale.util.AnyValue; -import org.redkale.util.AnyValueWriter; -import org.redkale.util.InstanceProvider; -import org.redkale.util.RedkaleClassLoader; -import org.redkale.util.RedkaleException; -import org.redkale.util.Utility; - -/** @author zhangjx */ -public class SourceModuleEngine extends ModuleEngine implements SourceManager { - - // Source 原始的配置资源, 只会存在redkale.datasource(.|[) redkale.cachesource(.|[)开头的配置项 - private final Properties sourceProperties = new Properties(); - - // CacheSource 资源 - private final List cacheSources = new CopyOnWriteArrayList<>(); - - private final ReentrantLock cacheSourceLock = new ReentrantLock(); - - // DataSource 资源 - private final List dataSources = new CopyOnWriteArrayList<>(); - - private final ReentrantLock dataSourceLock = new ReentrantLock(); - - // 原生sql解析器 - DataNativeSqlParser nativeSqlParser; - - public SourceModuleEngine(Application application) { - super(application); - } - - /** - * 判断模块的配置项合并策略, 返回null表示模块不识别此配置项 - * - * @param path 配置项路径 - * @param key 配置项名称 - * @param val1 配置项原值 - * @param val2 配置项新值 - * @return MergeEnum - */ - @Override - public AnyValue.MergeEnum mergeAppConfigStrategy(String path, String key, AnyValue val1, AnyValue val2) { - if ("cachesource".equals(path)) { - return AnyValue.MergeEnum.REPLACE; - } - if ("datasource".equals(path)) { - return AnyValue.MergeEnum.REPLACE; - } - return null; - } - - /** 配置项加载后被调用 */ - @Override - public void onEnvironmentLoaded(Properties allProps) { - allProps.forEach((key, val) -> { - if (key.toString().startsWith("redkale.datasource.") - || key.toString().startsWith("redkale.datasource[") - || key.toString().startsWith("redkale.cachesource.") - || key.toString().startsWith("redkale.cachesource[")) { - if (key.toString().endsWith(".name")) { - logger.log( - Level.WARNING, - "skip illegal key " + key + " in source config, key cannot endsWith '.name'"); - } else { - this.sourceProperties.put(key, val); - } - } - }); - } - - /** 结束Application.init方法前被调用 */ - @Override - public void onAppPostInit() { - // 加载原生sql解析器 - Iterator it = ServiceLoader.load( - DataNativeSqlParserProvider.class, application.getClassLoader()) - .iterator(); - RedkaleClassLoader.putServiceLoader(DataNativeSqlParserProvider.class); - List providers = new ArrayList<>(); - while (it.hasNext()) { - DataNativeSqlParserProvider provider = it.next(); - if (provider != null && provider.acceptsConf(null)) { - RedkaleClassLoader.putReflectionPublicConstructors( - provider.getClass(), provider.getClass().getName()); - providers.add(provider); - } - } - for (DataNativeSqlParserProvider provider : InstanceProvider.sort(providers)) { - this.nativeSqlParser = provider.createInstance(); - this.resourceFactory.register(DataNativeSqlParser.class, this.nativeSqlParser); - break; // only first provider - } - resourceFactory.register(SourceManager.class, this); - // --------------------------------- 注册 DataSource、CacheSource --------------------------------- - resourceFactory.register(new DataSourceLoader()); - resourceFactory.register(new CacheSourceLoader()); - resourceFactory.register(new DataSqlMapperLoader()); - } - - /** - * 配置项变更时被调用 - * - * @param namespace 命名空间 - * @param events 变更项 - */ - @Override - public void onEnvironmentChanged(String namespace, List events) { - Set sourceRemovedKeys = new HashSet<>(); - Properties sourceChangedProps = new Properties(); - - for (ResourceEvent event : events) { - if (event.name().startsWith("redkale.datasource.") - || event.name().startsWith("redkale.datasource[") - || event.name().startsWith("redkale.cachesource.") - || event.name().startsWith("redkale.cachesource[")) { - if (event.name().endsWith(".name")) { - logger.log( - Level.WARNING, - "skip illegal key " + event.name() + " in source config " - + (namespace == null ? "" : namespace) + ", key cannot endsWith '.name'"); - } else { - if (!Objects.equals(event.newValue(), this.sourceProperties.getProperty(event.name()))) { - if (event.newValue() == null) { - if (this.sourceProperties.containsKey(event.name())) { - sourceRemovedKeys.add(event.name()); - } - } else { - sourceChangedProps.put(event.name(), event.newValue()); - } - } - } - } - } - // 数据源配置项的变更 - if (!sourceChangedProps.isEmpty() || !sourceRemovedKeys.isEmpty()) { - Set cacheSourceNames = new LinkedHashSet<>(); - Set dataSourceNames = new LinkedHashSet<>(); - List keys = new ArrayList<>(); - keys.addAll(sourceRemovedKeys); - keys.addAll((Set) sourceChangedProps.keySet()); - for (final String key : keys) { - if (key.startsWith("redkale.cachesource[")) { - cacheSourceNames.add(key.substring("redkale.cachesource[".length(), key.indexOf(']'))); - } else if (key.startsWith("redkale.cachesource.")) { - String subkey = key.substring("redkale.cachesource.".length()); - int pos = subkey.indexOf('.'); - if (pos < 1) { - cacheSourceNames.add(""); - } else { - cacheSourceNames.add(subkey.substring(0, pos)); - } - } else if (key.startsWith("redkale.datasource[")) { - dataSourceNames.add(key.substring("redkale.datasource[".length(), key.indexOf(']'))); - } else if (key.startsWith("redkale.datasource.")) { - String subkey = key.substring("redkale.datasource.".length()); - int pos = subkey.indexOf('.'); - if (pos < 1) { - dataSourceNames.add(""); - } else { - dataSourceNames.add(subkey.substring(0, pos)); - } - } - } - // 更新缓存 - onSourceChanged("cachesource", cacheSourceNames, cacheSources, sourceRemovedKeys, sourceChangedProps); - // 更新数据库 - onSourceChanged("datasource", dataSourceNames, dataSources, sourceRemovedKeys, sourceChangedProps); - // 更新到内存配置 - sourceRemovedKeys.forEach(this.sourceProperties::remove); - this.sourceProperties.putAll(sourceChangedProps); - } - } - - private void onSourceChanged( - String sourceType, - Set sourceNames, - List sources, - Set sourceRemovedKeys, - Properties sourceChangedProps) { - for (String sourceName : sourceNames) { - Object source = Utility.find(sources, s -> Objects.equals(s.resourceName(), sourceName)); - if (source == null) { - continue; // 多余的数据源 - } - AnyValueWriter old = (AnyValueWriter) findSourceConfig(sourceName, sourceType); - Properties newProps = new Properties(); - this.sourceProperties.forEach((k, v) -> { - final String key = k.toString(); - String prefix = "redkale." + sourceType + "[" + sourceName + "]."; - int pos = key.indexOf(prefix); - if (pos < 0) { - prefix = "redkale." + sourceType + "." + sourceName + "."; - pos = key.indexOf(prefix); - } - if (pos < 0 && sourceName.isEmpty() && key.startsWith("redkale." + sourceType + ".")) { - String subKey = key.substring(("redkale." + sourceType + ".").length()); - if (subKey.indexOf('.') < 0) { - pos = 0; - } - } - if (pos < 0) { - return; // 不是同一name数据源配置项 - } - newProps.put(k, v); - }); - List changeEvents = new ArrayList<>(); - sourceChangedProps.forEach((k, v) -> { - final String key = k.toString(); - String prefix = "redkale." + sourceType + "[" + sourceName + "]."; - int pos = key.indexOf(prefix); - if (pos < 0) { - prefix = "redkale." + sourceType + "." + sourceName + "."; - pos = key.indexOf(prefix); - } - if (pos < 0 && sourceName.isEmpty() && key.startsWith("redkale." + sourceType + ".")) { - String subKey = key.substring(("redkale." + sourceType + ".").length()); - if (subKey.indexOf('.') < 0) { - pos = 0; - } - } - if (pos < 0) { - return; // 不是同一name数据源配置项 - } - newProps.put(k, v); - changeEvents.add(ResourceEvent.create( - key.substring(prefix.length()), v, this.sourceProperties.getProperty(key))); - }); - sourceRemovedKeys.forEach(k -> { - final String key = k; - String prefix = "redkale." + sourceType + "[" + sourceName + "]."; - int pos = key.indexOf(prefix); - if (pos < 0) { - prefix = "redkale." + sourceType + "." + sourceName + "."; - pos = key.indexOf(prefix); - } - if (pos < 0 && sourceName.isEmpty() && key.startsWith("redkale." + sourceType + ".")) { - String subKey = key.substring(("redkale." + sourceType + ".").length()); - if (subKey.indexOf('.') < 0) { - pos = 0; - } - } - if (pos < 0) { - return; - } - newProps.remove(k); // 不是同一name数据源配置项 - changeEvents.add(ResourceEvent.create( - key.substring(prefix.length()), null, this.sourceProperties.getProperty(key))); - }); - if (!changeEvents.isEmpty()) { - AnyValueWriter back = old == null ? null : old.copy(); - try { - if (old != null) { - AnyValue parent = AnyValue.loadFromProperties(newProps) - .getAnyValue("redkale") - .getAnyValue(sourceType); - AnyValue sub = parent.getAnyValue(sourceName); - if (sub == null && sourceName.isEmpty()) { - ((AnyValueWriter) parent).clearAnyEntrys(); - sub = parent; - } - old.replace(sub); - } - if (source instanceof AbstractDataSource) { - ((AbstractDataSource) source) - .onResourceChange(changeEvents.toArray(new ResourceEvent[changeEvents.size()])); - } else if (source instanceof AbstractCacheSource) { - ((AbstractCacheSource) source) - .onResourceChange(changeEvents.toArray(new ResourceEvent[changeEvents.size()])); - } - } catch (RuntimeException e) { - if (old != null) { - old.replace(back); // 还原配置 - } - throw e; - } - } - } - } - - /** 服务全部停掉后被调用 */ - @Override - public void onServersPostStop() { - for (DataSource source : dataSources) { - if (source == null) { - continue; - } - try { - if (source instanceof Service) { - long s = System.currentTimeMillis(); - ((Service) source) - .destroy(Sncp.isSncpDyn((Service) source) ? Sncp.getResourceConf((Service) source) : null); - logger.info(source + " destroy in " + (System.currentTimeMillis() - s) + " ms"); - } - } catch (Exception e) { - logger.log(Level.FINER, source.getClass() + " close DataSource erroneous", e); - } - } - for (CacheSource source : cacheSources) { - if (source == null) { - continue; - } - try { - if (source instanceof Service) { - long s = System.currentTimeMillis(); - ((Service) source) - .destroy(Sncp.isSncpDyn((Service) source) ? Sncp.getResourceConf((Service) source) : null); - logger.info(source + " destroy in " + (System.currentTimeMillis() - s) + " ms"); - } - } catch (Exception e) { - logger.log(Level.FINER, source.getClass() + " close CacheSource erroneous", e); - } - } - } - - /** - * 获取所有CacheSource, 不同资源名可能指向同一个CacheSource - * - * @return CacheSource集合 - */ - @Override - public Map getCacheSources() { - Map sources = new HashMap<>(); - cacheSources.forEach(v -> sources.put(v.resourceName(), v)); - return sources; - } - - @Override - public CacheSource loadCacheSource(final String sourceName, boolean autoMemory) { - cacheSourceLock.lock(); - try { - long st = System.currentTimeMillis(); - CacheSource old = resourceFactory.find(sourceName, CacheSource.class); - if (old != null) { - return old; - } - final AnyValue sourceConf = findSourceConfig(sourceName, "cachesource"); - if (sourceConf == null) { - if (!autoMemory) { - return null; - } - CacheSource source = new CacheMemorySource(sourceName); - cacheSources.add(source); - resourceFactory.register(sourceName, CacheSource.class, source); - if (!application.isCompileMode() && source instanceof Service) { - ((Service) source).init(sourceConf); - } - logger.info("Load CacheSource resourceName = '" + sourceName + "', source = " + source + " in " - + (System.currentTimeMillis() - st) + " ms"); - return source; - } - if (!sourceConf - .getValue(AbstractCacheSource.CACHE_SOURCE_RESOURCE, "") - .isEmpty()) { - CacheSource source = - loadCacheSource(sourceConf.getValue(AbstractCacheSource.CACHE_SOURCE_RESOURCE), autoMemory); - if (source != null) { - resourceFactory.register(sourceName, CacheSource.class, source); - } - return source; - } - try { - CacheSource source = AbstractCacheSource.createCacheSource( - application.getServerClassLoader(), - resourceFactory, - sourceConf, - sourceName, - application.isCompileMode()); - - cacheSources.add(source); - resourceFactory.register(sourceName, CacheSource.class, source); - logger.info("Load CacheSource resourceName = '" + sourceName + "', source = " + source + " in " - + (System.currentTimeMillis() - st) + " ms"); - return source; - } catch (RuntimeException ex) { - throw ex; - } catch (Exception e) { - logger.log(Level.SEVERE, "load application CaheSource error: " + sourceConf, e); - } - return null; - } finally { - cacheSourceLock.unlock(); - } - } - - /** - * 获取所有DataSource, 不同资源名可能指向同一个DataSource - * - * @return DataSource集合 - */ - @Override - public Map getDataSources() { - Map sources = new HashMap<>(); - dataSources.forEach(v -> sources.put(v.resourceName(), v)); - return sources; - } - - @Override - public DataSource loadDataSource(final String sourceName, boolean autoMemory) { - dataSourceLock.lock(); - try { - long st = System.currentTimeMillis(); - DataSource old = resourceFactory.find(sourceName, DataSource.class); - if (old != null) { - return old; - } - final AnyValue sourceConf = findSourceConfig(sourceName, "datasource"); - if (sourceConf == null) { - if (!autoMemory) { - return null; - } - DataSource source = new DataMemorySource(sourceName); - if (!application.isCompileMode() && source instanceof Service) { - resourceFactory.inject(sourceName, source); - ((Service) source).init(sourceConf); - } - dataSources.add(source); - resourceFactory.register(sourceName, DataSource.class, source); - logger.info("Load DataSource resourceName = '" + sourceName + "', source = " + source + " in " - + (System.currentTimeMillis() - st) + " ms"); - return source; - } - if (!sourceConf.getValue(DataSources.DATA_SOURCE_RESOURCE, "").isEmpty()) { - DataSource source = loadDataSource(sourceConf.getValue(DataSources.DATA_SOURCE_RESOURCE), autoMemory); - if (source != null) { - if (source instanceof DataMemorySource && source instanceof SearchSource) { - resourceFactory.register(sourceName, SearchSource.class, source); - } else { - resourceFactory.register(sourceName, DataSource.class, source); - if (source instanceof DataSqlSource) { - resourceFactory.register(sourceName, DataSqlSource.class, source); - } - if (source instanceof DataJdbcSource) { - resourceFactory.register(sourceName, DataJdbcSource.class, source); - } - } - } - return source; - } - try { - DataSource source = DataSources.createDataSource( - application.getServerClassLoader(), - resourceFactory, - sourceConf, - sourceName, - application.isCompileMode()); - - if (!application.isCompileMode() && source instanceof Service) { - resourceFactory.inject(sourceName, source); - ((Service) source).init(sourceConf); - } - dataSources.add(source); - if (source instanceof DataMemorySource && source instanceof SearchSource) { - resourceFactory.register(sourceName, SearchSource.class, source); - } else { - resourceFactory.register(sourceName, DataSource.class, source); - if (source instanceof DataSqlSource) { - resourceFactory.register(sourceName, DataSqlSource.class, source); - } - if (source instanceof DataJdbcSource) { - resourceFactory.register(sourceName, DataJdbcSource.class, source); - } - } - logger.info("Load DataSource resourceName = '" + sourceName + "', source = " + source + " in " - + (System.currentTimeMillis() - st) + " ms"); - return source; - } catch (RuntimeException ex) { - throw ex; - } catch (Exception e) { - logger.log(Level.SEVERE, "load application DataSource error: " + sourceConf, e); - } - return null; - } finally { - dataSourceLock.unlock(); - } - } - - private AnyValue findSourceConfig(String sourceName, String sourceType) { - Properties props = new Properties(); - String bprefix = "redkale." + sourceType; - String prefix1 = bprefix + "." + sourceName + "."; - String prefix2 = bprefix + "[" + sourceName + "]."; - this.sourceProperties.forEach((k, v) -> { - String key = k.toString(); - if (key.startsWith(prefix1)) { - props.put(key.substring(prefix1.length()), v); - } else if (key.startsWith(prefix2)) { - props.put(key.substring(prefix2.length()), v); - } - }); - if (props.isEmpty()) { - if (sourceName.isEmpty()) { - AnyValueWriter allConf = (AnyValueWriter) AnyValueWriter.loadFromProperties(props); - if (allConf.getStringEntrys() != null && allConf.getStringEntrys().length > 0) { - allConf.clearAnyEntrys(); - return allConf; - } - } - return null; - } - AnyValue conf = AnyValueWriter.loadFromProperties(props); - ((AnyValueWriter) conf).setValue("name", sourceName); - return conf; - } - - private class DataSqlMapperLoader implements ResourceTypeLoader { - - @Override - public Object load( - ResourceFactory rf, - String srcResourceName, - Object srcObj, - String resourceName, - Field field, - Object attachment) { - try { - if ((srcObj instanceof Service) && Sncp.isRemote((Service) srcObj)) { - return null; // 远程模式不得注入 - } - Class mapperType = (Class) field.getType(); - DataSqlMapper old = resourceFactory.find(resourceName, mapperType); - if (old != null) { - return old; - } - DataSource source = loadDataSource(resourceName, false); - DataSqlMapper mapper = - DataSqlMapperBuilder.createMapper(nativeSqlParser, (DataSqlSource) source, mapperType); - resourceFactory.register(resourceName, mapperType, mapper); - field.set(srcObj, mapper); - return mapper; - } catch (Exception e) { - logger.log(Level.SEVERE, DataSqlMapper.class.getSimpleName() + " inject to " + srcObj + " error", e); - throw e instanceof RuntimeException ? (RuntimeException) e : new RedkaleException(e); - } - } - - @Override - public Type resourceType() { - return DataSqlMapper.class; - } - } - - private class DataSourceLoader implements ResourceTypeLoader { - - @Override - public Object load( - ResourceFactory rf, - String srcResourceName, - Object srcObj, - String resourceName, - Field field, - Object attachment) { - try { - if ((srcObj instanceof Service) && Sncp.isRemote((Service) srcObj)) { - return null; // 远程模式不得注入 - } - DataSource source = loadDataSource(resourceName, false); - field.set(srcObj, source); - return source; - } catch (Exception e) { - logger.log(Level.SEVERE, "DataSource inject to " + srcObj + " error", e); - throw e instanceof RuntimeException ? (RuntimeException) e : new RedkaleException(e); - } - } - - @Override - public Type resourceType() { - return DataSource.class; - } - } - - private class CacheSourceLoader implements ResourceTypeLoader { - - @Override - public Object load( - ResourceFactory rf, - String srcResourceName, - Object srcObj, - String resourceName, - Field field, - Object attachment) { - try { - if ((srcObj instanceof Service) && Sncp.isRemote((Service) srcObj)) { - return null; // 远程模式不得注入 - } - if (srcObj instanceof Servlet) { - throw new RedkaleException("CacheSource cannot inject in Servlet " + srcObj); - } - final boolean ws = (srcObj instanceof org.redkale.net.http.WebSocketNodeService); - CacheSource source = loadCacheSource(resourceName, ws); - field.set(srcObj, source); - Resource res = field.getAnnotation(Resource.class); - if (res != null && res.required() && source == null) { - throw new RedkaleException("CacheSource (resourceName = '" + resourceName + "') not found"); - } else { - logger.info("Load CacheSource (type = " - + (source == null ? null : source.getClass().getSimpleName()) + ", resourceName = '" - + resourceName + "')"); - } - return source; - } catch (Exception e) { - logger.log(Level.SEVERE, "DataSource inject error", e); - throw e instanceof RuntimeException ? (RuntimeException) e : new RedkaleException(e); - } - } - - @Override - public Type resourceType() { - return CacheSource.class; - } - - @Override - public boolean autoNone() { - return false; - } - } -} +/* + * + */ +package org.redkale.source.spi; + +import java.lang.reflect.Field; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Properties; +import java.util.ServiceLoader; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.locks.ReentrantLock; +import java.util.logging.Level; +import org.redkale.annotation.Resource; +import org.redkale.boot.Application; +import org.redkale.boot.ModuleEngine; +import org.redkale.inject.Resourcable; +import org.redkale.inject.ResourceEvent; +import org.redkale.inject.ResourceFactory; +import org.redkale.inject.ResourceTypeLoader; +import org.redkale.net.Servlet; +import org.redkale.net.sncp.Sncp; +import org.redkale.service.Service; +import org.redkale.source.AbstractCacheSource; +import org.redkale.source.AbstractDataSource; +import org.redkale.source.CacheMemorySource; +import org.redkale.source.CacheSource; +import org.redkale.source.DataJdbcSource; +import org.redkale.source.DataMemorySource; +import org.redkale.source.DataNativeSqlParser; +import org.redkale.source.DataSource; +import org.redkale.source.DataSources; +import org.redkale.source.DataSqlMapper; +import org.redkale.source.DataSqlSource; +import org.redkale.source.SearchSource; +import org.redkale.source.SourceManager; +import org.redkale.util.AnyValue; +import org.redkale.util.AnyValueWriter; +import org.redkale.util.InstanceProvider; +import org.redkale.util.RedkaleClassLoader; +import org.redkale.util.RedkaleException; +import org.redkale.util.Utility; + +/** @author zhangjx */ +public class SourceModuleEngine extends ModuleEngine implements SourceManager { + + // Source 原始的配置资源, 只会存在redkale.datasource(.|[) redkale.cachesource(.|[)开头的配置项 + private final Properties sourceProperties = new Properties(); + + // CacheSource 资源 + private final List cacheSources = new CopyOnWriteArrayList<>(); + + private final ReentrantLock cacheSourceLock = new ReentrantLock(); + + // DataSource 资源 + private final List dataSources = new CopyOnWriteArrayList<>(); + + private final ReentrantLock dataSourceLock = new ReentrantLock(); + + // 原生sql解析器 + DataNativeSqlParser nativeSqlParser; + + public SourceModuleEngine(Application application) { + super(application); + } + + /** + * 判断模块的配置项合并策略, 返回null表示模块不识别此配置项 + * + * @param path 配置项路径 + * @param key 配置项名称 + * @param val1 配置项原值 + * @param val2 配置项新值 + * @return MergeEnum + */ + @Override + public AnyValue.MergeEnum mergeAppConfigStrategy(String path, String key, AnyValue val1, AnyValue val2) { + if ("cachesource".equals(path)) { + return AnyValue.MergeEnum.REPLACE; + } + if ("datasource".equals(path)) { + return AnyValue.MergeEnum.REPLACE; + } + return null; + } + + /** 配置项加载后被调用 */ + @Override + public void onEnvironmentLoaded(Properties allProps) { + allProps.forEach((key, val) -> { + if (key.toString().startsWith("redkale.datasource.") + || key.toString().startsWith("redkale.datasource[") + || key.toString().startsWith("redkale.cachesource.") + || key.toString().startsWith("redkale.cachesource[")) { + if (key.toString().endsWith(".name")) { + logger.log( + Level.WARNING, + "skip illegal key " + key + " in source config, key cannot endsWith '.name'"); + } else { + this.sourceProperties.put(key, val); + } + } + }); + } + + /** 结束Application.init方法前被调用 */ + @Override + public void onAppPostInit() { + // 加载原生sql解析器 + Iterator it = ServiceLoader.load( + DataNativeSqlParserProvider.class, application.getClassLoader()) + .iterator(); + RedkaleClassLoader.putServiceLoader(DataNativeSqlParserProvider.class); + List providers = new ArrayList<>(); + while (it.hasNext()) { + DataNativeSqlParserProvider provider = it.next(); + if (provider != null && provider.acceptsConf(null)) { + RedkaleClassLoader.putReflectionPublicConstructors( + provider.getClass(), provider.getClass().getName()); + providers.add(provider); + } + } + for (DataNativeSqlParserProvider provider : InstanceProvider.sort(providers)) { + this.nativeSqlParser = provider.createInstance(); + this.resourceFactory.register(DataNativeSqlParser.class, this.nativeSqlParser); + break; // only first provider + } + resourceFactory.register(SourceManager.class, this); + // --------------------------------- 注册 DataSource、CacheSource --------------------------------- + resourceFactory.register(new DataSourceLoader()); + resourceFactory.register(new CacheSourceLoader()); + resourceFactory.register(new DataSqlMapperLoader()); + } + + /** + * 配置项变更时被调用 + * + * @param namespace 命名空间 + * @param events 变更项 + */ + @Override + public void onEnvironmentChanged(String namespace, List events) { + Set sourceRemovedKeys = new HashSet<>(); + Properties sourceChangedProps = new Properties(); + + for (ResourceEvent event : events) { + if (event.name().startsWith("redkale.datasource.") + || event.name().startsWith("redkale.datasource[") + || event.name().startsWith("redkale.cachesource.") + || event.name().startsWith("redkale.cachesource[")) { + if (event.name().endsWith(".name")) { + logger.log( + Level.WARNING, + "skip illegal key " + event.name() + " in source config " + + (namespace == null ? "" : namespace) + ", key cannot endsWith '.name'"); + } else { + if (!Objects.equals(event.newValue(), this.sourceProperties.getProperty(event.name()))) { + if (event.newValue() == null) { + if (this.sourceProperties.containsKey(event.name())) { + sourceRemovedKeys.add(event.name()); + } + } else { + sourceChangedProps.put(event.name(), event.newValue()); + } + } + } + } + } + // 数据源配置项的变更 + if (!sourceChangedProps.isEmpty() || !sourceRemovedKeys.isEmpty()) { + Set cacheSourceNames = new LinkedHashSet<>(); + Set dataSourceNames = new LinkedHashSet<>(); + List keys = new ArrayList<>(); + keys.addAll(sourceRemovedKeys); + keys.addAll((Set) sourceChangedProps.keySet()); + for (final String key : keys) { + if (key.startsWith("redkale.cachesource[")) { + cacheSourceNames.add(key.substring("redkale.cachesource[".length(), key.indexOf(']'))); + } else if (key.startsWith("redkale.cachesource.")) { + String subkey = key.substring("redkale.cachesource.".length()); + int pos = subkey.indexOf('.'); + if (pos < 1) { + cacheSourceNames.add(""); + } else { + cacheSourceNames.add(subkey.substring(0, pos)); + } + } else if (key.startsWith("redkale.datasource[")) { + dataSourceNames.add(key.substring("redkale.datasource[".length(), key.indexOf(']'))); + } else if (key.startsWith("redkale.datasource.")) { + String subkey = key.substring("redkale.datasource.".length()); + int pos = subkey.indexOf('.'); + if (pos < 1) { + dataSourceNames.add(""); + } else { + dataSourceNames.add(subkey.substring(0, pos)); + } + } + } + // 更新缓存 + onSourceChanged("cachesource", cacheSourceNames, cacheSources, sourceRemovedKeys, sourceChangedProps); + // 更新数据库 + onSourceChanged("datasource", dataSourceNames, dataSources, sourceRemovedKeys, sourceChangedProps); + // 更新到内存配置 + sourceRemovedKeys.forEach(this.sourceProperties::remove); + this.sourceProperties.putAll(sourceChangedProps); + } + } + + private void onSourceChanged( + String sourceType, + Set sourceNames, + List sources, + Set sourceRemovedKeys, + Properties sourceChangedProps) { + for (String sourceName : sourceNames) { + Object source = Utility.find(sources, s -> Objects.equals(s.resourceName(), sourceName)); + if (source == null) { + continue; // 多余的数据源 + } + AnyValueWriter old = (AnyValueWriter) findSourceConfig(sourceName, sourceType); + Properties newProps = new Properties(); + this.sourceProperties.forEach((k, v) -> { + final String key = k.toString(); + String prefix = "redkale." + sourceType + "[" + sourceName + "]."; + int pos = key.indexOf(prefix); + if (pos < 0) { + prefix = "redkale." + sourceType + "." + sourceName + "."; + pos = key.indexOf(prefix); + } + if (pos < 0 && sourceName.isEmpty() && key.startsWith("redkale." + sourceType + ".")) { + String subKey = key.substring(("redkale." + sourceType + ".").length()); + if (subKey.indexOf('.') < 0) { + pos = 0; + } + } + if (pos < 0) { + return; // 不是同一name数据源配置项 + } + newProps.put(k, v); + }); + List changeEvents = new ArrayList<>(); + sourceChangedProps.forEach((k, v) -> { + final String key = k.toString(); + String prefix = "redkale." + sourceType + "[" + sourceName + "]."; + int pos = key.indexOf(prefix); + if (pos < 0) { + prefix = "redkale." + sourceType + "." + sourceName + "."; + pos = key.indexOf(prefix); + } + if (pos < 0 && sourceName.isEmpty() && key.startsWith("redkale." + sourceType + ".")) { + String subKey = key.substring(("redkale." + sourceType + ".").length()); + if (subKey.indexOf('.') < 0) { + pos = 0; + } + } + if (pos < 0) { + return; // 不是同一name数据源配置项 + } + newProps.put(k, v); + changeEvents.add(ResourceEvent.create( + key.substring(prefix.length()), v, this.sourceProperties.getProperty(key))); + }); + sourceRemovedKeys.forEach(k -> { + final String key = k; + String prefix = "redkale." + sourceType + "[" + sourceName + "]."; + int pos = key.indexOf(prefix); + if (pos < 0) { + prefix = "redkale." + sourceType + "." + sourceName + "."; + pos = key.indexOf(prefix); + } + if (pos < 0 && sourceName.isEmpty() && key.startsWith("redkale." + sourceType + ".")) { + String subKey = key.substring(("redkale." + sourceType + ".").length()); + if (subKey.indexOf('.') < 0) { + pos = 0; + } + } + if (pos < 0) { + return; + } + newProps.remove(k); // 不是同一name数据源配置项 + changeEvents.add(ResourceEvent.create( + key.substring(prefix.length()), null, this.sourceProperties.getProperty(key))); + }); + if (!changeEvents.isEmpty()) { + AnyValueWriter back = old == null ? null : old.copy(); + try { + if (old != null) { + AnyValue parent = AnyValue.loadFromProperties(newProps) + .getAnyValue("redkale") + .getAnyValue(sourceType); + AnyValue sub = parent.getAnyValue(sourceName); + if (sub == null && sourceName.isEmpty()) { + ((AnyValueWriter) parent).clearAnyEntrys(); + sub = parent; + } + old.replace(sub); + } + if (source instanceof AbstractDataSource) { + ((AbstractDataSource) source) + .onResourceChange(changeEvents.toArray(new ResourceEvent[changeEvents.size()])); + } else if (source instanceof AbstractCacheSource) { + ((AbstractCacheSource) source) + .onResourceChange(changeEvents.toArray(new ResourceEvent[changeEvents.size()])); + } + } catch (RuntimeException e) { + if (old != null) { + old.replace(back); // 还原配置 + } + throw e; + } + } + } + } + + /** 服务全部停掉后被调用 */ + @Override + public void onServersPostStop() { + for (DataSource source : dataSources) { + if (source == null) { + continue; + } + try { + if (source instanceof Service) { + long s = System.currentTimeMillis(); + ((Service) source) + .destroy(Sncp.isSncpDyn((Service) source) ? Sncp.getResourceConf((Service) source) : null); + logger.info(source + " destroy in " + (System.currentTimeMillis() - s) + " ms"); + } + } catch (Exception e) { + logger.log(Level.FINER, source.getClass() + " close DataSource erroneous", e); + } + } + for (CacheSource source : cacheSources) { + if (source == null) { + continue; + } + try { + if (source instanceof Service) { + long s = System.currentTimeMillis(); + ((Service) source) + .destroy(Sncp.isSncpDyn((Service) source) ? Sncp.getResourceConf((Service) source) : null); + logger.info(source + " destroy in " + (System.currentTimeMillis() - s) + " ms"); + } + } catch (Exception e) { + logger.log(Level.FINER, source.getClass() + " close CacheSource erroneous", e); + } + } + } + + /** + * 获取所有CacheSource, 不同资源名可能指向同一个CacheSource + * + * @return CacheSource集合 + */ + @Override + public Map getCacheSources() { + Map sources = new HashMap<>(); + cacheSources.forEach(v -> sources.put(v.resourceName(), v)); + return sources; + } + + @Override + public CacheSource loadCacheSource(final String sourceName, boolean autoMemory) { + cacheSourceLock.lock(); + try { + long st = System.currentTimeMillis(); + CacheSource old = resourceFactory.find(sourceName, CacheSource.class); + if (old != null) { + return old; + } + final AnyValue sourceConf = findSourceConfig(sourceName, "cachesource"); + if (sourceConf == null) { + if (!autoMemory) { + return null; + } + CacheSource source = new CacheMemorySource(sourceName); + cacheSources.add(source); + resourceFactory.register(sourceName, CacheSource.class, source); + if (!application.isCompileMode() && source instanceof Service) { + ((Service) source).init(sourceConf); + } + logger.info("Load CacheSource resourceName = '" + sourceName + "', source = " + source + " in " + + (System.currentTimeMillis() - st) + " ms"); + return source; + } + if (!sourceConf + .getValue(AbstractCacheSource.CACHE_SOURCE_RESOURCE, "") + .isEmpty()) { + CacheSource source = + loadCacheSource(sourceConf.getValue(AbstractCacheSource.CACHE_SOURCE_RESOURCE), autoMemory); + if (source != null) { + resourceFactory.register(sourceName, CacheSource.class, source); + } + return source; + } + try { + CacheSource source = AbstractCacheSource.createCacheSource( + application.getServerClassLoader(), + resourceFactory, + sourceConf, + sourceName, + application.isCompileMode()); + + cacheSources.add(source); + resourceFactory.register(sourceName, CacheSource.class, source); + logger.info("Load CacheSource resourceName = '" + sourceName + "', source = " + source + " in " + + (System.currentTimeMillis() - st) + " ms"); + return source; + } catch (RuntimeException ex) { + throw ex; + } catch (Exception e) { + logger.log(Level.SEVERE, "load application CaheSource error: " + sourceConf, e); + } + return null; + } finally { + cacheSourceLock.unlock(); + } + } + + /** + * 获取所有DataSource, 不同资源名可能指向同一个DataSource + * + * @return DataSource集合 + */ + @Override + public Map getDataSources() { + Map sources = new HashMap<>(); + dataSources.forEach(v -> sources.put(v.resourceName(), v)); + return sources; + } + + @Override + public DataSource loadDataSource(final String sourceName, boolean autoMemory) { + dataSourceLock.lock(); + try { + long st = System.currentTimeMillis(); + DataSource old = resourceFactory.find(sourceName, DataSource.class); + if (old != null) { + return old; + } + final AnyValue sourceConf = findSourceConfig(sourceName, "datasource"); + if (sourceConf == null) { + if (!autoMemory) { + return null; + } + DataSource source = new DataMemorySource(sourceName); + if (!application.isCompileMode() && source instanceof Service) { + resourceFactory.inject(sourceName, source); + ((Service) source).init(sourceConf); + } + dataSources.add(source); + resourceFactory.register(sourceName, DataSource.class, source); + logger.info("Load DataSource resourceName = '" + sourceName + "', source = " + source + " in " + + (System.currentTimeMillis() - st) + " ms"); + return source; + } + if (!sourceConf.getValue(DataSources.DATA_SOURCE_RESOURCE, "").isEmpty()) { + DataSource source = loadDataSource(sourceConf.getValue(DataSources.DATA_SOURCE_RESOURCE), autoMemory); + if (source != null) { + if (source instanceof DataMemorySource && source instanceof SearchSource) { + resourceFactory.register(sourceName, SearchSource.class, source); + } else { + resourceFactory.register(sourceName, DataSource.class, source); + if (source instanceof DataSqlSource) { + resourceFactory.register(sourceName, DataSqlSource.class, source); + } + if (source instanceof DataJdbcSource) { + resourceFactory.register(sourceName, DataJdbcSource.class, source); + } + } + } + return source; + } + try { + DataSource source = DataSources.createDataSource( + application.getServerClassLoader(), + resourceFactory, + sourceConf, + sourceName, + application.isCompileMode()); + + if (!application.isCompileMode() && source instanceof Service) { + resourceFactory.inject(sourceName, source); + ((Service) source).init(sourceConf); + } + dataSources.add(source); + if (source instanceof DataMemorySource && source instanceof SearchSource) { + resourceFactory.register(sourceName, SearchSource.class, source); + } else { + resourceFactory.register(sourceName, DataSource.class, source); + if (source instanceof DataSqlSource) { + resourceFactory.register(sourceName, DataSqlSource.class, source); + } + if (source instanceof DataJdbcSource) { + resourceFactory.register(sourceName, DataJdbcSource.class, source); + } + } + logger.info("Load DataSource resourceName = '" + sourceName + "', source = " + source + " in " + + (System.currentTimeMillis() - st) + " ms"); + return source; + } catch (RuntimeException ex) { + throw ex; + } catch (Exception e) { + logger.log(Level.SEVERE, "load application DataSource error: " + sourceConf, e); + } + return null; + } finally { + dataSourceLock.unlock(); + } + } + + private AnyValue findSourceConfig(String sourceName, String sourceType) { + Properties props = new Properties(); + String bprefix = "redkale." + sourceType; + String prefix1 = bprefix + "." + sourceName + "."; + String prefix2 = bprefix + "[" + sourceName + "]."; + this.sourceProperties.forEach((k, v) -> { + String key = k.toString(); + if (key.startsWith(prefix1)) { + props.put(key.substring(prefix1.length()), v); + } else if (key.startsWith(prefix2)) { + props.put(key.substring(prefix2.length()), v); + } + }); + if (props.isEmpty()) { + if (sourceName.isEmpty()) { + AnyValueWriter allConf = (AnyValueWriter) AnyValueWriter.loadFromProperties(props); + if (allConf.getStringEntrys() != null && allConf.getStringEntrys().length > 0) { + allConf.clearAnyEntrys(); + return allConf; + } + } + return null; + } + AnyValue conf = AnyValueWriter.loadFromProperties(props); + ((AnyValueWriter) conf).setValue("name", sourceName); + return conf; + } + + private class DataSqlMapperLoader implements ResourceTypeLoader { + + @Override + public Object load( + ResourceFactory rf, + String srcResourceName, + Object srcObj, + String resourceName, + Field field, + Object attachment) { + try { + if ((srcObj instanceof Service) && Sncp.isRemote((Service) srcObj)) { + return null; // 远程模式不得注入 + } + Class mapperType = (Class) field.getType(); + DataSqlMapper old = resourceFactory.find(resourceName, mapperType); + if (old != null) { + return old; + } + DataSource source = loadDataSource(resourceName, false); + DataSqlMapper mapper = + DataSqlMapperBuilder.createMapper(nativeSqlParser, (DataSqlSource) source, mapperType); + resourceFactory.register(resourceName, mapperType, mapper); + field.set(srcObj, mapper); + return mapper; + } catch (Exception e) { + logger.log(Level.SEVERE, DataSqlMapper.class.getSimpleName() + " inject to " + srcObj + " error", e); + throw e instanceof RuntimeException ? (RuntimeException) e : new RedkaleException(e); + } + } + + @Override + public Type resourceType() { + return DataSqlMapper.class; + } + } + + private class DataSourceLoader implements ResourceTypeLoader { + + @Override + public Object load( + ResourceFactory rf, + String srcResourceName, + Object srcObj, + String resourceName, + Field field, + Object attachment) { + try { + if ((srcObj instanceof Service) && Sncp.isRemote((Service) srcObj)) { + return null; // 远程模式不得注入 + } + DataSource source = loadDataSource(resourceName, false); + field.set(srcObj, source); + return source; + } catch (Exception e) { + logger.log(Level.SEVERE, "DataSource inject to " + srcObj + " error", e); + throw e instanceof RuntimeException ? (RuntimeException) e : new RedkaleException(e); + } + } + + @Override + public Type resourceType() { + return DataSource.class; + } + } + + private class CacheSourceLoader implements ResourceTypeLoader { + + @Override + public Object load( + ResourceFactory rf, + String srcResourceName, + Object srcObj, + String resourceName, + Field field, + Object attachment) { + try { + if ((srcObj instanceof Service) && Sncp.isRemote((Service) srcObj)) { + return null; // 远程模式不得注入 + } + if (srcObj instanceof Servlet) { + throw new RedkaleException("CacheSource cannot inject in Servlet " + srcObj); + } + final boolean ws = (srcObj instanceof org.redkale.net.http.WebSocketNodeService); + CacheSource source = loadCacheSource(resourceName, ws); + field.set(srcObj, source); + Resource res = field.getAnnotation(Resource.class); + if (res != null && res.required() && source == null) { + throw new RedkaleException("CacheSource (resourceName = '" + resourceName + "') not found"); + } else { + logger.info("Load CacheSource (type = " + + (source == null ? null : source.getClass().getSimpleName()) + ", resourceName = '" + + resourceName + "')"); + } + return source; + } catch (Exception e) { + logger.log(Level.SEVERE, "DataSource inject error", e); + throw e instanceof RuntimeException ? (RuntimeException) e : new RedkaleException(e); + } + } + + @Override + public Type resourceType() { + return CacheSource.class; + } + + @Override + public boolean autoNone() { + return false; + } + } +} diff --git a/src/main/java/org/redkale/util/AnonymousThreadFactory.java b/src/main/java/org/redkale/util/AnonymousThreadFactory.java index 4798c0031..5645d0124 100644 --- a/src/main/java/org/redkale/util/AnonymousThreadFactory.java +++ b/src/main/java/org/redkale/util/AnonymousThreadFactory.java @@ -1,39 +1,39 @@ -/// * -// * -// */ -// package org.redkale.util; -// -// import java.util.concurrent.ThreadFactory; -// import java.util.function.Function; -// -/// ** -// * 虚拟线程工厂 -// * -// * @author zhangjx -// * @since 2.8.0 -// */ -// public class AnonymousThreadFactory implements ThreadFactory, Function { -// -// private final ThreadFactory factory = Thread.ofVirtual().factory(); -// -// private final String name; -// -// public AnonymousThreadFactory(String name) { -// this.name = name; -// } -// -// @Override -// public ThreadFactory apply(String name) { -// return new AnonymousThreadFactory(name); -// } -// -// @Override -// public Thread newThread(Runnable r) { -// Thread t = factory.newThread(r); -// if (name != null) { -// t.setName(name); -// } -// return t; -// } -// -// } +/// * +// * +// */ +// package org.redkale.util; +// +// import java.util.concurrent.ThreadFactory; +// import java.util.function.Function; +// +/// ** +// * 虚拟线程工厂 +// * +// * @author zhangjx +// * @since 2.8.0 +// */ +// public class AnonymousThreadFactory implements ThreadFactory, Function { +// +// private final ThreadFactory factory = Thread.ofVirtual().factory(); +// +// private final String name; +// +// public AnonymousThreadFactory(String name) { +// this.name = name; +// } +// +// @Override +// public ThreadFactory apply(String name) { +// return new AnonymousThreadFactory(name); +// } +// +// @Override +// public Thread newThread(Runnable r) { +// Thread t = factory.newThread(r); +// if (name != null) { +// t.setName(name); +// } +// return t; +// } +// +// } diff --git a/src/main/java/org/redkale/util/AnonymousThreadLocal.java b/src/main/java/org/redkale/util/AnonymousThreadLocal.java index aa29c16dd..4ba011e50 100644 --- a/src/main/java/org/redkale/util/AnonymousThreadLocal.java +++ b/src/main/java/org/redkale/util/AnonymousThreadLocal.java @@ -1,48 +1,48 @@ -/// * -// * -// */ -// package org.redkale.util; -// -// import java.util.function.Function; -// import java.util.function.Supplier; -// -/// ** -// * ThreadScopedLocal, 兼容虚拟线程的ThreadLocal -// * -// *

-// * 详情见: https://redkale.org -// * -// * @author zhangjx -// * @since 2.8.0 -// */ -// public class AnonymousThreadLocal extends ThreadLocal implements Function, ThreadLocal> { -// -// private final Supplier supplier; -// -// public AnonymousThreadLocal(Supplier supplier) { -// this.supplier = supplier; -// } -// -// public ThreadLocal apply(Supplier supplier) { -// return new AnonymousThreadLocal<>(supplier); -// } -// -// @Override -// protected T initialValue() { -// return supplier.get(); -// } -// -// @Override -// public void set(T value) { -// Thread t = Thread.currentThread(); -// if (!t.isVirtual()) { -// super.set(value); -// } -// } -// -// @Override -// public T get() { -// Thread t = Thread.currentThread(); -// return t.isVirtual() ? initialValue() : super.get(); -// } -// } +/// * +// * +// */ +// package org.redkale.util; +// +// import java.util.function.Function; +// import java.util.function.Supplier; +// +/// ** +// * ThreadScopedLocal, 兼容虚拟线程的ThreadLocal +// * +// *

+// * 详情见: https://redkale.org +// * +// * @author zhangjx +// * @since 2.8.0 +// */ +// public class AnonymousThreadLocal extends ThreadLocal implements Function, ThreadLocal> { +// +// private final Supplier supplier; +// +// public AnonymousThreadLocal(Supplier supplier) { +// this.supplier = supplier; +// } +// +// public ThreadLocal apply(Supplier supplier) { +// return new AnonymousThreadLocal<>(supplier); +// } +// +// @Override +// protected T initialValue() { +// return supplier.get(); +// } +// +// @Override +// public void set(T value) { +// Thread t = Thread.currentThread(); +// if (!t.isVirtual()) { +// super.set(value); +// } +// } +// +// @Override +// public T get() { +// Thread t = Thread.currentThread(); +// return t.isVirtual() ? initialValue() : super.get(); +// } +// } diff --git a/src/main/java/org/redkale/util/AnonymousUnsafe.java b/src/main/java/org/redkale/util/AnonymousUnsafe.java index 0d7c8549a..5001b91f4 100644 --- a/src/main/java/org/redkale/util/AnonymousUnsafe.java +++ b/src/main/java/org/redkale/util/AnonymousUnsafe.java @@ -1,443 +1,443 @@ -// package org.redkale.util; -// -// import java.lang.reflect.Field; -// import java.nio.ByteBuffer; -// -// public class AnonymousUnsafe implements Unsafe { -// -// private final sun.misc.Unsafe unsafe; -// -// public AnonymousUnsafe(Object obj) { -// this.unsafe = (sun.misc.Unsafe) obj; -// } -// -// @Override -// public int getInt(Object o, long offset) { -// return unsafe.getInt(o, offset); -// } -// -// @Override -// public void putInt(Object o, long offset, int x) { -// unsafe.putInt(o, offset, x); -// } -// -// @Override -// public Object getObject(Object o, long offset) { -// return unsafe.getObject(o, offset); -// } -// -// @Override -// public void putObject(Object o, long offset, Object x) { -// unsafe.putObject(o, offset, x); -// } -// -// @Override -// public boolean getBoolean(Object o, long offset) { -// return unsafe.getBoolean(o, offset); -// } -// -// @Override -// public void putBoolean(Object o, long offset, boolean x) { -// unsafe.putBoolean(o, offset, x); -// } -// -// @Override -// public byte getByte(Object o, long offset) { -// return unsafe.getByte(o, offset); -// } -// -// @Override -// public void putByte(Object o, long offset, byte x) { -// unsafe.putByte(o, offset, x); -// } -// -// @Override -// public short getShort(Object o, long offset) { -// return unsafe.getShort(o, offset); -// } -// -// @Override -// public void putShort(Object o, long offset, short x) { -// unsafe.putShort(o, offset, x); -// } -// -// @Override -// public char getChar(Object o, long offset) { -// return unsafe.getChar(o, offset); -// } -// -// @Override -// public void putChar(Object o, long offset, char x) { -// unsafe.putChar(o, offset, x); -// } -// -// @Override -// public long getLong(Object o, long offset) { -// return unsafe.getLong(o, offset); -// } -// -// @Override -// public void putLong(Object o, long offset, long x) { -// unsafe.putLong(o, offset, x); -// } -// -// @Override -// public float getFloat(Object o, long offset) { -// return unsafe.getFloat(o, offset); -// } -// -// @Override -// public void putFloat(Object o, long offset, float x) { -// unsafe.putFloat(o, offset, x); -// } -// -// @Override -// public double getDouble(Object o, long offset) { -// return unsafe.getDouble(o, offset); -// } -// -// @Override -// public void putDouble(Object o, long offset, double x) { -// unsafe.putDouble(o, offset, x); -// } -// -// @Override -// public byte getByte(long address) { -// return unsafe.getByte(address); -// } -// -// @Override -// public void putByte(long address, byte x) { -// unsafe.putByte(address, x); -// } -// -// @Override -// public short getShort(long address) { -// return unsafe.getShort(address); -// } -// -// @Override -// public void putShort(long address, short x) { -// unsafe.putShort(address, x); -// } -// -// @Override -// public char getChar(long address) { -// return unsafe.getChar(address); -// } -// -// @Override -// public void putChar(long address, char x) { -// unsafe.putChar(address, x); -// } -// -// @Override -// public int getInt(long address) { -// return unsafe.getInt(address); -// } -// -// @Override -// public void putInt(long address, int x) { -// unsafe.putInt(address, x); -// } -// -// @Override -// public long getLong(long address) { -// return unsafe.getLong(address); -// } -// -// @Override -// public void putLong(long address, long x) { -// unsafe.putLong(address, x); -// } -// -// @Override -// public float getFloat(long address) { -// return unsafe.getFloat(address); -// } -// -// @Override -// public void putFloat(long address, float x) { -// unsafe.putFloat(address, x); -// } -// -// @Override -// public double getDouble(long address) { -// return unsafe.getDouble(address); -// } -// -// @Override -// public void putDouble(long address, double x) { -// unsafe.putDouble(address, x); -// } -// -// @Override -// public long getAddress(long address) { -// return unsafe.getAddress(address); -// } -// -// @Override -// public void putAddress(long address, long x) { -// unsafe.putAddress(address, x); -// } -// -// @Override -// public long allocateMemory(long bytes) { -// return unsafe.allocateMemory(bytes); -// } -// -// @Override -// public long reallocateMemory(long address, long bytes) { -// return unsafe.reallocateMemory(address, bytes); -// } -// -// @Override -// public void setMemory(Object o, long offset, long bytes, byte value) { -// unsafe.setMemory(o, offset, bytes, value); -// } -// -// @Override -// public void setMemory(long address, long bytes, byte value) { -// unsafe.setMemory(address, bytes, value); -// } -// -// @Override -// public void copyMemory(Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes) { -// unsafe.copyMemory(srcBase, srcOffset, destBase, destOffset, bytes); -// } -// -// @Override -// public void copyMemory(long srcAddress, long destAddress, long bytes) { -// unsafe.copyMemory(srcAddress, destAddress, bytes); -// } -// -// @Override -// public void freeMemory(long address) { -// unsafe.freeMemory(address); -// } -// -// @Override -// public long objectFieldOffset(Field f) { -// return unsafe.objectFieldOffset(f); -// } -// -// @Override -// public long staticFieldOffset(Field f) { -// return unsafe.staticFieldOffset(f); -// } -// -// @Override -// public Object staticFieldBase(Field f) { -// return unsafe.staticFieldBase(f); -// } -// -// @Override -// public int arrayBaseOffset(Class arrayClass) { -// return unsafe.arrayBaseOffset(arrayClass); -// } -// -// @Override -// public int arrayIndexScale(Class arrayClass) { -// return unsafe.arrayIndexScale(arrayClass); -// } -// -// @Override -// public int addressSize() { -// return unsafe.addressSize(); -// } -// -// @Override -// public int pageSize() { -// return unsafe.pageSize(); -// } -// -// @Override -// public Object allocateInstance(Class cls) throws InstantiationException { -// return unsafe.allocateInstance(cls); -// } -// -// @Override -// public void throwException(Throwable ee) { -// unsafe.throwException(ee); -// } -// -// @Override -// public boolean compareAndSwapObject(Object o, long offset, Object expected, Object x) { -// return unsafe.compareAndSwapObject(o, offset, expected, x); -// } -// -// @Override -// public boolean compareAndSwapInt(Object o, long offset, int expected, int x) { -// return unsafe.compareAndSwapInt(o, offset, expected, x); -// } -// -// @Override -// public boolean compareAndSwapLong(Object o, long offset, long expected, long x) { -// return unsafe.compareAndSwapLong(o, offset, expected, x); -// } -// -// @Override -// public Object getObjectVolatile(Object o, long offset) { -// return unsafe.getObjectVolatile(o, offset); -// } -// -// @Override -// public void putObjectVolatile(Object o, long offset, Object x) { -// unsafe.putObjectVolatile(o, offset, x); -// } -// -// @Override -// public int getIntVolatile(Object o, long offset) { -// return unsafe.getIntVolatile(o, offset); -// } -// -// @Override -// public void putIntVolatile(Object o, long offset, int x) { -// unsafe.putIntVolatile(o, offset, x); -// } -// -// @Override -// public boolean getBooleanVolatile(Object o, long offset) { -// return unsafe.getBooleanVolatile(o, offset); -// } -// -// @Override -// public void putBooleanVolatile(Object o, long offset, boolean x) { -// unsafe.putBooleanVolatile(o, offset, x); -// } -// -// @Override -// public byte getByteVolatile(Object o, long offset) { -// return unsafe.getByteVolatile(o, offset); -// } -// -// @Override -// public void putByteVolatile(Object o, long offset, byte x) { -// unsafe.putByteVolatile(o, offset, x); -// } -// -// @Override -// public short getShortVolatile(Object o, long offset) { -// return unsafe.getShortVolatile(o, offset); -// } -// -// @Override -// public void putShortVolatile(Object o, long offset, short x) { -// unsafe.putShortVolatile(o, offset, x); -// } -// -// @Override -// public char getCharVolatile(Object o, long offset) { -// return unsafe.getCharVolatile(o, offset); -// } -// -// @Override -// public void putCharVolatile(Object o, long offset, char x) { -// unsafe.putCharVolatile(o, offset, x); -// } -// -// @Override -// public long getLongVolatile(Object o, long offset) { -// return unsafe.getLongVolatile(o, offset); -// } -// -// @Override -// public void putLongVolatile(Object o, long offset, long x) { -// unsafe.putLongVolatile(o, offset, x); -// } -// -// @Override -// public float getFloatVolatile(Object o, long offset) { -// return unsafe.getFloatVolatile(o, offset); -// } -// -// @Override -// public void putFloatVolatile(Object o, long offset, float x) { -// unsafe.putFloatVolatile(o, offset, x); -// } -// -// @Override -// public double getDoubleVolatile(Object o, long offset) { -// return unsafe.getDoubleVolatile(o, offset); -// } -// -// @Override -// public void putDoubleVolatile(Object o, long offset, double x) { -// unsafe.putDoubleVolatile(o, offset, x); -// } -// -// @Override -// public void putOrderedObject(Object o, long offset, Object x) { -// unsafe.putOrderedObject(o, offset, x); -// } -// -// @Override -// public void putOrderedInt(Object o, long offset, int x) { -// unsafe.putOrderedInt(o, offset, x); -// } -// -// @Override -// public void putOrderedLong(Object o, long offset, long x) { -// unsafe.putOrderedLong(o, offset, x); -// } -// -// @Override -// public void unpark(Object thread) { -// unsafe.unpark(thread); -// } -// -// @Override -// public void park(boolean isAbsolute, long time) { -// unsafe.park(isAbsolute, time); -// } -// -// @Override -// public int getLoadAverage(double[] loadavg, int nelems) { -// return unsafe.getLoadAverage(loadavg, nelems); -// } -// -// @Override -// public int getAndAddInt(Object o, long offset, int delta) { -// return unsafe.getAndAddInt(o, offset, delta); -// } -// -// @Override -// public long getAndAddLong(Object o, long offset, long delta) { -// return unsafe.getAndAddLong(o, offset, delta); -// } -// -// @Override -// public int getAndSetInt(Object o, long offset, int newValue) { -// return unsafe.getAndSetInt(o, offset, newValue); -// } -// -// @Override -// public long getAndSetLong(Object o, long offset, long newValue) { -// return unsafe.getAndSetLong(o, offset, newValue); -// } -// -// @Override -// public Object getAndSetObject(Object o, long offset, Object newValue) { -// return unsafe.getAndSetObject(o, offset, newValue); -// } -// -// @Override -// public void loadFence() { -// unsafe.loadFence(); -// } -// -// @Override -// public void storeFence() { -// unsafe.storeFence(); -// } -// -// @Override -// public void fullFence() { -// unsafe.fullFence(); -// } -// -// @Override -// public void invokeCleaner(ByteBuffer directBuffer) { -// unsafe.invokeCleaner(directBuffer); -// } -// } +// package org.redkale.util; +// +// import java.lang.reflect.Field; +// import java.nio.ByteBuffer; +// +// public class AnonymousUnsafe implements Unsafe { +// +// private final sun.misc.Unsafe unsafe; +// +// public AnonymousUnsafe(Object obj) { +// this.unsafe = (sun.misc.Unsafe) obj; +// } +// +// @Override +// public int getInt(Object o, long offset) { +// return unsafe.getInt(o, offset); +// } +// +// @Override +// public void putInt(Object o, long offset, int x) { +// unsafe.putInt(o, offset, x); +// } +// +// @Override +// public Object getObject(Object o, long offset) { +// return unsafe.getObject(o, offset); +// } +// +// @Override +// public void putObject(Object o, long offset, Object x) { +// unsafe.putObject(o, offset, x); +// } +// +// @Override +// public boolean getBoolean(Object o, long offset) { +// return unsafe.getBoolean(o, offset); +// } +// +// @Override +// public void putBoolean(Object o, long offset, boolean x) { +// unsafe.putBoolean(o, offset, x); +// } +// +// @Override +// public byte getByte(Object o, long offset) { +// return unsafe.getByte(o, offset); +// } +// +// @Override +// public void putByte(Object o, long offset, byte x) { +// unsafe.putByte(o, offset, x); +// } +// +// @Override +// public short getShort(Object o, long offset) { +// return unsafe.getShort(o, offset); +// } +// +// @Override +// public void putShort(Object o, long offset, short x) { +// unsafe.putShort(o, offset, x); +// } +// +// @Override +// public char getChar(Object o, long offset) { +// return unsafe.getChar(o, offset); +// } +// +// @Override +// public void putChar(Object o, long offset, char x) { +// unsafe.putChar(o, offset, x); +// } +// +// @Override +// public long getLong(Object o, long offset) { +// return unsafe.getLong(o, offset); +// } +// +// @Override +// public void putLong(Object o, long offset, long x) { +// unsafe.putLong(o, offset, x); +// } +// +// @Override +// public float getFloat(Object o, long offset) { +// return unsafe.getFloat(o, offset); +// } +// +// @Override +// public void putFloat(Object o, long offset, float x) { +// unsafe.putFloat(o, offset, x); +// } +// +// @Override +// public double getDouble(Object o, long offset) { +// return unsafe.getDouble(o, offset); +// } +// +// @Override +// public void putDouble(Object o, long offset, double x) { +// unsafe.putDouble(o, offset, x); +// } +// +// @Override +// public byte getByte(long address) { +// return unsafe.getByte(address); +// } +// +// @Override +// public void putByte(long address, byte x) { +// unsafe.putByte(address, x); +// } +// +// @Override +// public short getShort(long address) { +// return unsafe.getShort(address); +// } +// +// @Override +// public void putShort(long address, short x) { +// unsafe.putShort(address, x); +// } +// +// @Override +// public char getChar(long address) { +// return unsafe.getChar(address); +// } +// +// @Override +// public void putChar(long address, char x) { +// unsafe.putChar(address, x); +// } +// +// @Override +// public int getInt(long address) { +// return unsafe.getInt(address); +// } +// +// @Override +// public void putInt(long address, int x) { +// unsafe.putInt(address, x); +// } +// +// @Override +// public long getLong(long address) { +// return unsafe.getLong(address); +// } +// +// @Override +// public void putLong(long address, long x) { +// unsafe.putLong(address, x); +// } +// +// @Override +// public float getFloat(long address) { +// return unsafe.getFloat(address); +// } +// +// @Override +// public void putFloat(long address, float x) { +// unsafe.putFloat(address, x); +// } +// +// @Override +// public double getDouble(long address) { +// return unsafe.getDouble(address); +// } +// +// @Override +// public void putDouble(long address, double x) { +// unsafe.putDouble(address, x); +// } +// +// @Override +// public long getAddress(long address) { +// return unsafe.getAddress(address); +// } +// +// @Override +// public void putAddress(long address, long x) { +// unsafe.putAddress(address, x); +// } +// +// @Override +// public long allocateMemory(long bytes) { +// return unsafe.allocateMemory(bytes); +// } +// +// @Override +// public long reallocateMemory(long address, long bytes) { +// return unsafe.reallocateMemory(address, bytes); +// } +// +// @Override +// public void setMemory(Object o, long offset, long bytes, byte value) { +// unsafe.setMemory(o, offset, bytes, value); +// } +// +// @Override +// public void setMemory(long address, long bytes, byte value) { +// unsafe.setMemory(address, bytes, value); +// } +// +// @Override +// public void copyMemory(Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes) { +// unsafe.copyMemory(srcBase, srcOffset, destBase, destOffset, bytes); +// } +// +// @Override +// public void copyMemory(long srcAddress, long destAddress, long bytes) { +// unsafe.copyMemory(srcAddress, destAddress, bytes); +// } +// +// @Override +// public void freeMemory(long address) { +// unsafe.freeMemory(address); +// } +// +// @Override +// public long objectFieldOffset(Field f) { +// return unsafe.objectFieldOffset(f); +// } +// +// @Override +// public long staticFieldOffset(Field f) { +// return unsafe.staticFieldOffset(f); +// } +// +// @Override +// public Object staticFieldBase(Field f) { +// return unsafe.staticFieldBase(f); +// } +// +// @Override +// public int arrayBaseOffset(Class arrayClass) { +// return unsafe.arrayBaseOffset(arrayClass); +// } +// +// @Override +// public int arrayIndexScale(Class arrayClass) { +// return unsafe.arrayIndexScale(arrayClass); +// } +// +// @Override +// public int addressSize() { +// return unsafe.addressSize(); +// } +// +// @Override +// public int pageSize() { +// return unsafe.pageSize(); +// } +// +// @Override +// public Object allocateInstance(Class cls) throws InstantiationException { +// return unsafe.allocateInstance(cls); +// } +// +// @Override +// public void throwException(Throwable ee) { +// unsafe.throwException(ee); +// } +// +// @Override +// public boolean compareAndSwapObject(Object o, long offset, Object expected, Object x) { +// return unsafe.compareAndSwapObject(o, offset, expected, x); +// } +// +// @Override +// public boolean compareAndSwapInt(Object o, long offset, int expected, int x) { +// return unsafe.compareAndSwapInt(o, offset, expected, x); +// } +// +// @Override +// public boolean compareAndSwapLong(Object o, long offset, long expected, long x) { +// return unsafe.compareAndSwapLong(o, offset, expected, x); +// } +// +// @Override +// public Object getObjectVolatile(Object o, long offset) { +// return unsafe.getObjectVolatile(o, offset); +// } +// +// @Override +// public void putObjectVolatile(Object o, long offset, Object x) { +// unsafe.putObjectVolatile(o, offset, x); +// } +// +// @Override +// public int getIntVolatile(Object o, long offset) { +// return unsafe.getIntVolatile(o, offset); +// } +// +// @Override +// public void putIntVolatile(Object o, long offset, int x) { +// unsafe.putIntVolatile(o, offset, x); +// } +// +// @Override +// public boolean getBooleanVolatile(Object o, long offset) { +// return unsafe.getBooleanVolatile(o, offset); +// } +// +// @Override +// public void putBooleanVolatile(Object o, long offset, boolean x) { +// unsafe.putBooleanVolatile(o, offset, x); +// } +// +// @Override +// public byte getByteVolatile(Object o, long offset) { +// return unsafe.getByteVolatile(o, offset); +// } +// +// @Override +// public void putByteVolatile(Object o, long offset, byte x) { +// unsafe.putByteVolatile(o, offset, x); +// } +// +// @Override +// public short getShortVolatile(Object o, long offset) { +// return unsafe.getShortVolatile(o, offset); +// } +// +// @Override +// public void putShortVolatile(Object o, long offset, short x) { +// unsafe.putShortVolatile(o, offset, x); +// } +// +// @Override +// public char getCharVolatile(Object o, long offset) { +// return unsafe.getCharVolatile(o, offset); +// } +// +// @Override +// public void putCharVolatile(Object o, long offset, char x) { +// unsafe.putCharVolatile(o, offset, x); +// } +// +// @Override +// public long getLongVolatile(Object o, long offset) { +// return unsafe.getLongVolatile(o, offset); +// } +// +// @Override +// public void putLongVolatile(Object o, long offset, long x) { +// unsafe.putLongVolatile(o, offset, x); +// } +// +// @Override +// public float getFloatVolatile(Object o, long offset) { +// return unsafe.getFloatVolatile(o, offset); +// } +// +// @Override +// public void putFloatVolatile(Object o, long offset, float x) { +// unsafe.putFloatVolatile(o, offset, x); +// } +// +// @Override +// public double getDoubleVolatile(Object o, long offset) { +// return unsafe.getDoubleVolatile(o, offset); +// } +// +// @Override +// public void putDoubleVolatile(Object o, long offset, double x) { +// unsafe.putDoubleVolatile(o, offset, x); +// } +// +// @Override +// public void putOrderedObject(Object o, long offset, Object x) { +// unsafe.putOrderedObject(o, offset, x); +// } +// +// @Override +// public void putOrderedInt(Object o, long offset, int x) { +// unsafe.putOrderedInt(o, offset, x); +// } +// +// @Override +// public void putOrderedLong(Object o, long offset, long x) { +// unsafe.putOrderedLong(o, offset, x); +// } +// +// @Override +// public void unpark(Object thread) { +// unsafe.unpark(thread); +// } +// +// @Override +// public void park(boolean isAbsolute, long time) { +// unsafe.park(isAbsolute, time); +// } +// +// @Override +// public int getLoadAverage(double[] loadavg, int nelems) { +// return unsafe.getLoadAverage(loadavg, nelems); +// } +// +// @Override +// public int getAndAddInt(Object o, long offset, int delta) { +// return unsafe.getAndAddInt(o, offset, delta); +// } +// +// @Override +// public long getAndAddLong(Object o, long offset, long delta) { +// return unsafe.getAndAddLong(o, offset, delta); +// } +// +// @Override +// public int getAndSetInt(Object o, long offset, int newValue) { +// return unsafe.getAndSetInt(o, offset, newValue); +// } +// +// @Override +// public long getAndSetLong(Object o, long offset, long newValue) { +// return unsafe.getAndSetLong(o, offset, newValue); +// } +// +// @Override +// public Object getAndSetObject(Object o, long offset, Object newValue) { +// return unsafe.getAndSetObject(o, offset, newValue); +// } +// +// @Override +// public void loadFence() { +// unsafe.loadFence(); +// } +// +// @Override +// public void storeFence() { +// unsafe.storeFence(); +// } +// +// @Override +// public void fullFence() { +// unsafe.fullFence(); +// } +// +// @Override +// public void invokeCleaner(ByteBuffer directBuffer) { +// unsafe.invokeCleaner(directBuffer); +// } +// } diff --git a/src/main/java/org/redkale/util/AnonymousVirtualExecutor.java b/src/main/java/org/redkale/util/AnonymousVirtualExecutor.java index a2f22149c..835e00306 100644 --- a/src/main/java/org/redkale/util/AnonymousVirtualExecutor.java +++ b/src/main/java/org/redkale/util/AnonymousVirtualExecutor.java @@ -1,21 +1,21 @@ -/// * -// * -// */ -// package org.redkale.util; -// -// import java.util.concurrent.Executor; -// -/// ** -// * 虚拟线程运行 -// * -// * @author zhangjx -// * @since 2.8.0 -// */ -// public class AnonymousVirtualExecutor implements Executor { -// -// @Override -// public void execute(Runnable t) { -// Thread.ofVirtual().name("Redkale-VirtualThread").start(t); -// } -// -// } +/// * +// * +// */ +// package org.redkale.util; +// +// import java.util.concurrent.Executor; +// +/// ** +// * 虚拟线程运行 +// * +// * @author zhangjx +// * @since 2.8.0 +// */ +// public class AnonymousVirtualExecutor implements Executor { +// +// @Override +// public void execute(Runnable t) { +// Thread.ofVirtual().name("Redkale-VirtualThread").start(t); +// } +// +// } diff --git a/src/main/java/org/redkale/util/AnonymousVirtualPoolFunction.java b/src/main/java/org/redkale/util/AnonymousVirtualPoolFunction.java index 85ead70d5..e5a762ce1 100644 --- a/src/main/java/org/redkale/util/AnonymousVirtualPoolFunction.java +++ b/src/main/java/org/redkale/util/AnonymousVirtualPoolFunction.java @@ -1,27 +1,27 @@ -/// * -// * -// */ -// package org.redkale.util; -// -// import java.util.concurrent.*; -// import java.util.function.Function; -// -/// ** -// * 虚拟线程池 -// * -// * @author zhangjx -// * @since 2.8.0 -// */ -// public class AnonymousVirtualPoolFunction implements Function { -// -// @Override -// public ExecutorService apply(String threadNameFormat) { -// final ThreadFactory factory = Thread.ofVirtual().factory(); -// final String threadName = String.format(threadNameFormat, "Virtual"); -// return Executors.newThreadPerTaskExecutor(r -> { -// Thread t = factory.newThread(r); -// t.setName(threadName); -// return t; -// }); -// } -// } +/// * +// * +// */ +// package org.redkale.util; +// +// import java.util.concurrent.*; +// import java.util.function.Function; +// +/// ** +// * 虚拟线程池 +// * +// * @author zhangjx +// * @since 2.8.0 +// */ +// public class AnonymousVirtualPoolFunction implements Function { +// +// @Override +// public ExecutorService apply(String threadNameFormat) { +// final ThreadFactory factory = Thread.ofVirtual().factory(); +// final String threadName = String.format(threadNameFormat, "Virtual"); +// return Executors.newThreadPerTaskExecutor(r -> { +// Thread t = factory.newThread(r); +// t.setName(threadName); +// return t; +// }); +// } +// } diff --git a/src/main/java/org/redkale/util/AnyValueWriter.java b/src/main/java/org/redkale/util/AnyValueWriter.java index 1d791a5d1..7bdc9f873 100644 --- a/src/main/java/org/redkale/util/AnyValueWriter.java +++ b/src/main/java/org/redkale/util/AnyValueWriter.java @@ -1,605 +1,605 @@ -/* - * - */ -package org.redkale.util; - -import java.util.LinkedHashSet; -import java.util.Objects; -import java.util.Set; -import java.util.function.BiConsumer; -import java.util.function.BiPredicate; -import org.redkale.convert.ConvertColumn; -import org.redkale.convert.ConvertDisabled; - -/** - * AnyValue的可写版 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -@SuppressWarnings("unchecked") -public class AnyValueWriter extends AnyValue { - - /** 区分name大小写的比较策略 */ - public static final BiPredicate EQUALS_PREDICATE = (name1, name2) -> name1.equals(name2); - - /** 不区分name大小写的比较策略 */ - public static final BiPredicate EQUALS_IGNORE = (name1, name2) -> name1.equalsIgnoreCase(name2); - - @ConvertColumn(index = 1) - private boolean ignoreCase; - - private BiPredicate predicate; - - @ConvertColumn(index = 2) - private Entry[] stringEntrys = new Entry[0]; - - @ConvertColumn(index = 3) - private Entry[] anyEntrys = new Entry[0]; - - int parentArrayIndex = -1; // 只可能被loadFromProperties方法赋值 - - /** - * 创建含name-value值的AnyValueWriter - * - * @param name name - * @param value value值 - * @return AnyValueWriter - */ - public static final AnyValueWriter create(String name, Number value) { - AnyValueWriter conf = new AnyValueWriter(); - conf.addValue(name, value); - return conf; - } - - /** - * 创建含name-value值的AnyValueWriter对象 - * - * @param name name - * @param value value值 - * @return AnyValueWriter对象 - */ - public static final AnyValueWriter create(String name, String value) { - AnyValueWriter conf = new AnyValueWriter(); - conf.addValue(name, value); - return conf; - } - - /** - * 创建含name-value值的AnyValueWriter对象 - * - * @param name name - * @param value value值 - * @return AnyValueWriter对象 - */ - public static final AnyValueWriter create(String name, AnyValue value) { - AnyValueWriter conf = new AnyValueWriter(); - conf.addValue(name, value); - return conf; - } - - /** 创建一个区分大小写比较策略的AnyValueWriter对象 */ - public AnyValueWriter() { - this(false); - } - - /** - * 创建AnyValueWriter对象 - * - * @param ignoreCase name是否不区分大小写 - */ - public AnyValueWriter(boolean ignoreCase) { - this.ignoreCase = ignoreCase; - this.predicate = ignoreCase ? EQUALS_IGNORE : EQUALS_PREDICATE; - } - - /** - * 创建共享此内容的AnyValueWriter对象 - * - * @return AnyValueWriter对象 - */ - public AnyValueWriter duplicate() { - AnyValueWriter rs = new AnyValueWriter(this.ignoreCase); - rs.stringEntrys = this.stringEntrys; - rs.anyEntrys = this.anyEntrys; - return rs; - } - - /** - * 复制一份对象 - * - * @return AnyValueWriter对象 - */ - @Override - public AnyValueWriter copy() { - AnyValueWriter rs = new AnyValueWriter(this.ignoreCase); - rs.predicate = this.predicate; - rs.parentArrayIndex = this.parentArrayIndex; - if (this.stringEntrys != null) { - rs.stringEntrys = new Entry[this.stringEntrys.length]; - for (int i = 0; i < rs.stringEntrys.length; i++) { - Entry en = this.stringEntrys[i]; - if (en == null) { - continue; - } - rs.stringEntrys[i] = new Entry(en.name, en.value); - } - } - if (this.anyEntrys != null) { - rs.anyEntrys = new Entry[this.anyEntrys.length]; - for (int i = 0; i < rs.anyEntrys.length; i++) { - Entry en = this.anyEntrys[i]; - if (en == null) { - continue; - } - rs.anyEntrys[i] = new Entry(en.name, en.value == null ? null : en.value.copy()); - } - } - return rs; - } - - /** - * 将另一个对象替换本对象 - * - * @param node 替换的对象 - * @return AnyValue - */ - @Override - public AnyValueWriter replace(AnyValue node) { - if (node != null) { - AnyValueWriter rs = (AnyValueWriter) node; - this.ignoreCase = rs.ignoreCase; - this.predicate = rs.predicate; - this.parentArrayIndex = rs.parentArrayIndex; - this.stringEntrys = rs.stringEntrys; - this.anyEntrys = rs.anyEntrys; - } - return this; - } - - /** - * 将另一个对象合并过来 - * - * @param node 代合并对象 - * @param func 判断覆盖方式的函数 - * @return AnyValue - */ - @Override - public AnyValueWriter merge(AnyValue node, MergeStrategy func) { - return merge(node, "", func); - } - - protected AnyValueWriter merge(AnyValue node0, String path, MergeStrategy func) { - if (node0 == null) { - return this; - } - if (node0 == this) { - throw new IllegalArgumentException(); - } - AnyValueWriter node = (AnyValueWriter) node0; - if (node.stringEntrys != null) { - for (Entry en : node.stringEntrys) { - if (en == null) { - continue; - } - setValue(en.name, en.value); - } - } - if (node.anyEntrys != null) { - for (Entry en : node.anyEntrys) { - if (en == null || en.value == null) { - continue; - } - Entry[] ns = getAnyValueEntrys(en.name); - if (ns == null || ns.length < 1) { - addValue(en.name, en.value); - } else { - boolean ok = false; - for (Entry item : ns) { - if (item == null) { - continue; - } - if (item.value != null - && en.value.parentArrayIndex == ((AnyValueWriter) item.value).parentArrayIndex) { - if (func == null) { - item.value.merge(en.value, func); - ok = true; - break; - } else { - MergeEnum funcVal = func.apply(path, en.name, en.value, item.value); - if (funcVal == MergeEnum.MERGE) { - String subPath = path.isEmpty() ? en.name : (path + "." + en.name); - ((AnyValueWriter) item.value).merge(en.value, subPath, func); - ok = true; - break; - } else if (funcVal == MergeEnum.REPLACE) { - item.value = en.value.copy(); - ok = true; - break; - } else if (funcVal == MergeEnum.IGNORE) { - ok = true; - break; - } - } - } - } - if (!ok) { - addValue(en.name, en.value); - } - } - } - } - return this; - } - - /** - * 合并两个AnyValue对象, 会去重, 没有的才增加 - * - * @param av AnyValue - * @return AnyValueWriter - */ - public AnyValueWriter addAllStringSet(final AnyValue av) { - if (av == null) { - return this; - } - final Entry[] strings = av.getStringEntrys(); - if (strings == null) { - return this; - } - for (Entry en : strings) { - if (!existsValue(en.name)) { - this.addValue(en.name, en.value); - } - } - return this; - } - - /** - * 合并两个AnyValue对象 不去重 - * - * @param av AnyValue - * @return AnyValueWriter - */ - public AnyValueWriter addAll(final AnyValue av) { - if (av == null) { - return this; - } - if (av instanceof AnyValueWriter) { - final AnyValueWriter adv = (AnyValueWriter) av; - if (adv.stringEntrys != null) { - for (Entry en : adv.stringEntrys) { - this.addValue(en.name, en.value); - } - } - if (adv.anyEntrys != null) { - for (Entry en : adv.anyEntrys) { - this.addValue(en.name, en.value); - } - } - } else { - final Entry[] strings = av.getStringEntrys(); - if (strings != null) { - for (Entry en : strings) { - this.addValue(en.name, en.value); - } - } - final Entry[] anys = av.getAnyEntrys(); - if (anys != null) { - for (Entry en : anys) { - this.addValue(en.name, en.value); - } - } - } - return this; - } - - /** - * 合并两个AnyValue对象 会去重 - * - * @param av AnyValue - * @return AnyValueWriter - */ - @ConvertDisabled - public AnyValueWriter setAll(final AnyValue av) { - if (av == null) { - return this; - } - if (av instanceof AnyValueWriter) { - final AnyValueWriter adv = (AnyValueWriter) av; - if (adv.stringEntrys != null) { - for (Entry en : adv.stringEntrys) { - this.setValue(en.name, en.value); - } - } - if (adv.anyEntrys != null) { - for (Entry en : adv.anyEntrys) { - this.setValue(en.name, en.value); - } - } - } else { - final Entry[] strings = av.getStringEntrys(); - if (strings != null) { - for (Entry en : strings) { - this.setValue(en.name, en.value); - } - } - final Entry[] anys = av.getAnyEntrys(); - if (anys != null) { - for (Entry en : anys) { - this.setValue(en.name, en.value); - } - } - } - return this; - } - - @Override - public void forEach(BiConsumer stringConsumer) { - forEach(stringConsumer, null); - } - - @Override - public void forEach(BiConsumer stringConsumer, BiConsumer anyConsumer) { - if (stringConsumer != null) { - for (Entry en : stringEntrys) { - stringConsumer.accept(en.name, en.value); - } - } - if (anyConsumer != null) { - for (Entry en : (Entry[]) anyEntrys) { - anyConsumer.accept(en.name, en.value); - } - } - } - - @Override - public Entry[] getStringEntrys() { - return stringEntrys; - } - - public void setStringEntrys(Entry[] stringEntrys) { - this.stringEntrys = stringEntrys; - } - - public void clearStringEntrys() { - this.stringEntrys = new Entry[0]; - } - - @Override - public Entry[] getAnyEntrys() { - return (Entry[]) (Entry[]) anyEntrys; - } - - public void setAnyEntrys(Entry[] anyEntrys) { - this.anyEntrys = anyEntrys; - } - - public void clearAnyEntrys() { - this.anyEntrys = new Entry[0]; - } - - public boolean isIgnoreCase() { - return ignoreCase; - } - - public void setIgnoreCase(boolean ignoreCase) { - this.ignoreCase = ignoreCase; - if (this.predicate == null) { - this.predicate = ignoreCase ? EQUALS_IGNORE : EQUALS_PREDICATE; - } - } - - @Override - @ConvertDisabled - public String[] getNames() { - Set set = new LinkedHashSet<>(); - for (Entry en : this.stringEntrys) { - set.add(en.name); - } - for (Entry en : this.anyEntrys) { - set.add(en.name); - } - return set.toArray(new String[set.size()]); - } - - @Override - public String[] getValues(String... names) { - return Entry.getStringArray(this.predicate, this.stringEntrys, names); - } - - @Override - public AnyValue[] getAnyValues(String... names) { - return Entry.getAnyValueArray(this.predicate, this.anyEntrys, names); - } - - @Override - public String[] getValues(String name) { - return Entry.getStringArray(this.predicate, this.stringEntrys, name); - } - - @Override - public AnyValue[] getAnyValues(String name) { - return Entry.getAnyValueArray(this.predicate, this.anyEntrys, name); - } - - protected Entry[] getAnyValueEntrys(String name) { - return Entry.getEntryAnyValueArray(this.predicate, this.anyEntrys, name); - } - - @Override - public String toString() { - return toString(0, (any, space) -> { - int index = ((AnyValueWriter) any).parentArrayIndex; - if (index < 0) { - return null; // 不能用"null" - } - return new StringBuilder() - .append(space) - .append(" '$index': ") - .append(index) - .append(",\r\n"); - }); - } - - public AnyValueWriter clear() { - if (this.stringEntrys != null && this.stringEntrys.length > 0) { - this.stringEntrys = new Entry[0]; - } - if (this.anyEntrys != null && this.anyEntrys.length > 0) { - this.anyEntrys = new Entry[0]; - } - return this; - } - - public AnyValueWriter setValue(String name, String value) { - Objects.requireNonNull(name); - if (!existsValue(name)) { - this.addValue(name, value); - } else { - for (Entry en : this.stringEntrys) { - if (predicate.test(en.name, name)) { - en.value = value; - return this; - } - } - } - return this; - } - - public AnyValueWriter setValue(String name, AnyValue value) { - Objects.requireNonNull(name); - if (!existsValue(name)) { - this.addValue(name, value); - } else { - for (Entry en : this.anyEntrys) { - if (predicate.test(en.name, name)) { - en.value = (AnyValueWriter) value; - return this; - } - } - } - return this; - } - - public AnyValueWriter put(String name, boolean value) { - return addValue(name, String.valueOf(value)); - } - - public AnyValueWriter put(String name, Number value) { - return addValue(name, String.valueOf(value)); - } - - public AnyValueWriter put(String name, String value) { - this.stringEntrys = Utility.append(this.stringEntrys, new Entry(name, value)); - return this; - } - - public AnyValueWriter addValue(String name, boolean value) { - return addValue(name, String.valueOf(value)); - } - - public AnyValueWriter addValue(String name, Number value) { - return addValue(name, String.valueOf(value)); - } - - public AnyValueWriter addValue(String name, String value) { - Objects.requireNonNull(name); - this.stringEntrys = Utility.append(this.stringEntrys, new Entry(name, value)); - return this; - } - - public AnyValueWriter addValue(String name, AnyValue value) { - Objects.requireNonNull(name); - this.anyEntrys = Utility.append(this.anyEntrys, new Entry(name, value)); - return this; - } - - public void clearParentArrayIndex(String name) { - for (Entry item : getAnyValueEntrys(name)) { - if (item.value != null) { - ((AnyValueWriter) item.value).parentArrayIndex = -1; - } - } - } - - public AnyValueWriter removeAnyValues(String name) { - Objects.requireNonNull(name); - if (this.anyEntrys == null) { - return this; - } - this.anyEntrys = Utility.remove(this.anyEntrys, t -> name.equals(((Entry) t).name)); - return this; - } - - public AnyValueWriter removeValue(String name, AnyValue value) { - Objects.requireNonNull(name); - if (value == null || this.anyEntrys == null) { - return this; - } - this.anyEntrys = Utility.remove( - this.anyEntrys, - t -> name.equals(((Entry) t).name) && ((Entry) t).getValue().equals(value)); - return this; - } - - public AnyValueWriter removeStringValues(String name) { - Objects.requireNonNull(name); - if (this.stringEntrys == null) { - return this; - } - this.stringEntrys = Utility.remove(this.stringEntrys, t -> name.equals(((Entry) t).name)); - return this; - } - - public AnyValueWriter removeValue(String name, String value) { - Objects.requireNonNull(name); - if (value == null || this.stringEntrys == null) { - return this; - } - this.stringEntrys = Utility.remove( - this.stringEntrys, - t -> name.equals(((Entry) t).name) && ((Entry) t).getValue().equals(value)); - return this; - } - - @Override - public AnyValue getAnyValue(String name) { - return getAnyValue(name, false); - } - - @Override - public AnyValue getAnyValue(String name, boolean create) { - for (Entry en : this.anyEntrys) { - if (predicate.test(en.name, name)) { - return en.value; - } - } - return create ? new AnyValueWriter() : null; - } - - @Override - public String get(String name) { - return getValue(name); - } - - @Override - public String getValue(String name) { - for (Entry en : this.stringEntrys) { - if (predicate.test(en.name, name)) { - return en.value; - } - } - return null; - } - - public boolean existsValue(String name) { - for (Entry en : this.stringEntrys) { - if (predicate.test(en.name, name)) { - return true; - } - } - return false; - } -} +/* + * + */ +package org.redkale.util; + +import java.util.LinkedHashSet; +import java.util.Objects; +import java.util.Set; +import java.util.function.BiConsumer; +import java.util.function.BiPredicate; +import org.redkale.convert.ConvertColumn; +import org.redkale.convert.ConvertDisabled; + +/** + * AnyValue的可写版 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +@SuppressWarnings("unchecked") +public class AnyValueWriter extends AnyValue { + + /** 区分name大小写的比较策略 */ + public static final BiPredicate EQUALS_PREDICATE = (name1, name2) -> name1.equals(name2); + + /** 不区分name大小写的比较策略 */ + public static final BiPredicate EQUALS_IGNORE = (name1, name2) -> name1.equalsIgnoreCase(name2); + + @ConvertColumn(index = 1) + private boolean ignoreCase; + + private BiPredicate predicate; + + @ConvertColumn(index = 2) + private Entry[] stringEntrys = new Entry[0]; + + @ConvertColumn(index = 3) + private Entry[] anyEntrys = new Entry[0]; + + int parentArrayIndex = -1; // 只可能被loadFromProperties方法赋值 + + /** + * 创建含name-value值的AnyValueWriter + * + * @param name name + * @param value value值 + * @return AnyValueWriter + */ + public static final AnyValueWriter create(String name, Number value) { + AnyValueWriter conf = new AnyValueWriter(); + conf.addValue(name, value); + return conf; + } + + /** + * 创建含name-value值的AnyValueWriter对象 + * + * @param name name + * @param value value值 + * @return AnyValueWriter对象 + */ + public static final AnyValueWriter create(String name, String value) { + AnyValueWriter conf = new AnyValueWriter(); + conf.addValue(name, value); + return conf; + } + + /** + * 创建含name-value值的AnyValueWriter对象 + * + * @param name name + * @param value value值 + * @return AnyValueWriter对象 + */ + public static final AnyValueWriter create(String name, AnyValue value) { + AnyValueWriter conf = new AnyValueWriter(); + conf.addValue(name, value); + return conf; + } + + /** 创建一个区分大小写比较策略的AnyValueWriter对象 */ + public AnyValueWriter() { + this(false); + } + + /** + * 创建AnyValueWriter对象 + * + * @param ignoreCase name是否不区分大小写 + */ + public AnyValueWriter(boolean ignoreCase) { + this.ignoreCase = ignoreCase; + this.predicate = ignoreCase ? EQUALS_IGNORE : EQUALS_PREDICATE; + } + + /** + * 创建共享此内容的AnyValueWriter对象 + * + * @return AnyValueWriter对象 + */ + public AnyValueWriter duplicate() { + AnyValueWriter rs = new AnyValueWriter(this.ignoreCase); + rs.stringEntrys = this.stringEntrys; + rs.anyEntrys = this.anyEntrys; + return rs; + } + + /** + * 复制一份对象 + * + * @return AnyValueWriter对象 + */ + @Override + public AnyValueWriter copy() { + AnyValueWriter rs = new AnyValueWriter(this.ignoreCase); + rs.predicate = this.predicate; + rs.parentArrayIndex = this.parentArrayIndex; + if (this.stringEntrys != null) { + rs.stringEntrys = new Entry[this.stringEntrys.length]; + for (int i = 0; i < rs.stringEntrys.length; i++) { + Entry en = this.stringEntrys[i]; + if (en == null) { + continue; + } + rs.stringEntrys[i] = new Entry(en.name, en.value); + } + } + if (this.anyEntrys != null) { + rs.anyEntrys = new Entry[this.anyEntrys.length]; + for (int i = 0; i < rs.anyEntrys.length; i++) { + Entry en = this.anyEntrys[i]; + if (en == null) { + continue; + } + rs.anyEntrys[i] = new Entry(en.name, en.value == null ? null : en.value.copy()); + } + } + return rs; + } + + /** + * 将另一个对象替换本对象 + * + * @param node 替换的对象 + * @return AnyValue + */ + @Override + public AnyValueWriter replace(AnyValue node) { + if (node != null) { + AnyValueWriter rs = (AnyValueWriter) node; + this.ignoreCase = rs.ignoreCase; + this.predicate = rs.predicate; + this.parentArrayIndex = rs.parentArrayIndex; + this.stringEntrys = rs.stringEntrys; + this.anyEntrys = rs.anyEntrys; + } + return this; + } + + /** + * 将另一个对象合并过来 + * + * @param node 代合并对象 + * @param func 判断覆盖方式的函数 + * @return AnyValue + */ + @Override + public AnyValueWriter merge(AnyValue node, MergeStrategy func) { + return merge(node, "", func); + } + + protected AnyValueWriter merge(AnyValue node0, String path, MergeStrategy func) { + if (node0 == null) { + return this; + } + if (node0 == this) { + throw new IllegalArgumentException(); + } + AnyValueWriter node = (AnyValueWriter) node0; + if (node.stringEntrys != null) { + for (Entry en : node.stringEntrys) { + if (en == null) { + continue; + } + setValue(en.name, en.value); + } + } + if (node.anyEntrys != null) { + for (Entry en : node.anyEntrys) { + if (en == null || en.value == null) { + continue; + } + Entry[] ns = getAnyValueEntrys(en.name); + if (ns == null || ns.length < 1) { + addValue(en.name, en.value); + } else { + boolean ok = false; + for (Entry item : ns) { + if (item == null) { + continue; + } + if (item.value != null + && en.value.parentArrayIndex == ((AnyValueWriter) item.value).parentArrayIndex) { + if (func == null) { + item.value.merge(en.value, func); + ok = true; + break; + } else { + MergeEnum funcVal = func.apply(path, en.name, en.value, item.value); + if (funcVal == MergeEnum.MERGE) { + String subPath = path.isEmpty() ? en.name : (path + "." + en.name); + ((AnyValueWriter) item.value).merge(en.value, subPath, func); + ok = true; + break; + } else if (funcVal == MergeEnum.REPLACE) { + item.value = en.value.copy(); + ok = true; + break; + } else if (funcVal == MergeEnum.IGNORE) { + ok = true; + break; + } + } + } + } + if (!ok) { + addValue(en.name, en.value); + } + } + } + } + return this; + } + + /** + * 合并两个AnyValue对象, 会去重, 没有的才增加 + * + * @param av AnyValue + * @return AnyValueWriter + */ + public AnyValueWriter addAllStringSet(final AnyValue av) { + if (av == null) { + return this; + } + final Entry[] strings = av.getStringEntrys(); + if (strings == null) { + return this; + } + for (Entry en : strings) { + if (!existsValue(en.name)) { + this.addValue(en.name, en.value); + } + } + return this; + } + + /** + * 合并两个AnyValue对象 不去重 + * + * @param av AnyValue + * @return AnyValueWriter + */ + public AnyValueWriter addAll(final AnyValue av) { + if (av == null) { + return this; + } + if (av instanceof AnyValueWriter) { + final AnyValueWriter adv = (AnyValueWriter) av; + if (adv.stringEntrys != null) { + for (Entry en : adv.stringEntrys) { + this.addValue(en.name, en.value); + } + } + if (adv.anyEntrys != null) { + for (Entry en : adv.anyEntrys) { + this.addValue(en.name, en.value); + } + } + } else { + final Entry[] strings = av.getStringEntrys(); + if (strings != null) { + for (Entry en : strings) { + this.addValue(en.name, en.value); + } + } + final Entry[] anys = av.getAnyEntrys(); + if (anys != null) { + for (Entry en : anys) { + this.addValue(en.name, en.value); + } + } + } + return this; + } + + /** + * 合并两个AnyValue对象 会去重 + * + * @param av AnyValue + * @return AnyValueWriter + */ + @ConvertDisabled + public AnyValueWriter setAll(final AnyValue av) { + if (av == null) { + return this; + } + if (av instanceof AnyValueWriter) { + final AnyValueWriter adv = (AnyValueWriter) av; + if (adv.stringEntrys != null) { + for (Entry en : adv.stringEntrys) { + this.setValue(en.name, en.value); + } + } + if (adv.anyEntrys != null) { + for (Entry en : adv.anyEntrys) { + this.setValue(en.name, en.value); + } + } + } else { + final Entry[] strings = av.getStringEntrys(); + if (strings != null) { + for (Entry en : strings) { + this.setValue(en.name, en.value); + } + } + final Entry[] anys = av.getAnyEntrys(); + if (anys != null) { + for (Entry en : anys) { + this.setValue(en.name, en.value); + } + } + } + return this; + } + + @Override + public void forEach(BiConsumer stringConsumer) { + forEach(stringConsumer, null); + } + + @Override + public void forEach(BiConsumer stringConsumer, BiConsumer anyConsumer) { + if (stringConsumer != null) { + for (Entry en : stringEntrys) { + stringConsumer.accept(en.name, en.value); + } + } + if (anyConsumer != null) { + for (Entry en : (Entry[]) anyEntrys) { + anyConsumer.accept(en.name, en.value); + } + } + } + + @Override + public Entry[] getStringEntrys() { + return stringEntrys; + } + + public void setStringEntrys(Entry[] stringEntrys) { + this.stringEntrys = stringEntrys; + } + + public void clearStringEntrys() { + this.stringEntrys = new Entry[0]; + } + + @Override + public Entry[] getAnyEntrys() { + return (Entry[]) (Entry[]) anyEntrys; + } + + public void setAnyEntrys(Entry[] anyEntrys) { + this.anyEntrys = anyEntrys; + } + + public void clearAnyEntrys() { + this.anyEntrys = new Entry[0]; + } + + public boolean isIgnoreCase() { + return ignoreCase; + } + + public void setIgnoreCase(boolean ignoreCase) { + this.ignoreCase = ignoreCase; + if (this.predicate == null) { + this.predicate = ignoreCase ? EQUALS_IGNORE : EQUALS_PREDICATE; + } + } + + @Override + @ConvertDisabled + public String[] getNames() { + Set set = new LinkedHashSet<>(); + for (Entry en : this.stringEntrys) { + set.add(en.name); + } + for (Entry en : this.anyEntrys) { + set.add(en.name); + } + return set.toArray(new String[set.size()]); + } + + @Override + public String[] getValues(String... names) { + return Entry.getStringArray(this.predicate, this.stringEntrys, names); + } + + @Override + public AnyValue[] getAnyValues(String... names) { + return Entry.getAnyValueArray(this.predicate, this.anyEntrys, names); + } + + @Override + public String[] getValues(String name) { + return Entry.getStringArray(this.predicate, this.stringEntrys, name); + } + + @Override + public AnyValue[] getAnyValues(String name) { + return Entry.getAnyValueArray(this.predicate, this.anyEntrys, name); + } + + protected Entry[] getAnyValueEntrys(String name) { + return Entry.getEntryAnyValueArray(this.predicate, this.anyEntrys, name); + } + + @Override + public String toString() { + return toString(0, (any, space) -> { + int index = ((AnyValueWriter) any).parentArrayIndex; + if (index < 0) { + return null; // 不能用"null" + } + return new StringBuilder() + .append(space) + .append(" '$index': ") + .append(index) + .append(",\r\n"); + }); + } + + public AnyValueWriter clear() { + if (this.stringEntrys != null && this.stringEntrys.length > 0) { + this.stringEntrys = new Entry[0]; + } + if (this.anyEntrys != null && this.anyEntrys.length > 0) { + this.anyEntrys = new Entry[0]; + } + return this; + } + + public AnyValueWriter setValue(String name, String value) { + Objects.requireNonNull(name); + if (!existsValue(name)) { + this.addValue(name, value); + } else { + for (Entry en : this.stringEntrys) { + if (predicate.test(en.name, name)) { + en.value = value; + return this; + } + } + } + return this; + } + + public AnyValueWriter setValue(String name, AnyValue value) { + Objects.requireNonNull(name); + if (!existsValue(name)) { + this.addValue(name, value); + } else { + for (Entry en : this.anyEntrys) { + if (predicate.test(en.name, name)) { + en.value = (AnyValueWriter) value; + return this; + } + } + } + return this; + } + + public AnyValueWriter put(String name, boolean value) { + return addValue(name, String.valueOf(value)); + } + + public AnyValueWriter put(String name, Number value) { + return addValue(name, String.valueOf(value)); + } + + public AnyValueWriter put(String name, String value) { + this.stringEntrys = Utility.append(this.stringEntrys, new Entry(name, value)); + return this; + } + + public AnyValueWriter addValue(String name, boolean value) { + return addValue(name, String.valueOf(value)); + } + + public AnyValueWriter addValue(String name, Number value) { + return addValue(name, String.valueOf(value)); + } + + public AnyValueWriter addValue(String name, String value) { + Objects.requireNonNull(name); + this.stringEntrys = Utility.append(this.stringEntrys, new Entry(name, value)); + return this; + } + + public AnyValueWriter addValue(String name, AnyValue value) { + Objects.requireNonNull(name); + this.anyEntrys = Utility.append(this.anyEntrys, new Entry(name, value)); + return this; + } + + public void clearParentArrayIndex(String name) { + for (Entry item : getAnyValueEntrys(name)) { + if (item.value != null) { + ((AnyValueWriter) item.value).parentArrayIndex = -1; + } + } + } + + public AnyValueWriter removeAnyValues(String name) { + Objects.requireNonNull(name); + if (this.anyEntrys == null) { + return this; + } + this.anyEntrys = Utility.remove(this.anyEntrys, t -> name.equals(((Entry) t).name)); + return this; + } + + public AnyValueWriter removeValue(String name, AnyValue value) { + Objects.requireNonNull(name); + if (value == null || this.anyEntrys == null) { + return this; + } + this.anyEntrys = Utility.remove( + this.anyEntrys, + t -> name.equals(((Entry) t).name) && ((Entry) t).getValue().equals(value)); + return this; + } + + public AnyValueWriter removeStringValues(String name) { + Objects.requireNonNull(name); + if (this.stringEntrys == null) { + return this; + } + this.stringEntrys = Utility.remove(this.stringEntrys, t -> name.equals(((Entry) t).name)); + return this; + } + + public AnyValueWriter removeValue(String name, String value) { + Objects.requireNonNull(name); + if (value == null || this.stringEntrys == null) { + return this; + } + this.stringEntrys = Utility.remove( + this.stringEntrys, + t -> name.equals(((Entry) t).name) && ((Entry) t).getValue().equals(value)); + return this; + } + + @Override + public AnyValue getAnyValue(String name) { + return getAnyValue(name, false); + } + + @Override + public AnyValue getAnyValue(String name, boolean create) { + for (Entry en : this.anyEntrys) { + if (predicate.test(en.name, name)) { + return en.value; + } + } + return create ? new AnyValueWriter() : null; + } + + @Override + public String get(String name) { + return getValue(name); + } + + @Override + public String getValue(String name) { + for (Entry en : this.stringEntrys) { + if (predicate.test(en.name, name)) { + return en.value; + } + } + return null; + } + + public boolean existsValue(String name) { + for (Entry en : this.stringEntrys) { + if (predicate.test(en.name, name)) { + return true; + } + } + return false; + } +} diff --git a/src/main/java/org/redkale/util/BoolRef.java b/src/main/java/org/redkale/util/BoolRef.java index f6a6130c8..015e59d43 100644 --- a/src/main/java/org/redkale/util/BoolRef.java +++ b/src/main/java/org/redkale/util/BoolRef.java @@ -1,46 +1,46 @@ -/* - * - */ -package org.redkale.util; - -/** - * 简单的boolean值引用 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public final class BoolRef { - - private boolean value; - - public BoolRef(boolean initialValue) { - this.value = initialValue; - } - - public BoolRef() {} - - public boolean get() { - return this.value; - } - - public void set(boolean newValue) { - this.value = newValue; - } - - public BoolRef asFalse() { - this.value = false; - return this; - } - - public BoolRef asTrue() { - this.value = true; - return this; - } - - @Override - public String toString() { - return String.valueOf(this.value); - } -} +/* + * + */ +package org.redkale.util; + +/** + * 简单的boolean值引用 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public final class BoolRef { + + private boolean value; + + public BoolRef(boolean initialValue) { + this.value = initialValue; + } + + public BoolRef() {} + + public boolean get() { + return this.value; + } + + public void set(boolean newValue) { + this.value = newValue; + } + + public BoolRef asFalse() { + this.value = false; + return this; + } + + public BoolRef asTrue() { + this.value = true; + return this; + } + + @Override + public String toString() { + return String.valueOf(this.value); + } +} diff --git a/src/main/java/org/redkale/util/ByteBufferPool.java b/src/main/java/org/redkale/util/ByteBufferPool.java index 0f286c267..0cc82b5e2 100644 --- a/src/main/java/org/redkale/util/ByteBufferPool.java +++ b/src/main/java/org/redkale/util/ByteBufferPool.java @@ -1,139 +1,139 @@ -/* - * - */ -package org.redkale.util; - -import java.nio.ByteBuffer; -import java.util.*; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.atomic.LongAdder; - -/** - * ByteBuffer的对象池
- * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public class ByteBufferPool extends ObjectPool { - - private final int bufferCapacity; - - protected ByteBufferPool( - ObjectPool parent, - LongAdder creatCounter, - LongAdder cycleCounter, - Thread unsafeThread, - int max, - int bufferCapacity, - Queue queue) { - super( - parent, - creatCounter, - cycleCounter, - unsafeThread, - max, - (Object... params) -> ByteBuffer.allocateDirect(bufferCapacity), - null, - (e) -> { - if (e == null || e.isReadOnly() || e.capacity() != bufferCapacity) { - return false; - } - e.clear(); - return true; - }, - queue); - this.bufferCapacity = bufferCapacity; - } - - // 非线程安全版 - public static ByteBufferPool createUnsafePool(int max, int bufferCapacity) { - return createUnsafePool(null, null, max, bufferCapacity); - } - - // 非线程安全版 - public static ByteBufferPool createUnsafePool( - LongAdder creatCounter, LongAdder cycleCounter, int max, int bufferCapacity) { - return createUnsafePool(null, creatCounter, cycleCounter, max, bufferCapacity); - } - - // 非线程安全版 - public static ByteBufferPool createUnsafePool(ByteBufferPool parent, int bufferCapacity) { - return createUnsafePool(parent, 2, bufferCapacity); - } - - // 非线程安全版 - public static ByteBufferPool createUnsafePool(ByteBufferPool parent, int max, int bufferCapacity) { - return createUnsafePool(parent, null, null, max, bufferCapacity); - } - - // 非线程安全版 - public static ByteBufferPool createUnsafePool( - ByteBufferPool parent, LongAdder creatCounter, LongAdder cycleCounter, int max, int bufferCapacity) { - return new ByteBufferPool( - parent, - creatCounter, - cycleCounter, - null, - Math.max(Utility.cpus(), max), - bufferCapacity, - new ArrayDeque<>(Math.max(Utility.cpus(), max))); - } - - // 非线程安全版 - public static ByteBufferPool createUnsafePool(Thread unsafeThread, int max, ByteBufferPool safePool) { - return createUnsafePool( - safePool, - safePool.getCreatCounter(), - safePool.getCycleCounter(), - unsafeThread, - max, - safePool.getBufferCapacity()); - } - - // 非线程安全版 - public static ByteBufferPool createUnsafePool( - ByteBufferPool parent, - LongAdder creatCounter, - LongAdder cycleCounter, - Thread unsafeThread, - int max, - int bufferCapacity) { - return new ByteBufferPool( - parent, - creatCounter, - cycleCounter, - unsafeThread, - Math.max(Utility.cpus(), max), - bufferCapacity, - new ArrayDeque<>(Math.max(Utility.cpus(), max))); - } - - // 线程安全版 - public static ByteBufferPool createSafePool(int bufferCapacity) { - return createSafePool(2, bufferCapacity); - } - - // 线程安全版 - public static ByteBufferPool createSafePool(int max, int bufferCapacity) { - return createSafePool(null, null, max, bufferCapacity); - } - - // 线程安全版 - public static ByteBufferPool createSafePool( - LongAdder creatCounter, LongAdder cycleCounter, int max, int bufferCapacity) { - return new ByteBufferPool( - null, - creatCounter, - cycleCounter, - null, - Math.max(Utility.cpus(), max), - bufferCapacity, - new LinkedBlockingQueue<>(Math.max(Utility.cpus(), max))); - } - - public int getBufferCapacity() { - return bufferCapacity; - } -} +/* + * + */ +package org.redkale.util; + +import java.nio.ByteBuffer; +import java.util.*; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.atomic.LongAdder; + +/** + * ByteBuffer的对象池
+ * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public class ByteBufferPool extends ObjectPool { + + private final int bufferCapacity; + + protected ByteBufferPool( + ObjectPool parent, + LongAdder creatCounter, + LongAdder cycleCounter, + Thread unsafeThread, + int max, + int bufferCapacity, + Queue queue) { + super( + parent, + creatCounter, + cycleCounter, + unsafeThread, + max, + (Object... params) -> ByteBuffer.allocateDirect(bufferCapacity), + null, + (e) -> { + if (e == null || e.isReadOnly() || e.capacity() != bufferCapacity) { + return false; + } + e.clear(); + return true; + }, + queue); + this.bufferCapacity = bufferCapacity; + } + + // 非线程安全版 + public static ByteBufferPool createUnsafePool(int max, int bufferCapacity) { + return createUnsafePool(null, null, max, bufferCapacity); + } + + // 非线程安全版 + public static ByteBufferPool createUnsafePool( + LongAdder creatCounter, LongAdder cycleCounter, int max, int bufferCapacity) { + return createUnsafePool(null, creatCounter, cycleCounter, max, bufferCapacity); + } + + // 非线程安全版 + public static ByteBufferPool createUnsafePool(ByteBufferPool parent, int bufferCapacity) { + return createUnsafePool(parent, 2, bufferCapacity); + } + + // 非线程安全版 + public static ByteBufferPool createUnsafePool(ByteBufferPool parent, int max, int bufferCapacity) { + return createUnsafePool(parent, null, null, max, bufferCapacity); + } + + // 非线程安全版 + public static ByteBufferPool createUnsafePool( + ByteBufferPool parent, LongAdder creatCounter, LongAdder cycleCounter, int max, int bufferCapacity) { + return new ByteBufferPool( + parent, + creatCounter, + cycleCounter, + null, + Math.max(Utility.cpus(), max), + bufferCapacity, + new ArrayDeque<>(Math.max(Utility.cpus(), max))); + } + + // 非线程安全版 + public static ByteBufferPool createUnsafePool(Thread unsafeThread, int max, ByteBufferPool safePool) { + return createUnsafePool( + safePool, + safePool.getCreatCounter(), + safePool.getCycleCounter(), + unsafeThread, + max, + safePool.getBufferCapacity()); + } + + // 非线程安全版 + public static ByteBufferPool createUnsafePool( + ByteBufferPool parent, + LongAdder creatCounter, + LongAdder cycleCounter, + Thread unsafeThread, + int max, + int bufferCapacity) { + return new ByteBufferPool( + parent, + creatCounter, + cycleCounter, + unsafeThread, + Math.max(Utility.cpus(), max), + bufferCapacity, + new ArrayDeque<>(Math.max(Utility.cpus(), max))); + } + + // 线程安全版 + public static ByteBufferPool createSafePool(int bufferCapacity) { + return createSafePool(2, bufferCapacity); + } + + // 线程安全版 + public static ByteBufferPool createSafePool(int max, int bufferCapacity) { + return createSafePool(null, null, max, bufferCapacity); + } + + // 线程安全版 + public static ByteBufferPool createSafePool( + LongAdder creatCounter, LongAdder cycleCounter, int max, int bufferCapacity) { + return new ByteBufferPool( + null, + creatCounter, + cycleCounter, + null, + Math.max(Utility.cpus(), max), + bufferCapacity, + new LinkedBlockingQueue<>(Math.max(Utility.cpus(), max))); + } + + public int getBufferCapacity() { + return bufferCapacity; + } +} diff --git a/src/main/java/org/redkale/util/ByteBufferWriter.java b/src/main/java/org/redkale/util/ByteBufferWriter.java index cc3bddfa3..54e56210c 100644 --- a/src/main/java/org/redkale/util/ByteBufferWriter.java +++ b/src/main/java/org/redkale/util/ByteBufferWriter.java @@ -1,230 +1,230 @@ -/* - * 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.util; - -import java.nio.*; -import java.util.function.Supplier; - -/** - * 以ByteBuffer为数据载体的Writer - * - *

详情见: https://redkale.org - * - * @author zhangjx - */ -public class ByteBufferWriter { - - private final Supplier supplier; - - private ByteBuffer[] buffers; - - private int position; - - private int writeBytesCounter = 0; // put(byte[] src, int offset, int length) 调用的次数 - - private boolean bigEndian = true; - - protected ByteBufferWriter(Supplier supplier) { - this.supplier = supplier; - } - - public static ByteBufferWriter create(Supplier supplier) { - return new ByteBufferWriter(supplier); - } - - public static ByteBufferWriter create(Supplier supplier, ByteBuffer one) { - ByteBufferWriter writer = new ByteBufferWriter(supplier); - writer.bigEndian = one.order() == ByteOrder.BIG_ENDIAN; - writer.buffers = new ByteBuffer[] {one}; - writer.position = one.position(); - return writer; - } - - public static ByteBuffer[] toBuffers(Supplier supplier, byte[] content) { - ByteBufferWriter writer = new ByteBufferWriter(supplier); - writer.put(false, content, 0, content.length); - return writer.toBuffers(); - } - - public static ByteBuffer[] toBuffers(Supplier supplier, byte[] content, int offset, int length) { - ByteBufferWriter writer = new ByteBufferWriter(supplier); - writer.put(false, content, offset, length); - return writer.toBuffers(); - } - - private ByteBuffer getLastBuffer(int size) { - if (this.buffers == null) { - ByteBuffer buf = supplier.get(); - this.bigEndian = buf.order() == ByteOrder.BIG_ENDIAN; - this.buffers = Utility.append(this.buffers, buf); - return buf; - } else if (this.buffers[this.buffers.length - 1].remaining() < size) { - ByteBuffer buf = supplier.get(); - this.buffers = Utility.append(this.buffers, buf); - return buf; - } - return this.buffers[this.buffers.length - 1]; - } - - public ByteBuffer[] toBuffers() { - if (buffers == null) { - return new ByteBuffer[0]; - } - for (ByteBuffer buf : this.buffers) { - buf.flip(); - } - return this.buffers; - } - - public int position() { - return position; - } - - public ByteBufferWriter put(byte b) { - getLastBuffer(1).put(b); - position++; - return this; - } - - public ByteBufferWriter putShort(short value) { - getLastBuffer(2).putShort(value); - position += 2; - return this; - } - - public ByteBufferWriter putInt(int value) { - getLastBuffer(4).putInt(value); - position += 4; - return this; - } - - // 重新设置指定位置的值 - public ByteBufferWriter putInt(final int index, int value) { - int start = 0; - ByteBuffer[] buffs = this.buffers; - for (int i = 0; i < buffs.length; i++) { - int pos = buffs[i].position(); - if (pos + start > index) { - int r = pos + start - index; - if (r >= 4) { - buffs[i].putInt(index - start, value); - return this; - } else { - byte b1 = bigEndian ? (byte) ((value >> 24) & 0xFF) : (byte) (value & 0xFF); - byte b2 = bigEndian ? (byte) ((value >> 16) & 0xFF) : (byte) ((value >> 8) & 0xFF); - byte b3 = bigEndian ? (byte) ((value >> 8) & 0xFF) : (byte) ((value >> 16) & 0xFF); - byte b4 = bigEndian ? (byte) (value & 0xFF) : (byte) ((value >> 24) & 0xFF); - if (r == 3) { - buffs[i].put(index - start, b1); - buffs[i].put(index - start + 1, b2); - buffs[i].put(index - start + 2, b3); - buffs[i + 1].put(0, b4); - } else if (r == 2) { - buffs[i].put(index - start, b1); - buffs[i].put(index - start + 1, b2); - buffs[i + 1].put(0, b3); - buffs[i + 1].put(1, b4); - } else if (r == 1) { - buffs[i].put(index - start, b1); - buffs[i + 1].put(0, b2); - buffs[i + 1].put(1, b3); - buffs[i + 1].put(2, b4); - } - return this; - } - } else { - start += pos; - } - } - throw new ArrayIndexOutOfBoundsException(index); - } - - // public static void main(String[] args) throws Throwable { - // ObjectPool pool = new ObjectPool<>(20, (p) -> ByteBuffer.allocate(10), (ByteBuffer t) -> - // t.clear(), (ByteBuffer t) -> false); - // ByteBufferWriter writer = ByteBufferWriter.create(pool); - // for (int i = 1; i <= 18; i++) { - // writer.put((byte) i); - // } - // System.out.println(Arrays.toString(toBytes(writer.toBuffers()))); - // - // writer = ByteBufferWriter.create(pool); - // for (int i = 1; i <= 18; i++) { - // writer.put((byte) i); - // } - // int value = 0x223344; - // byte[] b4 = new byte[]{(byte) ((value >> 24) & 0xFF), (byte) ((value >> 16) & 0xFF), (byte) ((value >> 8) - // & 0xFF), (byte) (value & 0xFF)}; - // writer.putInt(9, value); - // System.out.println(Arrays.toString(b4)); - // System.out.println(Arrays.toString(toBytes(writer.toBuffers()))); - // } - public ByteBufferWriter putFloat(float value) { - getLastBuffer(4).putFloat(value); - position += 4; - return this; - } - - public ByteBufferWriter putLong(long value) { - getLastBuffer(8).putLong(value); - position += 8; - return this; - } - - public ByteBufferWriter putDouble(double value) { - getLastBuffer(8).putDouble(value); - position += 8; - return this; - } - - public int put(byte[] src) { - return put(true, src, 0, src.length); - } - - public int put(byte[] src, int offset, int length) { - return put(true, src, offset, length); - } - - public int put(byte[] src, int offset, int length, byte[] src2, int offset2, int length2) { - ByteBuffer buf = getLastBuffer(1); - int remain = buf.remaining(); - if (remain >= length + length2) { - buf.put(src, offset, length); - if (src2 != null) { - buf.put(src2, offset2, length2); - } - position += length + length2; - this.writeBytesCounter++; - } else { - put(true, src, offset, length); - if (src2 != null) { - put(false, src2, offset2, length2); - } - } - return writeBytesCounter; - } - - private int put(boolean outside, byte[] src, int offset, int length) { - ByteBuffer buf = getLastBuffer(1); - int remain = buf.remaining(); - if (remain >= length) { - buf.put(src, offset, length); - position += length; - } else { - buf.put(src, offset, remain); - position += remain; - put(false, src, offset + remain, length - remain); - } - if (outside) { - this.writeBytesCounter++; - } - return writeBytesCounter; - } - - public int getWriteBytesCounter() { - return this.writeBytesCounter; - } -} +/* + * 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.util; + +import java.nio.*; +import java.util.function.Supplier; + +/** + * 以ByteBuffer为数据载体的Writer + * + *

详情见: https://redkale.org + * + * @author zhangjx + */ +public class ByteBufferWriter { + + private final Supplier supplier; + + private ByteBuffer[] buffers; + + private int position; + + private int writeBytesCounter = 0; // put(byte[] src, int offset, int length) 调用的次数 + + private boolean bigEndian = true; + + protected ByteBufferWriter(Supplier supplier) { + this.supplier = supplier; + } + + public static ByteBufferWriter create(Supplier supplier) { + return new ByteBufferWriter(supplier); + } + + public static ByteBufferWriter create(Supplier supplier, ByteBuffer one) { + ByteBufferWriter writer = new ByteBufferWriter(supplier); + writer.bigEndian = one.order() == ByteOrder.BIG_ENDIAN; + writer.buffers = new ByteBuffer[] {one}; + writer.position = one.position(); + return writer; + } + + public static ByteBuffer[] toBuffers(Supplier supplier, byte[] content) { + ByteBufferWriter writer = new ByteBufferWriter(supplier); + writer.put(false, content, 0, content.length); + return writer.toBuffers(); + } + + public static ByteBuffer[] toBuffers(Supplier supplier, byte[] content, int offset, int length) { + ByteBufferWriter writer = new ByteBufferWriter(supplier); + writer.put(false, content, offset, length); + return writer.toBuffers(); + } + + private ByteBuffer getLastBuffer(int size) { + if (this.buffers == null) { + ByteBuffer buf = supplier.get(); + this.bigEndian = buf.order() == ByteOrder.BIG_ENDIAN; + this.buffers = Utility.append(this.buffers, buf); + return buf; + } else if (this.buffers[this.buffers.length - 1].remaining() < size) { + ByteBuffer buf = supplier.get(); + this.buffers = Utility.append(this.buffers, buf); + return buf; + } + return this.buffers[this.buffers.length - 1]; + } + + public ByteBuffer[] toBuffers() { + if (buffers == null) { + return new ByteBuffer[0]; + } + for (ByteBuffer buf : this.buffers) { + buf.flip(); + } + return this.buffers; + } + + public int position() { + return position; + } + + public ByteBufferWriter put(byte b) { + getLastBuffer(1).put(b); + position++; + return this; + } + + public ByteBufferWriter putShort(short value) { + getLastBuffer(2).putShort(value); + position += 2; + return this; + } + + public ByteBufferWriter putInt(int value) { + getLastBuffer(4).putInt(value); + position += 4; + return this; + } + + // 重新设置指定位置的值 + public ByteBufferWriter putInt(final int index, int value) { + int start = 0; + ByteBuffer[] buffs = this.buffers; + for (int i = 0; i < buffs.length; i++) { + int pos = buffs[i].position(); + if (pos + start > index) { + int r = pos + start - index; + if (r >= 4) { + buffs[i].putInt(index - start, value); + return this; + } else { + byte b1 = bigEndian ? (byte) ((value >> 24) & 0xFF) : (byte) (value & 0xFF); + byte b2 = bigEndian ? (byte) ((value >> 16) & 0xFF) : (byte) ((value >> 8) & 0xFF); + byte b3 = bigEndian ? (byte) ((value >> 8) & 0xFF) : (byte) ((value >> 16) & 0xFF); + byte b4 = bigEndian ? (byte) (value & 0xFF) : (byte) ((value >> 24) & 0xFF); + if (r == 3) { + buffs[i].put(index - start, b1); + buffs[i].put(index - start + 1, b2); + buffs[i].put(index - start + 2, b3); + buffs[i + 1].put(0, b4); + } else if (r == 2) { + buffs[i].put(index - start, b1); + buffs[i].put(index - start + 1, b2); + buffs[i + 1].put(0, b3); + buffs[i + 1].put(1, b4); + } else if (r == 1) { + buffs[i].put(index - start, b1); + buffs[i + 1].put(0, b2); + buffs[i + 1].put(1, b3); + buffs[i + 1].put(2, b4); + } + return this; + } + } else { + start += pos; + } + } + throw new ArrayIndexOutOfBoundsException(index); + } + + // public static void main(String[] args) throws Throwable { + // ObjectPool pool = new ObjectPool<>(20, (p) -> ByteBuffer.allocate(10), (ByteBuffer t) -> + // t.clear(), (ByteBuffer t) -> false); + // ByteBufferWriter writer = ByteBufferWriter.create(pool); + // for (int i = 1; i <= 18; i++) { + // writer.put((byte) i); + // } + // System.out.println(Arrays.toString(toBytes(writer.toBuffers()))); + // + // writer = ByteBufferWriter.create(pool); + // for (int i = 1; i <= 18; i++) { + // writer.put((byte) i); + // } + // int value = 0x223344; + // byte[] b4 = new byte[]{(byte) ((value >> 24) & 0xFF), (byte) ((value >> 16) & 0xFF), (byte) ((value >> 8) + // & 0xFF), (byte) (value & 0xFF)}; + // writer.putInt(9, value); + // System.out.println(Arrays.toString(b4)); + // System.out.println(Arrays.toString(toBytes(writer.toBuffers()))); + // } + public ByteBufferWriter putFloat(float value) { + getLastBuffer(4).putFloat(value); + position += 4; + return this; + } + + public ByteBufferWriter putLong(long value) { + getLastBuffer(8).putLong(value); + position += 8; + return this; + } + + public ByteBufferWriter putDouble(double value) { + getLastBuffer(8).putDouble(value); + position += 8; + return this; + } + + public int put(byte[] src) { + return put(true, src, 0, src.length); + } + + public int put(byte[] src, int offset, int length) { + return put(true, src, offset, length); + } + + public int put(byte[] src, int offset, int length, byte[] src2, int offset2, int length2) { + ByteBuffer buf = getLastBuffer(1); + int remain = buf.remaining(); + if (remain >= length + length2) { + buf.put(src, offset, length); + if (src2 != null) { + buf.put(src2, offset2, length2); + } + position += length + length2; + this.writeBytesCounter++; + } else { + put(true, src, offset, length); + if (src2 != null) { + put(false, src2, offset2, length2); + } + } + return writeBytesCounter; + } + + private int put(boolean outside, byte[] src, int offset, int length) { + ByteBuffer buf = getLastBuffer(1); + int remain = buf.remaining(); + if (remain >= length) { + buf.put(src, offset, length); + position += length; + } else { + buf.put(src, offset, remain); + position += remain; + put(false, src, offset + remain, length - remain); + } + if (outside) { + this.writeBytesCounter++; + } + return writeBytesCounter; + } + + public int getWriteBytesCounter() { + return this.writeBytesCounter; + } +} diff --git a/src/main/java/org/redkale/util/Copier.java b/src/main/java/org/redkale/util/Copier.java index 158b8478e..b4362727f 100644 --- a/src/main/java/org/redkale/util/Copier.java +++ b/src/main/java/org/redkale/util/Copier.java @@ -1,1348 +1,1348 @@ -/* - * - */ -package org.redkale.util; - -import static org.redkale.asm.ClassWriter.COMPUTE_FRAMES; -import static org.redkale.asm.Opcodes.*; - -import java.lang.reflect.*; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.function.*; -import java.util.stream.Collectors; -import org.redkale.asm.*; -import org.redkale.asm.Type; - -/** - * JavaBean类对象的拷贝,相同的字段名会被拷贝
- * - *

详情见: https://redkale.org - * - * @author zhangjx - * @param 目标对象的数据类型 - * @param 源对象的数据类型 - * @since 2.8.0 - */ -public interface Copier extends BiFunction { - - /** 是否跳过值为null的字段 */ - public static final int OPTION_SKIP_NULL_VALUE = 1 << 1; // 2 - - /** 是否跳过值为空字符串的字段 */ - public static final int OPTION_SKIP_EMPTY_STRING = 1 << 2; // 4 - - /** 同名字段类型强制转换 */ - public static final int OPTION_ALLOW_TYPE_CAST = 1 << 3; // 8 - - /** - * 将源对象字段复制到目标对象 - * - * @param dest 目标对象 - * @param src 源对象 - * @return 目标对象 - */ - @Override - public D apply(S src, D dest); - - /** - * 将源对象字段复制到目标对象 - * - * @param 目标类泛型 - * @param 源类泛型 - * @param dest 目标对象 - * @param src 源对象 - * @return 目标对象 - */ - public static D copy(final S src, final D dest) { - return copy(src, dest, 0); - } - - /** - * 将源对象字段复制到目标对象 - * - * @param 目标类泛型 - * @param 源类泛型 - * @param dest 目标对象 - * @param src 源对象 - * @param options 可配项 - * @return 目标对象 - */ - public static D copy(final S src, final D dest, final int options) { - if (src == null || dest == null) { - return dest; - } - return load((Class) src.getClass(), (Class) dest.getClass(), options) - .apply(src, dest); - } - - /** - * 将源对象字段复制到目标对象 - * - * @param 目标类泛型 - * @param 源类泛型 - * @param destClass 目标类名 - * @param src 源对象 - * @return 目标对象 - */ - public static D copy(final S src, final Class destClass) { - return copy(src, destClass, 0); - } - - /** - * 将源对象字段复制到目标对象 - * - * @param 目标类泛型 - * @param 源类泛型 - * @param destClass 目标类名 - * @param src 源对象 - * @param options 可配项 - * @return 目标对象 - */ - public static D copy(final S src, final Class destClass, final int options) { - if (src == null) { - return null; - } - Creator creator = Creator.load(destClass); - return load((Class) src.getClass(), destClass, options).apply(src, creator.create()); - } - - /** - * 将源对象字段复制到目标对象 - * - * @param 源类泛型 - * @param src 源对象 - * @param options 可配项 - * @return 目标对象 - */ - public static Map copyToMap(final S src, final int options) { - if (src == null) { - return null; - } - HashMap dest = new HashMap(); - return load((Class) src.getClass(), HashMap.class, options).apply(src, dest); - } - - /** - * 创建源类到目标类的复制器并缓存 - * - * @param 目标类泛型 - * @param 源类泛型 - * @param destClass 目标类名 - * @param srcClass 源类名 - * @return 复制器 - */ - public static Function func(final Class srcClass, final Class destClass) { - return func(srcClass, destClass, 0); - } - - /** - * 创建源类到目标类的复制器并缓存 - * - * @param 目标类泛型 - * @param 源类泛型 - * @param destClass 目标类名 - * @param srcClass 源类名 - * @return 复制器 - */ - public static Function, Set> funcSet(final Class srcClass, final Class destClass) { - return funcSet(srcClass, destClass, 0); - } - - /** - * 创建源类到目标类的复制器并缓存 - * - * @param 目标类泛型 - * @param 源类泛型 - * @param destClass 目标类名 - * @param srcClass 源类名 - * @return 复制器 - */ - public static Function, List> funcList(final Class srcClass, final Class destClass) { - return funcList(srcClass, destClass, 0); - } - - /** - * 创建源类到目标类的复制器并缓存 - * - * @param 目标类泛型 - * @param 源类泛型 - * @param 集合泛型 - * @param destClass 目标类名 - * @param srcClass 源类名 - * @param collectionClass 集合类名 - * @return 复制器 - */ - public static Function, Collection> funcCollection( - final Class srcClass, final Class destClass, final Class collectionClass) { - return funcCollection(srcClass, destClass, 0, collectionClass); - } - - /** - * 创建源类到目标类的复制器并缓存 - * - * @param 目标类泛型 - * @param 源类泛型 - * @param destClass 目标类名 - * @param srcClass 源类名 - * @return 复制器 - */ - public static Copier load(final Class srcClass, final Class destClass) { - return load(srcClass, destClass, 0); - } - - /** - * 创建源类到目标类的复制器并缓存 - * - * @param 目标类泛型 - * @param 源类泛型 - * @param destClass 目标类名 - * @param srcClass 源类名 - * @param options 可配项 - * @return 复制器 - */ - public static Function, Set> funcSet( - final Class srcClass, final Class destClass, final int options) { - return (Function) funcCollection(srcClass, destClass, options, LinkedHashSet.class); - } - - /** - * 创建源类到目标类的复制器并缓存 - * - * @param 目标类泛型 - * @param 源类泛型 - * @param destClass 目标类名 - * @param srcClass 源类名 - * @param options 可配项 - * @return 复制器 - */ - public static Function, List> funcList( - final Class srcClass, final Class destClass, final int options) { - return (Function) funcCollection(srcClass, destClass, options, ArrayList.class); - } - - /** - * 创建源类到目标类的复制器并缓存 - * - * @param 目标类泛型 - * @param 源类泛型 - * @param 集合泛型 - * @param destClass 目标类名 - * @param srcClass 源类名 - * @param options 可配项 - * @param collectionClass 集合类名 - * @return 复制器 - */ - public static Function, Collection> funcCollection( - final Class srcClass, final Class destClass, final int options, final Class collectionClass) { - if (destClass == srcClass) { - return Inners.CopierInner.copierFuncListOneCaches - .computeIfAbsent(collectionClass, t -> new ConcurrentHashMap<>()) - .computeIfAbsent(options, t -> new ConcurrentHashMap<>()) - .computeIfAbsent(srcClass, v -> { - Creator creator = Creator.create(collectionClass); - Function func = func(srcClass, destClass, options); - Function, Collection> funcList = srcs -> { - if (srcs == null) { - return null; - } else if (srcs.isEmpty()) { - return creator.create(); - } else { - C list = creator.create(); - for (S s : srcs) { - list.add(func.apply(s)); - } - return list; - } - }; - return funcList; - }); - } else { - return Inners.CopierInner.copierFuncListTwoCaches - .computeIfAbsent(collectionClass, t -> new ConcurrentHashMap<>()) - .computeIfAbsent(options, t -> new ConcurrentHashMap<>()) - .computeIfAbsent(srcClass, t -> new ConcurrentHashMap<>()) - .computeIfAbsent(destClass, v -> { - Creator creator = Creator.create(collectionClass); - Function func = func(srcClass, destClass, options); - Function, Collection> funcList = srcs -> { - if (srcs == null) { - return null; - } else if (srcs.isEmpty()) { - return (C) creator.create(); - } else { - C list = creator.create(); - for (S s : srcs) { - list.add(func.apply(s)); - } - return list; - } - }; - return funcList; - }); - } - } - - /** - * 创建源类到目标类的复制器并缓存 - * - * @param 目标类泛型 - * @param 源类泛型 - * @param destClass 目标类名 - * @param srcClass 源类名 - * @param options 可配项 - * @return 复制器 - */ - public static Function func(final Class srcClass, final Class destClass, final int options) { - if (destClass == srcClass) { - return Inners.CopierInner.copierFuncOneCaches - .computeIfAbsent(options, t -> new ConcurrentHashMap<>()) - .computeIfAbsent(srcClass, v -> { - Copier copier = load(srcClass, destClass, options); - Creator creator = Creator.load(destClass); - Function func = src -> src == null ? null : copier.apply(src, creator.create()); - return func; - }); - } else { - return Inners.CopierInner.copierFuncTwoCaches - .computeIfAbsent(options, t -> new ConcurrentHashMap<>()) - .computeIfAbsent(srcClass, t -> new ConcurrentHashMap<>()) - .computeIfAbsent(destClass, v -> { - Copier copier = load(srcClass, destClass, options); - Creator creator = Creator.load(destClass); - Function func = src -> src == null ? null : copier.apply(src, creator.create()); - return func; - }); - } - } - - /** - * 创建源类到目标类的复制器并缓存 - * - * @param 目标类泛型 - * @param 源类泛型 - * @param destClass 目标类名 - * @param srcClass 源类名 - * @param options 可配项 - * @return 复制器 - */ - public static Copier load(final Class srcClass, final Class destClass, final int options) { - if (destClass == srcClass) { - return Inners.CopierInner.copierOneCaches - .computeIfAbsent(options, t -> new ConcurrentHashMap<>()) - .computeIfAbsent(srcClass, v -> create(srcClass, destClass, options)); - } else { - return Inners.CopierInner.copierTwoCaches - .computeIfAbsent(options, t -> new ConcurrentHashMap<>()) - .computeIfAbsent(srcClass, t -> new ConcurrentHashMap<>()) - .computeIfAbsent(destClass, v -> create(srcClass, destClass, options)); - } - } - - /** - * 创建源类到目标类的复制器 - * - * @param 目标类泛型 - * @param 源类泛型 - * @param destClass 目标类名 - * @param srcClass 源类名 - * @return 复制器 - */ - public static Copier create(final Class srcClass, final Class destClass) { - return create(srcClass, destClass, (BiPredicate) null, (Map) null); - } - - /** - * 创建源类到目标类的复制器 - * - * @param 目标类泛型 - * @param 源类泛型 - * @param destClass 目标类名 - * @param srcClass 源类名 - * @param names 源字段名与目标字段名的映射关系 - * @return 复制器 - */ - public static Copier create( - final Class srcClass, final Class destClass, final Map names) { - return create(srcClass, destClass, (BiPredicate) null, names); - } - - /** - * 创建源类到目标类的复制器 - * - * @param 目标类泛型 - * @param 源类泛型 - * @param destClass 目标类名 - * @param srcClass 源类名 - * @param srcColumnPredicate 需复制源类的字段名判断器 - * @return 复制器 - */ - @SuppressWarnings("unchecked") - public static Copier create( - final Class srcClass, final Class destClass, final Predicate srcColumnPredicate) { - return create(srcClass, destClass, (sc, m) -> srcColumnPredicate.test(m), (Map) null); - } - - /** - * 创建源类到目标类的复制器 - * - * @param 目标类泛型 - * @param 源类泛型 - * @param destClass 目标类名 - * @param srcClass 源类名 - * @param srcColumnPredicate 需复制源类的字段名判断器 - * @param names 源字段名与目标字段名的映射关系 - * @return 复制器 - */ - @SuppressWarnings("unchecked") - public static Copier create( - final Class srcClass, - final Class destClass, - final Predicate srcColumnPredicate, - final Map names) { - return create(srcClass, destClass, (sc, m) -> srcColumnPredicate.test(m), names); - } - - /** - * 创建源类到目标类的复制器 - * - * @param 目标类泛型 - * @param 源类泛型 - * @param destClass 目标类名 - * @param srcClass 源类名 - * @param srcColumnPredicate 需复制源类的字段名判断器 - * @return 复制器 - */ - @SuppressWarnings("unchecked") - public static Copier create( - final Class srcClass, - final Class destClass, - final BiPredicate srcColumnPredicate) { - return create(srcClass, destClass, srcColumnPredicate, (Map) null); - } - - /** - * 创建源类到目标类的复制器 - * - * @param 目标类泛型 - * @param 源类泛型 - * @param destClass 目标类名 - * @param srcClass 源类名 - * @param srcColumnPredicate 需复制源类的字段名判断器 - * @param names 源字段名与目标字段名的映射关系 - * @return 复制器 - */ - @SuppressWarnings("unchecked") - public static Copier create( - final Class srcClass, - final Class destClass, - final BiPredicate srcColumnPredicate, - final Map names) { - return create(srcClass, destClass, 0, srcColumnPredicate, names); - } - - /** - * 创建源类到目标类的复制器 - * - * @param 目标类泛型 - * @param 源类泛型 - * @param destClass 目标类名 - * @param srcClass 源类名 - * @param options 可配项 - * @return 复制器 - */ - @SuppressWarnings("unchecked") - public static Copier create(final Class srcClass, final Class destClass, final int options) { - return create(srcClass, destClass, options, (BiPredicate) null, (Map) null); - } - - /** - * 创建源类到目标类的复制器 - * - * @param 目标类泛型 - * @param 源类泛型 - * @param destClass 目标类名 - * @param srcClass 源类名 - * @param options 可配项 - * @param srcColumnPredicate 需复制源类的字段名判断器 - * @param nameAlias 源字段名与目标字段名的映射关系 - * @return 复制器 - */ - @SuppressWarnings("unchecked") - public static Copier create( - final Class srcClass, - final Class destClass, - final int options, - final BiPredicate srcColumnPredicate, - final Map nameAlias) { - final boolean skipNullValue = - (options & OPTION_SKIP_NULL_VALUE) > 0 || ConcurrentHashMap.class.isAssignableFrom(destClass); - final boolean skipEmptyString = (options & OPTION_SKIP_EMPTY_STRING) > 0; - final boolean allowTypeCast = (options & OPTION_ALLOW_TYPE_CAST) > 0; - final Predicate valPredicate = v -> !(skipNullValue && v == null) - && !(skipEmptyString && v instanceof CharSequence && ((CharSequence) v).length() == 0); - - if (Map.class.isAssignableFrom(destClass) && Map.class.isAssignableFrom(srcClass)) { - final Map names0 = nameAlias; - if (srcColumnPredicate != null) { - if (nameAlias != null) { - return (S src, D dest) -> { - if (src == null) { - return dest; - } - Map d = (Map) dest; - ((Map) src).forEach((k, v) -> { - if (srcColumnPredicate.test(null, k.toString()) && valPredicate.test(v)) { - d.put(names0.getOrDefault(k, k), v); - } - }); - return dest; - }; - } else { - return (S src, D dest) -> { - if (src == null) { - return dest; - } - Map d = (Map) dest; - ((Map) src).forEach((k, v) -> { - if (srcColumnPredicate.test(null, k.toString()) && valPredicate.test(v)) { - d.put(k, v); - } - }); - return dest; - }; - } - } else if (nameAlias != null) { - return (S src, D dest) -> { - if (src == null) { - return dest; - } - Map d = (Map) dest; - ((Map) src).forEach((k, v) -> { - if (valPredicate.test(v)) { - d.put(names0.getOrDefault(k, k), v); - } - }); - return dest; - }; - } - return new Copier() { - @Override - public D apply(S src, D dest) { - if (src == null) { - return dest; - } - if (options == 0) { - ((Map) dest).putAll((Map) src); - } else { - Map d = (Map) dest; - ((Map) src).forEach((k, v) -> { - if (valPredicate.test(v)) { - d.put(k, v); - } - }); - } - return dest; - } - }; - } - // ------------------------------------------------------------------------------ - final boolean destIsMap = Map.class.isAssignableFrom(destClass); - final boolean srcIsMap = Map.class.isAssignableFrom(srcClass); - final Predicate> throwPredicate = e -> !RuntimeException.class.isAssignableFrom(e); - final Map elements = new TreeMap<>(); - final Map destNewNames = new TreeMap<>(); - int ingoreCount = 0; - if (srcIsMap) { // Map -> JavaBean - for (java.lang.reflect.Field field : destClass.getFields()) { - if (Modifier.isStatic(field.getModifiers())) { - continue; - } - if (Modifier.isFinal(field.getModifiers())) { - continue; - } - if (!Modifier.isPublic(field.getModifiers())) { - continue; - } - final String sfname = field.getName(); - if (srcColumnPredicate != null && !srcColumnPredicate.test(field, sfname)) { - ingoreCount++; - continue; - } - final String dfname = nameAlias == null ? sfname : nameAlias.getOrDefault(sfname, sfname); - if (!Objects.equals(sfname, dfname)) { - destNewNames.put(sfname, dfname); - } - elements.put(dfname, field); - } - - for (java.lang.reflect.Method setter : destClass.getMethods()) { - if (Modifier.isStatic(setter.getModifiers())) { - continue; - } - if (setter.getParameterTypes().length != 1) { - continue; - } - if (Utility.contains(setter.getExceptionTypes(), throwPredicate)) { - continue; // setter方法带有非RuntimeException异常 - } - if (!setter.getName().startsWith("set")) { - continue; - } - String sfname = Utility.readFieldName(setter.getName()); - if (sfname.isEmpty()) { - continue; - } - if (srcColumnPredicate != null && !srcColumnPredicate.test(setter, sfname)) { - ingoreCount++; - continue; - } - final String dfname = nameAlias == null ? sfname : nameAlias.getOrDefault(sfname, sfname); - if (!Objects.equals(sfname, dfname)) { - destNewNames.put(sfname, dfname); - } - elements.put(dfname, setter); - } - } else { // JavaBean -> Map/JavaBean - for (java.lang.reflect.Field field : srcClass.getFields()) { - if (Modifier.isStatic(field.getModifiers())) { - continue; - } - if (Modifier.isFinal(field.getModifiers())) { - continue; - } - if (!Modifier.isPublic(field.getModifiers())) { - continue; - } - final String sfname = field.getName(); - if (srcColumnPredicate != null && !srcColumnPredicate.test(field, sfname)) { - ingoreCount++; - continue; - } - final String dfname = nameAlias == null ? sfname : nameAlias.getOrDefault(sfname, sfname); - if (!Objects.equals(sfname, dfname)) { - destNewNames.put(sfname, dfname); - } - elements.put(sfname, field); - } - for (java.lang.reflect.Method getter : srcClass.getMethods()) { - if (Modifier.isStatic(getter.getModifiers())) { - continue; - } - if (getter.getParameterTypes().length > 0) { - continue; - } - if ("getClass".equals(getter.getName())) { - continue; - } - if (Utility.contains(getter.getExceptionTypes(), throwPredicate)) { - continue; // setter方法带有非RuntimeException异常 - } - if (!getter.getName().startsWith("get") && !getter.getName().startsWith("is")) { - continue; - } - final String sfname = Utility.readFieldName(getter.getName()); - if (sfname.isEmpty()) { - continue; - } - if (srcColumnPredicate != null && !srcColumnPredicate.test(getter, sfname)) { - ingoreCount++; - continue; - } - final String dfname = nameAlias == null ? sfname : nameAlias.getOrDefault(sfname, sfname); - if (!Objects.equals(sfname, dfname)) { - destNewNames.put(sfname, dfname); - } - elements.put(sfname, getter); - } - } - StringBuilder extendInfo = new StringBuilder(); - if (ingoreCount > 0 || nameAlias != null) { - if (ingoreCount > 0) { - extendInfo.append(elements.keySet().stream().collect(Collectors.joining(","))); - } - if (nameAlias != null) { - if (extendInfo.length() > 0) { - extendInfo.append(";"); - } - destNewNames.forEach((k, v) -> extendInfo.append(k).append(':').append(v)); - } - } - // ------------------------------------------------------------------------------ - final String supDynName = Copier.class.getName().replace('.', '/'); - final String destClassName = destClass.getName().replace('.', '/'); - final String srcClassName = srcClass.getName().replace('.', '/'); - final String destDesc = Type.getDescriptor(destClass); - final String srcDesc = Type.getDescriptor(srcClass); - final ClassLoader loader = Thread.currentThread().getContextClassLoader(); - final String utilClassName = Utility.class.getName().replace('.', '/'); - final String newDynName = "org/redkaledyn/copier/_Dyn" + Copier.class.getSimpleName() + "_" + options - + "__" + srcClass.getName().replace('.', '_').replace('$', '_') - + (srcClass == destClass - ? "" - : ("__" + destClass.getName().replace('.', '_').replace('$', '_'))) - + (extendInfo.length() == 0 ? "" : Utility.md5Hex(extendInfo.toString())); - try { - Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.')); - return (Copier) (clz == null ? loader.loadClass(newDynName.replace('/', '.')) : clz) - .getDeclaredConstructor() - .newInstance(); - } catch (Throwable ex) { - // do nothing - } - - // ------------------------------------------------------------------------------ - ClassWriter cw = new ClassWriter(COMPUTE_FRAMES); - FieldVisitor fv; - MethodVisitor mv; - AnnotationVisitor av0; - - cw.visit( - V11, - ACC_PUBLIC + ACC_FINAL + ACC_SUPER, - newDynName, - "Ljava/lang/Object;L" + supDynName + "<" + srcDesc + destDesc + ">;", - "java/lang/Object", - new String[] {supDynName}); - - { // 构造函数 - mv = (cw.visitMethod(ACC_PUBLIC, "", "()V", null, null)); - // mv.setDebug(true); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); - mv.visitInsn(RETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - if (srcIsMap) { // Map -> JavaBean - { - mv = (cw.visitMethod(ACC_PUBLIC, "apply", "(" + srcDesc + destDesc + ")" + destDesc, null, null)); - // mv.setDebug(true); - { - // if(src == null) return null; - mv.visitVarInsn(ALOAD, 1); - Label ifLabel = new Label(); - mv.visitJumpInsn(IFNONNULL, ifLabel); - mv.visitVarInsn(ALOAD, 2); - mv.visitInsn(ARETURN); - mv.visitLabel(ifLabel); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - } - - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(ALOAD, 2); - mv.visitInvokeDynamicInsn( - "accept", - "(" + destDesc + ")Ljava/util/function/BiConsumer;", - new Handle( - Opcodes.H_INVOKESTATIC, - "java/lang/invoke/LambdaMetafactory", - "metafactory", - "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;", - false), - new Object[] { - Type.getType("(Ljava/lang/Object;Ljava/lang/Object;)V"), - new Handle( - Opcodes.H_INVOKESTATIC, - newDynName, - "lambda$0", - "(" + destDesc + "Ljava/lang/Object;Ljava/lang/Object;)V", - false), - Type.getType("(Ljava/lang/Object;Ljava/lang/Object;)V") - }); - mv.visitMethodInsn( - srcClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, - srcClassName, - "forEach", - "(Ljava/util/function/BiConsumer;)V", - srcClass.isInterface()); - mv.visitVarInsn(ALOAD, 2); - mv.visitInsn(ARETURN); - mv.visitMaxs(2, 3); - mv.visitEnd(); - } - { - mv = cw.visitMethod( - ACC_PRIVATE + ACC_STATIC + ACC_SYNTHETIC, - "lambda$0", - "(" + destDesc + "Ljava/lang/Object;Ljava/lang/Object;)V", - null, - null); - Label goLabel = new Label(); - int i = 0; - for (Map.Entry en : elements.entrySet()) { - final int index = ++i; - final java.lang.reflect.Type fieldType = en.getValue() instanceof Field - ? ((Field) en.getValue()).getGenericType() - : ((Method) en.getValue()).getGenericParameterTypes()[0]; - final Class fieldClass = en.getValue() instanceof Field - ? ((Field) en.getValue()).getType() - : ((Method) en.getValue()).getParameterTypes()[0]; - final boolean primitive = fieldClass.isPrimitive(); - final boolean charstr = CharSequence.class.isAssignableFrom(fieldClass); - - mv.visitLdcInsn(en.getKey()); - mv.visitVarInsn(ALOAD, 1); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z", false); - Label ifeq = index == elements.size() ? goLabel : new Label(); - mv.visitJumpInsn(IFEQ, ifeq); - if (skipNullValue || primitive) { - mv.visitVarInsn(ALOAD, 2); - mv.visitJumpInsn(IFNULL, ifeq); - } else if (skipEmptyString && charstr) { - mv.visitVarInsn(ALOAD, 2); - mv.visitJumpInsn(IFNULL, ifeq); - mv.visitVarInsn(ALOAD, 2); - mv.visitTypeInsn(INSTANCEOF, "java/lang/CharSequence"); - mv.visitJumpInsn(IFEQ, ifeq); - mv.visitVarInsn(ALOAD, 2); - mv.visitTypeInsn(CHECKCAST, "java/lang/CharSequence"); - mv.visitMethodInsn(INVOKEINTERFACE, "java/lang/CharSequence", "length", "()I", true); - mv.visitJumpInsn(IFLE, ifeq); - } - - mv.visitVarInsn(ALOAD, 0); - Asms.visitFieldInsn(mv, fieldClass); - - mv.visitVarInsn(ALOAD, 2); - mv.visitMethodInsn( - INVOKESTATIC, - utilClassName, - "convertValue", - "(Ljava/lang/reflect/Type;Ljava/lang/Object;)Ljava/lang/Object;", - false); - Asms.visitCheckCast(mv, fieldClass); - - if (en.getValue() instanceof Field) { - mv.visitFieldInsn(PUTFIELD, destClassName, en.getKey(), Type.getDescriptor(fieldClass)); - } else { - Method setter = (Method) en.getValue(); - mv.visitMethodInsn( - destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, - destClassName, - setter.getName(), - Type.getMethodDescriptor(setter), - destClass.isInterface()); - } - if (index == elements.size()) { - mv.visitLabel(goLabel); - } else { - mv.visitJumpInsn(GOTO, goLabel); - mv.visitLabel(ifeq); - } - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - } - - mv.visitInsn(RETURN); - mv.visitMaxs(3, 3); - mv.visitEnd(); - } - } else { // JavaBean -> Map/JavaBean - mv = (cw.visitMethod(ACC_PUBLIC, "apply", "(" + srcDesc + destDesc + ")" + destDesc, null, null)); - // mv.setDebug(true); - { - // if(src == null) return null; - mv.visitVarInsn(ALOAD, 1); - Label ifLabel = new Label(); - mv.visitJumpInsn(IFNONNULL, ifLabel); - mv.visitVarInsn(ALOAD, 2); - mv.visitInsn(ARETURN); - mv.visitLabel(ifLabel); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - } - - Predicate simpler = t -> t.isPrimitive() || t == String.class || Number.class.isAssignableFrom(t); - // 遍历所有字段 - for (Map.Entry en : elements.entrySet()) { - if (!(en.getValue() instanceof java.lang.reflect.Field)) { - continue; - } - java.lang.reflect.Field field = (java.lang.reflect.Field) en.getValue(); - final String sfname = en.getKey(); - - final String dfname = destNewNames.getOrDefault(sfname, sfname); - final Class srcFieldType = field.getType(); - final boolean charstr = CharSequence.class.isAssignableFrom(srcFieldType); - if (destIsMap) { // JavaBean -> Map - String td = Type.getDescriptor(srcFieldType); - if ((!skipNullValue && !(skipEmptyString && charstr)) || srcFieldType.isPrimitive()) { - mv.visitVarInsn(ALOAD, 2); - mv.visitLdcInsn(dfname); - mv.visitVarInsn(ALOAD, 1); - mv.visitFieldInsn(GETFIELD, srcClassName, sfname, td); - Asms.visitPrimitiveValueOf(mv, srcFieldType); - mv.visitMethodInsn( - destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, - destClassName, - "put", - "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", - destClass.isInterface()); - mv.visitInsn(POP); - } else { // skipNullValue OR (skipEmptyString && charstr) - mv.visitVarInsn(ALOAD, 1); - mv.visitFieldInsn(GETFIELD, srcClassName, sfname, td); - mv.visitVarInsn(ASTORE, 3); - mv.visitVarInsn(ALOAD, 3); - Label ifLabel = new Label(); - mv.visitJumpInsn(IFNULL, ifLabel); - if (skipEmptyString && charstr) { - mv.visitVarInsn(ALOAD, 3); - mv.visitTypeInsn(CHECKCAST, "java/lang/CharSequence"); - mv.visitMethodInsn(INVOKEINTERFACE, "java/lang/CharSequence", "length", "()I", true); - mv.visitJumpInsn(IFLE, ifLabel); - } - mv.visitVarInsn(ALOAD, 2); - mv.visitLdcInsn(dfname); - mv.visitVarInsn(ALOAD, 3); - mv.visitMethodInsn( - destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, - destClassName, - "put", - "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", - destClass.isInterface()); - mv.visitInsn(POP); - mv.visitLabel(ifLabel); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - } - } else { // JavaBean -> JavaBean - boolean needTypeCast = false; - java.lang.reflect.Method setter = null; - java.lang.reflect.Field setField = null; - try { - setField = destClass.getField(dfname); - if (field.getType() == setField.getType()) { - needTypeCast = false; - } else if (simpler.test(field.getType()) && simpler.test(setField.getType())) { - needTypeCast = true; - } else if (!field.getType().equals(setField.getType())) { - if (allowTypeCast) { - needTypeCast = true; - } else { - continue; - } - } - } catch (Exception e) { - String setterMethodName = "set" + Utility.firstCharUpperCase(dfname); - try { - setter = destClass.getMethod(setterMethodName, field.getType()); - if (Utility.contains(setter.getExceptionTypes(), throwPredicate)) { - continue; // setter方法带有非RuntimeException异常 - } - } catch (Exception e2) { - try { - for (java.lang.reflect.Method m : destClass.getMethods()) { - if (Modifier.isStatic(m.getModifiers())) { - continue; - } - if (Utility.contains(m.getExceptionTypes(), throwPredicate)) { - continue; // setter方法带有非RuntimeException异常 - } - if (m.getParameterTypes().length != 1) { - continue; - } - if (m.getName().equals(setterMethodName)) { - if (simpler.test(field.getType()) && simpler.test(setField.getType())) { - setter = m; - needTypeCast = true; - } else if (!allowTypeCast) { - setter = null; - } - break; - } - } - if (setter == null) { - continue; - } - } catch (Exception e3) { - continue; - } - } - } - String srcFieldDesc = Type.getDescriptor(srcFieldType); - final Class destFieldType = setter == null ? setField.getType() : setter.getParameterTypes()[0]; - boolean localSkipNull = - skipNullValue || (!srcFieldType.isPrimitive() && destFieldType.isPrimitive()); - if ((!localSkipNull && !(skipEmptyString && charstr)) - || (srcFieldType.isPrimitive() && !allowTypeCast) - || (srcFieldType.isPrimitive() && destFieldType.isPrimitive())) { - if (needTypeCast) { - mv.visitVarInsn(ALOAD, 2); - Asms.visitFieldInsn(mv, destFieldType); - mv.visitVarInsn(ALOAD, 1); - mv.visitFieldInsn(GETFIELD, srcClassName, sfname, srcFieldDesc); - Asms.visitPrimitiveValueOf(mv, srcFieldType); - mv.visitMethodInsn( - INVOKESTATIC, - utilClassName, - "convertValue", - "(Ljava/lang/reflect/Type;Ljava/lang/Object;)Ljava/lang/Object;", - false); - Asms.visitCheckCast(mv, destFieldType); - if (setter == null) { // src: field, dest: field - mv.visitFieldInsn(PUTFIELD, destClassName, dfname, Type.getDescriptor(destFieldType)); - } else { // src: field, dest: method - mv.visitMethodInsn( - destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, - destClassName, - setter.getName(), - Type.getMethodDescriptor(setter), - destClass.isInterface()); - if (setter.getReturnType() != void.class) { - mv.visitInsn(POP); - } - } - } else { - mv.visitVarInsn(ALOAD, 2); - mv.visitVarInsn(ALOAD, 1); - mv.visitFieldInsn(GETFIELD, srcClassName, sfname, srcFieldDesc); - if (setter == null) { // src: field, dest: field - mv.visitFieldInsn(PUTFIELD, destClassName, dfname, Type.getDescriptor(destFieldType)); - } else { // src: field, dest: method - mv.visitMethodInsn( - destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, - destClassName, - setter.getName(), - Type.getMethodDescriptor(setter), - destClass.isInterface()); - if (setter.getReturnType() != void.class) { - mv.visitInsn(POP); - } - } - } - } else { // skipNullValue OR (skipEmptyString && charstr) - mv.visitVarInsn(ALOAD, 1); - mv.visitFieldInsn(GETFIELD, srcClassName, sfname, srcFieldDesc); - mv.visitVarInsn(ASTORE, 3); - mv.visitVarInsn(ALOAD, 3); - Label ifLabel = new Label(); - mv.visitJumpInsn(IFNULL, ifLabel); - if (skipEmptyString && charstr) { - mv.visitVarInsn(ALOAD, 3); - mv.visitTypeInsn(CHECKCAST, "java/lang/CharSequence"); - mv.visitMethodInsn(INVOKEINTERFACE, "java/lang/CharSequence", "length", "()I", true); - mv.visitJumpInsn(IFLE, ifLabel); - } - if (needTypeCast) { - mv.visitVarInsn(ALOAD, 2); - Asms.visitFieldInsn(mv, destFieldType); - mv.visitVarInsn(ALOAD, 3); - Asms.visitPrimitiveValueOf(mv, srcFieldType); - mv.visitMethodInsn( - INVOKESTATIC, - utilClassName, - "convertValue", - "(Ljava/lang/reflect/Type;Ljava/lang/Object;)Ljava/lang/Object;", - false); - Asms.visitCheckCast(mv, destFieldType); - if (setter == null) { // src: field, dest: field - mv.visitFieldInsn(PUTFIELD, destClassName, dfname, Type.getDescriptor(destFieldType)); - } else { // src: field, dest: method - mv.visitMethodInsn( - destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, - destClassName, - setter.getName(), - Type.getMethodDescriptor(setter), - destClass.isInterface()); - if (setter.getReturnType() != void.class) { - mv.visitInsn(POP); - } - } - } else { - mv.visitVarInsn(ALOAD, 2); - mv.visitVarInsn(ALOAD, 3); - mv.visitTypeInsn(CHECKCAST, srcFieldType.getName().replace('.', '/')); - if (setter == null) { // src: field, dest: field - mv.visitFieldInsn(PUTFIELD, destClassName, dfname, srcFieldDesc); - } else { // src: field, dest: method - mv.visitMethodInsn( - destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, - destClassName, - setter.getName(), - Type.getMethodDescriptor(setter), - destClass.isInterface()); - if (setter.getReturnType() != void.class) { - mv.visitInsn(POP); - } - } - } - mv.visitLabel(ifLabel); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - } - } - } - // 遍历所有方法 - for (Map.Entry en : elements.entrySet()) { - if (!(en.getValue() instanceof java.lang.reflect.Method)) { - continue; - } - java.lang.reflect.Method getter = (java.lang.reflect.Method) en.getValue(); - final String sfname = en.getKey(); - - final String dfname = destNewNames.getOrDefault(sfname, sfname); - final Class srcFieldType = getter.getReturnType(); - final boolean charstr = CharSequence.class.isAssignableFrom(srcFieldType); - if (destIsMap) { // srcClass是JavaBean - if ((!skipNullValue && !(skipEmptyString && charstr)) || srcFieldType.isPrimitive()) { - mv.visitVarInsn(ALOAD, 2); - mv.visitLdcInsn(dfname); - mv.visitVarInsn(ALOAD, 1); - mv.visitMethodInsn( - srcClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, - srcClassName, - getter.getName(), - Type.getMethodDescriptor(getter), - srcClass.isInterface()); - Asms.visitPrimitiveValueOf(mv, srcFieldType); - mv.visitMethodInsn( - destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, - destClassName, - "put", - "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", - destClass.isInterface()); - mv.visitInsn(POP); - } else { // skipNullValue OR (skipEmptyString && charstr) - mv.visitVarInsn(ALOAD, 1); - mv.visitMethodInsn( - srcClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, - srcClassName, - getter.getName(), - Type.getMethodDescriptor(getter), - srcClass.isInterface()); - mv.visitVarInsn(ASTORE, 3); - mv.visitVarInsn(ALOAD, 3); - Label ifLabel = new Label(); - mv.visitJumpInsn(IFNULL, ifLabel); - if (skipEmptyString && charstr) { - mv.visitVarInsn(ALOAD, 3); - mv.visitTypeInsn(CHECKCAST, "java/lang/CharSequence"); - mv.visitMethodInsn(INVOKEINTERFACE, "java/lang/CharSequence", "length", "()I", true); - mv.visitJumpInsn(IFLE, ifLabel); - } - mv.visitVarInsn(ALOAD, 2); - mv.visitLdcInsn(dfname); - mv.visitVarInsn(ALOAD, 3); - mv.visitMethodInsn( - destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, - destClassName, - "put", - "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", - destClass.isInterface()); - mv.visitInsn(POP); - mv.visitLabel(ifLabel); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - } - } else { // srcClass、destClass是JavaBean - boolean needTypeCast = false; - java.lang.reflect.Method setter = null; - java.lang.reflect.Field setField = null; - String setterMethodName = "set" + Utility.firstCharUpperCase(dfname); - try { - setter = destClass.getMethod(setterMethodName, getter.getReturnType()); - if (Utility.contains(setter.getExceptionTypes(), throwPredicate)) { - continue; // setter方法带有非RuntimeException异常 - } - } catch (Exception e) { - if (allowTypeCast) { - try { - for (java.lang.reflect.Method m : destClass.getMethods()) { - if (Modifier.isStatic(m.getModifiers())) { - continue; - } - if (Utility.contains(m.getExceptionTypes(), throwPredicate)) { - continue; // setter方法带有非RuntimeException异常 - } - if (m.getParameterTypes().length != 1) { - continue; - } - if (m.getName().equals(setterMethodName)) { - setter = m; - needTypeCast = true; - break; - } - } - } catch (Exception e2) { - // do nothing - } - } - if (setter == null) { - try { - setField = destClass.getField(dfname); - if (!getter.getReturnType().equals(setField.getType())) { - if (allowTypeCast) { - needTypeCast = true; - } else { - continue; - } - } - } catch (Exception e3) { - continue; - } - } - } - final Class destFieldType = setter == null ? setField.getType() : setter.getParameterTypes()[0]; - boolean localSkipNull = - skipNullValue || (!srcFieldType.isPrimitive() && destFieldType.isPrimitive()); - if ((!localSkipNull && !(skipEmptyString && charstr)) - || (srcFieldType.isPrimitive() && !allowTypeCast) - || (srcFieldType.isPrimitive() && destFieldType.isPrimitive())) { - if (needTypeCast) { - mv.visitVarInsn(ALOAD, 2); - Asms.visitFieldInsn(mv, destFieldType); - mv.visitVarInsn(ALOAD, 1); - mv.visitMethodInsn( - srcClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, - srcClassName, - getter.getName(), - Type.getMethodDescriptor(getter), - srcClass.isInterface()); - Asms.visitPrimitiveValueOf(mv, srcFieldType); - mv.visitMethodInsn( - INVOKESTATIC, - utilClassName, - "convertValue", - "(Ljava/lang/reflect/Type;Ljava/lang/Object;)Ljava/lang/Object;", - false); - Asms.visitCheckCast(mv, destFieldType); - if (setter == null) { // src: method, dest: field - mv.visitFieldInsn(PUTFIELD, destClassName, dfname, Type.getDescriptor(destFieldType)); - } else { // src: method, dest: method - mv.visitMethodInsn( - destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, - destClassName, - setter.getName(), - Type.getMethodDescriptor(setter), - destClass.isInterface()); - if (setter.getReturnType() != void.class) { - mv.visitInsn(POP); - } - } - } else { - mv.visitVarInsn(ALOAD, 2); - mv.visitVarInsn(ALOAD, 1); - mv.visitMethodInsn( - srcClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, - srcClassName, - getter.getName(), - Type.getMethodDescriptor(getter), - srcClass.isInterface()); - if (setter == null) { // src: method, dest: field - mv.visitFieldInsn(PUTFIELD, destClassName, dfname, Type.getDescriptor(destFieldType)); - } else { // src: method, dest: method - mv.visitMethodInsn( - destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, - destClassName, - setter.getName(), - Type.getMethodDescriptor(setter), - destClass.isInterface()); - if (setter.getReturnType() != void.class) { - mv.visitInsn(POP); - } - } - } - } else { // skipNullValue OR (skipEmptyString && charstr) - mv.visitVarInsn(ALOAD, 1); - mv.visitMethodInsn( - srcClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, - srcClassName, - getter.getName(), - Type.getMethodDescriptor(getter), - srcClass.isInterface()); - mv.visitVarInsn(ASTORE, 3); - mv.visitVarInsn(ALOAD, 3); - Label ifLabel = new Label(); - mv.visitJumpInsn(IFNULL, ifLabel); - if (skipEmptyString && charstr) { - mv.visitVarInsn(ALOAD, 3); - mv.visitTypeInsn(CHECKCAST, "java/lang/CharSequence"); - mv.visitMethodInsn(INVOKEINTERFACE, "java/lang/CharSequence", "length", "()I", true); - mv.visitJumpInsn(IFLE, ifLabel); - } - if (needTypeCast) { - mv.visitVarInsn(ALOAD, 2); - Asms.visitFieldInsn(mv, destFieldType); - mv.visitVarInsn(ALOAD, 3); - Asms.visitPrimitiveValueOf(mv, srcFieldType); - mv.visitMethodInsn( - INVOKESTATIC, - utilClassName, - "convertValue", - "(Ljava/lang/reflect/Type;Ljava/lang/Object;)Ljava/lang/Object;", - false); - Asms.visitCheckCast(mv, destFieldType); - if (setter == null) { // src: method, dest: field - mv.visitFieldInsn(PUTFIELD, destClassName, dfname, Type.getDescriptor(destFieldType)); - } else { // src: method, dest: method - mv.visitMethodInsn( - destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, - destClassName, - setter.getName(), - Type.getMethodDescriptor(setter), - destClass.isInterface()); - if (setter.getReturnType() != void.class) { - mv.visitInsn(POP); - } - } - } else { - mv.visitVarInsn(ALOAD, 2); - mv.visitVarInsn(ALOAD, 3); - mv.visitTypeInsn(CHECKCAST, srcFieldType.getName().replace('.', '/')); - if (setter == null) { // src: method, dest: field - mv.visitFieldInsn( - PUTFIELD, destClassName, dfname, Type.getDescriptor(getter.getReturnType())); - } else { // src: method, dest: method - mv.visitMethodInsn( - destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, - destClassName, - setter.getName(), - Type.getMethodDescriptor(setter), - destClass.isInterface()); - if (setter.getReturnType() != void.class) { - mv.visitInsn(POP); - } - } - } - mv.visitLabel(ifLabel); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - } - } - } - mv.visitVarInsn(ALOAD, 2); - mv.visitInsn(ARETURN); - mv.visitMaxs(3, 3); - mv.visitEnd(); - } - { - mv = (cw.visitMethod( - ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC, - "apply", - "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", - null, - null)); - // mv.setDebug(true); - mv.visitVarInsn(ALOAD, 0); - mv.visitVarInsn(ALOAD, 1); - mv.visitTypeInsn(CHECKCAST, srcClassName); - mv.visitVarInsn(ALOAD, 2); - mv.visitTypeInsn(CHECKCAST, destClassName); - mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "apply", "(" + srcDesc + destDesc + ")" + destDesc, false); - mv.visitInsn(ARETURN); - mv.visitMaxs(3, 3); - mv.visitEnd(); - } - cw.visitEnd(); - // ------------------------------------------------------------------------------ - byte[] bytes = cw.toByteArray(); - Class newClazz = new ClassLoader(loader) { - public final Class loadClass(String name, byte[] b) { - return defineClass(name, b, 0, b.length); - } - }.loadClass(newDynName.replace('/', '.'), bytes); - RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, newClazz); - RedkaleClassLoader.putReflectionDeclaredConstructors(newClazz, newDynName.replace('/', '.')); - try { - return (Copier) newClazz.getDeclaredConstructor().newInstance(); - } catch (Exception ex) { - throw new RedkaleException(ex); - } - } -} +/* + * + */ +package org.redkale.util; + +import static org.redkale.asm.ClassWriter.COMPUTE_FRAMES; +import static org.redkale.asm.Opcodes.*; + +import java.lang.reflect.*; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.*; +import java.util.stream.Collectors; +import org.redkale.asm.*; +import org.redkale.asm.Type; + +/** + * JavaBean类对象的拷贝,相同的字段名会被拷贝
+ * + *

详情见: https://redkale.org + * + * @author zhangjx + * @param 目标对象的数据类型 + * @param 源对象的数据类型 + * @since 2.8.0 + */ +public interface Copier extends BiFunction { + + /** 是否跳过值为null的字段 */ + public static final int OPTION_SKIP_NULL_VALUE = 1 << 1; // 2 + + /** 是否跳过值为空字符串的字段 */ + public static final int OPTION_SKIP_EMPTY_STRING = 1 << 2; // 4 + + /** 同名字段类型强制转换 */ + public static final int OPTION_ALLOW_TYPE_CAST = 1 << 3; // 8 + + /** + * 将源对象字段复制到目标对象 + * + * @param dest 目标对象 + * @param src 源对象 + * @return 目标对象 + */ + @Override + public D apply(S src, D dest); + + /** + * 将源对象字段复制到目标对象 + * + * @param 目标类泛型 + * @param 源类泛型 + * @param dest 目标对象 + * @param src 源对象 + * @return 目标对象 + */ + public static D copy(final S src, final D dest) { + return copy(src, dest, 0); + } + + /** + * 将源对象字段复制到目标对象 + * + * @param 目标类泛型 + * @param 源类泛型 + * @param dest 目标对象 + * @param src 源对象 + * @param options 可配项 + * @return 目标对象 + */ + public static D copy(final S src, final D dest, final int options) { + if (src == null || dest == null) { + return dest; + } + return load((Class) src.getClass(), (Class) dest.getClass(), options) + .apply(src, dest); + } + + /** + * 将源对象字段复制到目标对象 + * + * @param 目标类泛型 + * @param 源类泛型 + * @param destClass 目标类名 + * @param src 源对象 + * @return 目标对象 + */ + public static D copy(final S src, final Class destClass) { + return copy(src, destClass, 0); + } + + /** + * 将源对象字段复制到目标对象 + * + * @param 目标类泛型 + * @param 源类泛型 + * @param destClass 目标类名 + * @param src 源对象 + * @param options 可配项 + * @return 目标对象 + */ + public static D copy(final S src, final Class destClass, final int options) { + if (src == null) { + return null; + } + Creator creator = Creator.load(destClass); + return load((Class) src.getClass(), destClass, options).apply(src, creator.create()); + } + + /** + * 将源对象字段复制到目标对象 + * + * @param 源类泛型 + * @param src 源对象 + * @param options 可配项 + * @return 目标对象 + */ + public static Map copyToMap(final S src, final int options) { + if (src == null) { + return null; + } + HashMap dest = new HashMap(); + return load((Class) src.getClass(), HashMap.class, options).apply(src, dest); + } + + /** + * 创建源类到目标类的复制器并缓存 + * + * @param 目标类泛型 + * @param 源类泛型 + * @param destClass 目标类名 + * @param srcClass 源类名 + * @return 复制器 + */ + public static Function func(final Class srcClass, final Class destClass) { + return func(srcClass, destClass, 0); + } + + /** + * 创建源类到目标类的复制器并缓存 + * + * @param 目标类泛型 + * @param 源类泛型 + * @param destClass 目标类名 + * @param srcClass 源类名 + * @return 复制器 + */ + public static Function, Set> funcSet(final Class srcClass, final Class destClass) { + return funcSet(srcClass, destClass, 0); + } + + /** + * 创建源类到目标类的复制器并缓存 + * + * @param 目标类泛型 + * @param 源类泛型 + * @param destClass 目标类名 + * @param srcClass 源类名 + * @return 复制器 + */ + public static Function, List> funcList(final Class srcClass, final Class destClass) { + return funcList(srcClass, destClass, 0); + } + + /** + * 创建源类到目标类的复制器并缓存 + * + * @param 目标类泛型 + * @param 源类泛型 + * @param 集合泛型 + * @param destClass 目标类名 + * @param srcClass 源类名 + * @param collectionClass 集合类名 + * @return 复制器 + */ + public static Function, Collection> funcCollection( + final Class srcClass, final Class destClass, final Class collectionClass) { + return funcCollection(srcClass, destClass, 0, collectionClass); + } + + /** + * 创建源类到目标类的复制器并缓存 + * + * @param 目标类泛型 + * @param 源类泛型 + * @param destClass 目标类名 + * @param srcClass 源类名 + * @return 复制器 + */ + public static Copier load(final Class srcClass, final Class destClass) { + return load(srcClass, destClass, 0); + } + + /** + * 创建源类到目标类的复制器并缓存 + * + * @param 目标类泛型 + * @param 源类泛型 + * @param destClass 目标类名 + * @param srcClass 源类名 + * @param options 可配项 + * @return 复制器 + */ + public static Function, Set> funcSet( + final Class srcClass, final Class destClass, final int options) { + return (Function) funcCollection(srcClass, destClass, options, LinkedHashSet.class); + } + + /** + * 创建源类到目标类的复制器并缓存 + * + * @param 目标类泛型 + * @param 源类泛型 + * @param destClass 目标类名 + * @param srcClass 源类名 + * @param options 可配项 + * @return 复制器 + */ + public static Function, List> funcList( + final Class srcClass, final Class destClass, final int options) { + return (Function) funcCollection(srcClass, destClass, options, ArrayList.class); + } + + /** + * 创建源类到目标类的复制器并缓存 + * + * @param 目标类泛型 + * @param 源类泛型 + * @param 集合泛型 + * @param destClass 目标类名 + * @param srcClass 源类名 + * @param options 可配项 + * @param collectionClass 集合类名 + * @return 复制器 + */ + public static Function, Collection> funcCollection( + final Class srcClass, final Class destClass, final int options, final Class collectionClass) { + if (destClass == srcClass) { + return Inners.CopierInner.copierFuncListOneCaches + .computeIfAbsent(collectionClass, t -> new ConcurrentHashMap<>()) + .computeIfAbsent(options, t -> new ConcurrentHashMap<>()) + .computeIfAbsent(srcClass, v -> { + Creator creator = Creator.create(collectionClass); + Function func = func(srcClass, destClass, options); + Function, Collection> funcList = srcs -> { + if (srcs == null) { + return null; + } else if (srcs.isEmpty()) { + return creator.create(); + } else { + C list = creator.create(); + for (S s : srcs) { + list.add(func.apply(s)); + } + return list; + } + }; + return funcList; + }); + } else { + return Inners.CopierInner.copierFuncListTwoCaches + .computeIfAbsent(collectionClass, t -> new ConcurrentHashMap<>()) + .computeIfAbsent(options, t -> new ConcurrentHashMap<>()) + .computeIfAbsent(srcClass, t -> new ConcurrentHashMap<>()) + .computeIfAbsent(destClass, v -> { + Creator creator = Creator.create(collectionClass); + Function func = func(srcClass, destClass, options); + Function, Collection> funcList = srcs -> { + if (srcs == null) { + return null; + } else if (srcs.isEmpty()) { + return (C) creator.create(); + } else { + C list = creator.create(); + for (S s : srcs) { + list.add(func.apply(s)); + } + return list; + } + }; + return funcList; + }); + } + } + + /** + * 创建源类到目标类的复制器并缓存 + * + * @param 目标类泛型 + * @param 源类泛型 + * @param destClass 目标类名 + * @param srcClass 源类名 + * @param options 可配项 + * @return 复制器 + */ + public static Function func(final Class srcClass, final Class destClass, final int options) { + if (destClass == srcClass) { + return Inners.CopierInner.copierFuncOneCaches + .computeIfAbsent(options, t -> new ConcurrentHashMap<>()) + .computeIfAbsent(srcClass, v -> { + Copier copier = load(srcClass, destClass, options); + Creator creator = Creator.load(destClass); + Function func = src -> src == null ? null : copier.apply(src, creator.create()); + return func; + }); + } else { + return Inners.CopierInner.copierFuncTwoCaches + .computeIfAbsent(options, t -> new ConcurrentHashMap<>()) + .computeIfAbsent(srcClass, t -> new ConcurrentHashMap<>()) + .computeIfAbsent(destClass, v -> { + Copier copier = load(srcClass, destClass, options); + Creator creator = Creator.load(destClass); + Function func = src -> src == null ? null : copier.apply(src, creator.create()); + return func; + }); + } + } + + /** + * 创建源类到目标类的复制器并缓存 + * + * @param 目标类泛型 + * @param 源类泛型 + * @param destClass 目标类名 + * @param srcClass 源类名 + * @param options 可配项 + * @return 复制器 + */ + public static Copier load(final Class srcClass, final Class destClass, final int options) { + if (destClass == srcClass) { + return Inners.CopierInner.copierOneCaches + .computeIfAbsent(options, t -> new ConcurrentHashMap<>()) + .computeIfAbsent(srcClass, v -> create(srcClass, destClass, options)); + } else { + return Inners.CopierInner.copierTwoCaches + .computeIfAbsent(options, t -> new ConcurrentHashMap<>()) + .computeIfAbsent(srcClass, t -> new ConcurrentHashMap<>()) + .computeIfAbsent(destClass, v -> create(srcClass, destClass, options)); + } + } + + /** + * 创建源类到目标类的复制器 + * + * @param 目标类泛型 + * @param 源类泛型 + * @param destClass 目标类名 + * @param srcClass 源类名 + * @return 复制器 + */ + public static Copier create(final Class srcClass, final Class destClass) { + return create(srcClass, destClass, (BiPredicate) null, (Map) null); + } + + /** + * 创建源类到目标类的复制器 + * + * @param 目标类泛型 + * @param 源类泛型 + * @param destClass 目标类名 + * @param srcClass 源类名 + * @param names 源字段名与目标字段名的映射关系 + * @return 复制器 + */ + public static Copier create( + final Class srcClass, final Class destClass, final Map names) { + return create(srcClass, destClass, (BiPredicate) null, names); + } + + /** + * 创建源类到目标类的复制器 + * + * @param 目标类泛型 + * @param 源类泛型 + * @param destClass 目标类名 + * @param srcClass 源类名 + * @param srcColumnPredicate 需复制源类的字段名判断器 + * @return 复制器 + */ + @SuppressWarnings("unchecked") + public static Copier create( + final Class srcClass, final Class destClass, final Predicate srcColumnPredicate) { + return create(srcClass, destClass, (sc, m) -> srcColumnPredicate.test(m), (Map) null); + } + + /** + * 创建源类到目标类的复制器 + * + * @param 目标类泛型 + * @param 源类泛型 + * @param destClass 目标类名 + * @param srcClass 源类名 + * @param srcColumnPredicate 需复制源类的字段名判断器 + * @param names 源字段名与目标字段名的映射关系 + * @return 复制器 + */ + @SuppressWarnings("unchecked") + public static Copier create( + final Class srcClass, + final Class destClass, + final Predicate srcColumnPredicate, + final Map names) { + return create(srcClass, destClass, (sc, m) -> srcColumnPredicate.test(m), names); + } + + /** + * 创建源类到目标类的复制器 + * + * @param 目标类泛型 + * @param 源类泛型 + * @param destClass 目标类名 + * @param srcClass 源类名 + * @param srcColumnPredicate 需复制源类的字段名判断器 + * @return 复制器 + */ + @SuppressWarnings("unchecked") + public static Copier create( + final Class srcClass, + final Class destClass, + final BiPredicate srcColumnPredicate) { + return create(srcClass, destClass, srcColumnPredicate, (Map) null); + } + + /** + * 创建源类到目标类的复制器 + * + * @param 目标类泛型 + * @param 源类泛型 + * @param destClass 目标类名 + * @param srcClass 源类名 + * @param srcColumnPredicate 需复制源类的字段名判断器 + * @param names 源字段名与目标字段名的映射关系 + * @return 复制器 + */ + @SuppressWarnings("unchecked") + public static Copier create( + final Class srcClass, + final Class destClass, + final BiPredicate srcColumnPredicate, + final Map names) { + return create(srcClass, destClass, 0, srcColumnPredicate, names); + } + + /** + * 创建源类到目标类的复制器 + * + * @param 目标类泛型 + * @param 源类泛型 + * @param destClass 目标类名 + * @param srcClass 源类名 + * @param options 可配项 + * @return 复制器 + */ + @SuppressWarnings("unchecked") + public static Copier create(final Class srcClass, final Class destClass, final int options) { + return create(srcClass, destClass, options, (BiPredicate) null, (Map) null); + } + + /** + * 创建源类到目标类的复制器 + * + * @param 目标类泛型 + * @param 源类泛型 + * @param destClass 目标类名 + * @param srcClass 源类名 + * @param options 可配项 + * @param srcColumnPredicate 需复制源类的字段名判断器 + * @param nameAlias 源字段名与目标字段名的映射关系 + * @return 复制器 + */ + @SuppressWarnings("unchecked") + public static Copier create( + final Class srcClass, + final Class destClass, + final int options, + final BiPredicate srcColumnPredicate, + final Map nameAlias) { + final boolean skipNullValue = + (options & OPTION_SKIP_NULL_VALUE) > 0 || ConcurrentHashMap.class.isAssignableFrom(destClass); + final boolean skipEmptyString = (options & OPTION_SKIP_EMPTY_STRING) > 0; + final boolean allowTypeCast = (options & OPTION_ALLOW_TYPE_CAST) > 0; + final Predicate valPredicate = v -> !(skipNullValue && v == null) + && !(skipEmptyString && v instanceof CharSequence && ((CharSequence) v).length() == 0); + + if (Map.class.isAssignableFrom(destClass) && Map.class.isAssignableFrom(srcClass)) { + final Map names0 = nameAlias; + if (srcColumnPredicate != null) { + if (nameAlias != null) { + return (S src, D dest) -> { + if (src == null) { + return dest; + } + Map d = (Map) dest; + ((Map) src).forEach((k, v) -> { + if (srcColumnPredicate.test(null, k.toString()) && valPredicate.test(v)) { + d.put(names0.getOrDefault(k, k), v); + } + }); + return dest; + }; + } else { + return (S src, D dest) -> { + if (src == null) { + return dest; + } + Map d = (Map) dest; + ((Map) src).forEach((k, v) -> { + if (srcColumnPredicate.test(null, k.toString()) && valPredicate.test(v)) { + d.put(k, v); + } + }); + return dest; + }; + } + } else if (nameAlias != null) { + return (S src, D dest) -> { + if (src == null) { + return dest; + } + Map d = (Map) dest; + ((Map) src).forEach((k, v) -> { + if (valPredicate.test(v)) { + d.put(names0.getOrDefault(k, k), v); + } + }); + return dest; + }; + } + return new Copier() { + @Override + public D apply(S src, D dest) { + if (src == null) { + return dest; + } + if (options == 0) { + ((Map) dest).putAll((Map) src); + } else { + Map d = (Map) dest; + ((Map) src).forEach((k, v) -> { + if (valPredicate.test(v)) { + d.put(k, v); + } + }); + } + return dest; + } + }; + } + // ------------------------------------------------------------------------------ + final boolean destIsMap = Map.class.isAssignableFrom(destClass); + final boolean srcIsMap = Map.class.isAssignableFrom(srcClass); + final Predicate> throwPredicate = e -> !RuntimeException.class.isAssignableFrom(e); + final Map elements = new TreeMap<>(); + final Map destNewNames = new TreeMap<>(); + int ingoreCount = 0; + if (srcIsMap) { // Map -> JavaBean + for (java.lang.reflect.Field field : destClass.getFields()) { + if (Modifier.isStatic(field.getModifiers())) { + continue; + } + if (Modifier.isFinal(field.getModifiers())) { + continue; + } + if (!Modifier.isPublic(field.getModifiers())) { + continue; + } + final String sfname = field.getName(); + if (srcColumnPredicate != null && !srcColumnPredicate.test(field, sfname)) { + ingoreCount++; + continue; + } + final String dfname = nameAlias == null ? sfname : nameAlias.getOrDefault(sfname, sfname); + if (!Objects.equals(sfname, dfname)) { + destNewNames.put(sfname, dfname); + } + elements.put(dfname, field); + } + + for (java.lang.reflect.Method setter : destClass.getMethods()) { + if (Modifier.isStatic(setter.getModifiers())) { + continue; + } + if (setter.getParameterTypes().length != 1) { + continue; + } + if (Utility.contains(setter.getExceptionTypes(), throwPredicate)) { + continue; // setter方法带有非RuntimeException异常 + } + if (!setter.getName().startsWith("set")) { + continue; + } + String sfname = Utility.readFieldName(setter.getName()); + if (sfname.isEmpty()) { + continue; + } + if (srcColumnPredicate != null && !srcColumnPredicate.test(setter, sfname)) { + ingoreCount++; + continue; + } + final String dfname = nameAlias == null ? sfname : nameAlias.getOrDefault(sfname, sfname); + if (!Objects.equals(sfname, dfname)) { + destNewNames.put(sfname, dfname); + } + elements.put(dfname, setter); + } + } else { // JavaBean -> Map/JavaBean + for (java.lang.reflect.Field field : srcClass.getFields()) { + if (Modifier.isStatic(field.getModifiers())) { + continue; + } + if (Modifier.isFinal(field.getModifiers())) { + continue; + } + if (!Modifier.isPublic(field.getModifiers())) { + continue; + } + final String sfname = field.getName(); + if (srcColumnPredicate != null && !srcColumnPredicate.test(field, sfname)) { + ingoreCount++; + continue; + } + final String dfname = nameAlias == null ? sfname : nameAlias.getOrDefault(sfname, sfname); + if (!Objects.equals(sfname, dfname)) { + destNewNames.put(sfname, dfname); + } + elements.put(sfname, field); + } + for (java.lang.reflect.Method getter : srcClass.getMethods()) { + if (Modifier.isStatic(getter.getModifiers())) { + continue; + } + if (getter.getParameterTypes().length > 0) { + continue; + } + if ("getClass".equals(getter.getName())) { + continue; + } + if (Utility.contains(getter.getExceptionTypes(), throwPredicate)) { + continue; // setter方法带有非RuntimeException异常 + } + if (!getter.getName().startsWith("get") && !getter.getName().startsWith("is")) { + continue; + } + final String sfname = Utility.readFieldName(getter.getName()); + if (sfname.isEmpty()) { + continue; + } + if (srcColumnPredicate != null && !srcColumnPredicate.test(getter, sfname)) { + ingoreCount++; + continue; + } + final String dfname = nameAlias == null ? sfname : nameAlias.getOrDefault(sfname, sfname); + if (!Objects.equals(sfname, dfname)) { + destNewNames.put(sfname, dfname); + } + elements.put(sfname, getter); + } + } + StringBuilder extendInfo = new StringBuilder(); + if (ingoreCount > 0 || nameAlias != null) { + if (ingoreCount > 0) { + extendInfo.append(elements.keySet().stream().collect(Collectors.joining(","))); + } + if (nameAlias != null) { + if (extendInfo.length() > 0) { + extendInfo.append(";"); + } + destNewNames.forEach((k, v) -> extendInfo.append(k).append(':').append(v)); + } + } + // ------------------------------------------------------------------------------ + final String supDynName = Copier.class.getName().replace('.', '/'); + final String destClassName = destClass.getName().replace('.', '/'); + final String srcClassName = srcClass.getName().replace('.', '/'); + final String destDesc = Type.getDescriptor(destClass); + final String srcDesc = Type.getDescriptor(srcClass); + final ClassLoader loader = Thread.currentThread().getContextClassLoader(); + final String utilClassName = Utility.class.getName().replace('.', '/'); + final String newDynName = "org/redkaledyn/copier/_Dyn" + Copier.class.getSimpleName() + "_" + options + + "__" + srcClass.getName().replace('.', '_').replace('$', '_') + + (srcClass == destClass + ? "" + : ("__" + destClass.getName().replace('.', '_').replace('$', '_'))) + + (extendInfo.length() == 0 ? "" : Utility.md5Hex(extendInfo.toString())); + try { + Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.')); + return (Copier) (clz == null ? loader.loadClass(newDynName.replace('/', '.')) : clz) + .getDeclaredConstructor() + .newInstance(); + } catch (Throwable ex) { + // do nothing + } + + // ------------------------------------------------------------------------------ + ClassWriter cw = new ClassWriter(COMPUTE_FRAMES); + FieldVisitor fv; + MethodVisitor mv; + AnnotationVisitor av0; + + cw.visit( + V11, + ACC_PUBLIC + ACC_FINAL + ACC_SUPER, + newDynName, + "Ljava/lang/Object;L" + supDynName + "<" + srcDesc + destDesc + ">;", + "java/lang/Object", + new String[] {supDynName}); + + { // 构造函数 + mv = (cw.visitMethod(ACC_PUBLIC, "", "()V", null, null)); + // mv.setDebug(true); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + if (srcIsMap) { // Map -> JavaBean + { + mv = (cw.visitMethod(ACC_PUBLIC, "apply", "(" + srcDesc + destDesc + ")" + destDesc, null, null)); + // mv.setDebug(true); + { + // if(src == null) return null; + mv.visitVarInsn(ALOAD, 1); + Label ifLabel = new Label(); + mv.visitJumpInsn(IFNONNULL, ifLabel); + mv.visitVarInsn(ALOAD, 2); + mv.visitInsn(ARETURN); + mv.visitLabel(ifLabel); + mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); + } + + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 2); + mv.visitInvokeDynamicInsn( + "accept", + "(" + destDesc + ")Ljava/util/function/BiConsumer;", + new Handle( + Opcodes.H_INVOKESTATIC, + "java/lang/invoke/LambdaMetafactory", + "metafactory", + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;", + false), + new Object[] { + Type.getType("(Ljava/lang/Object;Ljava/lang/Object;)V"), + new Handle( + Opcodes.H_INVOKESTATIC, + newDynName, + "lambda$0", + "(" + destDesc + "Ljava/lang/Object;Ljava/lang/Object;)V", + false), + Type.getType("(Ljava/lang/Object;Ljava/lang/Object;)V") + }); + mv.visitMethodInsn( + srcClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, + srcClassName, + "forEach", + "(Ljava/util/function/BiConsumer;)V", + srcClass.isInterface()); + mv.visitVarInsn(ALOAD, 2); + mv.visitInsn(ARETURN); + mv.visitMaxs(2, 3); + mv.visitEnd(); + } + { + mv = cw.visitMethod( + ACC_PRIVATE + ACC_STATIC + ACC_SYNTHETIC, + "lambda$0", + "(" + destDesc + "Ljava/lang/Object;Ljava/lang/Object;)V", + null, + null); + Label goLabel = new Label(); + int i = 0; + for (Map.Entry en : elements.entrySet()) { + final int index = ++i; + final java.lang.reflect.Type fieldType = en.getValue() instanceof Field + ? ((Field) en.getValue()).getGenericType() + : ((Method) en.getValue()).getGenericParameterTypes()[0]; + final Class fieldClass = en.getValue() instanceof Field + ? ((Field) en.getValue()).getType() + : ((Method) en.getValue()).getParameterTypes()[0]; + final boolean primitive = fieldClass.isPrimitive(); + final boolean charstr = CharSequence.class.isAssignableFrom(fieldClass); + + mv.visitLdcInsn(en.getKey()); + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z", false); + Label ifeq = index == elements.size() ? goLabel : new Label(); + mv.visitJumpInsn(IFEQ, ifeq); + if (skipNullValue || primitive) { + mv.visitVarInsn(ALOAD, 2); + mv.visitJumpInsn(IFNULL, ifeq); + } else if (skipEmptyString && charstr) { + mv.visitVarInsn(ALOAD, 2); + mv.visitJumpInsn(IFNULL, ifeq); + mv.visitVarInsn(ALOAD, 2); + mv.visitTypeInsn(INSTANCEOF, "java/lang/CharSequence"); + mv.visitJumpInsn(IFEQ, ifeq); + mv.visitVarInsn(ALOAD, 2); + mv.visitTypeInsn(CHECKCAST, "java/lang/CharSequence"); + mv.visitMethodInsn(INVOKEINTERFACE, "java/lang/CharSequence", "length", "()I", true); + mv.visitJumpInsn(IFLE, ifeq); + } + + mv.visitVarInsn(ALOAD, 0); + Asms.visitFieldInsn(mv, fieldClass); + + mv.visitVarInsn(ALOAD, 2); + mv.visitMethodInsn( + INVOKESTATIC, + utilClassName, + "convertValue", + "(Ljava/lang/reflect/Type;Ljava/lang/Object;)Ljava/lang/Object;", + false); + Asms.visitCheckCast(mv, fieldClass); + + if (en.getValue() instanceof Field) { + mv.visitFieldInsn(PUTFIELD, destClassName, en.getKey(), Type.getDescriptor(fieldClass)); + } else { + Method setter = (Method) en.getValue(); + mv.visitMethodInsn( + destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, + destClassName, + setter.getName(), + Type.getMethodDescriptor(setter), + destClass.isInterface()); + } + if (index == elements.size()) { + mv.visitLabel(goLabel); + } else { + mv.visitJumpInsn(GOTO, goLabel); + mv.visitLabel(ifeq); + } + mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); + } + + mv.visitInsn(RETURN); + mv.visitMaxs(3, 3); + mv.visitEnd(); + } + } else { // JavaBean -> Map/JavaBean + mv = (cw.visitMethod(ACC_PUBLIC, "apply", "(" + srcDesc + destDesc + ")" + destDesc, null, null)); + // mv.setDebug(true); + { + // if(src == null) return null; + mv.visitVarInsn(ALOAD, 1); + Label ifLabel = new Label(); + mv.visitJumpInsn(IFNONNULL, ifLabel); + mv.visitVarInsn(ALOAD, 2); + mv.visitInsn(ARETURN); + mv.visitLabel(ifLabel); + mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); + } + + Predicate simpler = t -> t.isPrimitive() || t == String.class || Number.class.isAssignableFrom(t); + // 遍历所有字段 + for (Map.Entry en : elements.entrySet()) { + if (!(en.getValue() instanceof java.lang.reflect.Field)) { + continue; + } + java.lang.reflect.Field field = (java.lang.reflect.Field) en.getValue(); + final String sfname = en.getKey(); + + final String dfname = destNewNames.getOrDefault(sfname, sfname); + final Class srcFieldType = field.getType(); + final boolean charstr = CharSequence.class.isAssignableFrom(srcFieldType); + if (destIsMap) { // JavaBean -> Map + String td = Type.getDescriptor(srcFieldType); + if ((!skipNullValue && !(skipEmptyString && charstr)) || srcFieldType.isPrimitive()) { + mv.visitVarInsn(ALOAD, 2); + mv.visitLdcInsn(dfname); + mv.visitVarInsn(ALOAD, 1); + mv.visitFieldInsn(GETFIELD, srcClassName, sfname, td); + Asms.visitPrimitiveValueOf(mv, srcFieldType); + mv.visitMethodInsn( + destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, + destClassName, + "put", + "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", + destClass.isInterface()); + mv.visitInsn(POP); + } else { // skipNullValue OR (skipEmptyString && charstr) + mv.visitVarInsn(ALOAD, 1); + mv.visitFieldInsn(GETFIELD, srcClassName, sfname, td); + mv.visitVarInsn(ASTORE, 3); + mv.visitVarInsn(ALOAD, 3); + Label ifLabel = new Label(); + mv.visitJumpInsn(IFNULL, ifLabel); + if (skipEmptyString && charstr) { + mv.visitVarInsn(ALOAD, 3); + mv.visitTypeInsn(CHECKCAST, "java/lang/CharSequence"); + mv.visitMethodInsn(INVOKEINTERFACE, "java/lang/CharSequence", "length", "()I", true); + mv.visitJumpInsn(IFLE, ifLabel); + } + mv.visitVarInsn(ALOAD, 2); + mv.visitLdcInsn(dfname); + mv.visitVarInsn(ALOAD, 3); + mv.visitMethodInsn( + destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, + destClassName, + "put", + "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", + destClass.isInterface()); + mv.visitInsn(POP); + mv.visitLabel(ifLabel); + mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); + } + } else { // JavaBean -> JavaBean + boolean needTypeCast = false; + java.lang.reflect.Method setter = null; + java.lang.reflect.Field setField = null; + try { + setField = destClass.getField(dfname); + if (field.getType() == setField.getType()) { + needTypeCast = false; + } else if (simpler.test(field.getType()) && simpler.test(setField.getType())) { + needTypeCast = true; + } else if (!field.getType().equals(setField.getType())) { + if (allowTypeCast) { + needTypeCast = true; + } else { + continue; + } + } + } catch (Exception e) { + String setterMethodName = "set" + Utility.firstCharUpperCase(dfname); + try { + setter = destClass.getMethod(setterMethodName, field.getType()); + if (Utility.contains(setter.getExceptionTypes(), throwPredicate)) { + continue; // setter方法带有非RuntimeException异常 + } + } catch (Exception e2) { + try { + for (java.lang.reflect.Method m : destClass.getMethods()) { + if (Modifier.isStatic(m.getModifiers())) { + continue; + } + if (Utility.contains(m.getExceptionTypes(), throwPredicate)) { + continue; // setter方法带有非RuntimeException异常 + } + if (m.getParameterTypes().length != 1) { + continue; + } + if (m.getName().equals(setterMethodName)) { + if (simpler.test(field.getType()) && simpler.test(setField.getType())) { + setter = m; + needTypeCast = true; + } else if (!allowTypeCast) { + setter = null; + } + break; + } + } + if (setter == null) { + continue; + } + } catch (Exception e3) { + continue; + } + } + } + String srcFieldDesc = Type.getDescriptor(srcFieldType); + final Class destFieldType = setter == null ? setField.getType() : setter.getParameterTypes()[0]; + boolean localSkipNull = + skipNullValue || (!srcFieldType.isPrimitive() && destFieldType.isPrimitive()); + if ((!localSkipNull && !(skipEmptyString && charstr)) + || (srcFieldType.isPrimitive() && !allowTypeCast) + || (srcFieldType.isPrimitive() && destFieldType.isPrimitive())) { + if (needTypeCast) { + mv.visitVarInsn(ALOAD, 2); + Asms.visitFieldInsn(mv, destFieldType); + mv.visitVarInsn(ALOAD, 1); + mv.visitFieldInsn(GETFIELD, srcClassName, sfname, srcFieldDesc); + Asms.visitPrimitiveValueOf(mv, srcFieldType); + mv.visitMethodInsn( + INVOKESTATIC, + utilClassName, + "convertValue", + "(Ljava/lang/reflect/Type;Ljava/lang/Object;)Ljava/lang/Object;", + false); + Asms.visitCheckCast(mv, destFieldType); + if (setter == null) { // src: field, dest: field + mv.visitFieldInsn(PUTFIELD, destClassName, dfname, Type.getDescriptor(destFieldType)); + } else { // src: field, dest: method + mv.visitMethodInsn( + destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, + destClassName, + setter.getName(), + Type.getMethodDescriptor(setter), + destClass.isInterface()); + if (setter.getReturnType() != void.class) { + mv.visitInsn(POP); + } + } + } else { + mv.visitVarInsn(ALOAD, 2); + mv.visitVarInsn(ALOAD, 1); + mv.visitFieldInsn(GETFIELD, srcClassName, sfname, srcFieldDesc); + if (setter == null) { // src: field, dest: field + mv.visitFieldInsn(PUTFIELD, destClassName, dfname, Type.getDescriptor(destFieldType)); + } else { // src: field, dest: method + mv.visitMethodInsn( + destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, + destClassName, + setter.getName(), + Type.getMethodDescriptor(setter), + destClass.isInterface()); + if (setter.getReturnType() != void.class) { + mv.visitInsn(POP); + } + } + } + } else { // skipNullValue OR (skipEmptyString && charstr) + mv.visitVarInsn(ALOAD, 1); + mv.visitFieldInsn(GETFIELD, srcClassName, sfname, srcFieldDesc); + mv.visitVarInsn(ASTORE, 3); + mv.visitVarInsn(ALOAD, 3); + Label ifLabel = new Label(); + mv.visitJumpInsn(IFNULL, ifLabel); + if (skipEmptyString && charstr) { + mv.visitVarInsn(ALOAD, 3); + mv.visitTypeInsn(CHECKCAST, "java/lang/CharSequence"); + mv.visitMethodInsn(INVOKEINTERFACE, "java/lang/CharSequence", "length", "()I", true); + mv.visitJumpInsn(IFLE, ifLabel); + } + if (needTypeCast) { + mv.visitVarInsn(ALOAD, 2); + Asms.visitFieldInsn(mv, destFieldType); + mv.visitVarInsn(ALOAD, 3); + Asms.visitPrimitiveValueOf(mv, srcFieldType); + mv.visitMethodInsn( + INVOKESTATIC, + utilClassName, + "convertValue", + "(Ljava/lang/reflect/Type;Ljava/lang/Object;)Ljava/lang/Object;", + false); + Asms.visitCheckCast(mv, destFieldType); + if (setter == null) { // src: field, dest: field + mv.visitFieldInsn(PUTFIELD, destClassName, dfname, Type.getDescriptor(destFieldType)); + } else { // src: field, dest: method + mv.visitMethodInsn( + destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, + destClassName, + setter.getName(), + Type.getMethodDescriptor(setter), + destClass.isInterface()); + if (setter.getReturnType() != void.class) { + mv.visitInsn(POP); + } + } + } else { + mv.visitVarInsn(ALOAD, 2); + mv.visitVarInsn(ALOAD, 3); + mv.visitTypeInsn(CHECKCAST, srcFieldType.getName().replace('.', '/')); + if (setter == null) { // src: field, dest: field + mv.visitFieldInsn(PUTFIELD, destClassName, dfname, srcFieldDesc); + } else { // src: field, dest: method + mv.visitMethodInsn( + destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, + destClassName, + setter.getName(), + Type.getMethodDescriptor(setter), + destClass.isInterface()); + if (setter.getReturnType() != void.class) { + mv.visitInsn(POP); + } + } + } + mv.visitLabel(ifLabel); + mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); + } + } + } + // 遍历所有方法 + for (Map.Entry en : elements.entrySet()) { + if (!(en.getValue() instanceof java.lang.reflect.Method)) { + continue; + } + java.lang.reflect.Method getter = (java.lang.reflect.Method) en.getValue(); + final String sfname = en.getKey(); + + final String dfname = destNewNames.getOrDefault(sfname, sfname); + final Class srcFieldType = getter.getReturnType(); + final boolean charstr = CharSequence.class.isAssignableFrom(srcFieldType); + if (destIsMap) { // srcClass是JavaBean + if ((!skipNullValue && !(skipEmptyString && charstr)) || srcFieldType.isPrimitive()) { + mv.visitVarInsn(ALOAD, 2); + mv.visitLdcInsn(dfname); + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn( + srcClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, + srcClassName, + getter.getName(), + Type.getMethodDescriptor(getter), + srcClass.isInterface()); + Asms.visitPrimitiveValueOf(mv, srcFieldType); + mv.visitMethodInsn( + destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, + destClassName, + "put", + "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", + destClass.isInterface()); + mv.visitInsn(POP); + } else { // skipNullValue OR (skipEmptyString && charstr) + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn( + srcClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, + srcClassName, + getter.getName(), + Type.getMethodDescriptor(getter), + srcClass.isInterface()); + mv.visitVarInsn(ASTORE, 3); + mv.visitVarInsn(ALOAD, 3); + Label ifLabel = new Label(); + mv.visitJumpInsn(IFNULL, ifLabel); + if (skipEmptyString && charstr) { + mv.visitVarInsn(ALOAD, 3); + mv.visitTypeInsn(CHECKCAST, "java/lang/CharSequence"); + mv.visitMethodInsn(INVOKEINTERFACE, "java/lang/CharSequence", "length", "()I", true); + mv.visitJumpInsn(IFLE, ifLabel); + } + mv.visitVarInsn(ALOAD, 2); + mv.visitLdcInsn(dfname); + mv.visitVarInsn(ALOAD, 3); + mv.visitMethodInsn( + destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, + destClassName, + "put", + "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", + destClass.isInterface()); + mv.visitInsn(POP); + mv.visitLabel(ifLabel); + mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); + } + } else { // srcClass、destClass是JavaBean + boolean needTypeCast = false; + java.lang.reflect.Method setter = null; + java.lang.reflect.Field setField = null; + String setterMethodName = "set" + Utility.firstCharUpperCase(dfname); + try { + setter = destClass.getMethod(setterMethodName, getter.getReturnType()); + if (Utility.contains(setter.getExceptionTypes(), throwPredicate)) { + continue; // setter方法带有非RuntimeException异常 + } + } catch (Exception e) { + if (allowTypeCast) { + try { + for (java.lang.reflect.Method m : destClass.getMethods()) { + if (Modifier.isStatic(m.getModifiers())) { + continue; + } + if (Utility.contains(m.getExceptionTypes(), throwPredicate)) { + continue; // setter方法带有非RuntimeException异常 + } + if (m.getParameterTypes().length != 1) { + continue; + } + if (m.getName().equals(setterMethodName)) { + setter = m; + needTypeCast = true; + break; + } + } + } catch (Exception e2) { + // do nothing + } + } + if (setter == null) { + try { + setField = destClass.getField(dfname); + if (!getter.getReturnType().equals(setField.getType())) { + if (allowTypeCast) { + needTypeCast = true; + } else { + continue; + } + } + } catch (Exception e3) { + continue; + } + } + } + final Class destFieldType = setter == null ? setField.getType() : setter.getParameterTypes()[0]; + boolean localSkipNull = + skipNullValue || (!srcFieldType.isPrimitive() && destFieldType.isPrimitive()); + if ((!localSkipNull && !(skipEmptyString && charstr)) + || (srcFieldType.isPrimitive() && !allowTypeCast) + || (srcFieldType.isPrimitive() && destFieldType.isPrimitive())) { + if (needTypeCast) { + mv.visitVarInsn(ALOAD, 2); + Asms.visitFieldInsn(mv, destFieldType); + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn( + srcClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, + srcClassName, + getter.getName(), + Type.getMethodDescriptor(getter), + srcClass.isInterface()); + Asms.visitPrimitiveValueOf(mv, srcFieldType); + mv.visitMethodInsn( + INVOKESTATIC, + utilClassName, + "convertValue", + "(Ljava/lang/reflect/Type;Ljava/lang/Object;)Ljava/lang/Object;", + false); + Asms.visitCheckCast(mv, destFieldType); + if (setter == null) { // src: method, dest: field + mv.visitFieldInsn(PUTFIELD, destClassName, dfname, Type.getDescriptor(destFieldType)); + } else { // src: method, dest: method + mv.visitMethodInsn( + destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, + destClassName, + setter.getName(), + Type.getMethodDescriptor(setter), + destClass.isInterface()); + if (setter.getReturnType() != void.class) { + mv.visitInsn(POP); + } + } + } else { + mv.visitVarInsn(ALOAD, 2); + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn( + srcClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, + srcClassName, + getter.getName(), + Type.getMethodDescriptor(getter), + srcClass.isInterface()); + if (setter == null) { // src: method, dest: field + mv.visitFieldInsn(PUTFIELD, destClassName, dfname, Type.getDescriptor(destFieldType)); + } else { // src: method, dest: method + mv.visitMethodInsn( + destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, + destClassName, + setter.getName(), + Type.getMethodDescriptor(setter), + destClass.isInterface()); + if (setter.getReturnType() != void.class) { + mv.visitInsn(POP); + } + } + } + } else { // skipNullValue OR (skipEmptyString && charstr) + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn( + srcClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, + srcClassName, + getter.getName(), + Type.getMethodDescriptor(getter), + srcClass.isInterface()); + mv.visitVarInsn(ASTORE, 3); + mv.visitVarInsn(ALOAD, 3); + Label ifLabel = new Label(); + mv.visitJumpInsn(IFNULL, ifLabel); + if (skipEmptyString && charstr) { + mv.visitVarInsn(ALOAD, 3); + mv.visitTypeInsn(CHECKCAST, "java/lang/CharSequence"); + mv.visitMethodInsn(INVOKEINTERFACE, "java/lang/CharSequence", "length", "()I", true); + mv.visitJumpInsn(IFLE, ifLabel); + } + if (needTypeCast) { + mv.visitVarInsn(ALOAD, 2); + Asms.visitFieldInsn(mv, destFieldType); + mv.visitVarInsn(ALOAD, 3); + Asms.visitPrimitiveValueOf(mv, srcFieldType); + mv.visitMethodInsn( + INVOKESTATIC, + utilClassName, + "convertValue", + "(Ljava/lang/reflect/Type;Ljava/lang/Object;)Ljava/lang/Object;", + false); + Asms.visitCheckCast(mv, destFieldType); + if (setter == null) { // src: method, dest: field + mv.visitFieldInsn(PUTFIELD, destClassName, dfname, Type.getDescriptor(destFieldType)); + } else { // src: method, dest: method + mv.visitMethodInsn( + destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, + destClassName, + setter.getName(), + Type.getMethodDescriptor(setter), + destClass.isInterface()); + if (setter.getReturnType() != void.class) { + mv.visitInsn(POP); + } + } + } else { + mv.visitVarInsn(ALOAD, 2); + mv.visitVarInsn(ALOAD, 3); + mv.visitTypeInsn(CHECKCAST, srcFieldType.getName().replace('.', '/')); + if (setter == null) { // src: method, dest: field + mv.visitFieldInsn( + PUTFIELD, destClassName, dfname, Type.getDescriptor(getter.getReturnType())); + } else { // src: method, dest: method + mv.visitMethodInsn( + destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, + destClassName, + setter.getName(), + Type.getMethodDescriptor(setter), + destClass.isInterface()); + if (setter.getReturnType() != void.class) { + mv.visitInsn(POP); + } + } + } + mv.visitLabel(ifLabel); + mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); + } + } + } + mv.visitVarInsn(ALOAD, 2); + mv.visitInsn(ARETURN); + mv.visitMaxs(3, 3); + mv.visitEnd(); + } + { + mv = (cw.visitMethod( + ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC, + "apply", + "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", + null, + null)); + // mv.setDebug(true); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 1); + mv.visitTypeInsn(CHECKCAST, srcClassName); + mv.visitVarInsn(ALOAD, 2); + mv.visitTypeInsn(CHECKCAST, destClassName); + mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "apply", "(" + srcDesc + destDesc + ")" + destDesc, false); + mv.visitInsn(ARETURN); + mv.visitMaxs(3, 3); + mv.visitEnd(); + } + cw.visitEnd(); + // ------------------------------------------------------------------------------ + byte[] bytes = cw.toByteArray(); + Class newClazz = new ClassLoader(loader) { + public final Class loadClass(String name, byte[] b) { + return defineClass(name, b, 0, b.length); + } + }.loadClass(newDynName.replace('/', '.'), bytes); + RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, newClazz); + RedkaleClassLoader.putReflectionDeclaredConstructors(newClazz, newDynName.replace('/', '.')); + try { + return (Copier) newClazz.getDeclaredConstructor().newInstance(); + } catch (Exception ex) { + throw new RedkaleException(ex); + } + } +} diff --git a/src/main/java/org/redkale/util/Creator.java b/src/main/java/org/redkale/util/Creator.java index fd4de1c43..c54e777d5 100644 --- a/src/main/java/org/redkale/util/Creator.java +++ b/src/main/java/org/redkale/util/Creator.java @@ -1,621 +1,621 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ -package org.redkale.util; - -import static org.redkale.asm.Opcodes.*; - -import java.io.*; -import java.lang.reflect.*; -import java.net.*; -import java.util.*; -import java.util.AbstractMap.SimpleEntry; -import java.util.concurrent.*; -import java.util.function.*; -import org.redkale.annotation.ConstructorParameters; -import org.redkale.asm.*; -import org.redkale.asm.Type; - -/** - * 实现一个类的构造方法。 代替低效的反射实现方式。 不支持数组类。 常见的无参数的构造函数类都可以自动生成Creator, 对应自定义的类可以提供一个静态构建Creator方法。 例如: - * - *
- * - *
- * public class Record {
- *
- *    private final int id;
- *
- *    private String name;
- *
- *    Record(int id, String name) {
- *        this.id = id;
- *        this.name = name;
- *    }
- *
- *    private static Creator createCreator() {
- *        return new Creator<Record>() {
- *            @Override
- *            @ConstructorParameters({"id", "name"})
- *            public Record create(Object... params) {
- *                if(params[0] == null) params[0] = 0;
- *                return new Record((Integer) params[0], (String) params[1]);
- *            }
- *         };
- *    }
- * }
- * 
- * - *
- * - * 或者: - * - *
- * - *
- * public class Record {
- *
- *    private final int id;
- *
- *    private String name;
- *
- *    @ConstructorParameters({"id", "name"})
- *    public Record(int id, String name) {
- *        this.id = id;
- *        this.name = name;
- *    }
- * }
- * 
- * - *
- * - *

详情见: https://redkale.org - * - * @author zhangjx - * @param 构建对象的数据类型 - */ -public interface Creator { - - /** - * 创建对象 - * - * @param params 构造函数的参数 - * @return 构建的对象 - */ - public T create(Object... params); - - /** - * 参数类型数组 - * - * @since 2.8.0 - * @return 参数类型数组 - */ - default Class[] paramTypes() { - return new Class[0]; - } - - /** - * 创建指定类型对象数组的IntFunction - * - * @param 泛型 - * @param type 类型 - * @return IntFunction - */ - public static IntFunction funcArray(final Class type) { - return Inners.CreatorInner.arrayCacheMap.computeIfAbsent(type, Inners.CreatorInner::createArrayFunction); - } - - public static IntFunction funcStringArray() { - return Inners.CreatorInner.stringFuncArray; - } - - public static Creator load(Class clazz) { - return Inners.CreatorInner.creatorCacheMap.computeIfAbsent(clazz, v -> create(clazz)); - } - - public static Creator register(Class clazz, final Supplier supplier) { - Creator creator = (Object... params) -> supplier.get(); - Inners.CreatorInner.creatorCacheMap.put(clazz, creator); - return creator; - } - - public static Creator register(final LambdaSupplier supplier) { - Creator creator = (Object... params) -> supplier.get(); - Inners.CreatorInner.creatorCacheMap.put(LambdaSupplier.readClass(supplier), creator); - return creator; - } - - /** - * 创建指定大小的对象数组 - * - * @param 泛型 - * @param type 类型 - * @param size 数组大小 - * @return 数组 - */ - public static T[] newArray(final Class type, final int size) { - if (type == int.class) { - return (T[]) (Object) new int[size]; - } - if (type == byte.class) { - return (T[]) (Object) new byte[size]; - } - if (type == long.class) { - return (T[]) (Object) new long[size]; - } - if (type == String.class) { - return (T[]) new String[size]; - } - if (type == Object.class) { - return (T[]) new Object[size]; - } - if (type == boolean.class) { - return (T[]) (Object) new boolean[size]; - } - if (type == short.class) { - return (T[]) (Object) new short[size]; - } - if (type == char.class) { - return (T[]) (Object) new char[size]; - } - if (type == float.class) { - return (T[]) (Object) new float[size]; - } - if (type == double.class) { - return (T[]) (Object) new double[size]; - } - return funcArray(type).apply(size); - } - - /** - * 根据Supplier生产Creator - * - * @param 构建类的数据类型 - * @param supplier Supplier - * @return Creator对象 - */ - public static Creator create(final Supplier supplier) { - Objects.requireNonNull(supplier); - return (Object... params) -> supplier.get(); - } - - /** - * 根据Function生产Creator - * - * @param 构建类的数据类型 - * @param func Function - * @return Creator对象 - */ - public static Creator create(final Function func) { - Objects.requireNonNull(func); - return (Object... params) -> func.apply(params); - } - - /** - * 根据指定的class采用ASM技术生产Creator。 - * - * @param 构建类的数据类型 - * @param clazz 构建类 - * @return Creator对象 - */ - @SuppressWarnings("unchecked") - public static Creator create(Class clazz) { - if (List.class.isAssignableFrom(clazz) - && (clazz.isAssignableFrom(ArrayList.class) - || clazz.getName().startsWith("java.util.Collections") - || clazz.getName().startsWith("java.util.ImmutableCollections") - || clazz.getName().startsWith("java.util.Arrays"))) { - clazz = (Class) ArrayList.class; - } else if (Map.class.isAssignableFrom(clazz) - && (clazz.isAssignableFrom(HashMap.class) - || clazz.getName().startsWith("java.util.Collections") - || clazz.getName().startsWith("java.util.ImmutableCollections"))) { - clazz = (Class) HashMap.class; - } else if (Set.class.isAssignableFrom(clazz) - && (clazz.isAssignableFrom(HashSet.class) - || clazz.getName().startsWith("java.util.Collections") - || clazz.getName().startsWith("java.util.ImmutableCollections"))) { - clazz = (Class) HashSet.class; - } else if (Map.class.isAssignableFrom(clazz) && clazz.isAssignableFrom(ConcurrentHashMap.class)) { - clazz = (Class) ConcurrentHashMap.class; - } else if (Deque.class.isAssignableFrom(clazz) - && (clazz.isAssignableFrom(ArrayDeque.class) - || clazz.getName().startsWith("java.util.Collections") - || clazz.getName().startsWith("java.util.ImmutableCollections"))) { - clazz = (Class) ArrayDeque.class; - } else if (Collection.class.isAssignableFrom(clazz) && clazz.isAssignableFrom(ArrayList.class)) { - clazz = (Class) ArrayList.class; - } else if (Map.Entry.class.isAssignableFrom(clazz) - && (Modifier.isInterface(clazz.getModifiers()) - || Modifier.isAbstract(clazz.getModifiers()) - || !Modifier.isPublic(clazz.getModifiers()))) { - clazz = (Class) AbstractMap.SimpleEntry.class; - } else if (Iterable.class == clazz) { - clazz = (Class) ArrayList.class; - } else if (CompletionStage.class.isAssignableFrom(clazz) && clazz.isAssignableFrom(CompletableFuture.class)) { - clazz = (Class) CompletableFuture.class; - } else if (Future.class.isAssignableFrom(clazz) && clazz.isAssignableFrom(CompletableFuture.class)) { - clazz = (Class) CompletableFuture.class; - } - Creator creator = Inners.CreatorInner.creatorCacheMap.get(clazz); - if (creator != null) { - return creator; - } - if (clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers())) { - throw new RedkaleException("[" + clazz + "] is a interface or abstract class, cannot create it's Creator."); - } - for (final Method method : clazz.getDeclaredMethods()) { // 查找类中是否存在提供创建Creator实例的静态方法 - if (!Modifier.isStatic(method.getModifiers())) { - continue; - } - if (method.getParameterTypes().length != 0) { - continue; - } - if (method.getReturnType() != Creator.class) { - continue; - } - try { - method.setAccessible(true); - Creator c = (Creator) method.invoke(null); - if (c != null) { - RedkaleClassLoader.putReflectionDeclaredMethods(clazz.getName()); - RedkaleClassLoader.putReflectionMethod(clazz.getName(), method); - return c; - } - } catch (Exception e) { - throw new RedkaleException(e); - } - } - final String supDynName = Creator.class.getName().replace('.', '/'); - final String interName = clazz.getName().replace('.', '/'); - final String interDesc = Type.getDescriptor(clazz); - ClassLoader loader = Thread.currentThread().getContextClassLoader(); - if (String.class.getClassLoader() != clazz.getClassLoader()) { - loader = clazz.getClassLoader(); - } - final String newDynName = "org/redkaledyn/creator/_Dyn" + Creator.class.getSimpleName() + "__" - + clazz.getName().replace('.', '_').replace('$', '_'); - try { - Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.')); - return (Creator) (clz == null ? loader.loadClass(newDynName.replace('/', '.')) : clz) - .getDeclaredConstructor() - .newInstance(); - } catch (Throwable ex) { - // do nothing - } - - Constructor constructor0 = null; - SimpleEntry[] constructorParameters0 = null; // 构造函数的参数 - - if (constructor0 == null) { // 1、查找public的空参数构造函数 - for (Constructor c : clazz.getConstructors()) { - if (c.getParameterCount() == 0) { - constructor0 = c; - constructorParameters0 = new SimpleEntry[0]; - break; - } - } - } - if (constructor0 == null) { // 2、查找public带ConstructorParameters注解的构造函数 - for (Constructor c : clazz.getConstructors()) { - ConstructorParameters cp = (ConstructorParameters) c.getAnnotation(ConstructorParameters.class); - if (cp == null) { - continue; - } - SimpleEntry[] fields = - Inners.CreatorInner.getConstructorField(clazz, c.getParameterCount(), cp.value()); - if (fields != null) { - constructor0 = c; - constructorParameters0 = fields; - break; - } - } - } - if (constructor0 == null) { // 3、查找public且不带ConstructorParameters注解的构造函数 - List cs = new ArrayList<>(); - for (Constructor c : clazz.getConstructors()) { - if (c.getAnnotation(ConstructorParameters.class) != null) { - continue; - } - if (c.getParameterCount() < 1) { - continue; - } - cs.add(c); - } - // 优先参数最多的构造函数 - cs.sort((o1, o2) -> o2.getParameterCount() - o1.getParameterCount()); - for (Constructor c : cs) { - SimpleEntry[] fields = Inners.CreatorInner.getConstructorField( - clazz, c.getParameterCount(), Type.getConstructorDescriptor(c)); - if (fields != null) { - constructor0 = c; - constructorParameters0 = fields; - break; - } - } - } - if (constructor0 == null) { // 4、查找非private带ConstructorParameters的构造函数 - for (Constructor c : clazz.getDeclaredConstructors()) { - if (Modifier.isPublic(c.getModifiers()) || Modifier.isPrivate(c.getModifiers())) { - continue; - } - ConstructorParameters cp = (ConstructorParameters) c.getAnnotation(ConstructorParameters.class); - if (cp == null) { - continue; - } - SimpleEntry[] fields = - Inners.CreatorInner.getConstructorField(clazz, c.getParameterCount(), cp.value()); - if (fields != null) { - constructor0 = c; - constructorParameters0 = fields; - break; - } - } - } - if (constructor0 == null) { // 5、查找非private且不带ConstructorParameters的构造函数 - List cs = new ArrayList<>(); - for (Constructor c : clazz.getDeclaredConstructors()) { - if (Modifier.isPublic(c.getModifiers()) || Modifier.isPrivate(c.getModifiers())) { - continue; - } - if (c.getAnnotation(ConstructorParameters.class) != null) { - continue; - } - if (c.getParameterCount() < 1) { - continue; - } - cs.add(c); - } - // 优先参数最多的构造函数 - cs.sort((o1, o2) -> o2.getParameterCount() - o1.getParameterCount()); - for (Constructor c : cs) { - SimpleEntry[] fields = Inners.CreatorInner.getConstructorField( - clazz, c.getParameterCount(), Type.getConstructorDescriptor(c)); - if (fields != null) { - constructor0 = c; - constructorParameters0 = fields; - break; - } - } - } - final Constructor constructor = constructor0; - final SimpleEntry[] constructorParameters = constructorParameters0; - if (constructor == null || constructorParameters == null) { - throw new RedkaleException( - "[" + clazz + "] have no public or ConstructorParameters-Annotation constructor."); - } - final int[] iconsts = {ICONST_0, ICONST_1, ICONST_2, ICONST_3, ICONST_4, ICONST_5}; - // ------------------------------------------------------------- - ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); - FieldVisitor fv; - MethodVisitor mv; - AnnotationVisitor av0; - cw.visit( - V11, - ACC_PUBLIC + ACC_FINAL + ACC_SUPER, - newDynName, - "Ljava/lang/Object;L" + supDynName + "<" + interDesc + ">;", - "java/lang/Object", - new String[] {supDynName}); - - { // Creator自身的构造方法 - mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); - mv.visitInsn(RETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - { // paramTypes 方法 - mv = cw.visitMethod(ACC_PUBLIC, "paramTypes", "()[Ljava/lang/Class;", null, null); - int paramLen = constructorParameters.length; - if (paramLen < 6) { - mv.visitInsn(ICONST_0 + paramLen); - } else if (paramLen <= Byte.MAX_VALUE) { - mv.visitIntInsn(BIPUSH, paramLen); - } else if (paramLen <= Short.MAX_VALUE) { - mv.visitIntInsn(SIPUSH, paramLen); - } else { - mv.visitLdcInsn(paramLen); - } - mv.visitTypeInsn(ANEWARRAY, "java/lang/Class"); - - for (int i = 0; i < constructorParameters.length; i++) { - final Class pt = constructorParameters[i].getValue(); - mv.visitInsn(DUP); - if (i < 6) { - mv.visitInsn(iconsts[i]); - } else if (i <= Byte.MAX_VALUE) { - mv.visitIntInsn(BIPUSH, i); - } else if (i <= Short.MAX_VALUE) { - mv.visitIntInsn(SIPUSH, i); - } else { - mv.visitLdcInsn(i); - } - Asms.visitFieldInsn(mv, pt); - mv.visitInsn(AASTORE); - } - mv.visitInsn(ARETURN); - mv.visitMaxs(4, 1); - mv.visitEnd(); - } - { // create 方法 - mv = cw.visitMethod( - ACC_PUBLIC + ACC_VARARGS, "create", "([Ljava/lang/Object;)L" + interName + ";", null, null); - if (constructorParameters.length > 0) { - av0 = mv.visitAnnotation(Type.getDescriptor(ConstructorParameters.class), true); - AnnotationVisitor av1 = av0.visitArray("value"); - for (SimpleEntry n : constructorParameters) { - av1.visit(null, n.getKey()); - } - av1.visitEnd(); - av0.visitEnd(); - } - { // 有Primitive数据类型且值为null的参数需要赋默认值 - for (int i = 0; i < constructorParameters.length; i++) { - final Class pt = constructorParameters[i].getValue(); - if (!pt.isPrimitive()) { - continue; - } - mv.visitVarInsn(ALOAD, 1); - if (i < 6) { - mv.visitInsn(iconsts[i]); - } else if (i <= Byte.MAX_VALUE) { - mv.visitIntInsn(BIPUSH, i); - } else if (i <= Short.MAX_VALUE) { - mv.visitIntInsn(SIPUSH, i); - } else { - mv.visitLdcInsn(i); - } - mv.visitInsn(AALOAD); - Label lab = new Label(); - mv.visitJumpInsn(IFNONNULL, lab); - mv.visitVarInsn(ALOAD, 1); - if (i < 6) { - mv.visitInsn(iconsts[i]); - } else if (i <= Byte.MAX_VALUE) { - mv.visitIntInsn(BIPUSH, i); - } else if (i <= Short.MAX_VALUE) { - mv.visitIntInsn(SIPUSH, i); - } else { - mv.visitLdcInsn(i); - } - if (pt == int.class) { - mv.visitInsn(ICONST_0); - mv.visitMethodInsn( - INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false); - } else if (pt == long.class) { - mv.visitInsn(LCONST_0); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;", false); - } else if (pt == boolean.class) { - mv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "FALSE", "Ljava/lang/Boolean;"); - } else if (pt == short.class) { - mv.visitInsn(ICONST_0); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;", false); - } else if (pt == float.class) { - mv.visitInsn(FCONST_0); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", false); - } else if (pt == byte.class) { - mv.visitInsn(ICONST_0); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;", false); - } else if (pt == double.class) { - mv.visitInsn(DCONST_0); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", false); - } else if (pt == char.class) { - mv.visitInsn(ICONST_0); - mv.visitMethodInsn( - INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;", false); - } - mv.visitInsn(AASTORE); - mv.visitLabel(lab); - } - } - mv.visitTypeInsn(NEW, interName); - mv.visitInsn(DUP); - // --------------------------------------- - { - for (int i = 0; i < constructorParameters.length; i++) { - mv.visitVarInsn(ALOAD, 1); - if (i < 6) { - mv.visitInsn(iconsts[i]); - } else if (i <= Byte.MAX_VALUE) { - mv.visitIntInsn(BIPUSH, i); - } else if (i <= Short.MAX_VALUE) { - mv.visitIntInsn(SIPUSH, i); - } else { - mv.visitLdcInsn(i); - } - mv.visitInsn(AALOAD); - final Class ct = constructorParameters[i].getValue(); - if (ct.isPrimitive()) { - final Class bigct = TypeToken.primitiveToWrapper(ct); - mv.visitTypeInsn(CHECKCAST, bigct.getName().replace('.', '/')); - try { - Method pm = bigct.getMethod(ct.getSimpleName() + "Value"); - mv.visitMethodInsn( - INVOKEVIRTUAL, - bigct.getName().replace('.', '/'), - pm.getName(), - Type.getMethodDescriptor(pm), - false); - } catch (Exception ex) { - throw new RedkaleException(ex); // 不可能会发生 - } - } else { - mv.visitTypeInsn(CHECKCAST, ct.getName().replace('.', '/')); - } - } - } - // --------------------------------------- - mv.visitMethodInsn(INVOKESPECIAL, interName, "", Type.getConstructorDescriptor(constructor), false); - mv.visitInsn(ARETURN); - mv.visitMaxs((constructorParameters.length > 0 ? (constructorParameters.length + 3) : 2), 2); - mv.visitEnd(); - } - { // 虚拟 create 方法 - mv = cw.visitMethod( - ACC_PUBLIC + ACC_BRIDGE + ACC_VARARGS + ACC_SYNTHETIC, - "create", - "([Ljava/lang/Object;)Ljava/lang/Object;", - null, - null); - mv.visitVarInsn(ALOAD, 0); - mv.visitVarInsn(ALOAD, 1); - mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "create", "([Ljava/lang/Object;)" + interDesc, false); - mv.visitInsn(ARETURN); - mv.visitMaxs(2, 2); - mv.visitEnd(); - } - cw.visitEnd(); - final byte[] bytes = cw.toByteArray(); - final boolean ispub = Modifier.isPublic(constructor.getModifiers()); - Class resultClazz = null; - if (loader instanceof URLClassLoader && !ispub) { - try { - final URLClassLoader urlLoader = (URLClassLoader) loader; - final URL url = new URL( - "memclass", "localhost", -1, "/" + newDynName.replace('/', '.') + "/", new URLStreamHandler() { - @Override - protected URLConnection openConnection(URL u) throws IOException { - return new URLConnection(u) { - @Override - public void connect() throws IOException { - // do nothing - } - - @Override - public InputStream getInputStream() throws IOException { - return new ByteArrayInputStream(bytes); - } - }; - } - }); - Method addURLMethod = URLClassLoader.class.getDeclaredMethod("addURL", URL.class); - addURLMethod.setAccessible(true); - addURLMethod.invoke(urlLoader, url); - resultClazz = urlLoader.loadClass(newDynName.replace('/', '.')); - } catch (Throwable t) { // 异常无需理会, 使用下一种loader方式 - t.printStackTrace(); - } - } - if (!ispub && resultClazz == null) { - throw new RedkaleException( - "[" + clazz + "] have no public or ConstructorParameters-Annotation constructor."); - } - try { - if (resultClazz == null) { - resultClazz = new ClassLoader(loader) { - public final Class loadClass(String name, byte[] b) { - return defineClass(name, b, 0, b.length); - } - }.loadClass(newDynName.replace('/', '.'), bytes); - } - RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, resultClazz); - RedkaleClassLoader.putReflectionDeclaredConstructors(resultClazz, newDynName.replace('/', '.')); - return (Creator) resultClazz.getDeclaredConstructor().newInstance(); - } catch (Exception ex) { - throw new RedkaleException(ex); - } - } -} +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.util; + +import static org.redkale.asm.Opcodes.*; + +import java.io.*; +import java.lang.reflect.*; +import java.net.*; +import java.util.*; +import java.util.AbstractMap.SimpleEntry; +import java.util.concurrent.*; +import java.util.function.*; +import org.redkale.annotation.ConstructorParameters; +import org.redkale.asm.*; +import org.redkale.asm.Type; + +/** + * 实现一个类的构造方法。 代替低效的反射实现方式。 不支持数组类。 常见的无参数的构造函数类都可以自动生成Creator, 对应自定义的类可以提供一个静态构建Creator方法。 例如: + * + *

+ * + *
+ * public class Record {
+ *
+ *    private final int id;
+ *
+ *    private String name;
+ *
+ *    Record(int id, String name) {
+ *        this.id = id;
+ *        this.name = name;
+ *    }
+ *
+ *    private static Creator createCreator() {
+ *        return new Creator<Record>() {
+ *            @Override
+ *            @ConstructorParameters({"id", "name"})
+ *            public Record create(Object... params) {
+ *                if(params[0] == null) params[0] = 0;
+ *                return new Record((Integer) params[0], (String) params[1]);
+ *            }
+ *         };
+ *    }
+ * }
+ * 
+ * + *
+ * + * 或者: + * + *
+ * + *
+ * public class Record {
+ *
+ *    private final int id;
+ *
+ *    private String name;
+ *
+ *    @ConstructorParameters({"id", "name"})
+ *    public Record(int id, String name) {
+ *        this.id = id;
+ *        this.name = name;
+ *    }
+ * }
+ * 
+ * + *
+ * + *

详情见: https://redkale.org + * + * @author zhangjx + * @param 构建对象的数据类型 + */ +public interface Creator { + + /** + * 创建对象 + * + * @param params 构造函数的参数 + * @return 构建的对象 + */ + public T create(Object... params); + + /** + * 参数类型数组 + * + * @since 2.8.0 + * @return 参数类型数组 + */ + default Class[] paramTypes() { + return new Class[0]; + } + + /** + * 创建指定类型对象数组的IntFunction + * + * @param 泛型 + * @param type 类型 + * @return IntFunction + */ + public static IntFunction funcArray(final Class type) { + return Inners.CreatorInner.arrayCacheMap.computeIfAbsent(type, Inners.CreatorInner::createArrayFunction); + } + + public static IntFunction funcStringArray() { + return Inners.CreatorInner.stringFuncArray; + } + + public static Creator load(Class clazz) { + return Inners.CreatorInner.creatorCacheMap.computeIfAbsent(clazz, v -> create(clazz)); + } + + public static Creator register(Class clazz, final Supplier supplier) { + Creator creator = (Object... params) -> supplier.get(); + Inners.CreatorInner.creatorCacheMap.put(clazz, creator); + return creator; + } + + public static Creator register(final LambdaSupplier supplier) { + Creator creator = (Object... params) -> supplier.get(); + Inners.CreatorInner.creatorCacheMap.put(LambdaSupplier.readClass(supplier), creator); + return creator; + } + + /** + * 创建指定大小的对象数组 + * + * @param 泛型 + * @param type 类型 + * @param size 数组大小 + * @return 数组 + */ + public static T[] newArray(final Class type, final int size) { + if (type == int.class) { + return (T[]) (Object) new int[size]; + } + if (type == byte.class) { + return (T[]) (Object) new byte[size]; + } + if (type == long.class) { + return (T[]) (Object) new long[size]; + } + if (type == String.class) { + return (T[]) new String[size]; + } + if (type == Object.class) { + return (T[]) new Object[size]; + } + if (type == boolean.class) { + return (T[]) (Object) new boolean[size]; + } + if (type == short.class) { + return (T[]) (Object) new short[size]; + } + if (type == char.class) { + return (T[]) (Object) new char[size]; + } + if (type == float.class) { + return (T[]) (Object) new float[size]; + } + if (type == double.class) { + return (T[]) (Object) new double[size]; + } + return funcArray(type).apply(size); + } + + /** + * 根据Supplier生产Creator + * + * @param 构建类的数据类型 + * @param supplier Supplier + * @return Creator对象 + */ + public static Creator create(final Supplier supplier) { + Objects.requireNonNull(supplier); + return (Object... params) -> supplier.get(); + } + + /** + * 根据Function生产Creator + * + * @param 构建类的数据类型 + * @param func Function + * @return Creator对象 + */ + public static Creator create(final Function func) { + Objects.requireNonNull(func); + return (Object... params) -> func.apply(params); + } + + /** + * 根据指定的class采用ASM技术生产Creator。 + * + * @param 构建类的数据类型 + * @param clazz 构建类 + * @return Creator对象 + */ + @SuppressWarnings("unchecked") + public static Creator create(Class clazz) { + if (List.class.isAssignableFrom(clazz) + && (clazz.isAssignableFrom(ArrayList.class) + || clazz.getName().startsWith("java.util.Collections") + || clazz.getName().startsWith("java.util.ImmutableCollections") + || clazz.getName().startsWith("java.util.Arrays"))) { + clazz = (Class) ArrayList.class; + } else if (Map.class.isAssignableFrom(clazz) + && (clazz.isAssignableFrom(HashMap.class) + || clazz.getName().startsWith("java.util.Collections") + || clazz.getName().startsWith("java.util.ImmutableCollections"))) { + clazz = (Class) HashMap.class; + } else if (Set.class.isAssignableFrom(clazz) + && (clazz.isAssignableFrom(HashSet.class) + || clazz.getName().startsWith("java.util.Collections") + || clazz.getName().startsWith("java.util.ImmutableCollections"))) { + clazz = (Class) HashSet.class; + } else if (Map.class.isAssignableFrom(clazz) && clazz.isAssignableFrom(ConcurrentHashMap.class)) { + clazz = (Class) ConcurrentHashMap.class; + } else if (Deque.class.isAssignableFrom(clazz) + && (clazz.isAssignableFrom(ArrayDeque.class) + || clazz.getName().startsWith("java.util.Collections") + || clazz.getName().startsWith("java.util.ImmutableCollections"))) { + clazz = (Class) ArrayDeque.class; + } else if (Collection.class.isAssignableFrom(clazz) && clazz.isAssignableFrom(ArrayList.class)) { + clazz = (Class) ArrayList.class; + } else if (Map.Entry.class.isAssignableFrom(clazz) + && (Modifier.isInterface(clazz.getModifiers()) + || Modifier.isAbstract(clazz.getModifiers()) + || !Modifier.isPublic(clazz.getModifiers()))) { + clazz = (Class) AbstractMap.SimpleEntry.class; + } else if (Iterable.class == clazz) { + clazz = (Class) ArrayList.class; + } else if (CompletionStage.class.isAssignableFrom(clazz) && clazz.isAssignableFrom(CompletableFuture.class)) { + clazz = (Class) CompletableFuture.class; + } else if (Future.class.isAssignableFrom(clazz) && clazz.isAssignableFrom(CompletableFuture.class)) { + clazz = (Class) CompletableFuture.class; + } + Creator creator = Inners.CreatorInner.creatorCacheMap.get(clazz); + if (creator != null) { + return creator; + } + if (clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers())) { + throw new RedkaleException("[" + clazz + "] is a interface or abstract class, cannot create it's Creator."); + } + for (final Method method : clazz.getDeclaredMethods()) { // 查找类中是否存在提供创建Creator实例的静态方法 + if (!Modifier.isStatic(method.getModifiers())) { + continue; + } + if (method.getParameterTypes().length != 0) { + continue; + } + if (method.getReturnType() != Creator.class) { + continue; + } + try { + method.setAccessible(true); + Creator c = (Creator) method.invoke(null); + if (c != null) { + RedkaleClassLoader.putReflectionDeclaredMethods(clazz.getName()); + RedkaleClassLoader.putReflectionMethod(clazz.getName(), method); + return c; + } + } catch (Exception e) { + throw new RedkaleException(e); + } + } + final String supDynName = Creator.class.getName().replace('.', '/'); + final String interName = clazz.getName().replace('.', '/'); + final String interDesc = Type.getDescriptor(clazz); + ClassLoader loader = Thread.currentThread().getContextClassLoader(); + if (String.class.getClassLoader() != clazz.getClassLoader()) { + loader = clazz.getClassLoader(); + } + final String newDynName = "org/redkaledyn/creator/_Dyn" + Creator.class.getSimpleName() + "__" + + clazz.getName().replace('.', '_').replace('$', '_'); + try { + Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.')); + return (Creator) (clz == null ? loader.loadClass(newDynName.replace('/', '.')) : clz) + .getDeclaredConstructor() + .newInstance(); + } catch (Throwable ex) { + // do nothing + } + + Constructor constructor0 = null; + SimpleEntry[] constructorParameters0 = null; // 构造函数的参数 + + if (constructor0 == null) { // 1、查找public的空参数构造函数 + for (Constructor c : clazz.getConstructors()) { + if (c.getParameterCount() == 0) { + constructor0 = c; + constructorParameters0 = new SimpleEntry[0]; + break; + } + } + } + if (constructor0 == null) { // 2、查找public带ConstructorParameters注解的构造函数 + for (Constructor c : clazz.getConstructors()) { + ConstructorParameters cp = (ConstructorParameters) c.getAnnotation(ConstructorParameters.class); + if (cp == null) { + continue; + } + SimpleEntry[] fields = + Inners.CreatorInner.getConstructorField(clazz, c.getParameterCount(), cp.value()); + if (fields != null) { + constructor0 = c; + constructorParameters0 = fields; + break; + } + } + } + if (constructor0 == null) { // 3、查找public且不带ConstructorParameters注解的构造函数 + List cs = new ArrayList<>(); + for (Constructor c : clazz.getConstructors()) { + if (c.getAnnotation(ConstructorParameters.class) != null) { + continue; + } + if (c.getParameterCount() < 1) { + continue; + } + cs.add(c); + } + // 优先参数最多的构造函数 + cs.sort((o1, o2) -> o2.getParameterCount() - o1.getParameterCount()); + for (Constructor c : cs) { + SimpleEntry[] fields = Inners.CreatorInner.getConstructorField( + clazz, c.getParameterCount(), Type.getConstructorDescriptor(c)); + if (fields != null) { + constructor0 = c; + constructorParameters0 = fields; + break; + } + } + } + if (constructor0 == null) { // 4、查找非private带ConstructorParameters的构造函数 + for (Constructor c : clazz.getDeclaredConstructors()) { + if (Modifier.isPublic(c.getModifiers()) || Modifier.isPrivate(c.getModifiers())) { + continue; + } + ConstructorParameters cp = (ConstructorParameters) c.getAnnotation(ConstructorParameters.class); + if (cp == null) { + continue; + } + SimpleEntry[] fields = + Inners.CreatorInner.getConstructorField(clazz, c.getParameterCount(), cp.value()); + if (fields != null) { + constructor0 = c; + constructorParameters0 = fields; + break; + } + } + } + if (constructor0 == null) { // 5、查找非private且不带ConstructorParameters的构造函数 + List cs = new ArrayList<>(); + for (Constructor c : clazz.getDeclaredConstructors()) { + if (Modifier.isPublic(c.getModifiers()) || Modifier.isPrivate(c.getModifiers())) { + continue; + } + if (c.getAnnotation(ConstructorParameters.class) != null) { + continue; + } + if (c.getParameterCount() < 1) { + continue; + } + cs.add(c); + } + // 优先参数最多的构造函数 + cs.sort((o1, o2) -> o2.getParameterCount() - o1.getParameterCount()); + for (Constructor c : cs) { + SimpleEntry[] fields = Inners.CreatorInner.getConstructorField( + clazz, c.getParameterCount(), Type.getConstructorDescriptor(c)); + if (fields != null) { + constructor0 = c; + constructorParameters0 = fields; + break; + } + } + } + final Constructor constructor = constructor0; + final SimpleEntry[] constructorParameters = constructorParameters0; + if (constructor == null || constructorParameters == null) { + throw new RedkaleException( + "[" + clazz + "] have no public or ConstructorParameters-Annotation constructor."); + } + final int[] iconsts = {ICONST_0, ICONST_1, ICONST_2, ICONST_3, ICONST_4, ICONST_5}; + // ------------------------------------------------------------- + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); + FieldVisitor fv; + MethodVisitor mv; + AnnotationVisitor av0; + cw.visit( + V11, + ACC_PUBLIC + ACC_FINAL + ACC_SUPER, + newDynName, + "Ljava/lang/Object;L" + supDynName + "<" + interDesc + ">;", + "java/lang/Object", + new String[] {supDynName}); + + { // Creator自身的构造方法 + mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + { // paramTypes 方法 + mv = cw.visitMethod(ACC_PUBLIC, "paramTypes", "()[Ljava/lang/Class;", null, null); + int paramLen = constructorParameters.length; + if (paramLen < 6) { + mv.visitInsn(ICONST_0 + paramLen); + } else if (paramLen <= Byte.MAX_VALUE) { + mv.visitIntInsn(BIPUSH, paramLen); + } else if (paramLen <= Short.MAX_VALUE) { + mv.visitIntInsn(SIPUSH, paramLen); + } else { + mv.visitLdcInsn(paramLen); + } + mv.visitTypeInsn(ANEWARRAY, "java/lang/Class"); + + for (int i = 0; i < constructorParameters.length; i++) { + final Class pt = constructorParameters[i].getValue(); + mv.visitInsn(DUP); + if (i < 6) { + mv.visitInsn(iconsts[i]); + } else if (i <= Byte.MAX_VALUE) { + mv.visitIntInsn(BIPUSH, i); + } else if (i <= Short.MAX_VALUE) { + mv.visitIntInsn(SIPUSH, i); + } else { + mv.visitLdcInsn(i); + } + Asms.visitFieldInsn(mv, pt); + mv.visitInsn(AASTORE); + } + mv.visitInsn(ARETURN); + mv.visitMaxs(4, 1); + mv.visitEnd(); + } + { // create 方法 + mv = cw.visitMethod( + ACC_PUBLIC + ACC_VARARGS, "create", "([Ljava/lang/Object;)L" + interName + ";", null, null); + if (constructorParameters.length > 0) { + av0 = mv.visitAnnotation(Type.getDescriptor(ConstructorParameters.class), true); + AnnotationVisitor av1 = av0.visitArray("value"); + for (SimpleEntry n : constructorParameters) { + av1.visit(null, n.getKey()); + } + av1.visitEnd(); + av0.visitEnd(); + } + { // 有Primitive数据类型且值为null的参数需要赋默认值 + for (int i = 0; i < constructorParameters.length; i++) { + final Class pt = constructorParameters[i].getValue(); + if (!pt.isPrimitive()) { + continue; + } + mv.visitVarInsn(ALOAD, 1); + if (i < 6) { + mv.visitInsn(iconsts[i]); + } else if (i <= Byte.MAX_VALUE) { + mv.visitIntInsn(BIPUSH, i); + } else if (i <= Short.MAX_VALUE) { + mv.visitIntInsn(SIPUSH, i); + } else { + mv.visitLdcInsn(i); + } + mv.visitInsn(AALOAD); + Label lab = new Label(); + mv.visitJumpInsn(IFNONNULL, lab); + mv.visitVarInsn(ALOAD, 1); + if (i < 6) { + mv.visitInsn(iconsts[i]); + } else if (i <= Byte.MAX_VALUE) { + mv.visitIntInsn(BIPUSH, i); + } else if (i <= Short.MAX_VALUE) { + mv.visitIntInsn(SIPUSH, i); + } else { + mv.visitLdcInsn(i); + } + if (pt == int.class) { + mv.visitInsn(ICONST_0); + mv.visitMethodInsn( + INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false); + } else if (pt == long.class) { + mv.visitInsn(LCONST_0); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;", false); + } else if (pt == boolean.class) { + mv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "FALSE", "Ljava/lang/Boolean;"); + } else if (pt == short.class) { + mv.visitInsn(ICONST_0); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;", false); + } else if (pt == float.class) { + mv.visitInsn(FCONST_0); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", false); + } else if (pt == byte.class) { + mv.visitInsn(ICONST_0); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;", false); + } else if (pt == double.class) { + mv.visitInsn(DCONST_0); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", false); + } else if (pt == char.class) { + mv.visitInsn(ICONST_0); + mv.visitMethodInsn( + INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;", false); + } + mv.visitInsn(AASTORE); + mv.visitLabel(lab); + } + } + mv.visitTypeInsn(NEW, interName); + mv.visitInsn(DUP); + // --------------------------------------- + { + for (int i = 0; i < constructorParameters.length; i++) { + mv.visitVarInsn(ALOAD, 1); + if (i < 6) { + mv.visitInsn(iconsts[i]); + } else if (i <= Byte.MAX_VALUE) { + mv.visitIntInsn(BIPUSH, i); + } else if (i <= Short.MAX_VALUE) { + mv.visitIntInsn(SIPUSH, i); + } else { + mv.visitLdcInsn(i); + } + mv.visitInsn(AALOAD); + final Class ct = constructorParameters[i].getValue(); + if (ct.isPrimitive()) { + final Class bigct = TypeToken.primitiveToWrapper(ct); + mv.visitTypeInsn(CHECKCAST, bigct.getName().replace('.', '/')); + try { + Method pm = bigct.getMethod(ct.getSimpleName() + "Value"); + mv.visitMethodInsn( + INVOKEVIRTUAL, + bigct.getName().replace('.', '/'), + pm.getName(), + Type.getMethodDescriptor(pm), + false); + } catch (Exception ex) { + throw new RedkaleException(ex); // 不可能会发生 + } + } else { + mv.visitTypeInsn(CHECKCAST, ct.getName().replace('.', '/')); + } + } + } + // --------------------------------------- + mv.visitMethodInsn(INVOKESPECIAL, interName, "", Type.getConstructorDescriptor(constructor), false); + mv.visitInsn(ARETURN); + mv.visitMaxs((constructorParameters.length > 0 ? (constructorParameters.length + 3) : 2), 2); + mv.visitEnd(); + } + { // 虚拟 create 方法 + mv = cw.visitMethod( + ACC_PUBLIC + ACC_BRIDGE + ACC_VARARGS + ACC_SYNTHETIC, + "create", + "([Ljava/lang/Object;)Ljava/lang/Object;", + null, + null); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "create", "([Ljava/lang/Object;)" + interDesc, false); + mv.visitInsn(ARETURN); + mv.visitMaxs(2, 2); + mv.visitEnd(); + } + cw.visitEnd(); + final byte[] bytes = cw.toByteArray(); + final boolean ispub = Modifier.isPublic(constructor.getModifiers()); + Class resultClazz = null; + if (loader instanceof URLClassLoader && !ispub) { + try { + final URLClassLoader urlLoader = (URLClassLoader) loader; + final URL url = new URL( + "memclass", "localhost", -1, "/" + newDynName.replace('/', '.') + "/", new URLStreamHandler() { + @Override + protected URLConnection openConnection(URL u) throws IOException { + return new URLConnection(u) { + @Override + public void connect() throws IOException { + // do nothing + } + + @Override + public InputStream getInputStream() throws IOException { + return new ByteArrayInputStream(bytes); + } + }; + } + }); + Method addURLMethod = URLClassLoader.class.getDeclaredMethod("addURL", URL.class); + addURLMethod.setAccessible(true); + addURLMethod.invoke(urlLoader, url); + resultClazz = urlLoader.loadClass(newDynName.replace('/', '.')); + } catch (Throwable t) { // 异常无需理会, 使用下一种loader方式 + t.printStackTrace(); + } + } + if (!ispub && resultClazz == null) { + throw new RedkaleException( + "[" + clazz + "] have no public or ConstructorParameters-Annotation constructor."); + } + try { + if (resultClazz == null) { + resultClazz = new ClassLoader(loader) { + public final Class loadClass(String name, byte[] b) { + return defineClass(name, b, 0, b.length); + } + }.loadClass(newDynName.replace('/', '.'), bytes); + } + RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, resultClazz); + RedkaleClassLoader.putReflectionDeclaredConstructors(resultClazz, newDynName.replace('/', '.')); + return (Creator) resultClazz.getDeclaredConstructor().newInstance(); + } catch (Exception ex) { + throw new RedkaleException(ex); + } + } +} diff --git a/src/main/java/org/redkale/util/Flows.java b/src/main/java/org/redkale/util/Flows.java index 1048829ed..21b2e610b 100644 --- a/src/main/java/org/redkale/util/Flows.java +++ b/src/main/java/org/redkale/util/Flows.java @@ -1,322 +1,322 @@ -/* - * 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.util; - -import static org.redkale.util.Utility.hexToBin; - -import java.lang.reflect.*; -import java.util.*; -import java.util.concurrent.*; -import java.util.function.Function; - -/** - * Flow简单的操作 - * - *

详情见: https://redkale.org - * - * @since 2.5.0 - */ -public abstract class Flows { - - /** - * - * - *

- * - *
-     * public class AnonymousMonoFutureFunction implements java.util.function.Function<Object, java.util.concurrent.CompletableFuture> {
-     *
-     *      @Override
-     *      public java.util.concurrent.CompletableFuture apply(Object t) {
-     *          return ((reactor.core.publisher.Mono) t).toFuture();
-     *      }
-     *
-     * }
-     * 
- * - *
- */ - private static final String FUNCTION_MONO_FUTRUE_BINARY = "cafebabe0000003700220a000200030700040c0005000" - + "60100106a6176612f6c616e672f4f626a6563740100063c696e69743e01000328295607000801001b72656163746f722f636f72652" - + "f7075626c69736865722f4d6f6e6f0a0007000a0c000b000c010008746f46757475726501002a28294c6a6176612f7574696c2f636" - + "f6e63757272656e742f436f6d706c657461626c654675747572653b0a000e000f0700100c0011001201002c6f72672f7265646b616" - + "c652f7574696c2f416e6f6e796d6f75734d6f6e6f46757475726546756e6374696f6e0100056170706c7901003c284c6a6176612f6" - + "c616e672f4f626a6563743b294c6a6176612f7574696c2f636f6e63757272656e742f436f6d706c657461626c654675747572653b0" - + "7001401001b6a6176612f7574696c2f66756e6374696f6e2f46756e6374696f6e010004436f646501000f4c696e654e756d6265725" - + "461626c650100124c6f63616c5661726961626c655461626c650100047468697301002e4c6f72672f7265646b616c652f7574696c2" - + "f416e6f6e796d6f75734d6f6e6f46757475726546756e6374696f6e3b010001740100124c6a6176612f6c616e672f4f626a6563743" - + "b0100104d6574686f64506172616d6574657273010026284c6a6176612f6c616e672f4f626a6563743b294c6a6176612f6c616e672" - + "f4f626a6563743b0100095369676e617475726501006b4c6a6176612f6c616e672f4f626a6563743b4c6a6176612f7574696c2f667" - + "56e6374696f6e2f46756e6374696f6e3c4c6a6176612f6c616e672f4f626a6563743b4c6a6176612f7574696c2f636f6e637572726" - + "56e742f436f6d706c657461626c654675747572653b3e3b01000a536f7572636546696c65010020416e6f6e796d6f75734d6f6e6f4" - + "6757475726546756e6374696f6e2e6a6176610021000e00020001001300000003000100050006000100150000002f0001000100000" - + "0052ab70001b10000000200160000000600010000000c00170000000c0001000000050018001900000001001100120002001500000" - + "03c00010002000000082bc00007b60009b000000002001600000006000100000010001700000016000200000008001800190000000" - + "00008001a001b0001001c0000000501001a000010410011001d000200150000003000020002000000062a2bb6000db000000002001" - + "60000000600010000000c00170000000c000100000006001800190000001c0000000501001a10000002001e00000002001f0020000" - + "000020021"; - - /** - * - * - *
- * - *
-     * public class AnonymousFluxFutureFunction implements java.util.function.Function<Object, java.util.concurrent.CompletableFuture> {
-     *
-     *      @Override
-     *      public java.util.concurrent.CompletableFuture apply(Object t) {
-     *          return ((reactor.core.publisher.Flux) t).collectList().toFuture();
-     *      }
-     *
-     * }
-     * 
- * - *
- */ - private static final String FUNCTION_FLUX_FUTRUE_BINARY = "cafebabe0000003700280a000200030700040c0005000" - + "60100106a6176612f6c616e672f4f626a6563740100063c696e69743e01000328295607000801001b72656163746f722f636f72" - + "652f7075626c69736865722f466c75780a0007000a0c000b000c01000b636f6c6c6563744c69737401001f28294c72656163746" - + "f722f636f72652f7075626c69736865722f4d6f6e6f3b0a000e000f0700100c0011001201001b72656163746f722f636f72652f" - + "7075626c69736865722f4d6f6e6f010008746f46757475726501002a28294c6a6176612f7574696c2f636f6e63757272656e742" - + "f436f6d706c657461626c654675747572653b0a001400150700160c0017001801002c6f72672f7265646b616c652f7574696c2f" - + "416e6f6e796d6f7573466c757846757475726546756e6374696f6e0100056170706c7901003c284c6a6176612f6c616e672f4f6" - + "26a6563743b294c6a6176612f7574696c2f636f6e63757272656e742f436f6d706c657461626c654675747572653b07001a0100" - + "1b6a6176612f7574696c2f66756e6374696f6e2f46756e6374696f6e010004436f646501000f4c696e654e756d6265725461626" - + "c650100124c6f63616c5661726961626c655461626c650100047468697301002e4c6f72672f7265646b616c652f7574696c2f41" - + "6e6f6e796d6f7573466c757846757475726546756e6374696f6e3b010001740100124c6a6176612f6c616e672f4f626a6563743" - + "b0100104d6574686f64506172616d6574657273010026284c6a6176612f6c616e672f4f626a6563743b294c6a6176612f6c616e" - + "672f4f626a6563743b0100095369676e617475726501006b4c6a6176612f6c616e672f4f626a6563743b4c6a6176612f7574696" - + "c2f66756e6374696f6e2f46756e6374696f6e3c4c6a6176612f6c616e672f4f626a6563743b4c6a6176612f7574696c2f636f6e" - + "63757272656e742f436f6d706c657461626c654675747572653b3e3b01000a536f7572636546696c65010020416e6f6e796d6f7" - + "573466c757846757475726546756e6374696f6e2e6a61766100210014000200010019000000030001000500060001001b000000" - + "2f00010001000000052ab70001b100000002001c0000000600010000000c001d0000000c000100000005001e001f00000001001" - + "700180002001b0000003f000100020000000b2bc00007b60009b6000db000000002001c00000006000100000010001d00000016" - + "00020000000b001e001f00000000000b00200021000100220000000501002000001041001700230002001b00000030000200020" - + "00000062a2bb60013b000000002001c0000000600010000000c001d0000000c000100000006001e001f00000022000000050100" - + "201000000200240000000200250026000000020027"; - - private static final Class reactorMonoClass; - - private static final Class reactorFluxClass; - - private static final Function reactorMonoFunction; - - private static final Function reactorFluxFunction; - - static { - Class reactorMonoClass0 = null; - Class reactorFluxClass0 = null; - Function reactorMonoFunction0 = null; - Function reactorFluxFunction0 = null; - - if (!"executable".equals(System.getProperty("org.graalvm.nativeimage.kind"))) { // not native-image - try { - // - reactorMonoClass0 = - Thread.currentThread().getContextClassLoader().loadClass("reactor.core.publisher.Mono"); - Class> monoFuncClass = null; - try { - monoFuncClass = (Class) Thread.currentThread() - .getContextClassLoader() - .loadClass("org.redkale.util.AnonymousMonoFutureFunction"); - } catch (Throwable t) { - // do nothing - } - if (monoFuncClass == null) { - byte[] classBytes = hexToBin(FUNCTION_MONO_FUTRUE_BINARY); - monoFuncClass = (Class>) - new ClassLoader() { - public final Class loadClass(String name, byte[] b) { - return defineClass(name, b, 0, b.length); - } - }.loadClass("org.redkale.util.AnonymousMonoFutureFunction", classBytes); - RedkaleClassLoader.putDynClass(monoFuncClass.getName(), classBytes, monoFuncClass); - } - RedkaleClassLoader.putReflectionDeclaredConstructors(monoFuncClass, monoFuncClass.getName()); - reactorMonoFunction0 = (Function) - monoFuncClass.getDeclaredConstructor().newInstance(); - // - reactorFluxClass0 = - Thread.currentThread().getContextClassLoader().loadClass("reactor.core.publisher.Flux"); - Class> fluxFuncClass = null; - try { - fluxFuncClass = (Class) Thread.currentThread() - .getContextClassLoader() - .loadClass("org.redkale.util.AnonymousFluxFutureFunction"); - } catch (Throwable t) { - // do nothing - } - if (fluxFuncClass == null) { - byte[] classBytes = hexToBin(FUNCTION_FLUX_FUTRUE_BINARY); - fluxFuncClass = (Class>) - new ClassLoader() { - public final Class loadClass(String name, byte[] b) { - return defineClass(name, b, 0, b.length); - } - }.loadClass("org.redkale.util.AnonymousFluxFutureFunction", classBytes); - RedkaleClassLoader.putDynClass(fluxFuncClass.getName(), classBytes, fluxFuncClass); - } - RedkaleClassLoader.putReflectionDeclaredConstructors(fluxFuncClass, fluxFuncClass.getName()); - reactorFluxFunction0 = (Function) - fluxFuncClass.getDeclaredConstructor().newInstance(); - } catch (Throwable t) { - // do nothing - } - } - - reactorMonoClass = reactorMonoClass0; - reactorFluxClass = reactorFluxClass0; - reactorMonoFunction = reactorMonoFunction0; - reactorFluxFunction = reactorFluxFunction0; - } - - Flows() {} - - public static boolean maybePublisherClass(Class value) { - if (value == null) { - return false; - } - if (reactorFluxFunction != null) { - if (reactorMonoClass.isAssignableFrom(value)) { - return true; - } - if (reactorFluxClass.isAssignableFrom(value)) { - return true; - } - } - return Flow.Publisher.class.isAssignableFrom(value); - } - - public static Type maybePublisherSubType(Type value) { - if (value == null) { - return null; - } - if (!(value instanceof ParameterizedType)) { - return null; - } - ParameterizedType pt = (ParameterizedType) value; - Type parent = pt.getRawType() == null ? pt.getOwnerType() : pt.getRawType(); - if (!(parent instanceof Class)) { - return null; - } - if (pt.getActualTypeArguments().length != 1) { - return null; - } - if (reactorFluxFunction != null) { - if (reactorMonoClass.isAssignableFrom((Class) parent)) { - return pt.getActualTypeArguments()[0]; - } - if (reactorFluxClass.isAssignableFrom((Class) parent)) { - return pt.getActualTypeArguments()[0]; - } - } - if (Flow.Publisher.class.isAssignableFrom((Class) parent)) { - return pt.getActualTypeArguments()[0]; - } - return null; - } - - public static Object maybePublisherToFuture(Object value) { - if (value == null) { - return value; - } - if (reactorFluxFunction != null) { - Class clazz = value.getClass(); - if (reactorMonoClass.isAssignableFrom(clazz)) { - return reactorMonoFunction.apply(value); - } - if (reactorFluxClass.isAssignableFrom(clazz)) { - return reactorFluxFunction.apply(value); - } - if (Flow.Publisher.class.isAssignableFrom(clazz)) { - return createMonoFuture((Flow.Publisher) value); - } - } - return value; - } - - public static final CompletableFuture> createFluxFuture(Flow.Publisher publisher) { - SubscriberListFuture future = new SubscriberListFuture<>(); - publisher.subscribe(future); - return future; - } - - public static final CompletableFuture createMonoFuture(Flow.Publisher publisher) { - SubscriberFuture future = new SubscriberFuture<>(); - publisher.subscribe(future); - return future; - } - - /** - * 简单的CompletableFuture与Flow.Subscriber的结合类。 - * - *

详情见: https://redkale.org - * - * @since 2.5.0 - * @param T - */ - public static class SubscriberFuture extends CompletableFuture implements Flow.Subscriber { - - protected T rs; - - @Override - public void onSubscribe(Flow.Subscription s) { - s.request(Integer.MAX_VALUE); - } - - @Override - public void onNext(T item) { - rs = item; - } - - @Override - public void onError(Throwable t) { - completeExceptionally(t); - } - - @Override - public void onComplete() { - complete(rs); - } - } - - /** - * 简单的CompletableFuture与Flow.Subscriber的结合类。 - * - *

详情见: https://redkale.org - * - * @since 2.5.0 - * @param T - */ - public static class SubscriberListFuture extends CompletableFuture> implements Flow.Subscriber { - - protected List rs; - - @Override - public void onSubscribe(Flow.Subscription s) { - s.request(Integer.MAX_VALUE); - } - - @Override - public void onNext(T item) { - if (rs == null) { - rs = new ArrayList<>(); - } - rs.add(item); - } - - @Override - public void onError(Throwable t) { - completeExceptionally(t); - } - - @Override - public void onComplete() { - complete(rs == null ? new ArrayList<>() : rs); - } - } -} +/* + * 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.util; + +import static org.redkale.util.Utility.hexToBin; + +import java.lang.reflect.*; +import java.util.*; +import java.util.concurrent.*; +import java.util.function.Function; + +/** + * Flow简单的操作 + * + *

详情见: https://redkale.org + * + * @since 2.5.0 + */ +public abstract class Flows { + + /** + * + * + *

+ * + *
+     * public class AnonymousMonoFutureFunction implements java.util.function.Function<Object, java.util.concurrent.CompletableFuture> {
+     *
+     *      @Override
+     *      public java.util.concurrent.CompletableFuture apply(Object t) {
+     *          return ((reactor.core.publisher.Mono) t).toFuture();
+     *      }
+     *
+     * }
+     * 
+ * + *
+ */ + private static final String FUNCTION_MONO_FUTRUE_BINARY = "cafebabe0000003700220a000200030700040c0005000" + + "60100106a6176612f6c616e672f4f626a6563740100063c696e69743e01000328295607000801001b72656163746f722f636f72652" + + "f7075626c69736865722f4d6f6e6f0a0007000a0c000b000c010008746f46757475726501002a28294c6a6176612f7574696c2f636" + + "f6e63757272656e742f436f6d706c657461626c654675747572653b0a000e000f0700100c0011001201002c6f72672f7265646b616" + + "c652f7574696c2f416e6f6e796d6f75734d6f6e6f46757475726546756e6374696f6e0100056170706c7901003c284c6a6176612f6" + + "c616e672f4f626a6563743b294c6a6176612f7574696c2f636f6e63757272656e742f436f6d706c657461626c654675747572653b0" + + "7001401001b6a6176612f7574696c2f66756e6374696f6e2f46756e6374696f6e010004436f646501000f4c696e654e756d6265725" + + "461626c650100124c6f63616c5661726961626c655461626c650100047468697301002e4c6f72672f7265646b616c652f7574696c2" + + "f416e6f6e796d6f75734d6f6e6f46757475726546756e6374696f6e3b010001740100124c6a6176612f6c616e672f4f626a6563743" + + "b0100104d6574686f64506172616d6574657273010026284c6a6176612f6c616e672f4f626a6563743b294c6a6176612f6c616e672" + + "f4f626a6563743b0100095369676e617475726501006b4c6a6176612f6c616e672f4f626a6563743b4c6a6176612f7574696c2f667" + + "56e6374696f6e2f46756e6374696f6e3c4c6a6176612f6c616e672f4f626a6563743b4c6a6176612f7574696c2f636f6e637572726" + + "56e742f436f6d706c657461626c654675747572653b3e3b01000a536f7572636546696c65010020416e6f6e796d6f75734d6f6e6f4" + + "6757475726546756e6374696f6e2e6a6176610021000e00020001001300000003000100050006000100150000002f0001000100000" + + "0052ab70001b10000000200160000000600010000000c00170000000c0001000000050018001900000001001100120002001500000" + + "03c00010002000000082bc00007b60009b000000002001600000006000100000010001700000016000200000008001800190000000" + + "00008001a001b0001001c0000000501001a000010410011001d000200150000003000020002000000062a2bb6000db000000002001" + + "60000000600010000000c00170000000c000100000006001800190000001c0000000501001a10000002001e00000002001f0020000" + + "000020021"; + + /** + * + * + *
+ * + *
+     * public class AnonymousFluxFutureFunction implements java.util.function.Function<Object, java.util.concurrent.CompletableFuture> {
+     *
+     *      @Override
+     *      public java.util.concurrent.CompletableFuture apply(Object t) {
+     *          return ((reactor.core.publisher.Flux) t).collectList().toFuture();
+     *      }
+     *
+     * }
+     * 
+ * + *
+ */ + private static final String FUNCTION_FLUX_FUTRUE_BINARY = "cafebabe0000003700280a000200030700040c0005000" + + "60100106a6176612f6c616e672f4f626a6563740100063c696e69743e01000328295607000801001b72656163746f722f636f72" + + "652f7075626c69736865722f466c75780a0007000a0c000b000c01000b636f6c6c6563744c69737401001f28294c72656163746" + + "f722f636f72652f7075626c69736865722f4d6f6e6f3b0a000e000f0700100c0011001201001b72656163746f722f636f72652f" + + "7075626c69736865722f4d6f6e6f010008746f46757475726501002a28294c6a6176612f7574696c2f636f6e63757272656e742" + + "f436f6d706c657461626c654675747572653b0a001400150700160c0017001801002c6f72672f7265646b616c652f7574696c2f" + + "416e6f6e796d6f7573466c757846757475726546756e6374696f6e0100056170706c7901003c284c6a6176612f6c616e672f4f6" + + "26a6563743b294c6a6176612f7574696c2f636f6e63757272656e742f436f6d706c657461626c654675747572653b07001a0100" + + "1b6a6176612f7574696c2f66756e6374696f6e2f46756e6374696f6e010004436f646501000f4c696e654e756d6265725461626" + + "c650100124c6f63616c5661726961626c655461626c650100047468697301002e4c6f72672f7265646b616c652f7574696c2f41" + + "6e6f6e796d6f7573466c757846757475726546756e6374696f6e3b010001740100124c6a6176612f6c616e672f4f626a6563743" + + "b0100104d6574686f64506172616d6574657273010026284c6a6176612f6c616e672f4f626a6563743b294c6a6176612f6c616e" + + "672f4f626a6563743b0100095369676e617475726501006b4c6a6176612f6c616e672f4f626a6563743b4c6a6176612f7574696" + + "c2f66756e6374696f6e2f46756e6374696f6e3c4c6a6176612f6c616e672f4f626a6563743b4c6a6176612f7574696c2f636f6e" + + "63757272656e742f436f6d706c657461626c654675747572653b3e3b01000a536f7572636546696c65010020416e6f6e796d6f7" + + "573466c757846757475726546756e6374696f6e2e6a61766100210014000200010019000000030001000500060001001b000000" + + "2f00010001000000052ab70001b100000002001c0000000600010000000c001d0000000c000100000005001e001f00000001001" + + "700180002001b0000003f000100020000000b2bc00007b60009b6000db000000002001c00000006000100000010001d00000016" + + "00020000000b001e001f00000000000b00200021000100220000000501002000001041001700230002001b00000030000200020" + + "00000062a2bb60013b000000002001c0000000600010000000c001d0000000c000100000006001e001f00000022000000050100" + + "201000000200240000000200250026000000020027"; + + private static final Class reactorMonoClass; + + private static final Class reactorFluxClass; + + private static final Function reactorMonoFunction; + + private static final Function reactorFluxFunction; + + static { + Class reactorMonoClass0 = null; + Class reactorFluxClass0 = null; + Function reactorMonoFunction0 = null; + Function reactorFluxFunction0 = null; + + if (!"executable".equals(System.getProperty("org.graalvm.nativeimage.kind"))) { // not native-image + try { + // + reactorMonoClass0 = + Thread.currentThread().getContextClassLoader().loadClass("reactor.core.publisher.Mono"); + Class> monoFuncClass = null; + try { + monoFuncClass = (Class) Thread.currentThread() + .getContextClassLoader() + .loadClass("org.redkale.util.AnonymousMonoFutureFunction"); + } catch (Throwable t) { + // do nothing + } + if (monoFuncClass == null) { + byte[] classBytes = hexToBin(FUNCTION_MONO_FUTRUE_BINARY); + monoFuncClass = (Class>) + new ClassLoader() { + public final Class loadClass(String name, byte[] b) { + return defineClass(name, b, 0, b.length); + } + }.loadClass("org.redkale.util.AnonymousMonoFutureFunction", classBytes); + RedkaleClassLoader.putDynClass(monoFuncClass.getName(), classBytes, monoFuncClass); + } + RedkaleClassLoader.putReflectionDeclaredConstructors(monoFuncClass, monoFuncClass.getName()); + reactorMonoFunction0 = (Function) + monoFuncClass.getDeclaredConstructor().newInstance(); + // + reactorFluxClass0 = + Thread.currentThread().getContextClassLoader().loadClass("reactor.core.publisher.Flux"); + Class> fluxFuncClass = null; + try { + fluxFuncClass = (Class) Thread.currentThread() + .getContextClassLoader() + .loadClass("org.redkale.util.AnonymousFluxFutureFunction"); + } catch (Throwable t) { + // do nothing + } + if (fluxFuncClass == null) { + byte[] classBytes = hexToBin(FUNCTION_FLUX_FUTRUE_BINARY); + fluxFuncClass = (Class>) + new ClassLoader() { + public final Class loadClass(String name, byte[] b) { + return defineClass(name, b, 0, b.length); + } + }.loadClass("org.redkale.util.AnonymousFluxFutureFunction", classBytes); + RedkaleClassLoader.putDynClass(fluxFuncClass.getName(), classBytes, fluxFuncClass); + } + RedkaleClassLoader.putReflectionDeclaredConstructors(fluxFuncClass, fluxFuncClass.getName()); + reactorFluxFunction0 = (Function) + fluxFuncClass.getDeclaredConstructor().newInstance(); + } catch (Throwable t) { + // do nothing + } + } + + reactorMonoClass = reactorMonoClass0; + reactorFluxClass = reactorFluxClass0; + reactorMonoFunction = reactorMonoFunction0; + reactorFluxFunction = reactorFluxFunction0; + } + + Flows() {} + + public static boolean maybePublisherClass(Class value) { + if (value == null) { + return false; + } + if (reactorFluxFunction != null) { + if (reactorMonoClass.isAssignableFrom(value)) { + return true; + } + if (reactorFluxClass.isAssignableFrom(value)) { + return true; + } + } + return Flow.Publisher.class.isAssignableFrom(value); + } + + public static Type maybePublisherSubType(Type value) { + if (value == null) { + return null; + } + if (!(value instanceof ParameterizedType)) { + return null; + } + ParameterizedType pt = (ParameterizedType) value; + Type parent = pt.getRawType() == null ? pt.getOwnerType() : pt.getRawType(); + if (!(parent instanceof Class)) { + return null; + } + if (pt.getActualTypeArguments().length != 1) { + return null; + } + if (reactorFluxFunction != null) { + if (reactorMonoClass.isAssignableFrom((Class) parent)) { + return pt.getActualTypeArguments()[0]; + } + if (reactorFluxClass.isAssignableFrom((Class) parent)) { + return pt.getActualTypeArguments()[0]; + } + } + if (Flow.Publisher.class.isAssignableFrom((Class) parent)) { + return pt.getActualTypeArguments()[0]; + } + return null; + } + + public static Object maybePublisherToFuture(Object value) { + if (value == null) { + return value; + } + if (reactorFluxFunction != null) { + Class clazz = value.getClass(); + if (reactorMonoClass.isAssignableFrom(clazz)) { + return reactorMonoFunction.apply(value); + } + if (reactorFluxClass.isAssignableFrom(clazz)) { + return reactorFluxFunction.apply(value); + } + if (Flow.Publisher.class.isAssignableFrom(clazz)) { + return createMonoFuture((Flow.Publisher) value); + } + } + return value; + } + + public static final CompletableFuture> createFluxFuture(Flow.Publisher publisher) { + SubscriberListFuture future = new SubscriberListFuture<>(); + publisher.subscribe(future); + return future; + } + + public static final CompletableFuture createMonoFuture(Flow.Publisher publisher) { + SubscriberFuture future = new SubscriberFuture<>(); + publisher.subscribe(future); + return future; + } + + /** + * 简单的CompletableFuture与Flow.Subscriber的结合类。 + * + *

详情见: https://redkale.org + * + * @since 2.5.0 + * @param T + */ + public static class SubscriberFuture extends CompletableFuture implements Flow.Subscriber { + + protected T rs; + + @Override + public void onSubscribe(Flow.Subscription s) { + s.request(Integer.MAX_VALUE); + } + + @Override + public void onNext(T item) { + rs = item; + } + + @Override + public void onError(Throwable t) { + completeExceptionally(t); + } + + @Override + public void onComplete() { + complete(rs); + } + } + + /** + * 简单的CompletableFuture与Flow.Subscriber的结合类。 + * + *

详情见: https://redkale.org + * + * @since 2.5.0 + * @param T + */ + public static class SubscriberListFuture extends CompletableFuture> implements Flow.Subscriber { + + protected List rs; + + @Override + public void onSubscribe(Flow.Subscription s) { + s.request(Integer.MAX_VALUE); + } + + @Override + public void onNext(T item) { + if (rs == null) { + rs = new ArrayList<>(); + } + rs.add(item); + } + + @Override + public void onError(Throwable t) { + completeExceptionally(t); + } + + @Override + public void onComplete() { + complete(rs == null ? new ArrayList<>() : rs); + } + } +} diff --git a/src/main/java/org/redkale/util/Inners.java b/src/main/java/org/redkale/util/Inners.java index 698fc63ec..0a9f9837a 100644 --- a/src/main/java/org/redkale/util/Inners.java +++ b/src/main/java/org/redkale/util/Inners.java @@ -1,336 +1,336 @@ -/* - * - */ -package org.redkale.util; - -import static org.redkale.asm.Opcodes.*; - -import java.io.*; -import java.lang.reflect.*; -import java.math.*; -import java.net.*; -import java.nio.ByteBuffer; -import java.util.*; -import java.util.concurrent.*; -import java.util.function.*; -import java.util.logging.*; -import java.util.stream.Stream; -import org.redkale.asm.*; - -/** @author zhangjx */ -class Inners { - - private Inners() {} - - static class CreatorInner { - - static final Logger logger = Logger.getLogger(Creator.class.getSimpleName()); - - static final Map creatorCacheMap = new HashMap<>(); - - static final Map arrayCacheMap = new ConcurrentHashMap<>(); - - static final IntFunction stringFuncArray = x -> new String[x]; - - private CreatorInner() {} - - static { - creatorCacheMap.put(Object.class, p -> new Object()); - creatorCacheMap.put(ArrayList.class, p -> new ArrayList<>()); - creatorCacheMap.put(HashMap.class, p -> new HashMap<>()); - creatorCacheMap.put(HashSet.class, p -> new HashSet<>()); - creatorCacheMap.put(LinkedHashSet.class, p -> new LinkedHashSet<>()); - creatorCacheMap.put(LinkedHashMap.class, p -> new LinkedHashMap<>()); - creatorCacheMap.put(Stream.class, p -> new ArrayList<>().stream()); - creatorCacheMap.put(ConcurrentHashMap.class, p -> new ConcurrentHashMap<>()); - creatorCacheMap.put(CompletableFuture.class, p -> new CompletableFuture<>()); - creatorCacheMap.put(CompletionStage.class, p -> new CompletableFuture<>()); - creatorCacheMap.put(Future.class, p -> new CompletableFuture<>()); - creatorCacheMap.put(AnyValueWriter.class, p -> new AnyValueWriter()); - creatorCacheMap.put(AnyValue.class, p -> new AnyValueWriter()); - creatorCacheMap.put(Map.Entry.class, new Creator() { - @Override - @org.redkale.annotation.ConstructorParameters({"key", "value"}) - public Map.Entry create(Object... params) { - return new AbstractMap.SimpleEntry(params[0], params[1]); - } - - @Override - public Class[] paramTypes() { - return new Class[] {Object.class, Object.class}; - } - }); - creatorCacheMap.put(AbstractMap.SimpleEntry.class, new Creator() { - @Override - @org.redkale.annotation.ConstructorParameters({"key", "value"}) - public AbstractMap.SimpleEntry create(Object... params) { - return new AbstractMap.SimpleEntry(params[0], params[1]); - } - - @Override - public Class[] paramTypes() { - return new Class[] {Object.class, Object.class}; - } - }); - - arrayCacheMap.put(int.class, t -> new int[t]); - arrayCacheMap.put(byte.class, t -> new byte[t]); - arrayCacheMap.put(long.class, t -> new long[t]); - arrayCacheMap.put(String.class, t -> new String[t]); - arrayCacheMap.put(Object.class, t -> new Object[t]); - arrayCacheMap.put(boolean.class, t -> new boolean[t]); - arrayCacheMap.put(short.class, t -> new short[t]); - arrayCacheMap.put(char.class, t -> new char[t]); - arrayCacheMap.put(float.class, t -> new float[t]); - arrayCacheMap.put(double.class, t -> new double[t]); - arrayCacheMap.put(BigInteger.class, t -> new BigInteger[t]); - arrayCacheMap.put(BigDecimal.class, t -> new BigDecimal[t]); - arrayCacheMap.put(ByteBuffer.class, t -> new ByteBuffer[t]); - arrayCacheMap.put(SocketAddress.class, t -> new SocketAddress[t]); - arrayCacheMap.put(InetSocketAddress.class, t -> new InetSocketAddress[t]); - arrayCacheMap.put(CompletableFuture.class, t -> new CompletableFuture[t]); - } - - static class SimpleClassVisitor extends ClassVisitor { - - private final String constructorDesc; - - private final List fieldNames; - - private boolean started; - - public SimpleClassVisitor(int api, List fieldNames, String constructorDesc) { - super(api); - this.fieldNames = fieldNames; - this.constructorDesc = constructorDesc; - } - - @Override - public MethodVisitor visitMethod( - int access, String name, String desc, String signature, String[] exceptions) { - if (java.lang.reflect.Modifier.isStatic(access) || !"".equals(name)) { - return null; - } - if (constructorDesc != null && !constructorDesc.equals(desc)) { - return null; - } - if (this.started) { - return null; - } - this.started = true; - // 返回的List中参数列表可能会比方法参数量多,因为方法内的临时变量也会存入list中, 所以需要list的元素集合比方法的参数多 - return new MethodVisitor(Opcodes.ASM6) { - @Override - public void visitLocalVariable( - String name, String description, String signature, Label start, Label end, int index) { - if (index < 1) { - return; - } - int size = fieldNames.size(); - // index不会按顺序执行的 - if (index > size) { - for (int i = size; i < index; i++) { - fieldNames.add(" "); - } - fieldNames.set(index - 1, name); - } - fieldNames.set(index - 1, name); - } - }; - } - } - - public static AbstractMap.SimpleEntry[] getConstructorField( - Class clazz, int paramCount, String constructorDesc) { - String n = clazz.getName(); - InputStream in = clazz.getResourceAsStream(n.substring(n.lastIndexOf('.') + 1) + ".class"); - if (in == null) { - return null; - } - ByteArrayOutputStream out = new ByteArrayOutputStream(1024); - byte[] bytes = new byte[1024]; - int pos; - try { - while ((pos = in.read(bytes)) != -1) { - out.write(bytes, 0, pos); - } - in.close(); - } catch (IOException io) { - return null; - } - final List fieldNames = new ArrayList<>(); - new ClassReader(out.toByteArray()) - .accept(new SimpleClassVisitor(Opcodes.ASM6, fieldNames, constructorDesc), 0); - while (fieldNames.remove(" ")) - ; // 删掉空元素 - if (fieldNames.isEmpty()) { - return null; - } - if (paramCount == fieldNames.size()) { - return getConstructorField(clazz, paramCount, fieldNames.toArray(new String[fieldNames.size()])); - } else { - String[] fs = new String[paramCount]; - for (int i = 0; i < fs.length; i++) { - fs[i] = fieldNames.get(i); - } - return getConstructorField(clazz, paramCount, fs); - } - } - - public static AbstractMap.SimpleEntry[] getConstructorField( - Class clazz, int paramCount, String[] names) { - AbstractMap.SimpleEntry[] se = new AbstractMap.SimpleEntry[names.length]; - for (int i = 0; i < names.length; i++) { // 查询参数名对应的Field - try { - Field field = clazz.getDeclaredField(names[i]); - se[i] = new AbstractMap.SimpleEntry<>(field.getName(), field.getType()); - } catch (NoSuchFieldException fe) { - Class cz = clazz; - Field field = null; - while ((cz = cz.getSuperclass()) != Object.class) { - try { - field = cz.getDeclaredField(names[i]); - break; - } catch (NoSuchFieldException nsfe) { - // do nothing - } - } - if (field == null) { - return null; - } - se[i] = new AbstractMap.SimpleEntry<>(field.getName(), field.getType()); - } catch (Exception e) { - if (logger.isLoggable(Level.FINE)) { - logger.log(Level.FINE, clazz + " getConstructorField error", e); - } - return null; - } - } - return se; - } - - public static AbstractMap.SimpleEntry[] getConstructorField( - Class clazz, int paramCount, Parameter[] params) { - AbstractMap.SimpleEntry[] se = new AbstractMap.SimpleEntry[params.length]; - for (int i = 0; i < params.length; i++) { // 查询参数名对应的Field - try { - Field field = clazz.getDeclaredField(params[i].getName()); - se[i] = new AbstractMap.SimpleEntry<>(field.getName(), field.getType()); - } catch (Exception e) { - return null; - } - } - return se; - } - - public static IntFunction createArrayFunction(final Class clazz) { - final String interName = clazz.getName().replace('.', '/'); - final String interDesc = org.redkale.asm.Type.getDescriptor(clazz); - final ClassLoader loader = clazz.getClassLoader(); - final String newDynName = "org/redkaledyn/creator/_DynArrayFunction__" - + clazz.getName().replace('.', '_').replace('$', '_'); - try { - Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.')); - return (IntFunction) (clz == null ? loader.loadClass(newDynName.replace('/', '.')) : clz) - .getDeclaredConstructor() - .newInstance(); - } catch (Throwable ex) { - // do nothing - } - - // ------------------------------------------------------------- - ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); - MethodVisitor mv; - cw.visit( - V11, - ACC_PUBLIC + ACC_FINAL + ACC_SUPER, - newDynName, - "Ljava/lang/Object;Ljava/util/function/IntFunction<[" + interDesc + ">;", - "java/lang/Object", - new String[] {"java/util/function/IntFunction"}); - - { // IntFunction自身的构造方法 - mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); - mv.visitInsn(RETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - { // apply 方法 - mv = cw.visitMethod(ACC_PUBLIC, "apply", "(I)[" + interDesc, null, null); - mv.visitVarInsn(ILOAD, 1); - mv.visitTypeInsn(ANEWARRAY, interName); - mv.visitInsn(ARETURN); - mv.visitMaxs(1, 2); - mv.visitEnd(); - } - { // 虚拟 apply 方法 - mv = cw.visitMethod( - ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC, "apply", "(I)Ljava/lang/Object;", null, null); - mv.visitVarInsn(ALOAD, 0); - mv.visitVarInsn(ILOAD, 1); - mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "apply", "(I)[" + interDesc, false); - mv.visitInsn(ARETURN); - mv.visitMaxs(2, 2); - mv.visitEnd(); - } - cw.visitEnd(); - final byte[] bytes = cw.toByteArray(); - try { - Class resultClazz = new ClassLoader(loader) { - public final Class loadClass(String name, byte[] b) { - return defineClass(name, b, 0, b.length); - } - }.loadClass(newDynName.replace('/', '.'), bytes); - RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, resultClazz); - RedkaleClassLoader.putReflectionDeclaredConstructors(resultClazz, newDynName.replace('/', '.')); - return (IntFunction) resultClazz.getDeclaredConstructor().newInstance(); - } catch (Throwable ex) { - // ex.printStackTrace(); //一般不会发生, native-image在没有预编译情况下会报错 - return t -> (T[]) Array.newInstance(clazz, t); - } - } - } - - static class CopierInner { - - static final ConcurrentHashMap> copierOneCaches = - new ConcurrentHashMap(); - - static final ConcurrentHashMap>> - copierTwoCaches = new ConcurrentHashMap(); - - static final ConcurrentHashMap> copierFuncOneCaches = - new ConcurrentHashMap(); - - static final ConcurrentHashMap>> - copierFuncTwoCaches = new ConcurrentHashMap(); - - static final ConcurrentHashMap>> - copierFuncListOneCaches = new ConcurrentHashMap(); - - static final ConcurrentHashMap< - Class, ConcurrentHashMap>>> - copierFuncListTwoCaches = new ConcurrentHashMap(); - - private CopierInner() {} - - public static void clearCopierCache() { - copierOneCaches.clear(); - copierTwoCaches.clear(); - copierFuncOneCaches.clear(); - copierFuncTwoCaches.clear(); - copierFuncListOneCaches.clear(); - copierFuncListTwoCaches.clear(); - } - } - - static class InvokerInner { - - static final ConcurrentHashMap> invokerCaches = - new ConcurrentHashMap(); - - private InvokerInner() {} - } -} +/* + * + */ +package org.redkale.util; + +import static org.redkale.asm.Opcodes.*; + +import java.io.*; +import java.lang.reflect.*; +import java.math.*; +import java.net.*; +import java.nio.ByteBuffer; +import java.util.*; +import java.util.concurrent.*; +import java.util.function.*; +import java.util.logging.*; +import java.util.stream.Stream; +import org.redkale.asm.*; + +/** @author zhangjx */ +class Inners { + + private Inners() {} + + static class CreatorInner { + + static final Logger logger = Logger.getLogger(Creator.class.getSimpleName()); + + static final Map creatorCacheMap = new HashMap<>(); + + static final Map arrayCacheMap = new ConcurrentHashMap<>(); + + static final IntFunction stringFuncArray = x -> new String[x]; + + private CreatorInner() {} + + static { + creatorCacheMap.put(Object.class, p -> new Object()); + creatorCacheMap.put(ArrayList.class, p -> new ArrayList<>()); + creatorCacheMap.put(HashMap.class, p -> new HashMap<>()); + creatorCacheMap.put(HashSet.class, p -> new HashSet<>()); + creatorCacheMap.put(LinkedHashSet.class, p -> new LinkedHashSet<>()); + creatorCacheMap.put(LinkedHashMap.class, p -> new LinkedHashMap<>()); + creatorCacheMap.put(Stream.class, p -> new ArrayList<>().stream()); + creatorCacheMap.put(ConcurrentHashMap.class, p -> new ConcurrentHashMap<>()); + creatorCacheMap.put(CompletableFuture.class, p -> new CompletableFuture<>()); + creatorCacheMap.put(CompletionStage.class, p -> new CompletableFuture<>()); + creatorCacheMap.put(Future.class, p -> new CompletableFuture<>()); + creatorCacheMap.put(AnyValueWriter.class, p -> new AnyValueWriter()); + creatorCacheMap.put(AnyValue.class, p -> new AnyValueWriter()); + creatorCacheMap.put(Map.Entry.class, new Creator() { + @Override + @org.redkale.annotation.ConstructorParameters({"key", "value"}) + public Map.Entry create(Object... params) { + return new AbstractMap.SimpleEntry(params[0], params[1]); + } + + @Override + public Class[] paramTypes() { + return new Class[] {Object.class, Object.class}; + } + }); + creatorCacheMap.put(AbstractMap.SimpleEntry.class, new Creator() { + @Override + @org.redkale.annotation.ConstructorParameters({"key", "value"}) + public AbstractMap.SimpleEntry create(Object... params) { + return new AbstractMap.SimpleEntry(params[0], params[1]); + } + + @Override + public Class[] paramTypes() { + return new Class[] {Object.class, Object.class}; + } + }); + + arrayCacheMap.put(int.class, t -> new int[t]); + arrayCacheMap.put(byte.class, t -> new byte[t]); + arrayCacheMap.put(long.class, t -> new long[t]); + arrayCacheMap.put(String.class, t -> new String[t]); + arrayCacheMap.put(Object.class, t -> new Object[t]); + arrayCacheMap.put(boolean.class, t -> new boolean[t]); + arrayCacheMap.put(short.class, t -> new short[t]); + arrayCacheMap.put(char.class, t -> new char[t]); + arrayCacheMap.put(float.class, t -> new float[t]); + arrayCacheMap.put(double.class, t -> new double[t]); + arrayCacheMap.put(BigInteger.class, t -> new BigInteger[t]); + arrayCacheMap.put(BigDecimal.class, t -> new BigDecimal[t]); + arrayCacheMap.put(ByteBuffer.class, t -> new ByteBuffer[t]); + arrayCacheMap.put(SocketAddress.class, t -> new SocketAddress[t]); + arrayCacheMap.put(InetSocketAddress.class, t -> new InetSocketAddress[t]); + arrayCacheMap.put(CompletableFuture.class, t -> new CompletableFuture[t]); + } + + static class SimpleClassVisitor extends ClassVisitor { + + private final String constructorDesc; + + private final List fieldNames; + + private boolean started; + + public SimpleClassVisitor(int api, List fieldNames, String constructorDesc) { + super(api); + this.fieldNames = fieldNames; + this.constructorDesc = constructorDesc; + } + + @Override + public MethodVisitor visitMethod( + int access, String name, String desc, String signature, String[] exceptions) { + if (java.lang.reflect.Modifier.isStatic(access) || !"".equals(name)) { + return null; + } + if (constructorDesc != null && !constructorDesc.equals(desc)) { + return null; + } + if (this.started) { + return null; + } + this.started = true; + // 返回的List中参数列表可能会比方法参数量多,因为方法内的临时变量也会存入list中, 所以需要list的元素集合比方法的参数多 + return new MethodVisitor(Opcodes.ASM6) { + @Override + public void visitLocalVariable( + String name, String description, String signature, Label start, Label end, int index) { + if (index < 1) { + return; + } + int size = fieldNames.size(); + // index不会按顺序执行的 + if (index > size) { + for (int i = size; i < index; i++) { + fieldNames.add(" "); + } + fieldNames.set(index - 1, name); + } + fieldNames.set(index - 1, name); + } + }; + } + } + + public static AbstractMap.SimpleEntry[] getConstructorField( + Class clazz, int paramCount, String constructorDesc) { + String n = clazz.getName(); + InputStream in = clazz.getResourceAsStream(n.substring(n.lastIndexOf('.') + 1) + ".class"); + if (in == null) { + return null; + } + ByteArrayOutputStream out = new ByteArrayOutputStream(1024); + byte[] bytes = new byte[1024]; + int pos; + try { + while ((pos = in.read(bytes)) != -1) { + out.write(bytes, 0, pos); + } + in.close(); + } catch (IOException io) { + return null; + } + final List fieldNames = new ArrayList<>(); + new ClassReader(out.toByteArray()) + .accept(new SimpleClassVisitor(Opcodes.ASM6, fieldNames, constructorDesc), 0); + while (fieldNames.remove(" ")) + ; // 删掉空元素 + if (fieldNames.isEmpty()) { + return null; + } + if (paramCount == fieldNames.size()) { + return getConstructorField(clazz, paramCount, fieldNames.toArray(new String[fieldNames.size()])); + } else { + String[] fs = new String[paramCount]; + for (int i = 0; i < fs.length; i++) { + fs[i] = fieldNames.get(i); + } + return getConstructorField(clazz, paramCount, fs); + } + } + + public static AbstractMap.SimpleEntry[] getConstructorField( + Class clazz, int paramCount, String[] names) { + AbstractMap.SimpleEntry[] se = new AbstractMap.SimpleEntry[names.length]; + for (int i = 0; i < names.length; i++) { // 查询参数名对应的Field + try { + Field field = clazz.getDeclaredField(names[i]); + se[i] = new AbstractMap.SimpleEntry<>(field.getName(), field.getType()); + } catch (NoSuchFieldException fe) { + Class cz = clazz; + Field field = null; + while ((cz = cz.getSuperclass()) != Object.class) { + try { + field = cz.getDeclaredField(names[i]); + break; + } catch (NoSuchFieldException nsfe) { + // do nothing + } + } + if (field == null) { + return null; + } + se[i] = new AbstractMap.SimpleEntry<>(field.getName(), field.getType()); + } catch (Exception e) { + if (logger.isLoggable(Level.FINE)) { + logger.log(Level.FINE, clazz + " getConstructorField error", e); + } + return null; + } + } + return se; + } + + public static AbstractMap.SimpleEntry[] getConstructorField( + Class clazz, int paramCount, Parameter[] params) { + AbstractMap.SimpleEntry[] se = new AbstractMap.SimpleEntry[params.length]; + for (int i = 0; i < params.length; i++) { // 查询参数名对应的Field + try { + Field field = clazz.getDeclaredField(params[i].getName()); + se[i] = new AbstractMap.SimpleEntry<>(field.getName(), field.getType()); + } catch (Exception e) { + return null; + } + } + return se; + } + + public static IntFunction createArrayFunction(final Class clazz) { + final String interName = clazz.getName().replace('.', '/'); + final String interDesc = org.redkale.asm.Type.getDescriptor(clazz); + final ClassLoader loader = clazz.getClassLoader(); + final String newDynName = "org/redkaledyn/creator/_DynArrayFunction__" + + clazz.getName().replace('.', '_').replace('$', '_'); + try { + Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.')); + return (IntFunction) (clz == null ? loader.loadClass(newDynName.replace('/', '.')) : clz) + .getDeclaredConstructor() + .newInstance(); + } catch (Throwable ex) { + // do nothing + } + + // ------------------------------------------------------------- + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); + MethodVisitor mv; + cw.visit( + V11, + ACC_PUBLIC + ACC_FINAL + ACC_SUPER, + newDynName, + "Ljava/lang/Object;Ljava/util/function/IntFunction<[" + interDesc + ">;", + "java/lang/Object", + new String[] {"java/util/function/IntFunction"}); + + { // IntFunction自身的构造方法 + mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + { // apply 方法 + mv = cw.visitMethod(ACC_PUBLIC, "apply", "(I)[" + interDesc, null, null); + mv.visitVarInsn(ILOAD, 1); + mv.visitTypeInsn(ANEWARRAY, interName); + mv.visitInsn(ARETURN); + mv.visitMaxs(1, 2); + mv.visitEnd(); + } + { // 虚拟 apply 方法 + mv = cw.visitMethod( + ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC, "apply", "(I)Ljava/lang/Object;", null, null); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ILOAD, 1); + mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "apply", "(I)[" + interDesc, false); + mv.visitInsn(ARETURN); + mv.visitMaxs(2, 2); + mv.visitEnd(); + } + cw.visitEnd(); + final byte[] bytes = cw.toByteArray(); + try { + Class resultClazz = new ClassLoader(loader) { + public final Class loadClass(String name, byte[] b) { + return defineClass(name, b, 0, b.length); + } + }.loadClass(newDynName.replace('/', '.'), bytes); + RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, resultClazz); + RedkaleClassLoader.putReflectionDeclaredConstructors(resultClazz, newDynName.replace('/', '.')); + return (IntFunction) resultClazz.getDeclaredConstructor().newInstance(); + } catch (Throwable ex) { + // ex.printStackTrace(); //一般不会发生, native-image在没有预编译情况下会报错 + return t -> (T[]) Array.newInstance(clazz, t); + } + } + } + + static class CopierInner { + + static final ConcurrentHashMap> copierOneCaches = + new ConcurrentHashMap(); + + static final ConcurrentHashMap>> + copierTwoCaches = new ConcurrentHashMap(); + + static final ConcurrentHashMap> copierFuncOneCaches = + new ConcurrentHashMap(); + + static final ConcurrentHashMap>> + copierFuncTwoCaches = new ConcurrentHashMap(); + + static final ConcurrentHashMap>> + copierFuncListOneCaches = new ConcurrentHashMap(); + + static final ConcurrentHashMap< + Class, ConcurrentHashMap>>> + copierFuncListTwoCaches = new ConcurrentHashMap(); + + private CopierInner() {} + + public static void clearCopierCache() { + copierOneCaches.clear(); + copierTwoCaches.clear(); + copierFuncOneCaches.clear(); + copierFuncTwoCaches.clear(); + copierFuncListOneCaches.clear(); + copierFuncListTwoCaches.clear(); + } + } + + static class InvokerInner { + + static final ConcurrentHashMap> invokerCaches = + new ConcurrentHashMap(); + + private InvokerInner() {} + } +} diff --git a/src/main/java/org/redkale/util/Invoker.java b/src/main/java/org/redkale/util/Invoker.java index 5a4ca3ec5..4c9746429 100644 --- a/src/main/java/org/redkale/util/Invoker.java +++ b/src/main/java/org/redkale/util/Invoker.java @@ -1,225 +1,225 @@ -/* - * 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.util; - -import static org.redkale.asm.Opcodes.*; - -import java.lang.reflect.*; -import java.util.concurrent.ConcurrentHashMap; -import org.redkale.asm.*; -import org.redkale.asm.Type; - -/** - * 动态生成指定public方法的调用对象, 替代Method.invoke的反射方式 - * - *

详情见: https://redkale.org - * - * @param 泛型 - * @param 泛型 - * @author zhangjx - * @since 2.5.0 - */ -public interface Invoker { - - /** - * 调用方法放回值, 调用静态方法obj=null - * - * @param obj 操作对象 - * @param params 方法的参数 - * @return 方法返回的结果 - */ - public R invoke(C obj, Object... params); - - public static Invoker load(final Class clazz, final String methodName, final Class... paramTypes) { - java.lang.reflect.Method method = null; - try { - method = clazz.getMethod(methodName, paramTypes); - } catch (Exception ex) { - throw new RedkaleException(ex); - } - return load(clazz, method); - } - - public static Invoker create( - final Class clazz, final String methodName, final Class... paramTypes) { - java.lang.reflect.Method method = null; - try { - method = clazz.getMethod(methodName, paramTypes); - } catch (Exception ex) { - throw new RedkaleException(ex); - } - return create(clazz, method); - } - - public static Invoker load(final Class clazz, final Method method) { - return Inners.InvokerInner.invokerCaches - .computeIfAbsent(clazz, t -> new ConcurrentHashMap<>()) - .computeIfAbsent(method, v -> create(clazz, method)); - } - - public static Invoker create(final Class clazz, final Method method) { - RedkaleClassLoader.putReflectionDeclaredMethods(clazz.getName()); - RedkaleClassLoader.putReflectionMethod(clazz.getName(), method); - boolean throwFlag = Utility.contains( - method.getExceptionTypes(), - e -> !RuntimeException.class.isAssignableFrom(e)); // 方法是否会抛出非RuntimeException异常 - boolean staticFlag = Modifier.isStatic(method.getModifiers()); - final Class returnType = (Class) method.getReturnType(); - final String supDynName = Invoker.class.getName().replace('.', '/'); - final String interName = clazz.getName().replace('.', '/'); - final String interDesc = Type.getDescriptor(clazz); - final String returnPrimiveDesc = Type.getDescriptor(returnType); - String returnDesc = Type.getDescriptor(returnType); - if (returnType == boolean.class) { - returnDesc = Type.getDescriptor(Boolean.class); - } else if (returnType == byte.class) { - returnDesc = Type.getDescriptor(Byte.class); - } else if (returnType == short.class) { - returnDesc = Type.getDescriptor(Short.class); - } else if (returnType == char.class) { - returnDesc = Type.getDescriptor(Character.class); - } else if (returnType == int.class) { - returnDesc = Type.getDescriptor(Integer.class); - } else if (returnType == float.class) { - returnDesc = Type.getDescriptor(Float.class); - } else if (returnType == long.class) { - returnDesc = Type.getDescriptor(Long.class); - } else if (returnType == double.class) { - returnDesc = Type.getDescriptor(Double.class); - } else if (returnType == void.class) { - returnDesc = Type.getDescriptor(Void.class); - } - ClassLoader loader = Thread.currentThread().getContextClassLoader(); - StringBuilder sbpts = new StringBuilder(); - for (Class c : method.getParameterTypes()) { - sbpts.append('_').append(c.getName().replace('.', '_').replace('$', '_')); - } - final String newDynName = "org/redkaledyn/invoker/_Dyn" + Invoker.class.getSimpleName() + "_" - + clazz.getName().replace('.', '_').replace('$', '_') + "_" + method.getName() + sbpts; - try { - Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.')); - return (Invoker) (clz == null ? loader.loadClass(newDynName.replace('/', '.')) : clz) - .getDeclaredConstructor() - .newInstance(); - } catch (Throwable ex) { - // do nothing - } - // ------------------------------------------------------------- - ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); - FieldVisitor fv; - MethodDebugVisitor mv; - AnnotationVisitor av0; - cw.visit( - V11, - ACC_PUBLIC + ACC_FINAL + ACC_SUPER, - newDynName, - "Ljava/lang/Object;L" + supDynName + "<" + interDesc + returnDesc + ">;", - "java/lang/Object", - new String[] {supDynName}); - - { // Invoker自身的构造方法 - mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "", "()V", null, null)); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); - mv.visitInsn(RETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - { // invoke 方法 - mv = new MethodDebugVisitor(cw.visitMethod( - ACC_PUBLIC + ACC_VARARGS, - "invoke", - "(" + interDesc + "[Ljava/lang/Object;)" + returnDesc, - null, - null)); - - Label label0 = new Label(); - Label label1 = new Label(); - Label label2 = new Label(); - if (throwFlag) { - mv.visitTryCatchBlock(label0, label1, label2, "java/lang/Throwable"); - mv.visitLabel(label0); - } - if (!staticFlag) { - mv.visitVarInsn(ALOAD, 1); - } - - StringBuilder paramDescs = new StringBuilder(); - int paramIndex = 0; - for (Class paramType : method.getParameterTypes()) { - // 参数 - mv.visitVarInsn(ALOAD, 2); - Asms.visitInsn(mv, paramIndex); - mv.visitInsn(AALOAD); - Asms.visitCheckCast(mv, paramType); - paramDescs.append(Type.getDescriptor(paramType)); - paramIndex++; - } - - mv.visitMethodInsn( - staticFlag ? INVOKESTATIC : (clazz.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL), - interName, - method.getName(), - "(" + paramDescs + ")" + returnPrimiveDesc, - !staticFlag && clazz.isInterface()); - if (returnType == void.class) { - mv.visitInsn(ACONST_NULL); - } else { - Asms.visitPrimitiveValueOf(mv, returnType); - } - mv.visitLabel(label1); - mv.visitInsn(ARETURN); - if (throwFlag) { - mv.visitLabel(label2); - mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {"java/lang/Throwable"}); - mv.visitVarInsn(ASTORE, 3); - mv.visitTypeInsn(NEW, "java/lang/RuntimeException"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 3); - mv.visitMethodInsn( - INVOKESPECIAL, "java/lang/RuntimeException", "", "(Ljava/lang/Throwable;)V", false); - mv.visitInsn(ATHROW); - } - mv.visitMaxs(3 + method.getParameterCount(), 4); - mv.visitEnd(); - } - - { // 虚拟 invoke 方法 - mv = new MethodDebugVisitor(cw.visitMethod( - ACC_PUBLIC + ACC_BRIDGE + ACC_VARARGS + ACC_SYNTHETIC, - "invoke", - "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", - null, - null)); - mv.visitVarInsn(ALOAD, 0); - mv.visitVarInsn(ALOAD, 1); - mv.visitTypeInsn(CHECKCAST, interName); - mv.visitVarInsn(ALOAD, 2); - mv.visitMethodInsn( - INVOKEVIRTUAL, newDynName, "invoke", "(" + interDesc + "[Ljava/lang/Object;)" + returnDesc, false); - mv.visitInsn(ARETURN); - mv.visitMaxs(3, 3); - mv.visitEnd(); - } - cw.visitEnd(); - final byte[] bytes = cw.toByteArray(); - Class resultClazz = null; - try { - if (resultClazz == null) { - resultClazz = new ClassLoader(loader) { - public final Class loadClass(String name, byte[] b) { - return defineClass(name, b, 0, b.length); - } - }.loadClass(newDynName.replace('/', '.'), bytes); - } - RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, resultClazz); - RedkaleClassLoader.putReflectionDeclaredConstructors(resultClazz, newDynName.replace('/', '.')); - return (Invoker) resultClazz.getDeclaredConstructor().newInstance(); - } catch (Exception ex) { - throw new RedkaleException(ex); - } - } -} +/* + * 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.util; + +import static org.redkale.asm.Opcodes.*; + +import java.lang.reflect.*; +import java.util.concurrent.ConcurrentHashMap; +import org.redkale.asm.*; +import org.redkale.asm.Type; + +/** + * 动态生成指定public方法的调用对象, 替代Method.invoke的反射方式 + * + *

详情见: https://redkale.org + * + * @param 泛型 + * @param 泛型 + * @author zhangjx + * @since 2.5.0 + */ +public interface Invoker { + + /** + * 调用方法放回值, 调用静态方法obj=null + * + * @param obj 操作对象 + * @param params 方法的参数 + * @return 方法返回的结果 + */ + public R invoke(C obj, Object... params); + + public static Invoker load(final Class clazz, final String methodName, final Class... paramTypes) { + java.lang.reflect.Method method = null; + try { + method = clazz.getMethod(methodName, paramTypes); + } catch (Exception ex) { + throw new RedkaleException(ex); + } + return load(clazz, method); + } + + public static Invoker create( + final Class clazz, final String methodName, final Class... paramTypes) { + java.lang.reflect.Method method = null; + try { + method = clazz.getMethod(methodName, paramTypes); + } catch (Exception ex) { + throw new RedkaleException(ex); + } + return create(clazz, method); + } + + public static Invoker load(final Class clazz, final Method method) { + return Inners.InvokerInner.invokerCaches + .computeIfAbsent(clazz, t -> new ConcurrentHashMap<>()) + .computeIfAbsent(method, v -> create(clazz, method)); + } + + public static Invoker create(final Class clazz, final Method method) { + RedkaleClassLoader.putReflectionDeclaredMethods(clazz.getName()); + RedkaleClassLoader.putReflectionMethod(clazz.getName(), method); + boolean throwFlag = Utility.contains( + method.getExceptionTypes(), + e -> !RuntimeException.class.isAssignableFrom(e)); // 方法是否会抛出非RuntimeException异常 + boolean staticFlag = Modifier.isStatic(method.getModifiers()); + final Class returnType = (Class) method.getReturnType(); + final String supDynName = Invoker.class.getName().replace('.', '/'); + final String interName = clazz.getName().replace('.', '/'); + final String interDesc = Type.getDescriptor(clazz); + final String returnPrimiveDesc = Type.getDescriptor(returnType); + String returnDesc = Type.getDescriptor(returnType); + if (returnType == boolean.class) { + returnDesc = Type.getDescriptor(Boolean.class); + } else if (returnType == byte.class) { + returnDesc = Type.getDescriptor(Byte.class); + } else if (returnType == short.class) { + returnDesc = Type.getDescriptor(Short.class); + } else if (returnType == char.class) { + returnDesc = Type.getDescriptor(Character.class); + } else if (returnType == int.class) { + returnDesc = Type.getDescriptor(Integer.class); + } else if (returnType == float.class) { + returnDesc = Type.getDescriptor(Float.class); + } else if (returnType == long.class) { + returnDesc = Type.getDescriptor(Long.class); + } else if (returnType == double.class) { + returnDesc = Type.getDescriptor(Double.class); + } else if (returnType == void.class) { + returnDesc = Type.getDescriptor(Void.class); + } + ClassLoader loader = Thread.currentThread().getContextClassLoader(); + StringBuilder sbpts = new StringBuilder(); + for (Class c : method.getParameterTypes()) { + sbpts.append('_').append(c.getName().replace('.', '_').replace('$', '_')); + } + final String newDynName = "org/redkaledyn/invoker/_Dyn" + Invoker.class.getSimpleName() + "_" + + clazz.getName().replace('.', '_').replace('$', '_') + "_" + method.getName() + sbpts; + try { + Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.')); + return (Invoker) (clz == null ? loader.loadClass(newDynName.replace('/', '.')) : clz) + .getDeclaredConstructor() + .newInstance(); + } catch (Throwable ex) { + // do nothing + } + // ------------------------------------------------------------- + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); + FieldVisitor fv; + MethodDebugVisitor mv; + AnnotationVisitor av0; + cw.visit( + V11, + ACC_PUBLIC + ACC_FINAL + ACC_SUPER, + newDynName, + "Ljava/lang/Object;L" + supDynName + "<" + interDesc + returnDesc + ">;", + "java/lang/Object", + new String[] {supDynName}); + + { // Invoker自身的构造方法 + mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "", "()V", null, null)); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + { // invoke 方法 + mv = new MethodDebugVisitor(cw.visitMethod( + ACC_PUBLIC + ACC_VARARGS, + "invoke", + "(" + interDesc + "[Ljava/lang/Object;)" + returnDesc, + null, + null)); + + Label label0 = new Label(); + Label label1 = new Label(); + Label label2 = new Label(); + if (throwFlag) { + mv.visitTryCatchBlock(label0, label1, label2, "java/lang/Throwable"); + mv.visitLabel(label0); + } + if (!staticFlag) { + mv.visitVarInsn(ALOAD, 1); + } + + StringBuilder paramDescs = new StringBuilder(); + int paramIndex = 0; + for (Class paramType : method.getParameterTypes()) { + // 参数 + mv.visitVarInsn(ALOAD, 2); + Asms.visitInsn(mv, paramIndex); + mv.visitInsn(AALOAD); + Asms.visitCheckCast(mv, paramType); + paramDescs.append(Type.getDescriptor(paramType)); + paramIndex++; + } + + mv.visitMethodInsn( + staticFlag ? INVOKESTATIC : (clazz.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL), + interName, + method.getName(), + "(" + paramDescs + ")" + returnPrimiveDesc, + !staticFlag && clazz.isInterface()); + if (returnType == void.class) { + mv.visitInsn(ACONST_NULL); + } else { + Asms.visitPrimitiveValueOf(mv, returnType); + } + mv.visitLabel(label1); + mv.visitInsn(ARETURN); + if (throwFlag) { + mv.visitLabel(label2); + mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {"java/lang/Throwable"}); + mv.visitVarInsn(ASTORE, 3); + mv.visitTypeInsn(NEW, "java/lang/RuntimeException"); + mv.visitInsn(DUP); + mv.visitVarInsn(ALOAD, 3); + mv.visitMethodInsn( + INVOKESPECIAL, "java/lang/RuntimeException", "", "(Ljava/lang/Throwable;)V", false); + mv.visitInsn(ATHROW); + } + mv.visitMaxs(3 + method.getParameterCount(), 4); + mv.visitEnd(); + } + + { // 虚拟 invoke 方法 + mv = new MethodDebugVisitor(cw.visitMethod( + ACC_PUBLIC + ACC_BRIDGE + ACC_VARARGS + ACC_SYNTHETIC, + "invoke", + "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", + null, + null)); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 1); + mv.visitTypeInsn(CHECKCAST, interName); + mv.visitVarInsn(ALOAD, 2); + mv.visitMethodInsn( + INVOKEVIRTUAL, newDynName, "invoke", "(" + interDesc + "[Ljava/lang/Object;)" + returnDesc, false); + mv.visitInsn(ARETURN); + mv.visitMaxs(3, 3); + mv.visitEnd(); + } + cw.visitEnd(); + final byte[] bytes = cw.toByteArray(); + Class resultClazz = null; + try { + if (resultClazz == null) { + resultClazz = new ClassLoader(loader) { + public final Class loadClass(String name, byte[] b) { + return defineClass(name, b, 0, b.length); + } + }.loadClass(newDynName.replace('/', '.'), bytes); + } + RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, resultClazz); + RedkaleClassLoader.putReflectionDeclaredConstructors(resultClazz, newDynName.replace('/', '.')); + return (Invoker) resultClazz.getDeclaredConstructor().newInstance(); + } catch (Exception ex) { + throw new RedkaleException(ex); + } + } +} diff --git a/src/main/java/org/redkale/util/LambdaBiConsumer.java b/src/main/java/org/redkale/util/LambdaBiConsumer.java index 508578aa5..4e9024223 100644 --- a/src/main/java/org/redkale/util/LambdaBiConsumer.java +++ b/src/main/java/org/redkale/util/LambdaBiConsumer.java @@ -1,29 +1,29 @@ -/* - * - */ -package org.redkale.util; - -import java.io.Serializable; -import java.util.function.BiConsumer; - -/** - * Lambda的BiConsumer自定义类 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - * @param 泛型 - * @param 泛型 - */ -@FunctionalInterface -public interface LambdaBiConsumer extends BiConsumer, Serializable { - - public static String readColumn(LambdaBiConsumer consumer) { - return Utility.readFieldName(consumer); - } - - public static Class readClass(LambdaBiConsumer consumer) { - return Utility.readClassName(consumer); - } -} +/* + * + */ +package org.redkale.util; + +import java.io.Serializable; +import java.util.function.BiConsumer; + +/** + * Lambda的BiConsumer自定义类 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + * @param 泛型 + * @param 泛型 + */ +@FunctionalInterface +public interface LambdaBiConsumer extends BiConsumer, Serializable { + + public static String readColumn(LambdaBiConsumer consumer) { + return Utility.readFieldName(consumer); + } + + public static Class readClass(LambdaBiConsumer consumer) { + return Utility.readClassName(consumer); + } +} diff --git a/src/main/java/org/redkale/util/LambdaFunction.java b/src/main/java/org/redkale/util/LambdaFunction.java index 9997ad441..ffaf3f97c 100644 --- a/src/main/java/org/redkale/util/LambdaFunction.java +++ b/src/main/java/org/redkale/util/LambdaFunction.java @@ -1,33 +1,33 @@ -/* - * - */ -package org.redkale.util; - -import java.io.Serializable; -import java.util.function.Function; - -/** - * Lambda的Function自定义类 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - * @param 泛型 - * @param 泛型 - */ -@FunctionalInterface -public interface LambdaFunction extends Function, Serializable { - - public static String[] readColumns(LambdaFunction... funcs) { - String[] columns = new String[funcs.length]; - for (int i = 0; i < columns.length; i++) { - columns[i] = readColumn(funcs[i]); - } - return columns; - } - - public static String readColumn(LambdaFunction func) { - return Utility.readFieldName(func); - } -} +/* + * + */ +package org.redkale.util; + +import java.io.Serializable; +import java.util.function.Function; + +/** + * Lambda的Function自定义类 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + * @param 泛型 + * @param 泛型 + */ +@FunctionalInterface +public interface LambdaFunction extends Function, Serializable { + + public static String[] readColumns(LambdaFunction... funcs) { + String[] columns = new String[funcs.length]; + for (int i = 0; i < columns.length; i++) { + columns[i] = readColumn(funcs[i]); + } + return columns; + } + + public static String readColumn(LambdaFunction func) { + return Utility.readFieldName(func); + } +} diff --git a/src/main/java/org/redkale/util/LambdaSupplier.java b/src/main/java/org/redkale/util/LambdaSupplier.java index ca5127f5e..80eb481da 100644 --- a/src/main/java/org/redkale/util/LambdaSupplier.java +++ b/src/main/java/org/redkale/util/LambdaSupplier.java @@ -1,28 +1,28 @@ -/* - * - */ -package org.redkale.util; - -import java.io.Serializable; -import java.util.function.Supplier; - -/** - * Lambda的Supplier自定义类 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - * @param 泛型 - */ -@FunctionalInterface -public interface LambdaSupplier extends Supplier, Serializable { - - public static String readColumn(LambdaSupplier func) { - return Utility.readFieldName(func); - } - - public static Class readClass(LambdaSupplier func) { - return Utility.readClassName(func); - } -} +/* + * + */ +package org.redkale.util; + +import java.io.Serializable; +import java.util.function.Supplier; + +/** + * Lambda的Supplier自定义类 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + * @param 泛型 + */ +@FunctionalInterface +public interface LambdaSupplier extends Supplier, Serializable { + + public static String readColumn(LambdaSupplier func) { + return Utility.readFieldName(func); + } + + public static Class readClass(LambdaSupplier func) { + return Utility.readClassName(func); + } +} diff --git a/src/main/java/org/redkale/util/MissingParamException.java b/src/main/java/org/redkale/util/MissingParamException.java index 3c092803c..20249acba 100644 --- a/src/main/java/org/redkale/util/MissingParamException.java +++ b/src/main/java/org/redkale/util/MissingParamException.java @@ -1,43 +1,43 @@ -/* - * - */ -package org.redkale.util; - -/** - * 缺失参数异常类 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public class MissingParamException extends RedkaleException { - - private String parameter; - - public MissingParamException() { - super(); - } - - public MissingParamException(String parameter) { - super("Missing parameter " + parameter); - this.parameter = parameter; - } - - public MissingParamException(String parameter, Throwable cause) { - super("Missing parameter " + parameter, cause); - this.parameter = parameter; - } - - public MissingParamException(Throwable cause) { - super(cause); - } - - public String getParameter() { - return parameter; - } - - public static MissingParamException of(String parameter) { - return new MissingParamException(parameter); - } -} +/* + * + */ +package org.redkale.util; + +/** + * 缺失参数异常类 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public class MissingParamException extends RedkaleException { + + private String parameter; + + public MissingParamException() { + super(); + } + + public MissingParamException(String parameter) { + super("Missing parameter " + parameter); + this.parameter = parameter; + } + + public MissingParamException(String parameter, Throwable cause) { + super("Missing parameter " + parameter, cause); + this.parameter = parameter; + } + + public MissingParamException(Throwable cause) { + super(cause); + } + + public String getParameter() { + return parameter; + } + + public static MissingParamException of(String parameter) { + return new MissingParamException(parameter); + } +} diff --git a/src/main/java/org/redkale/util/MultiHashKey.java b/src/main/java/org/redkale/util/MultiHashKey.java index 743691e64..ae6ca7e12 100644 --- a/src/main/java/org/redkale/util/MultiHashKey.java +++ b/src/main/java/org/redkale/util/MultiHashKey.java @@ -1,28 +1,28 @@ -/* - * - */ -package org.redkale.util; - -/** - * 根据参数动态生成key - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public interface MultiHashKey { - - public String keyFor(Object... args); - - /** - * key只支持带#{}的表达式, 且不能嵌套,错误示例:name_#{key_#{id}} - * - * @param paramNames 参数名 - * @param key key表达式 - * @return MultiHashKey - */ - public static MultiHashKey create(String[] paramNames, String key) { - return MultiHashKeys.create(paramNames, key); - } -} +/* + * + */ +package org.redkale.util; + +/** + * 根据参数动态生成key + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public interface MultiHashKey { + + public String keyFor(Object... args); + + /** + * key只支持带#{}的表达式, 且不能嵌套,错误示例:name_#{key_#{id}} + * + * @param paramNames 参数名 + * @param key key表达式 + * @return MultiHashKey + */ + public static MultiHashKey create(String[] paramNames, String key) { + return MultiHashKeys.create(paramNames, key); + } +} diff --git a/src/main/java/org/redkale/util/MultiHashKeys.java b/src/main/java/org/redkale/util/MultiHashKeys.java index e11c7d5da..08b7af98a 100644 --- a/src/main/java/org/redkale/util/MultiHashKeys.java +++ b/src/main/java/org/redkale/util/MultiHashKeys.java @@ -1,215 +1,215 @@ -/* - * - */ -package org.redkale.util; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; - -/** @author zhangjx */ -class MultiHashKeys { - - public static MultiHashKey create(String[] paramNames, String key) { - Objects.requireNonNull(key, "key for " + MultiHashKey.class.getSimpleName() + " is null"); - if (key.indexOf('{') < 0) { // 字符串常量 - return new StringKey(key); - } else { - Objects.requireNonNull(paramNames, "paramNames for " + MultiHashKey.class.getSimpleName() + " is null"); - char last = 0; - boolean paraming = false; - char[] chars = key.toCharArray(); - StringBuilder sb = new StringBuilder(); - List list = new ArrayList<>(); - for (int i = 0; i < chars.length; i++) { - char ch = chars[i]; - if (ch == '{') { - if (paraming) { - throw new RedkaleException(MultiHashKey.class.getSimpleName() + " parse error, key: " + key); - } - if (last == '#') { - String name = sb.substring(0, sb.length() - 1); - if (!name.isEmpty()) { - list.add(new StringKey(name)); - } - sb.delete(0, sb.length()); - paraming = true; - } else if (last == '\\') { - sb.deleteCharAt(sb.length() - 1); - sb.append(ch); - } else { - sb.append(ch); - } - } else if (ch == '}' && last == '\\') { - sb.deleteCharAt(sb.length() - 1); - sb.append(ch); - } else if (ch == '}' && paraming) { - String name = sb.toString(); - sb.delete(0, sb.length()); - if (name.indexOf('.') > 0) { - list.add(new ParamsKey(paramNames, name)); - } else { - list.add(new ParamKey(paramNames, name)); - } - paraming = false; - } else { - sb.append(ch); - } - last = ch; - } - if (sb.length() > 0) { - list.add(new StringKey(sb.toString())); - } - if (list.size() == 1) { - return list.get(0); - } - return new ArrayKey(list.toArray(new MultiHashKey[list.size()])); - } - } - - static class ArrayKey implements MultiHashKey { - - private final MultiHashKey[] keys; - - public ArrayKey(MultiHashKey[] keys) { - this.keys = keys; - } - - @Override - public String keyFor(Object... args) { - StringBuilder sb = new StringBuilder(); - for (MultiHashKey key : keys) { - sb.append(key.keyFor(args)); - } - return sb.toString(); - } - - @Override - public String toString() { - return ArrayKey.class.getSimpleName() + Arrays.toString(keys); - } - } - - static class ParamsKey implements MultiHashKey { - - private static final ConcurrentHashMap attrCache = new ConcurrentHashMap<>(); - - private final int index; - - private final String fullField; - - private final String[] fields; - - public ParamsKey(int index, String fullField) { - this.index = index; - this.fullField = fullField; - this.fields = fullField.split("\\."); - } - - public ParamsKey(String[] paramNames, String fullField) { - int rs = -1; - for (int i = 0; i < paramNames.length; i++) { - if (fullField.startsWith(paramNames[i] + '.')) { - rs = i; - break; - } - } - if (rs < 0) { - throw new RedkaleException(fullField + " not found in " + Arrays.toString(paramNames)); - } - this.index = rs; - this.fullField = fullField; - this.fields = fullField.split("\\."); - } - - @Override - public String keyFor(Object... args) { - return String.valueOf(get(args[index])); - } - - private Object get(Object val) { - if (val == null) { - return val; - } - String[] subs = fields; - for (int i = 1; i < subs.length; i++) { - String fieldName = subs[i]; - Class clz = val.getClass(); - Attribute attr = attrCache.computeIfAbsent( - clz.getName() + ":" + fieldName, k -> Attribute.create(clz, fieldName)); - val = attr.get(val); - if (val == null) { - return val; - } - } - return val; - } - - @Override - public String toString() { - return ParamsKey.class.getSimpleName() + "{field: " + fullField + ", index: " + index + "}"; - } - } - - static class ParamKey implements MultiHashKey { - - private final int index; - - private final String field; - - public ParamKey(int index, String field) { - this.index = index; - this.field = field; - } - - public ParamKey(String[] paramNames, String field) { - int rs = -1; - for (int i = 0; i < paramNames.length; i++) { - if (field.equalsIgnoreCase(paramNames[i])) { - rs = i; - break; - } - } - if (rs < 0) { - throw new RedkaleException(field + " not found in " + Arrays.toString(paramNames)); - } - this.index = rs; - this.field = field; - } - - @Override - public String keyFor(Object... args) { - return String.valueOf(args[index]); - } - - @Override - public String toString() { - return ParamKey.class.getSimpleName() + "{field: " + field + ", index: " + index + "}"; - } - } - - static class StringKey implements MultiHashKey { - - private final String key; - - public StringKey(String key) { - this.key = key; - } - - @Override - public String keyFor(Object... args) { - return key; - } - - @Override - public String toString() { - return StringKey.class.getSimpleName() + "{key: " + key + "}"; - } - } - - private MultiHashKeys() { - // do nothing - } -} +/* + * + */ +package org.redkale.util; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; + +/** @author zhangjx */ +class MultiHashKeys { + + public static MultiHashKey create(String[] paramNames, String key) { + Objects.requireNonNull(key, "key for " + MultiHashKey.class.getSimpleName() + " is null"); + if (key.indexOf('{') < 0) { // 字符串常量 + return new StringKey(key); + } else { + Objects.requireNonNull(paramNames, "paramNames for " + MultiHashKey.class.getSimpleName() + " is null"); + char last = 0; + boolean paraming = false; + char[] chars = key.toCharArray(); + StringBuilder sb = new StringBuilder(); + List list = new ArrayList<>(); + for (int i = 0; i < chars.length; i++) { + char ch = chars[i]; + if (ch == '{') { + if (paraming) { + throw new RedkaleException(MultiHashKey.class.getSimpleName() + " parse error, key: " + key); + } + if (last == '#') { + String name = sb.substring(0, sb.length() - 1); + if (!name.isEmpty()) { + list.add(new StringKey(name)); + } + sb.delete(0, sb.length()); + paraming = true; + } else if (last == '\\') { + sb.deleteCharAt(sb.length() - 1); + sb.append(ch); + } else { + sb.append(ch); + } + } else if (ch == '}' && last == '\\') { + sb.deleteCharAt(sb.length() - 1); + sb.append(ch); + } else if (ch == '}' && paraming) { + String name = sb.toString(); + sb.delete(0, sb.length()); + if (name.indexOf('.') > 0) { + list.add(new ParamsKey(paramNames, name)); + } else { + list.add(new ParamKey(paramNames, name)); + } + paraming = false; + } else { + sb.append(ch); + } + last = ch; + } + if (sb.length() > 0) { + list.add(new StringKey(sb.toString())); + } + if (list.size() == 1) { + return list.get(0); + } + return new ArrayKey(list.toArray(new MultiHashKey[list.size()])); + } + } + + static class ArrayKey implements MultiHashKey { + + private final MultiHashKey[] keys; + + public ArrayKey(MultiHashKey[] keys) { + this.keys = keys; + } + + @Override + public String keyFor(Object... args) { + StringBuilder sb = new StringBuilder(); + for (MultiHashKey key : keys) { + sb.append(key.keyFor(args)); + } + return sb.toString(); + } + + @Override + public String toString() { + return ArrayKey.class.getSimpleName() + Arrays.toString(keys); + } + } + + static class ParamsKey implements MultiHashKey { + + private static final ConcurrentHashMap attrCache = new ConcurrentHashMap<>(); + + private final int index; + + private final String fullField; + + private final String[] fields; + + public ParamsKey(int index, String fullField) { + this.index = index; + this.fullField = fullField; + this.fields = fullField.split("\\."); + } + + public ParamsKey(String[] paramNames, String fullField) { + int rs = -1; + for (int i = 0; i < paramNames.length; i++) { + if (fullField.startsWith(paramNames[i] + '.')) { + rs = i; + break; + } + } + if (rs < 0) { + throw new RedkaleException(fullField + " not found in " + Arrays.toString(paramNames)); + } + this.index = rs; + this.fullField = fullField; + this.fields = fullField.split("\\."); + } + + @Override + public String keyFor(Object... args) { + return String.valueOf(get(args[index])); + } + + private Object get(Object val) { + if (val == null) { + return val; + } + String[] subs = fields; + for (int i = 1; i < subs.length; i++) { + String fieldName = subs[i]; + Class clz = val.getClass(); + Attribute attr = attrCache.computeIfAbsent( + clz.getName() + ":" + fieldName, k -> Attribute.create(clz, fieldName)); + val = attr.get(val); + if (val == null) { + return val; + } + } + return val; + } + + @Override + public String toString() { + return ParamsKey.class.getSimpleName() + "{field: " + fullField + ", index: " + index + "}"; + } + } + + static class ParamKey implements MultiHashKey { + + private final int index; + + private final String field; + + public ParamKey(int index, String field) { + this.index = index; + this.field = field; + } + + public ParamKey(String[] paramNames, String field) { + int rs = -1; + for (int i = 0; i < paramNames.length; i++) { + if (field.equalsIgnoreCase(paramNames[i])) { + rs = i; + break; + } + } + if (rs < 0) { + throw new RedkaleException(field + " not found in " + Arrays.toString(paramNames)); + } + this.index = rs; + this.field = field; + } + + @Override + public String keyFor(Object... args) { + return String.valueOf(args[index]); + } + + @Override + public String toString() { + return ParamKey.class.getSimpleName() + "{field: " + field + ", index: " + index + "}"; + } + } + + static class StringKey implements MultiHashKey { + + private final String key; + + public StringKey(String key) { + this.key = key; + } + + @Override + public String keyFor(Object... args) { + return key; + } + + @Override + public String toString() { + return StringKey.class.getSimpleName() + "{key: " + key + "}"; + } + } + + private MultiHashKeys() { + // do nothing + } +} diff --git a/src/main/java/org/redkale/util/ObjectRef.java b/src/main/java/org/redkale/util/ObjectRef.java index 366383deb..08e5e6aa7 100644 --- a/src/main/java/org/redkale/util/ObjectRef.java +++ b/src/main/java/org/redkale/util/ObjectRef.java @@ -1,43 +1,43 @@ -/* - * - */ -package org.redkale.util; - -/** - * 简单的对象引用 - * - *

详情见: https://redkale.org - * - * @param 泛型 - * @author zhangjx - * @since 2.8.0 - */ -public final class ObjectRef { - - private V value; - - public ObjectRef(V initialValue) { - this.value = initialValue; - } - - public ObjectRef() {} - - public final V get() { - return this.value; - } - - public final void set(V newValue) { - this.value = newValue; - } - - public final void setIfNull(V newValue) { - if (this.value == null) { - this.value = newValue; - } - } - - @Override - public String toString() { - return String.valueOf(this.value); - } -} +/* + * + */ +package org.redkale.util; + +/** + * 简单的对象引用 + * + *

详情见: https://redkale.org + * + * @param 泛型 + * @author zhangjx + * @since 2.8.0 + */ +public final class ObjectRef { + + private V value; + + public ObjectRef(V initialValue) { + this.value = initialValue; + } + + public ObjectRef() {} + + public final V get() { + return this.value; + } + + public final void set(V newValue) { + this.value = newValue; + } + + public final void setIfNull(V newValue) { + if (this.value == null) { + this.value = newValue; + } + } + + @Override + public String toString() { + return String.valueOf(this.value); + } +} diff --git a/src/main/java/org/redkale/util/RedkaleException.java b/src/main/java/org/redkale/util/RedkaleException.java index 2660f98ec..7eac33628 100644 --- a/src/main/java/org/redkale/util/RedkaleException.java +++ b/src/main/java/org/redkale/util/RedkaleException.java @@ -1,31 +1,31 @@ -/* - * - */ -package org.redkale.util; - -/** - * redkale的异常基础类
- * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public class RedkaleException extends RuntimeException { - - public RedkaleException() { - super(); - } - - public RedkaleException(String s) { - super(s); - } - - public RedkaleException(String message, Throwable cause) { - super(message, cause); - } - - public RedkaleException(Throwable cause) { - super(cause); - } -} +/* + * + */ +package org.redkale.util; + +/** + * redkale的异常基础类
+ * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public class RedkaleException extends RuntimeException { + + public RedkaleException() { + super(); + } + + public RedkaleException(String s) { + super(s); + } + + public RedkaleException(String message, Throwable cause) { + super(message, cause); + } + + public RedkaleException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/org/redkale/util/ResourceEvent.java b/src/main/java/org/redkale/util/ResourceEvent.java index c359534de..4bb38bda8 100644 --- a/src/main/java/org/redkale/util/ResourceEvent.java +++ b/src/main/java/org/redkale/util/ResourceEvent.java @@ -1,16 +1,16 @@ -/* - * - */ -package org.redkale.util; - -/** - * 详情见: https://redkale.org - * - * @see org.redkale.inject.ResourceEvent - * @param 泛型 - * @author zhangjx - * @since 2.7.0 - * @deprecated replaced by org.redkale.inject.ResourceEvent - */ -@Deprecated(since = "2.8.0") -public interface ResourceEvent extends org.redkale.inject.ResourceEvent {} +/* + * + */ +package org.redkale.util; + +/** + * 详情见: https://redkale.org + * + * @see org.redkale.inject.ResourceEvent + * @param 泛型 + * @author zhangjx + * @since 2.7.0 + * @deprecated replaced by org.redkale.inject.ResourceEvent + */ +@Deprecated(since = "2.8.0") +public interface ResourceEvent extends org.redkale.inject.ResourceEvent {} diff --git a/src/main/java/org/redkale/util/ThrowSupplier.java b/src/main/java/org/redkale/util/ThrowSupplier.java index 243d189f8..38ad2a3a7 100644 --- a/src/main/java/org/redkale/util/ThrowSupplier.java +++ b/src/main/java/org/redkale/util/ThrowSupplier.java @@ -1,28 +1,28 @@ -/* - * - */ -package org.redkale.util; - -import org.redkale.annotation.ClassDepends; - -/** - * 抛异常版的Supplier - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @param 泛型 - * @since 2.8.0 - */ -@ClassDepends -@FunctionalInterface -public interface ThrowSupplier { - - /** - * Gets a result. - * - * @return a result - * @throws java.lang.Throwable Throwable - */ - T get() throws Throwable; -} +/* + * + */ +package org.redkale.util; + +import org.redkale.annotation.ClassDepends; + +/** + * 抛异常版的Supplier + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @param 泛型 + * @since 2.8.0 + */ +@ClassDepends +@FunctionalInterface +public interface ThrowSupplier { + + /** + * Gets a result. + * + * @return a result + * @throws java.lang.Throwable Throwable + */ + T get() throws Throwable; +} diff --git a/src/main/java/org/redkale/util/Times.java b/src/main/java/org/redkale/util/Times.java index 554a86d24..a1e64838c 100644 --- a/src/main/java/org/redkale/util/Times.java +++ b/src/main/java/org/redkale/util/Times.java @@ -1,348 +1,348 @@ -/* - * - */ -package org.redkale.util; - -import java.time.Instant; -import java.time.LocalDate; -import java.time.ZoneId; -import java.util.Calendar; -import java.util.TimeZone; - -/** - * 时间日期工具类 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - */ -public final class Times { - - private static final int ZONE_RAW_OFFSET = TimeZone.getDefault().getRawOffset(); - - static final String FORMAT_SECONDS = "%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS"; // yyyy-MM-dd HH:mm:ss - - static final String FORMAT_MILLS = "%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%1$tL"; // yyyy-MM-dd HH:mm:ss.fff - - private Times() { - // do nothind - } - - /** - * 获取格式为yyyy-MM-dd HH:mm:ss的当前时间 - * - * @return 格式为yyyy-MM-dd HH:mm:ss的时间值 - */ - public static String now() { - return String.format(FORMAT_SECONDS, System.currentTimeMillis()); - } - - /** - * 获取格式为yyyy-MM-dd HH:mm:ss.fff的当前时间 - * - * @return 格式为yyyy-MM-dd HH:mm:ss.fff的时间值 - */ - public static String nowMillis() { - return String.format(FORMAT_MILLS, System.currentTimeMillis()); - } - - /** - * 将指定时间格式化为 yyyy-MM-dd HH:mm:ss - * - * @param time 待格式化的时间 - * @return 格式为yyyy-MM-dd HH:mm:ss的时间值 - */ - public static String formatTime(long time) { - return String.format(FORMAT_SECONDS, time); - } - - /** - * 将时间值转换为长度为9的36进制值 - * - * @param time 时间值 - * @return 36进制时间值 - */ - public static String format36time(long time) { - return Long.toString(time, 36); - } - - /** - * 获取当天凌晨零点的格林时间 - * - * @return 毫秒数 - */ - public static long midnight() { - return midnight(System.currentTimeMillis()); - } - - /** - * 获取指定时间当天凌晨零点的格林时间 - * - * @param time 指定时间 - * @return 毫秒数 - */ - public static long midnight(long time) { - return (time + ZONE_RAW_OFFSET) / 86400000 * 86400000 - ZONE_RAW_OFFSET; - } - - /** - * 获取当天20151231格式的int值 - * - * @return 20151231格式的int值 - */ - public static int today() { - java.time.LocalDate today = java.time.LocalDate.now(); - return today.getYear() * 10000 + today.getMonthValue() * 100 + today.getDayOfMonth(); - } - - /** - * 获取当天151231格式的int值 - * - * @return 151231格式的int值 - */ - public static int todayYYMMDD() { - java.time.LocalDate today = java.time.LocalDate.now(); - return today.getYear() % 100 * 10000 + today.getMonthValue() * 100 + today.getDayOfMonth(); - } - - /** - * 获取当天1512312359格式的int值 - * - * @return 1512312359格式的int值 - */ - public static int todayYYMMDDHHmm() { - java.time.LocalDateTime today = java.time.LocalDateTime.now(); - return today.getYear() % 100 * 100_00_00_00 - + today.getMonthValue() * 100_00_00 - + today.getDayOfMonth() * 100_00 - + today.getHour() * 100 - + today.getMinute(); - } - - /** - * 获取当天20151231235959格式的int值 - * - * @return 20151231235959格式的int值 - */ - public static long todayYYYYMMDDHHmmss() { - java.time.LocalDateTime today = java.time.LocalDateTime.now(); - return today.getYear() * 100_00_00_00_00L - + today.getMonthValue() * 100_00_00_00 - + today.getDayOfMonth() * 100_00_00 - + today.getHour() * 100_00 - + today.getMinute() * 100 - + today.getSecond(); - } - - /** - * 获取当天151231235959格式的int值 - * - * @return 151231235959格式的int值 - */ - public static long todayYYMMDDHHmmss() { - java.time.LocalDateTime today = java.time.LocalDateTime.now(); - return today.getYear() % 100 * 100_00_00_00_00L - + today.getMonthValue() * 100_00_00_00 - + today.getDayOfMonth() * 100_00_00 - + today.getHour() * 100_00 - + today.getMinute() * 100 - + today.getSecond(); - } - - /** - * 获取明天20151230格式的int值 - * - * @return 20151230格式的int值 - */ - public static int tomorrow() { - Calendar cal = Calendar.getInstance(); - cal.add(Calendar.DAY_OF_YEAR, 1); - return cal.get(Calendar.YEAR) * 10000 + (cal.get(Calendar.MONTH) + 1) * 100 + cal.get(Calendar.DAY_OF_MONTH); - } - - /** - * 获取明天151230格式的int值 - * - * @return 151230格式的int值 - */ - public static int tomorrowYYMMDD() { - Calendar cal = Calendar.getInstance(); - cal.add(Calendar.DAY_OF_YEAR, 1); - return cal.get(Calendar.YEAR) % 100 * 10000 - + (cal.get(Calendar.MONTH) + 1) * 100 - + cal.get(Calendar.DAY_OF_MONTH); - } - - /** - * 获取昨天20151230格式的int值 - * - * @return 20151230格式的int值 - */ - public static int yesterday() { - Calendar cal = Calendar.getInstance(); - cal.add(Calendar.DAY_OF_YEAR, -1); - return cal.get(Calendar.YEAR) * 10000 + (cal.get(Calendar.MONTH) + 1) * 100 + cal.get(Calendar.DAY_OF_MONTH); - } - - /** - * 获取昨天151230格式的int值 - * - * @return 151230格式的int值 - */ - public static int yesterdayYYMMDD() { - Calendar cal = Calendar.getInstance(); - cal.add(Calendar.DAY_OF_YEAR, -1); - return cal.get(Calendar.YEAR) % 100 * 10000 - + (cal.get(Calendar.MONTH) + 1) * 100 - + cal.get(Calendar.DAY_OF_MONTH); - } - - /** - * 获取指定时间的20160202格式的int值 - * - * @param time 指定时间 - * @return 毫秒数 - */ - public static int yyyyMMdd(long time) { - Calendar cal = Calendar.getInstance(); - cal.setTimeInMillis(time); - return cal.get(Calendar.YEAR) * 10000 + (cal.get(Calendar.MONTH) + 1) * 100 + cal.get(Calendar.DAY_OF_MONTH); - } - - /** - * 获取指定时间的160202格式的int值 - * - * @param time 指定时间 - * @return 毫秒数 - */ - public static int yyMMdd(long time) { - Calendar cal = Calendar.getInstance(); - cal.setTimeInMillis(time); - return cal.get(Calendar.YEAR) % 100 * 10000 - + (cal.get(Calendar.MONTH) + 1) * 100 - + cal.get(Calendar.DAY_OF_MONTH); - } - - /** - * 获取当天16020223格式的int值 - * - * @param time 指定时间 - * @return 16020223格式的int值 - */ - public static int yyMMDDHHmm(long time) { - Calendar cal = Calendar.getInstance(); - cal.setTimeInMillis(time); - return cal.get(Calendar.YEAR) % 100 * 100_00_00 - + (cal.get(Calendar.MONTH) + 1) * 100_00 - + cal.get(Calendar.DAY_OF_MONTH) * 100 - + cal.get(Calendar.HOUR_OF_DAY); - } - - /** - * 获取时间点所在星期的周一 - * - * @param time 指定时间 - * @return 毫秒数 - */ - public static long monday(long time) { - ZoneId zid = ZoneId.systemDefault(); - Instant instant = Instant.ofEpochMilli(time); - LocalDate ld = instant.atZone(zid).toLocalDate(); - ld = ld.minusDays(ld.getDayOfWeek().getValue() - 1); - return ld.atStartOfDay(zid).toInstant().toEpochMilli(); - } - - /** - * 获取时间点所在星期的周日 - * - * @param time 指定时间 - * @return 毫秒数 - */ - public static long sunday(long time) { - ZoneId zid = ZoneId.systemDefault(); - Instant instant = Instant.ofEpochMilli(time); - LocalDate ld = instant.atZone(zid).toLocalDate(); - ld = ld.plusDays(7 - ld.getDayOfWeek().getValue()); - return ld.atStartOfDay(zid).toInstant().toEpochMilli(); - } - - /** - * 获取时间点所在月份的1号 - * - * @param time 指定时间 - * @return 毫秒数 - */ - public static long monthFirstDay(long time) { - ZoneId zid = ZoneId.systemDefault(); - Instant instant = Instant.ofEpochMilli(time); - LocalDate ld = instant.atZone(zid).toLocalDate().withDayOfMonth(1); - return ld.atStartOfDay(zid).toInstant().toEpochMilli(); - } - - /** - * 获取时间点所在月份的最后一天 - * - * @param time 指定时间 - * @return 毫秒数 - */ - public static long monthLastDay(long time) { - ZoneId zid = ZoneId.systemDefault(); - Instant instant = Instant.ofEpochMilli(time); - LocalDate ld = instant.atZone(zid).toLocalDate(); - ld = ld.withDayOfMonth(ld.lengthOfMonth()); - return ld.atStartOfDay(zid).toInstant().toEpochMilli(); - } - - /** - * 将时间格式化, 支持%1$ty 和 %ty两种格式 - * - * @param format 格式 - * @param size 带%t的个数,值小于0则需要计算 - * @param time 时间 - * @since 2.7.0 - * @return 时间格式化 - */ - public static String formatTime(String format, int size, Object time) { - if (size < 0) { - int c = 0; - if (!format.contains("%1$")) { - for (char ch : format.toCharArray()) { - if (ch == '%') { - c++; - } - } - } - size = c; - } - if (size <= 1) { - return String.format(format, time); - } - if (size == 2) { - return String.format(format, time, time); - } - if (size == 3) { - return String.format(format, time, time, time); - } - if (size == 4) { - return String.format(format, time, time, time, time); - } - if (size == 5) { - return String.format(format, time, time, time, time, time); - } - if (size == 6) { - return String.format(format, time, time, time, time, time, time); - } - if (size == 7) { - return String.format(format, time, time, time, time, time, time, time); - } - if (size == 8) { - return String.format(format, time, time, time, time, time, time, time); - } - Object[] args = new Object[size]; - for (int i = 0; i < size; i++) { - args[i] = time; - } - return String.format(format, args); - } -} +/* + * + */ +package org.redkale.util; + +import java.time.Instant; +import java.time.LocalDate; +import java.time.ZoneId; +import java.util.Calendar; +import java.util.TimeZone; + +/** + * 时间日期工具类 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public final class Times { + + private static final int ZONE_RAW_OFFSET = TimeZone.getDefault().getRawOffset(); + + static final String FORMAT_SECONDS = "%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS"; // yyyy-MM-dd HH:mm:ss + + static final String FORMAT_MILLS = "%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%1$tL"; // yyyy-MM-dd HH:mm:ss.fff + + private Times() { + // do nothind + } + + /** + * 获取格式为yyyy-MM-dd HH:mm:ss的当前时间 + * + * @return 格式为yyyy-MM-dd HH:mm:ss的时间值 + */ + public static String now() { + return String.format(FORMAT_SECONDS, System.currentTimeMillis()); + } + + /** + * 获取格式为yyyy-MM-dd HH:mm:ss.fff的当前时间 + * + * @return 格式为yyyy-MM-dd HH:mm:ss.fff的时间值 + */ + public static String nowMillis() { + return String.format(FORMAT_MILLS, System.currentTimeMillis()); + } + + /** + * 将指定时间格式化为 yyyy-MM-dd HH:mm:ss + * + * @param time 待格式化的时间 + * @return 格式为yyyy-MM-dd HH:mm:ss的时间值 + */ + public static String formatTime(long time) { + return String.format(FORMAT_SECONDS, time); + } + + /** + * 将时间值转换为长度为9的36进制值 + * + * @param time 时间值 + * @return 36进制时间值 + */ + public static String format36time(long time) { + return Long.toString(time, 36); + } + + /** + * 获取当天凌晨零点的格林时间 + * + * @return 毫秒数 + */ + public static long midnight() { + return midnight(System.currentTimeMillis()); + } + + /** + * 获取指定时间当天凌晨零点的格林时间 + * + * @param time 指定时间 + * @return 毫秒数 + */ + public static long midnight(long time) { + return (time + ZONE_RAW_OFFSET) / 86400000 * 86400000 - ZONE_RAW_OFFSET; + } + + /** + * 获取当天20151231格式的int值 + * + * @return 20151231格式的int值 + */ + public static int today() { + java.time.LocalDate today = java.time.LocalDate.now(); + return today.getYear() * 10000 + today.getMonthValue() * 100 + today.getDayOfMonth(); + } + + /** + * 获取当天151231格式的int值 + * + * @return 151231格式的int值 + */ + public static int todayYYMMDD() { + java.time.LocalDate today = java.time.LocalDate.now(); + return today.getYear() % 100 * 10000 + today.getMonthValue() * 100 + today.getDayOfMonth(); + } + + /** + * 获取当天1512312359格式的int值 + * + * @return 1512312359格式的int值 + */ + public static int todayYYMMDDHHmm() { + java.time.LocalDateTime today = java.time.LocalDateTime.now(); + return today.getYear() % 100 * 100_00_00_00 + + today.getMonthValue() * 100_00_00 + + today.getDayOfMonth() * 100_00 + + today.getHour() * 100 + + today.getMinute(); + } + + /** + * 获取当天20151231235959格式的int值 + * + * @return 20151231235959格式的int值 + */ + public static long todayYYYYMMDDHHmmss() { + java.time.LocalDateTime today = java.time.LocalDateTime.now(); + return today.getYear() * 100_00_00_00_00L + + today.getMonthValue() * 100_00_00_00 + + today.getDayOfMonth() * 100_00_00 + + today.getHour() * 100_00 + + today.getMinute() * 100 + + today.getSecond(); + } + + /** + * 获取当天151231235959格式的int值 + * + * @return 151231235959格式的int值 + */ + public static long todayYYMMDDHHmmss() { + java.time.LocalDateTime today = java.time.LocalDateTime.now(); + return today.getYear() % 100 * 100_00_00_00_00L + + today.getMonthValue() * 100_00_00_00 + + today.getDayOfMonth() * 100_00_00 + + today.getHour() * 100_00 + + today.getMinute() * 100 + + today.getSecond(); + } + + /** + * 获取明天20151230格式的int值 + * + * @return 20151230格式的int值 + */ + public static int tomorrow() { + Calendar cal = Calendar.getInstance(); + cal.add(Calendar.DAY_OF_YEAR, 1); + return cal.get(Calendar.YEAR) * 10000 + (cal.get(Calendar.MONTH) + 1) * 100 + cal.get(Calendar.DAY_OF_MONTH); + } + + /** + * 获取明天151230格式的int值 + * + * @return 151230格式的int值 + */ + public static int tomorrowYYMMDD() { + Calendar cal = Calendar.getInstance(); + cal.add(Calendar.DAY_OF_YEAR, 1); + return cal.get(Calendar.YEAR) % 100 * 10000 + + (cal.get(Calendar.MONTH) + 1) * 100 + + cal.get(Calendar.DAY_OF_MONTH); + } + + /** + * 获取昨天20151230格式的int值 + * + * @return 20151230格式的int值 + */ + public static int yesterday() { + Calendar cal = Calendar.getInstance(); + cal.add(Calendar.DAY_OF_YEAR, -1); + return cal.get(Calendar.YEAR) * 10000 + (cal.get(Calendar.MONTH) + 1) * 100 + cal.get(Calendar.DAY_OF_MONTH); + } + + /** + * 获取昨天151230格式的int值 + * + * @return 151230格式的int值 + */ + public static int yesterdayYYMMDD() { + Calendar cal = Calendar.getInstance(); + cal.add(Calendar.DAY_OF_YEAR, -1); + return cal.get(Calendar.YEAR) % 100 * 10000 + + (cal.get(Calendar.MONTH) + 1) * 100 + + cal.get(Calendar.DAY_OF_MONTH); + } + + /** + * 获取指定时间的20160202格式的int值 + * + * @param time 指定时间 + * @return 毫秒数 + */ + public static int yyyyMMdd(long time) { + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(time); + return cal.get(Calendar.YEAR) * 10000 + (cal.get(Calendar.MONTH) + 1) * 100 + cal.get(Calendar.DAY_OF_MONTH); + } + + /** + * 获取指定时间的160202格式的int值 + * + * @param time 指定时间 + * @return 毫秒数 + */ + public static int yyMMdd(long time) { + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(time); + return cal.get(Calendar.YEAR) % 100 * 10000 + + (cal.get(Calendar.MONTH) + 1) * 100 + + cal.get(Calendar.DAY_OF_MONTH); + } + + /** + * 获取当天16020223格式的int值 + * + * @param time 指定时间 + * @return 16020223格式的int值 + */ + public static int yyMMDDHHmm(long time) { + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(time); + return cal.get(Calendar.YEAR) % 100 * 100_00_00 + + (cal.get(Calendar.MONTH) + 1) * 100_00 + + cal.get(Calendar.DAY_OF_MONTH) * 100 + + cal.get(Calendar.HOUR_OF_DAY); + } + + /** + * 获取时间点所在星期的周一 + * + * @param time 指定时间 + * @return 毫秒数 + */ + public static long monday(long time) { + ZoneId zid = ZoneId.systemDefault(); + Instant instant = Instant.ofEpochMilli(time); + LocalDate ld = instant.atZone(zid).toLocalDate(); + ld = ld.minusDays(ld.getDayOfWeek().getValue() - 1); + return ld.atStartOfDay(zid).toInstant().toEpochMilli(); + } + + /** + * 获取时间点所在星期的周日 + * + * @param time 指定时间 + * @return 毫秒数 + */ + public static long sunday(long time) { + ZoneId zid = ZoneId.systemDefault(); + Instant instant = Instant.ofEpochMilli(time); + LocalDate ld = instant.atZone(zid).toLocalDate(); + ld = ld.plusDays(7 - ld.getDayOfWeek().getValue()); + return ld.atStartOfDay(zid).toInstant().toEpochMilli(); + } + + /** + * 获取时间点所在月份的1号 + * + * @param time 指定时间 + * @return 毫秒数 + */ + public static long monthFirstDay(long time) { + ZoneId zid = ZoneId.systemDefault(); + Instant instant = Instant.ofEpochMilli(time); + LocalDate ld = instant.atZone(zid).toLocalDate().withDayOfMonth(1); + return ld.atStartOfDay(zid).toInstant().toEpochMilli(); + } + + /** + * 获取时间点所在月份的最后一天 + * + * @param time 指定时间 + * @return 毫秒数 + */ + public static long monthLastDay(long time) { + ZoneId zid = ZoneId.systemDefault(); + Instant instant = Instant.ofEpochMilli(time); + LocalDate ld = instant.atZone(zid).toLocalDate(); + ld = ld.withDayOfMonth(ld.lengthOfMonth()); + return ld.atStartOfDay(zid).toInstant().toEpochMilli(); + } + + /** + * 将时间格式化, 支持%1$ty 和 %ty两种格式 + * + * @param format 格式 + * @param size 带%t的个数,值小于0则需要计算 + * @param time 时间 + * @since 2.7.0 + * @return 时间格式化 + */ + public static String formatTime(String format, int size, Object time) { + if (size < 0) { + int c = 0; + if (!format.contains("%1$")) { + for (char ch : format.toCharArray()) { + if (ch == '%') { + c++; + } + } + } + size = c; + } + if (size <= 1) { + return String.format(format, time); + } + if (size == 2) { + return String.format(format, time, time); + } + if (size == 3) { + return String.format(format, time, time, time); + } + if (size == 4) { + return String.format(format, time, time, time, time); + } + if (size == 5) { + return String.format(format, time, time, time, time, time); + } + if (size == 6) { + return String.format(format, time, time, time, time, time, time); + } + if (size == 7) { + return String.format(format, time, time, time, time, time, time, time); + } + if (size == 8) { + return String.format(format, time, time, time, time, time, time, time); + } + Object[] args = new Object[size]; + for (int i = 0; i < size; i++) { + args[i] = time; + } + return String.format(format, args); + } +} diff --git a/src/main/java/org/redkale/util/Unsafe.java b/src/main/java/org/redkale/util/Unsafe.java index c7e016e4c..1e2df6cd2 100644 --- a/src/main/java/org/redkale/util/Unsafe.java +++ b/src/main/java/org/redkale/util/Unsafe.java @@ -1,191 +1,191 @@ -/* - * 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.util; - -import java.lang.reflect.Field; - -/** - * sun.misc.Unsafe 封装类 - * - *

详情见: https://redkale.org - * - * @author zhangjx - * @since 2.5.0 - */ -public interface Unsafe { - - public int getInt(Object o, long offset); - - public void putInt(Object o, long offset, int x); - - public Object getObject(Object o, long offset); - - public void putObject(Object o, long offset, Object x); - - public boolean getBoolean(Object o, long offset); - - public void putBoolean(Object o, long offset, boolean x); - - public byte getByte(Object o, long offset); - - public void putByte(Object o, long offset, byte x); - - public short getShort(Object o, long offset); - - public void putShort(Object o, long offset, short x); - - public char getChar(Object o, long offset); - - public void putChar(Object o, long offset, char x); - - public long getLong(Object o, long offset); - - public void putLong(Object o, long offset, long x); - - public float getFloat(Object o, long offset); - - public void putFloat(Object o, long offset, float x); - - public double getDouble(Object o, long offset); - - public void putDouble(Object o, long offset, double x); - - public byte getByte(long address); - - public void putByte(long address, byte x); - - public short getShort(long address); - - public void putShort(long address, short x); - - public char getChar(long address); - - public void putChar(long address, char x); - - public int getInt(long address); - - public void putInt(long address, int x); - - public long getLong(long address); - - public void putLong(long address, long x); - - public float getFloat(long address); - - public void putFloat(long address, float x); - - public double getDouble(long address); - - public void putDouble(long address, double x); - - public long getAddress(long address); - - public void putAddress(long address, long x); - - public long allocateMemory(long bytes); - - public long reallocateMemory(long address, long bytes); - - public void setMemory(Object o, long offset, long bytes, byte value); - - public void setMemory(long address, long bytes, byte value); - - public void copyMemory(Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes); - - public void copyMemory(long srcAddress, long destAddress, long bytes); - - public void freeMemory(long address); - - public long objectFieldOffset(Field f); - - public long staticFieldOffset(Field f); - - public Object staticFieldBase(Field f); - - public int arrayBaseOffset(Class arrayClass); - - public int arrayIndexScale(Class arrayClass); - - public int addressSize(); - - public int pageSize(); - - public Object allocateInstance(Class cls) throws InstantiationException; - - public void throwException(Throwable ee); - - public boolean compareAndSwapObject(Object o, long offset, Object expected, Object x); - - public boolean compareAndSwapInt(Object o, long offset, int expected, int x); - - public boolean compareAndSwapLong(Object o, long offset, long expected, long x); - - public Object getObjectVolatile(Object o, long offset); - - public void putObjectVolatile(Object o, long offset, Object x); - - public int getIntVolatile(Object o, long offset); - - public void putIntVolatile(Object o, long offset, int x); - - public boolean getBooleanVolatile(Object o, long offset); - - public void putBooleanVolatile(Object o, long offset, boolean x); - - public byte getByteVolatile(Object o, long offset); - - public void putByteVolatile(Object o, long offset, byte x); - - public short getShortVolatile(Object o, long offset); - - public void putShortVolatile(Object o, long offset, short x); - - public char getCharVolatile(Object o, long offset); - - public void putCharVolatile(Object o, long offset, char x); - - public long getLongVolatile(Object o, long offset); - - public void putLongVolatile(Object o, long offset, long x); - - public float getFloatVolatile(Object o, long offset); - - public void putFloatVolatile(Object o, long offset, float x); - - public double getDoubleVolatile(Object o, long offset); - - public void putDoubleVolatile(Object o, long offset, double x); - - public void putOrderedObject(Object o, long offset, Object x); - - public void putOrderedInt(Object o, long offset, int x); - - public void putOrderedLong(Object o, long offset, long x); - - public void unpark(Object thread); - - public void park(boolean isAbsolute, long time); - - public int getLoadAverage(double[] loadavg, int nelems); - - public int getAndAddInt(Object o, long offset, int delta); - - public long getAndAddLong(Object o, long offset, long delta); - - public int getAndSetInt(Object o, long offset, int newValue); - - public long getAndSetLong(Object o, long offset, long newValue); - - public Object getAndSetObject(Object o, long offset, Object newValue); - - public void loadFence(); - - public void storeFence(); - - public void fullFence(); - - public void invokeCleaner(java.nio.ByteBuffer directBuffer); -} +/* + * 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.util; + +import java.lang.reflect.Field; + +/** + * sun.misc.Unsafe 封装类 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.5.0 + */ +public interface Unsafe { + + public int getInt(Object o, long offset); + + public void putInt(Object o, long offset, int x); + + public Object getObject(Object o, long offset); + + public void putObject(Object o, long offset, Object x); + + public boolean getBoolean(Object o, long offset); + + public void putBoolean(Object o, long offset, boolean x); + + public byte getByte(Object o, long offset); + + public void putByte(Object o, long offset, byte x); + + public short getShort(Object o, long offset); + + public void putShort(Object o, long offset, short x); + + public char getChar(Object o, long offset); + + public void putChar(Object o, long offset, char x); + + public long getLong(Object o, long offset); + + public void putLong(Object o, long offset, long x); + + public float getFloat(Object o, long offset); + + public void putFloat(Object o, long offset, float x); + + public double getDouble(Object o, long offset); + + public void putDouble(Object o, long offset, double x); + + public byte getByte(long address); + + public void putByte(long address, byte x); + + public short getShort(long address); + + public void putShort(long address, short x); + + public char getChar(long address); + + public void putChar(long address, char x); + + public int getInt(long address); + + public void putInt(long address, int x); + + public long getLong(long address); + + public void putLong(long address, long x); + + public float getFloat(long address); + + public void putFloat(long address, float x); + + public double getDouble(long address); + + public void putDouble(long address, double x); + + public long getAddress(long address); + + public void putAddress(long address, long x); + + public long allocateMemory(long bytes); + + public long reallocateMemory(long address, long bytes); + + public void setMemory(Object o, long offset, long bytes, byte value); + + public void setMemory(long address, long bytes, byte value); + + public void copyMemory(Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes); + + public void copyMemory(long srcAddress, long destAddress, long bytes); + + public void freeMemory(long address); + + public long objectFieldOffset(Field f); + + public long staticFieldOffset(Field f); + + public Object staticFieldBase(Field f); + + public int arrayBaseOffset(Class arrayClass); + + public int arrayIndexScale(Class arrayClass); + + public int addressSize(); + + public int pageSize(); + + public Object allocateInstance(Class cls) throws InstantiationException; + + public void throwException(Throwable ee); + + public boolean compareAndSwapObject(Object o, long offset, Object expected, Object x); + + public boolean compareAndSwapInt(Object o, long offset, int expected, int x); + + public boolean compareAndSwapLong(Object o, long offset, long expected, long x); + + public Object getObjectVolatile(Object o, long offset); + + public void putObjectVolatile(Object o, long offset, Object x); + + public int getIntVolatile(Object o, long offset); + + public void putIntVolatile(Object o, long offset, int x); + + public boolean getBooleanVolatile(Object o, long offset); + + public void putBooleanVolatile(Object o, long offset, boolean x); + + public byte getByteVolatile(Object o, long offset); + + public void putByteVolatile(Object o, long offset, byte x); + + public short getShortVolatile(Object o, long offset); + + public void putShortVolatile(Object o, long offset, short x); + + public char getCharVolatile(Object o, long offset); + + public void putCharVolatile(Object o, long offset, char x); + + public long getLongVolatile(Object o, long offset); + + public void putLongVolatile(Object o, long offset, long x); + + public float getFloatVolatile(Object o, long offset); + + public void putFloatVolatile(Object o, long offset, float x); + + public double getDoubleVolatile(Object o, long offset); + + public void putDoubleVolatile(Object o, long offset, double x); + + public void putOrderedObject(Object o, long offset, Object x); + + public void putOrderedInt(Object o, long offset, int x); + + public void putOrderedLong(Object o, long offset, long x); + + public void unpark(Object thread); + + public void park(boolean isAbsolute, long time); + + public int getLoadAverage(double[] loadavg, int nelems); + + public int getAndAddInt(Object o, long offset, int delta); + + public long getAndAddLong(Object o, long offset, long delta); + + public int getAndSetInt(Object o, long offset, int newValue); + + public long getAndSetLong(Object o, long offset, long newValue); + + public Object getAndSetObject(Object o, long offset, Object newValue); + + public void loadFence(); + + public void storeFence(); + + public void fullFence(); + + public void invokeCleaner(java.nio.ByteBuffer directBuffer); +} diff --git a/src/main/java/org/redkale/util/XmlReader.java b/src/main/java/org/redkale/util/XmlReader.java index b9b2e45d6..6158fc45f 100644 --- a/src/main/java/org/redkale/util/XmlReader.java +++ b/src/main/java/org/redkale/util/XmlReader.java @@ -1,431 +1,431 @@ -/* - * 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.util; - -import java.nio.charset.StandardCharsets; -import java.util.*; -import java.util.function.BinaryOperator; - -/** - * 简单的xml读取器, 只读element节点信息,其他信息(如: namespace、comment、docdecl等)都会丢弃 - * - *

详情见: https://redkale.org - * - * @author zhangjx - */ -public class XmlReader { - - protected int position = -1; - - private char[] text; - - private int limit; - - private Deque tags = new ArrayDeque<>(); - - protected int lineNumber; - - protected int columnNumber; - - protected BinaryOperator attrFunc; - - private static class TagNode { - - public String tag; - - public AnyValueWriter config; - - public TagNode(String tag, AnyValueWriter node) { - this.tag = tag; - this.config = node; - } - } - - public XmlReader(String text) { - this(Utility.charArray(text)); - } - - public XmlReader(char[] text) { - setText(text, 0, text.length); - } - - public XmlReader(char[] text, int start, int len) { - setText(text, start, len); - } - - private void setText(char[] text, int start, int len) { - this.text = text; - this.position = start - 1; - this.limit = start + len - 1; - } - - public XmlReader attrFunc(BinaryOperator func) { - this.attrFunc = func; - return this; - } - - public AnyValue read() { - AnyValueWriter root = AnyValueWriter.create(); - char ch; - lineNumber++; - ByteArray array = new ByteArray(128); - while ((ch = nextGoodChar()) > 0) { - if (ch == '<') { - char ch2 = nextChar(); - if (ch2 == '!') { - char ch3 = nextChar(); - if (ch3 == '-') { - readComment(); - } else if (ch3 == '[') { - readCDSect(root, array); - } else if (ch3 == 'D') { - readDocdecl(root, array); - } else { - throw newException("unexpected character in markup " + ch3); - } - } else if (ch2 == '?') { - readXmlDecl(root, array); - } else if (ch2 == '/') { // 节点结束 - String tag = readEndTag(); - if (tags.isEmpty()) { - throw newException("unexpected end tag " + tag); - } - if (!tags.getFirst().tag.equals(tag)) { - throw newException("expected end tag " + tags.getFirst().tag + " but " + tag); - } - tags.removeFirst(); - if (tags.isEmpty()) { - break; - } - } else { // 节点开始 - readStartTag(root); - } - } else { - int start = this.position; - for (; ; ) { - ch = nextChar(); - if (ch == '<') { - backChar(ch); - break; - } - } - String content = escape(new String(this.text, start, this.position + 1 - start)); - if (tags.isEmpty()) { - root.addValue(AnyValue.XML_TEXT_NODE_NAME, content); - } else { - tags.getFirst().config.addValue(AnyValue.XML_TEXT_NODE_NAME, content); - } - } - } - return root; - } - - /** - * 读取下一个字符, 不跳过空白字符 - * - * @return 空白字符或有效字符 - */ - protected char nextChar() { - if (this.position == this.limit) { - throw newException("read EOF"); - } - char ch = this.text[++this.position]; - if (ch == '\n') { - this.lineNumber++; - this.columnNumber = 0; - } - this.columnNumber++; - return ch; - } - - /** - * 跳过空白字符, 返回一个非空白字符 - * - * @return 有效字符 - */ - protected char nextGoodChar() { - char c = nextChar(); - if (c > ' ') { - return c; - } - for (; ; ) { - c = nextChar(); - if (c > ' ') { - return c; - } - } - } - - /** - * 回退最后读取的字符 - * - * @param ch 后退的字符 - */ - protected void backChar(char ch) { - this.position--; - } - - // 返回是否endtag, 即以 />结尾 - protected boolean readTagAttribute(String tag, AnyValueWriter config) { - boolean first = true; - boolean endtag = false; - boolean endattr = false; - char ch = nextGoodChar(); - if (ch == '/') { - return true; - } - int start = this.position; - for (; ; ) { - if (ch == '=') { - break; - } else if (ch >= '0' && ch <= '9') { - if (first) { - throw newException("illegal character " + ch); - } - } else if (ch >= 'a' && ch <= 'z') { - // do nothing - } else if (ch >= 'A' && ch <= 'Z') { - // do nothing - } else if (ch == '.' || ch == '-' || ch == '_' || ch == ':') { - if (first) { - throw newException("illegal character " + ch); - } - } else { - throw newException("illegal character " + ch); - } - ch = nextChar(); - first = false; - } - String attrName = new String(this.text, start, this.position - start); - String attrValue; - ch = nextGoodChar(); - if (ch == '"' || ch == '\'') { - final char quote = ch; - start = this.position + 1; - for (; ; ) { - ch = nextChar(); - if (ch == quote) { - break; - } - } - attrValue = escape(new String(this.text, start, this.position - start)); - } else { - ch = nextGoodChar(); - start = this.position; - for (; ; ) { - if (ch == '/') { - endtag = true; - break; - } - if (ch == '>') { - endattr = true; - break; - } else if (ch <= ' ') { - break; - } - ch = nextChar(); - } - attrValue = escape(new String(this.text, start, this.position - start)); - } - if (attrFunc != null) { - attrValue = attrFunc.apply(attrName, attrValue); - } - config.addValue(attrName, attrValue); - if (endtag) { - return endtag; - } - if (endattr) { - return false; - } - ch = nextGoodChar(); - if (ch == '>') { - return false; - } - if (ch == '/') { - return true; - } - backChar(ch); - return readTagAttribute(tag, config); - } - - protected void readStartTag(AnyValueWriter root) { - final int start = this.position; - boolean hasattr = false; - boolean endtag = false; - - char ch = nextGoodChar(); - for (; ; ) { - if (ch == '>') { - break; - } else if (ch == '/') { - endtag = true; - break; - } else if (ch <= ' ') { - hasattr = true; - break; - } - ch = nextChar(); - } - final String tag = new String(this.text, start, this.position - start).trim(); - AnyValueWriter config = AnyValueWriter.create(); - TagNode tagNode = new TagNode(tag, config); - if (tags.isEmpty()) { - root.addValue(tag, tagNode.config); - } else { - tags.getFirst().config.addValue(tag, tagNode.config); - } - if (hasattr) { - endtag = readTagAttribute(tag, config); - } - if (endtag) { - if (nextChar() != '>') { - throw newException("expected /> for tag end"); - } - return; - } - tags.addFirst(tagNode); - } - - protected String readEndTag() { - final int start = this.position + 1; // 跳过'/' - char ch; - for (; ; ) { - ch = nextChar(); - if (ch == '>') { - break; - } - } - return new String(this.text, start, this.position - start).trim(); - } - - protected void readComment() { // 读取到 ' && dash >= 2) { - break; - } else if (ch == '-') { - dash++; - } else { - dash = 0; - } - } - } - - protected void readDocdecl( - AnyValueWriter root, - ByteArray array) { // 读取到 ' - if (nextChar() != 'O') { - throw newException("expected ') { - array.putByte(ch); - root.setValue("", array.toString(StandardCharsets.UTF_8)); - break; - } - array.putByte(ch); - } - } - - protected void readCDSect( - AnyValueWriter root, ByteArray array) { // 读取到 ' Char*)) ]]>' - if (nextChar() != 'C') { - throw newException("expected ') { - if (this.text[this.position - 1] != ']' && this.text[this.position - 2] != ']') { - throw newException("in cdsect after two dashes (]]) next character must be >"); - } - array.putByte(ch); - root.setValue("", array.toString(StandardCharsets.UTF_8)); - break; - } - array.putByte(ch); - } - } - - protected void readXmlDecl( - AnyValueWriter root, ByteArray array) { // 读取到 - char ch; - array.clear(); - array.putByte('<'); - array.putByte('?'); - for (; ; ) { - ch = nextChar(); - if (ch == '>') { - if (this.text[this.position - 1] != '?') { - throw newException("in xmldecl after ? next character must be >"); - } - array.putByte(ch); - root.setValue("", array.toString(StandardCharsets.UTF_8)); - break; - } - array.putByte(ch); - } - } - - protected static String escape(String value) { - return value.replace(""", "/") - .replace("<", "<") - .replace(">", ">") - .replace("&", "&"); - } - - protected RedkaleException newException(String msg) { - return newException(msg, (Throwable) null); - } - - protected RedkaleException newException(String msg, Throwable chain) { - return new RedkaleException((msg == null ? "" : (msg + " ")) - + "(line: " + this.lineNumber + ", column: " + this.columnNumber + ", position:" + this.position + ") " - + (chain == null ? "" : ("caused by: " + chain))); - } -} +/* + * 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.util; + +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.function.BinaryOperator; + +/** + * 简单的xml读取器, 只读element节点信息,其他信息(如: namespace、comment、docdecl等)都会丢弃 + * + *

详情见: https://redkale.org + * + * @author zhangjx + */ +public class XmlReader { + + protected int position = -1; + + private char[] text; + + private int limit; + + private Deque tags = new ArrayDeque<>(); + + protected int lineNumber; + + protected int columnNumber; + + protected BinaryOperator attrFunc; + + private static class TagNode { + + public String tag; + + public AnyValueWriter config; + + public TagNode(String tag, AnyValueWriter node) { + this.tag = tag; + this.config = node; + } + } + + public XmlReader(String text) { + this(Utility.charArray(text)); + } + + public XmlReader(char[] text) { + setText(text, 0, text.length); + } + + public XmlReader(char[] text, int start, int len) { + setText(text, start, len); + } + + private void setText(char[] text, int start, int len) { + this.text = text; + this.position = start - 1; + this.limit = start + len - 1; + } + + public XmlReader attrFunc(BinaryOperator func) { + this.attrFunc = func; + return this; + } + + public AnyValue read() { + AnyValueWriter root = AnyValueWriter.create(); + char ch; + lineNumber++; + ByteArray array = new ByteArray(128); + while ((ch = nextGoodChar()) > 0) { + if (ch == '<') { + char ch2 = nextChar(); + if (ch2 == '!') { + char ch3 = nextChar(); + if (ch3 == '-') { + readComment(); + } else if (ch3 == '[') { + readCDSect(root, array); + } else if (ch3 == 'D') { + readDocdecl(root, array); + } else { + throw newException("unexpected character in markup " + ch3); + } + } else if (ch2 == '?') { + readXmlDecl(root, array); + } else if (ch2 == '/') { // 节点结束 + String tag = readEndTag(); + if (tags.isEmpty()) { + throw newException("unexpected end tag " + tag); + } + if (!tags.getFirst().tag.equals(tag)) { + throw newException("expected end tag " + tags.getFirst().tag + " but " + tag); + } + tags.removeFirst(); + if (tags.isEmpty()) { + break; + } + } else { // 节点开始 + readStartTag(root); + } + } else { + int start = this.position; + for (; ; ) { + ch = nextChar(); + if (ch == '<') { + backChar(ch); + break; + } + } + String content = escape(new String(this.text, start, this.position + 1 - start)); + if (tags.isEmpty()) { + root.addValue(AnyValue.XML_TEXT_NODE_NAME, content); + } else { + tags.getFirst().config.addValue(AnyValue.XML_TEXT_NODE_NAME, content); + } + } + } + return root; + } + + /** + * 读取下一个字符, 不跳过空白字符 + * + * @return 空白字符或有效字符 + */ + protected char nextChar() { + if (this.position == this.limit) { + throw newException("read EOF"); + } + char ch = this.text[++this.position]; + if (ch == '\n') { + this.lineNumber++; + this.columnNumber = 0; + } + this.columnNumber++; + return ch; + } + + /** + * 跳过空白字符, 返回一个非空白字符 + * + * @return 有效字符 + */ + protected char nextGoodChar() { + char c = nextChar(); + if (c > ' ') { + return c; + } + for (; ; ) { + c = nextChar(); + if (c > ' ') { + return c; + } + } + } + + /** + * 回退最后读取的字符 + * + * @param ch 后退的字符 + */ + protected void backChar(char ch) { + this.position--; + } + + // 返回是否endtag, 即以 />结尾 + protected boolean readTagAttribute(String tag, AnyValueWriter config) { + boolean first = true; + boolean endtag = false; + boolean endattr = false; + char ch = nextGoodChar(); + if (ch == '/') { + return true; + } + int start = this.position; + for (; ; ) { + if (ch == '=') { + break; + } else if (ch >= '0' && ch <= '9') { + if (first) { + throw newException("illegal character " + ch); + } + } else if (ch >= 'a' && ch <= 'z') { + // do nothing + } else if (ch >= 'A' && ch <= 'Z') { + // do nothing + } else if (ch == '.' || ch == '-' || ch == '_' || ch == ':') { + if (first) { + throw newException("illegal character " + ch); + } + } else { + throw newException("illegal character " + ch); + } + ch = nextChar(); + first = false; + } + String attrName = new String(this.text, start, this.position - start); + String attrValue; + ch = nextGoodChar(); + if (ch == '"' || ch == '\'') { + final char quote = ch; + start = this.position + 1; + for (; ; ) { + ch = nextChar(); + if (ch == quote) { + break; + } + } + attrValue = escape(new String(this.text, start, this.position - start)); + } else { + ch = nextGoodChar(); + start = this.position; + for (; ; ) { + if (ch == '/') { + endtag = true; + break; + } + if (ch == '>') { + endattr = true; + break; + } else if (ch <= ' ') { + break; + } + ch = nextChar(); + } + attrValue = escape(new String(this.text, start, this.position - start)); + } + if (attrFunc != null) { + attrValue = attrFunc.apply(attrName, attrValue); + } + config.addValue(attrName, attrValue); + if (endtag) { + return endtag; + } + if (endattr) { + return false; + } + ch = nextGoodChar(); + if (ch == '>') { + return false; + } + if (ch == '/') { + return true; + } + backChar(ch); + return readTagAttribute(tag, config); + } + + protected void readStartTag(AnyValueWriter root) { + final int start = this.position; + boolean hasattr = false; + boolean endtag = false; + + char ch = nextGoodChar(); + for (; ; ) { + if (ch == '>') { + break; + } else if (ch == '/') { + endtag = true; + break; + } else if (ch <= ' ') { + hasattr = true; + break; + } + ch = nextChar(); + } + final String tag = new String(this.text, start, this.position - start).trim(); + AnyValueWriter config = AnyValueWriter.create(); + TagNode tagNode = new TagNode(tag, config); + if (tags.isEmpty()) { + root.addValue(tag, tagNode.config); + } else { + tags.getFirst().config.addValue(tag, tagNode.config); + } + if (hasattr) { + endtag = readTagAttribute(tag, config); + } + if (endtag) { + if (nextChar() != '>') { + throw newException("expected /> for tag end"); + } + return; + } + tags.addFirst(tagNode); + } + + protected String readEndTag() { + final int start = this.position + 1; // 跳过'/' + char ch; + for (; ; ) { + ch = nextChar(); + if (ch == '>') { + break; + } + } + return new String(this.text, start, this.position - start).trim(); + } + + protected void readComment() { // 读取到 ' && dash >= 2) { + break; + } else if (ch == '-') { + dash++; + } else { + dash = 0; + } + } + } + + protected void readDocdecl( + AnyValueWriter root, + ByteArray array) { // 读取到 ' + if (nextChar() != 'O') { + throw newException("expected ') { + array.putByte(ch); + root.setValue("", array.toString(StandardCharsets.UTF_8)); + break; + } + array.putByte(ch); + } + } + + protected void readCDSect( + AnyValueWriter root, ByteArray array) { // 读取到 ' Char*)) ]]>' + if (nextChar() != 'C') { + throw newException("expected ') { + if (this.text[this.position - 1] != ']' && this.text[this.position - 2] != ']') { + throw newException("in cdsect after two dashes (]]) next character must be >"); + } + array.putByte(ch); + root.setValue("", array.toString(StandardCharsets.UTF_8)); + break; + } + array.putByte(ch); + } + } + + protected void readXmlDecl( + AnyValueWriter root, ByteArray array) { // 读取到 + char ch; + array.clear(); + array.putByte('<'); + array.putByte('?'); + for (; ; ) { + ch = nextChar(); + if (ch == '>') { + if (this.text[this.position - 1] != '?') { + throw newException("in xmldecl after ? next character must be >"); + } + array.putByte(ch); + root.setValue("", array.toString(StandardCharsets.UTF_8)); + break; + } + array.putByte(ch); + } + } + + protected static String escape(String value) { + return value.replace(""", "/") + .replace("<", "<") + .replace(">", ">") + .replace("&", "&"); + } + + protected RedkaleException newException(String msg) { + return newException(msg, (Throwable) null); + } + + protected RedkaleException newException(String msg, Throwable chain) { + return new RedkaleException((msg == null ? "" : (msg + " ")) + + "(line: " + this.lineNumber + ", column: " + this.columnNumber + ", position:" + this.position + ") " + + (chain == null ? "" : ("caused by: " + chain))); + } +} diff --git a/src/test/java/org/redkale/test/asm/AsmCreator.java b/src/test/java/org/redkale/test/asm/AsmCreator.java index 57c121769..f87828bd7 100644 --- a/src/test/java/org/redkale/test/asm/AsmCreator.java +++ b/src/test/java/org/redkale/test/asm/AsmCreator.java @@ -1,39 +1,39 @@ -/* - * 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.test.asm; - -import java.io.*; -import org.redkale.util.Utility; - -/** @author zhangjx */ -public class AsmCreator { - - public static void main(String[] args) throws Throwable { - boolean realasm = false; // 从http://forge.ow2.org/projects/asm/ 下载最新asm的src放在 srcasmroot 目录下 - File srcasmroot = new File("D:/JAVA/JDK源码/jdk/internal/org/objectweb/asm"); - if (realasm) srcasmroot = new File("D:/JAVA/JDK源码/org/objectweb/asm"); - File destasmroot = new File("D:/Java-Projects/RedkaleProject/src/main/java/org/redkale/asm"); - String line = null; - LineNumberReader txtin = new LineNumberReader(new FileReader(new File(destasmroot, "asm.txt"))); - while ((line = txtin.readLine()) != null) { - line = line.trim(); - if (!line.endsWith(".java")) continue; - File srcfile = new File(srcasmroot, line); - if (!srcfile.isFile()) continue; - File destfile = new File(destasmroot, line); - String content = Utility.readThenClose(new FileInputStream(srcfile)); - FileOutputStream out = new FileOutputStream(destfile); - out.write(content.replace("jdk.internal.org.objectweb", "org.redkale") - .replace("org.objectweb", "org.redkale") - .replace("", "<tt>") - .replace("", "</tt>") - .replace("{@link org.redkale.asm.tree.MethodNode#getLabelNode} method.", "") - .getBytes()); - out.close(); - } - // 需要屏蔽ClassReader中判断checks the class version的部分 - } -} +/* + * 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.test.asm; + +import java.io.*; +import org.redkale.util.Utility; + +/** @author zhangjx */ +public class AsmCreator { + + public static void main(String[] args) throws Throwable { + boolean realasm = false; // 从http://forge.ow2.org/projects/asm/ 下载最新asm的src放在 srcasmroot 目录下 + File srcasmroot = new File("D:/JAVA/JDK源码/jdk/internal/org/objectweb/asm"); + if (realasm) srcasmroot = new File("D:/JAVA/JDK源码/org/objectweb/asm"); + File destasmroot = new File("D:/Java-Projects/RedkaleProject/src/main/java/org/redkale/asm"); + String line = null; + LineNumberReader txtin = new LineNumberReader(new FileReader(new File(destasmroot, "asm.txt"))); + while ((line = txtin.readLine()) != null) { + line = line.trim(); + if (!line.endsWith(".java")) continue; + File srcfile = new File(srcasmroot, line); + if (!srcfile.isFile()) continue; + File destfile = new File(destasmroot, line); + String content = Utility.readThenClose(new FileInputStream(srcfile)); + FileOutputStream out = new FileOutputStream(destfile); + out.write(content.replace("jdk.internal.org.objectweb", "org.redkale") + .replace("org.objectweb", "org.redkale") + .replace("", "<tt>") + .replace("", "</tt>") + .replace("{@link org.redkale.asm.tree.MethodNode#getLabelNode} method.", "") + .getBytes()); + out.close(); + } + // 需要屏蔽ClassReader中判断checks the class version的部分 + } +} diff --git a/src/test/java/org/redkale/test/cache/CacheInstance.java b/src/test/java/org/redkale/test/cache/CacheInstance.java index f969dcd9e..a8d481bcf 100644 --- a/src/test/java/org/redkale/test/cache/CacheInstance.java +++ b/src/test/java/org/redkale/test/cache/CacheInstance.java @@ -1,119 +1,119 @@ -/* - * - */ -package org.redkale.test.cache; - -import java.io.File; -import java.io.IOException; -import java.time.Duration; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; -import org.redkale.annotation.Resource; -import org.redkale.cache.CacheManager; -import org.redkale.cache.Cached; -import org.redkale.service.Service; -import org.redkale.source.Range; -import org.redkale.util.RedkaleException; - -/** @author zhangjx */ -public class CacheInstance implements Service { - - @Resource - private CacheManager cacheManager; - - // 修改远程缓存的key值 - public void updateName(String code, Map map) { - cacheManager.remoteSetString(code, code + "_" + map.get("id"), Duration.ofMillis(60)); - } - - @Cached(key = "#{code}_#{map.id}", remoteExpire = "60", timeUnit = TimeUnit.MILLISECONDS) - public String getName(String code, Map map) { - return code + "-" + map; - } - - @Cached(key = "name", localExpire = "30") - public String getName() { - return "haha"; - } - - @Cached(key = "name", localExpire = "30", remoteExpire = "60") - public String getName2() throws RedkaleException { - return "haha"; - } - - @Cached(key = "name", localExpire = "30") - public CompletableFuture getNameAsync() { - return CompletableFuture.completedFuture("nameAsync"); - } - - @Cached(key = "name", localExpire = "30", remoteExpire = "60") - public CompletableFuture getName2Async() throws IOException, InstantiationException { - return CompletableFuture.completedFuture("name2Async"); - } - - @Cached(key = "info_#{id}_file#{files.one}", localExpire = "30", remoteExpire = "60") - public File getInfo(ParamBean bean, int id, List idList, Map files) { - return new File("aa.txt"); - } - - @Cached(key = "info_#{id}_file#{files.one}", localExpire = "30", remoteExpire = "60") - public CompletableFuture getInfoAsync(ParamBean bean, int id, List idList, Map files) { - return CompletableFuture.completedFuture(new File("aa.txt")); - } - - @Cached( - key = "info_#{id}_file#{files.one}", - localExpire = "30", - remoteExpire = "60", - timeUnit = TimeUnit.MILLISECONDS) - public CompletableFuture> getInfo2Async( - ParamBean bean, int id, List idList, Map files) - throws IOException, InstantiationException { - return CompletableFuture.completedFuture(null); - } - - public static class ParamBean { - - private String name; - - private int day; - - private Integer status; - - private Range.IntRange range; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public int getDay() { - return day; - } - - public void setDay(int day) { - this.day = day; - } - - public Integer getStatus() { - return status; - } - - public void setStatus(Integer status) { - this.status = status; - } - - public Range.IntRange getRange() { - return range; - } - - public void setRange(Range.IntRange range) { - this.range = range; - } - } -} +/* + * + */ +package org.redkale.test.cache; + +import java.io.File; +import java.io.IOException; +import java.time.Duration; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; +import org.redkale.annotation.Resource; +import org.redkale.cache.CacheManager; +import org.redkale.cache.Cached; +import org.redkale.service.Service; +import org.redkale.source.Range; +import org.redkale.util.RedkaleException; + +/** @author zhangjx */ +public class CacheInstance implements Service { + + @Resource + private CacheManager cacheManager; + + // 修改远程缓存的key值 + public void updateName(String code, Map map) { + cacheManager.remoteSetString(code, code + "_" + map.get("id"), Duration.ofMillis(60)); + } + + @Cached(key = "#{code}_#{map.id}", remoteExpire = "60", timeUnit = TimeUnit.MILLISECONDS) + public String getName(String code, Map map) { + return code + "-" + map; + } + + @Cached(key = "name", localExpire = "30") + public String getName() { + return "haha"; + } + + @Cached(key = "name", localExpire = "30", remoteExpire = "60") + public String getName2() throws RedkaleException { + return "haha"; + } + + @Cached(key = "name", localExpire = "30") + public CompletableFuture getNameAsync() { + return CompletableFuture.completedFuture("nameAsync"); + } + + @Cached(key = "name", localExpire = "30", remoteExpire = "60") + public CompletableFuture getName2Async() throws IOException, InstantiationException { + return CompletableFuture.completedFuture("name2Async"); + } + + @Cached(key = "info_#{id}_file#{files.one}", localExpire = "30", remoteExpire = "60") + public File getInfo(ParamBean bean, int id, List idList, Map files) { + return new File("aa.txt"); + } + + @Cached(key = "info_#{id}_file#{files.one}", localExpire = "30", remoteExpire = "60") + public CompletableFuture getInfoAsync(ParamBean bean, int id, List idList, Map files) { + return CompletableFuture.completedFuture(new File("aa.txt")); + } + + @Cached( + key = "info_#{id}_file#{files.one}", + localExpire = "30", + remoteExpire = "60", + timeUnit = TimeUnit.MILLISECONDS) + public CompletableFuture> getInfo2Async( + ParamBean bean, int id, List idList, Map files) + throws IOException, InstantiationException { + return CompletableFuture.completedFuture(null); + } + + public static class ParamBean { + + private String name; + + private int day; + + private Integer status; + + private Range.IntRange range; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getDay() { + return day; + } + + public void setDay(int day) { + this.day = day; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public Range.IntRange getRange() { + return range; + } + + public void setRange(Range.IntRange range) { + this.range = range; + } + } +} diff --git a/src/test/java/org/redkale/test/cache/CacheInstanceTest.java b/src/test/java/org/redkale/test/cache/CacheInstanceTest.java index c453a41a9..5ef63c1fb 100644 --- a/src/test/java/org/redkale/test/cache/CacheInstanceTest.java +++ b/src/test/java/org/redkale/test/cache/CacheInstanceTest.java @@ -1,62 +1,62 @@ -/* - * - */ -package org.redkale.test.cache; - -import java.net.InetSocketAddress; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.redkale.cache.CacheManager; -import org.redkale.cache.spi.CacheAsmMethodBoost; -import org.redkale.cache.spi.CacheManagerService; -import org.redkale.inject.ResourceFactory; -import org.redkale.net.AsyncGroup; -import org.redkale.net.client.ClientAddress; -import org.redkale.net.sncp.Sncp; -import org.redkale.net.sncp.SncpClient; -import org.redkale.net.sncp.SncpRpcGroups; -import org.redkale.source.CacheMemorySource; -import org.redkale.util.Environment; -import org.redkale.util.Utility; - -/** @author zhangjx */ -public class CacheInstanceTest { - - private static ResourceFactory resourceFactory; - - private static CacheManagerService manager; - - public static void main(String[] args) throws Throwable { - CacheInstanceTest test = new CacheInstanceTest(); - init(); - test.run1(); - test.run2(); - } - - @BeforeAll - public static void init() throws Exception { - resourceFactory = ResourceFactory.create(); - resourceFactory.register(new Environment()); - CacheMemorySource remoteSource = new CacheMemorySource("cache-remote"); - remoteSource.init(null); - manager = CacheManagerService.create(remoteSource); - manager.init(null); - resourceFactory.register("", CacheManager.class, manager); - } - - @Test - public void run1() throws Exception { - Class serviceClass = CacheInstance.class; - CacheAsmMethodBoost boost = new CacheAsmMethodBoost(false, serviceClass); - SncpRpcGroups grous = new SncpRpcGroups(); - AsyncGroup iGroup = AsyncGroup.create("", Utility.newScheduledExecutor(1), 0, 0); - SncpClient client = new SncpClient( - "", iGroup, "0", new InetSocketAddress("127.0.0.1", 8080), new ClientAddress(), "TCP", 1, 16); - CacheInstance instance = Sncp.createLocalService( - null, "", serviceClass, boost, resourceFactory, grous, client, null, null, null); - // System.out.println(instance.getName()); - } - - @Test - public void run2() throws Exception {} -} +/* + * + */ +package org.redkale.test.cache; + +import java.net.InetSocketAddress; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.redkale.cache.CacheManager; +import org.redkale.cache.spi.CacheAsmMethodBoost; +import org.redkale.cache.spi.CacheManagerService; +import org.redkale.inject.ResourceFactory; +import org.redkale.net.AsyncGroup; +import org.redkale.net.client.ClientAddress; +import org.redkale.net.sncp.Sncp; +import org.redkale.net.sncp.SncpClient; +import org.redkale.net.sncp.SncpRpcGroups; +import org.redkale.source.CacheMemorySource; +import org.redkale.util.Environment; +import org.redkale.util.Utility; + +/** @author zhangjx */ +public class CacheInstanceTest { + + private static ResourceFactory resourceFactory; + + private static CacheManagerService manager; + + public static void main(String[] args) throws Throwable { + CacheInstanceTest test = new CacheInstanceTest(); + init(); + test.run1(); + test.run2(); + } + + @BeforeAll + public static void init() throws Exception { + resourceFactory = ResourceFactory.create(); + resourceFactory.register(new Environment()); + CacheMemorySource remoteSource = new CacheMemorySource("cache-remote"); + remoteSource.init(null); + manager = CacheManagerService.create(remoteSource); + manager.init(null); + resourceFactory.register("", CacheManager.class, manager); + } + + @Test + public void run1() throws Exception { + Class serviceClass = CacheInstance.class; + CacheAsmMethodBoost boost = new CacheAsmMethodBoost(false, serviceClass); + SncpRpcGroups grous = new SncpRpcGroups(); + AsyncGroup iGroup = AsyncGroup.create("", Utility.newScheduledExecutor(1), 0, 0); + SncpClient client = new SncpClient( + "", iGroup, "0", new InetSocketAddress("127.0.0.1", 8080), new ClientAddress(), "TCP", 1, 16); + CacheInstance instance = Sncp.createLocalService( + null, "", serviceClass, boost, resourceFactory, grous, client, null, null, null); + // System.out.println(instance.getName()); + } + + @Test + public void run2() throws Exception {} +} diff --git a/src/test/java/org/redkale/test/cache/CacheManagerTest.java b/src/test/java/org/redkale/test/cache/CacheManagerTest.java index 98e1a8ad1..9b192b899 100644 --- a/src/test/java/org/redkale/test/cache/CacheManagerTest.java +++ b/src/test/java/org/redkale/test/cache/CacheManagerTest.java @@ -1,144 +1,144 @@ -/* - * - */ -package org.redkale.test.cache; - -import java.time.Duration; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicInteger; -import org.junit.jupiter.api.*; -import org.redkale.cache.spi.CacheManagerService; -import org.redkale.convert.json.JsonConvert; -import org.redkale.source.CacheMemorySource; -import org.redkale.util.Utility; - -/** @author zhangjx */ -public class CacheManagerTest { - - private static CacheManagerService manager; - - public static void main(String[] args) throws Throwable { - CacheManagerTest test = new CacheManagerTest(); - init(); - test.run1(); - test.run2(); - } - - @BeforeAll - public static void init() throws Exception { - CacheMemorySource remoteSource = new CacheMemorySource("cache-remote"); - remoteSource.init(null); - manager = CacheManagerService.create(remoteSource); - manager.init(null); - } - - @Test - public void run1() throws Exception { - Duration expire = Duration.ofMillis(290); - manager.localSetString("user", "name:haha", "myha", expire); - Assertions.assertEquals(manager.localGetString("user", "name:haha"), "myha"); - Utility.sleep(300); - Assertions.assertTrue(manager.localGetString("user", "name:haha") == null); - - CachingBean bean = new CachingBean(); - bean.setName("tom"); - bean.setRemark("这是名字备注"); - - String json = bean.toString(); - manager.localSet("user", bean.getName(), CachingBean.class, bean, expire); - Assertions.assertEquals( - manager.localGet("user", bean.getName(), CachingBean.class).toString(), json); - bean.setRemark(bean.getRemark() + "-新备注"); - Assertions.assertEquals( - manager.localGet("user", bean.getName(), CachingBean.class).toString(), json); - } - - @Test - public void run2() throws Exception { - int count = 50; - ParallelBean bean = new ParallelBean(); - Duration localExpire = Duration.ofMillis(190); - Duration remoteExpire = Duration.ofMillis(400); - { - CountDownLatch cdl = new CountDownLatch(count); - for (int i = 0; i < count; i++) { - new Thread(() -> { - manager.bothGetSet( - "ParallelBean", - "name", - String.class, - false, - localExpire, - remoteExpire, - () -> bean.getName()); - cdl.countDown(); - }) - .start(); - } - cdl.await(); - } - Assertions.assertEquals(1, ParallelBean.c1.get()); - Utility.sleep(200); - manager.bothGetSet( - "ParallelBean", "name", String.class, false, localExpire, remoteExpire, () -> bean.getName()); - Assertions.assertEquals(1, ParallelBean.c1.get()); - Utility.sleep(200); - { - CountDownLatch cdl = new CountDownLatch(count); - for (int i = 0; i < count; i++) { - new Thread(() -> { - manager.bothGetSet( - "ParallelBean", - "name", - String.class, - false, - localExpire, - remoteExpire, - () -> bean.getName()); - cdl.countDown(); - }) - .start(); - } - cdl.await(); - } - Assertions.assertEquals(2, ParallelBean.c1.get()); - } - - public static class ParallelBean { - - public static final AtomicInteger c1 = new AtomicInteger(); - - public String getName() { - c1.incrementAndGet(); - System.out.println("执行了getName方法(" + c1.get() + ")"); - return "hello"; - } - } - - public static class CachingBean { - - private String name; - - private String remark; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getRemark() { - return remark; - } - - public void setRemark(String remark) { - this.remark = remark; - } - - public String toString() { - return JsonConvert.root().convertTo(this); - } - } -} +/* + * + */ +package org.redkale.test.cache; + +import java.time.Duration; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicInteger; +import org.junit.jupiter.api.*; +import org.redkale.cache.spi.CacheManagerService; +import org.redkale.convert.json.JsonConvert; +import org.redkale.source.CacheMemorySource; +import org.redkale.util.Utility; + +/** @author zhangjx */ +public class CacheManagerTest { + + private static CacheManagerService manager; + + public static void main(String[] args) throws Throwable { + CacheManagerTest test = new CacheManagerTest(); + init(); + test.run1(); + test.run2(); + } + + @BeforeAll + public static void init() throws Exception { + CacheMemorySource remoteSource = new CacheMemorySource("cache-remote"); + remoteSource.init(null); + manager = CacheManagerService.create(remoteSource); + manager.init(null); + } + + @Test + public void run1() throws Exception { + Duration expire = Duration.ofMillis(290); + manager.localSetString("user", "name:haha", "myha", expire); + Assertions.assertEquals(manager.localGetString("user", "name:haha"), "myha"); + Utility.sleep(300); + Assertions.assertTrue(manager.localGetString("user", "name:haha") == null); + + CachingBean bean = new CachingBean(); + bean.setName("tom"); + bean.setRemark("这是名字备注"); + + String json = bean.toString(); + manager.localSet("user", bean.getName(), CachingBean.class, bean, expire); + Assertions.assertEquals( + manager.localGet("user", bean.getName(), CachingBean.class).toString(), json); + bean.setRemark(bean.getRemark() + "-新备注"); + Assertions.assertEquals( + manager.localGet("user", bean.getName(), CachingBean.class).toString(), json); + } + + @Test + public void run2() throws Exception { + int count = 50; + ParallelBean bean = new ParallelBean(); + Duration localExpire = Duration.ofMillis(190); + Duration remoteExpire = Duration.ofMillis(400); + { + CountDownLatch cdl = new CountDownLatch(count); + for (int i = 0; i < count; i++) { + new Thread(() -> { + manager.bothGetSet( + "ParallelBean", + "name", + String.class, + false, + localExpire, + remoteExpire, + () -> bean.getName()); + cdl.countDown(); + }) + .start(); + } + cdl.await(); + } + Assertions.assertEquals(1, ParallelBean.c1.get()); + Utility.sleep(200); + manager.bothGetSet( + "ParallelBean", "name", String.class, false, localExpire, remoteExpire, () -> bean.getName()); + Assertions.assertEquals(1, ParallelBean.c1.get()); + Utility.sleep(200); + { + CountDownLatch cdl = new CountDownLatch(count); + for (int i = 0; i < count; i++) { + new Thread(() -> { + manager.bothGetSet( + "ParallelBean", + "name", + String.class, + false, + localExpire, + remoteExpire, + () -> bean.getName()); + cdl.countDown(); + }) + .start(); + } + cdl.await(); + } + Assertions.assertEquals(2, ParallelBean.c1.get()); + } + + public static class ParallelBean { + + public static final AtomicInteger c1 = new AtomicInteger(); + + public String getName() { + c1.incrementAndGet(); + System.out.println("执行了getName方法(" + c1.get() + ")"); + return "hello"; + } + } + + public static class CachingBean { + + private String name; + + private String remark; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getRemark() { + return remark; + } + + public void setRemark(String remark) { + this.remark = remark; + } + + public String toString() { + return JsonConvert.root().convertTo(this); + } + } +} diff --git a/src/test/java/org/redkale/test/cache/_DynLocalCacheInstance.java b/src/test/java/org/redkale/test/cache/_DynLocalCacheInstance.java index e00714565..0a573080c 100644 --- a/src/test/java/org/redkale/test/cache/_DynLocalCacheInstance.java +++ b/src/test/java/org/redkale/test/cache/_DynLocalCacheInstance.java @@ -1,172 +1,172 @@ -/* - * - */ -package org.redkale.test.cache; - -import java.io.File; -import java.io.IOException; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; -import org.redkale.annotation.Resource; -import org.redkale.annotation.ResourceType; -import org.redkale.cache.spi.CacheAction; -import org.redkale.cache.spi.DynForCache; -import org.redkale.net.sncp.Sncp.SncpDyn; -import org.redkale.util.AnyValue; -import org.redkale.util.RedkaleException; -import org.redkale.util.ThrowSupplier; - -@Resource(name = "") -@SncpDyn(remote = false, type = CacheInstance.class) -@ResourceType(CacheInstance.class) -public class _DynLocalCacheInstance extends CacheInstance { - - private AnyValue _redkale_conf; - - private String _redkale_mq; - - private CacheAction _redkale_getNameCacheAction1; - - private CacheAction _redkale_getInfoCacheAction2; - - private CacheAction _redkale_getNameAsyncCacheAction3; - - private CacheAction _redkale_getInfo2AsyncCacheAction4; - - private CacheAction _redkale_getName2AsyncCacheAction5; - - private CacheAction _redkale_getInfoAsyncCacheAction6; - - private CacheAction _redkale_getName2CacheAction7; - - public _DynLocalCacheInstance() {} - - @DynForCache( - dynField = "_redkale_getNameCacheAction1", - hash = "", - key = "name", - nullable = false, - timeUnit = TimeUnit.SECONDS, - remoteExpire = "-1", - localExpire = "30") - public String getName() { - ThrowSupplier supplier = () -> this.getName_afterCache(); - return _redkale_getNameCacheAction1.get(supplier); - } - - private String getName_afterCache() { - return super.getName(); - } - - @DynForCache( - dynField = "_redkale_getInfoCacheAction2", - hash = "", - key = "info_#{id}_file#{files.one}", - nullable = false, - timeUnit = TimeUnit.SECONDS, - remoteExpire = "60", - localExpire = "30") - public File getInfo(CacheInstance.ParamBean bean, int id, List idList, Map files) { - ThrowSupplier supplier = () -> this.getInfo_afterCache(bean, id, idList, files); - return _redkale_getInfoCacheAction2.get(supplier); - } - - private File getInfo_afterCache( - CacheInstance.ParamBean bean, int id, List idList, Map files) { - return super.getInfo(bean, id, idList, files); - } - - @DynForCache( - dynField = "_redkale_getNameAsyncCacheAction3", - hash = "", - key = "name", - nullable = false, - timeUnit = TimeUnit.SECONDS, - remoteExpire = "-1", - localExpire = "30") - public CompletableFuture getNameAsync() { - ThrowSupplier> supplier = () -> this.getNameAsync_afterCache(); - return _redkale_getNameAsyncCacheAction3.get(supplier); - } - - private CompletableFuture getNameAsync_afterCache() { - return super.getNameAsync(); - } - - @DynForCache( - dynField = "_redkale_getInfo2AsyncCacheAction4", - hash = "", - key = "info_#{id}_file#{files.one}", - nullable = false, - timeUnit = TimeUnit.SECONDS, - remoteExpire = "60", - localExpire = "30") - public CompletableFuture> getInfo2Async( - CacheInstance.ParamBean bean, int id, List idList, Map files) - throws IOException, InstantiationException { - ThrowSupplier>> supplier = - () -> this.getInfo2Async_afterCache(bean, id, idList, files); - return _redkale_getInfo2AsyncCacheAction4.get(supplier, bean, id, idList, files); - } - - private CompletableFuture> getInfo2Async_afterCache( - CacheInstance.ParamBean bean, int id, List idList, Map files) - throws IOException, InstantiationException { - return super.getInfo2Async(bean, id, idList, files); - } - - @DynForCache( - dynField = "_redkale_getName2AsyncCacheAction5", - hash = "", - key = "name", - nullable = false, - timeUnit = TimeUnit.SECONDS, - remoteExpire = "60", - localExpire = "30") - public CompletableFuture getName2Async() throws IOException, InstantiationException { - ThrowSupplier> supplier = () -> this.getName2Async_afterCache(); - return _redkale_getName2AsyncCacheAction5.get(supplier); - } - - private CompletableFuture getName2Async_afterCache() throws IOException, InstantiationException { - return super.getName2Async(); - } - - @DynForCache( - dynField = "_redkale_getInfoAsyncCacheAction6", - hash = "", - key = "info_#{id}_file#{files.one}", - nullable = false, - timeUnit = TimeUnit.SECONDS, - remoteExpire = "60", - localExpire = "30") - public CompletableFuture getInfoAsync( - CacheInstance.ParamBean bean, int id, List idList, Map files) { - ThrowSupplier> supplier = () -> this.getInfoAsync_afterCache(bean, id, idList, files); - return _redkale_getInfoAsyncCacheAction6.get(supplier, bean, id, idList, files); - } - - private CompletableFuture getInfoAsync_afterCache( - CacheInstance.ParamBean bean, int id, List idList, Map files) { - return super.getInfoAsync(bean, id, idList, files); - } - - @DynForCache( - dynField = "_redkale_getName2CacheAction7", - hash = "", - key = "name", - nullable = false, - timeUnit = TimeUnit.SECONDS, - remoteExpire = "60", - localExpire = "30") - public String getName2() throws RedkaleException { - ThrowSupplier supplier = () -> this.getName2_afterCache(); - return _redkale_getName2CacheAction7.get(supplier); - } - - private String getName2_afterCache() throws RedkaleException { - return super.getName2(); - } -} +/* + * + */ +package org.redkale.test.cache; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; +import org.redkale.annotation.Resource; +import org.redkale.annotation.ResourceType; +import org.redkale.cache.spi.CacheAction; +import org.redkale.cache.spi.DynForCache; +import org.redkale.net.sncp.Sncp.SncpDyn; +import org.redkale.util.AnyValue; +import org.redkale.util.RedkaleException; +import org.redkale.util.ThrowSupplier; + +@Resource(name = "") +@SncpDyn(remote = false, type = CacheInstance.class) +@ResourceType(CacheInstance.class) +public class _DynLocalCacheInstance extends CacheInstance { + + private AnyValue _redkale_conf; + + private String _redkale_mq; + + private CacheAction _redkale_getNameCacheAction1; + + private CacheAction _redkale_getInfoCacheAction2; + + private CacheAction _redkale_getNameAsyncCacheAction3; + + private CacheAction _redkale_getInfo2AsyncCacheAction4; + + private CacheAction _redkale_getName2AsyncCacheAction5; + + private CacheAction _redkale_getInfoAsyncCacheAction6; + + private CacheAction _redkale_getName2CacheAction7; + + public _DynLocalCacheInstance() {} + + @DynForCache( + dynField = "_redkale_getNameCacheAction1", + hash = "", + key = "name", + nullable = false, + timeUnit = TimeUnit.SECONDS, + remoteExpire = "-1", + localExpire = "30") + public String getName() { + ThrowSupplier supplier = () -> this.getName_afterCache(); + return _redkale_getNameCacheAction1.get(supplier); + } + + private String getName_afterCache() { + return super.getName(); + } + + @DynForCache( + dynField = "_redkale_getInfoCacheAction2", + hash = "", + key = "info_#{id}_file#{files.one}", + nullable = false, + timeUnit = TimeUnit.SECONDS, + remoteExpire = "60", + localExpire = "30") + public File getInfo(CacheInstance.ParamBean bean, int id, List idList, Map files) { + ThrowSupplier supplier = () -> this.getInfo_afterCache(bean, id, idList, files); + return _redkale_getInfoCacheAction2.get(supplier); + } + + private File getInfo_afterCache( + CacheInstance.ParamBean bean, int id, List idList, Map files) { + return super.getInfo(bean, id, idList, files); + } + + @DynForCache( + dynField = "_redkale_getNameAsyncCacheAction3", + hash = "", + key = "name", + nullable = false, + timeUnit = TimeUnit.SECONDS, + remoteExpire = "-1", + localExpire = "30") + public CompletableFuture getNameAsync() { + ThrowSupplier> supplier = () -> this.getNameAsync_afterCache(); + return _redkale_getNameAsyncCacheAction3.get(supplier); + } + + private CompletableFuture getNameAsync_afterCache() { + return super.getNameAsync(); + } + + @DynForCache( + dynField = "_redkale_getInfo2AsyncCacheAction4", + hash = "", + key = "info_#{id}_file#{files.one}", + nullable = false, + timeUnit = TimeUnit.SECONDS, + remoteExpire = "60", + localExpire = "30") + public CompletableFuture> getInfo2Async( + CacheInstance.ParamBean bean, int id, List idList, Map files) + throws IOException, InstantiationException { + ThrowSupplier>> supplier = + () -> this.getInfo2Async_afterCache(bean, id, idList, files); + return _redkale_getInfo2AsyncCacheAction4.get(supplier, bean, id, idList, files); + } + + private CompletableFuture> getInfo2Async_afterCache( + CacheInstance.ParamBean bean, int id, List idList, Map files) + throws IOException, InstantiationException { + return super.getInfo2Async(bean, id, idList, files); + } + + @DynForCache( + dynField = "_redkale_getName2AsyncCacheAction5", + hash = "", + key = "name", + nullable = false, + timeUnit = TimeUnit.SECONDS, + remoteExpire = "60", + localExpire = "30") + public CompletableFuture getName2Async() throws IOException, InstantiationException { + ThrowSupplier> supplier = () -> this.getName2Async_afterCache(); + return _redkale_getName2AsyncCacheAction5.get(supplier); + } + + private CompletableFuture getName2Async_afterCache() throws IOException, InstantiationException { + return super.getName2Async(); + } + + @DynForCache( + dynField = "_redkale_getInfoAsyncCacheAction6", + hash = "", + key = "info_#{id}_file#{files.one}", + nullable = false, + timeUnit = TimeUnit.SECONDS, + remoteExpire = "60", + localExpire = "30") + public CompletableFuture getInfoAsync( + CacheInstance.ParamBean bean, int id, List idList, Map files) { + ThrowSupplier> supplier = () -> this.getInfoAsync_afterCache(bean, id, idList, files); + return _redkale_getInfoAsyncCacheAction6.get(supplier, bean, id, idList, files); + } + + private CompletableFuture getInfoAsync_afterCache( + CacheInstance.ParamBean bean, int id, List idList, Map files) { + return super.getInfoAsync(bean, id, idList, files); + } + + @DynForCache( + dynField = "_redkale_getName2CacheAction7", + hash = "", + key = "name", + nullable = false, + timeUnit = TimeUnit.SECONDS, + remoteExpire = "60", + localExpire = "30") + public String getName2() throws RedkaleException { + ThrowSupplier supplier = () -> this.getName2_afterCache(); + return _redkale_getName2CacheAction7.get(supplier); + } + + private String getName2_afterCache() throws RedkaleException { + return super.getName2(); + } +} diff --git a/src/test/java/org/redkale/test/convert/BiFunctionConvertTest.java b/src/test/java/org/redkale/test/convert/BiFunctionConvertTest.java index 6860c8077..a2916a827 100644 --- a/src/test/java/org/redkale/test/convert/BiFunctionConvertTest.java +++ b/src/test/java/org/redkale/test/convert/BiFunctionConvertTest.java @@ -1,73 +1,73 @@ -/* - * 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.test.convert; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import org.redkale.convert.ConvertField; -import org.redkale.convert.json.JsonConvert; -import org.redkale.util.Attribute; - -/** @author zhangjx */ -public class BiFunctionConvertTest { - - public static class GamePlayer { - - public int userid; - - public String username; - - public int[] cards; - } - - public static class GameTable { - - public int tableid; - - public GamePlayer[] players; - } - - @Test - public void run() throws Throwable { - GamePlayer player1 = new GamePlayer(); - player1.userid = 1; - player1.username = "玩家1"; - player1.cards = new int[] {11, 12, 13, 14, 15}; - GamePlayer player2 = new GamePlayer(); - player2.userid = 2; - player2.username = "玩家2"; - player2.cards = new int[] {21, 22, 23, 24, 25}; - GamePlayer player3 = new GamePlayer(); - player3.userid = 3; - player3.username = "玩家3"; - player3.cards = new int[] {31, 32, 33, 34, 35}; - GameTable table = new GameTable(); - table.tableid = 100; - table.players = new GamePlayer[] {player1, player2, player3}; - JsonConvert convert1 = JsonConvert.root(); - System.out.println(convert1.convertTo(table)); - JsonConvert convert2 = convert1.newConvert( - (Attribute t, Object u) -> { - if (t.field().equals("cards") && u instanceof GamePlayer) { - int userid = ((GamePlayer) u).userid; - if (userid == 3) return null; // 玩家3的cards不输出 - return t.get(u); - } - return t.get(u); - }, - (Object u) -> { - if (table != u) return null; - // return new ConvertField[]{new ConvertField("extcol1", 30), new ConvertField("extcol2", "扩展字段值")}; - return ConvertField.ofArray("extcol1", 30, "extcol2", "扩展字段值"); - }); - System.out.println(convert2.convertTo(table)); - Assertions.assertEquals( - "{\"players\":[{\"cards\":[11,12,13,14,15],\"userid\":1,\"username\":\"玩家1\"},{\"cards\":[21,22,23,24,25],\"userid\":2,\"username\":\"玩家2\"},{\"userid\":3,\"username\":\"玩家3\"}],\"tableid\":100,\"extcol1\":30,\"extcol2\":\"扩展字段值\"}", - convert2.convertTo(table)); - // {"players":[{"cards":[11,12,13,14,15],"userid":1,"username":"玩家1"},{"cards":[21,22,23,24,25],"userid":2,"username":"玩家2"},{"cards":[31,32,33,34,35],"userid":3,"username":"玩家3"}],"tableid":100} - // {"players":[{"cards":[11,12,13,14,15],"userid":1,"username":"玩家1"},{"cards":[21,22,23,24,25],"userid":2,"username":"玩家2"},{"userid":3,"username":"玩家3"}],"tableid":100,"extcol1":30,"extcol2":"扩展字段值"} - } -} +/* + * 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.test.convert; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.redkale.convert.ConvertField; +import org.redkale.convert.json.JsonConvert; +import org.redkale.util.Attribute; + +/** @author zhangjx */ +public class BiFunctionConvertTest { + + public static class GamePlayer { + + public int userid; + + public String username; + + public int[] cards; + } + + public static class GameTable { + + public int tableid; + + public GamePlayer[] players; + } + + @Test + public void run() throws Throwable { + GamePlayer player1 = new GamePlayer(); + player1.userid = 1; + player1.username = "玩家1"; + player1.cards = new int[] {11, 12, 13, 14, 15}; + GamePlayer player2 = new GamePlayer(); + player2.userid = 2; + player2.username = "玩家2"; + player2.cards = new int[] {21, 22, 23, 24, 25}; + GamePlayer player3 = new GamePlayer(); + player3.userid = 3; + player3.username = "玩家3"; + player3.cards = new int[] {31, 32, 33, 34, 35}; + GameTable table = new GameTable(); + table.tableid = 100; + table.players = new GamePlayer[] {player1, player2, player3}; + JsonConvert convert1 = JsonConvert.root(); + System.out.println(convert1.convertTo(table)); + JsonConvert convert2 = convert1.newConvert( + (Attribute t, Object u) -> { + if (t.field().equals("cards") && u instanceof GamePlayer) { + int userid = ((GamePlayer) u).userid; + if (userid == 3) return null; // 玩家3的cards不输出 + return t.get(u); + } + return t.get(u); + }, + (Object u) -> { + if (table != u) return null; + // return new ConvertField[]{new ConvertField("extcol1", 30), new ConvertField("extcol2", "扩展字段值")}; + return ConvertField.ofArray("extcol1", 30, "extcol2", "扩展字段值"); + }); + System.out.println(convert2.convertTo(table)); + Assertions.assertEquals( + "{\"players\":[{\"cards\":[11,12,13,14,15],\"userid\":1,\"username\":\"玩家1\"},{\"cards\":[21,22,23,24,25],\"userid\":2,\"username\":\"玩家2\"},{\"userid\":3,\"username\":\"玩家3\"}],\"tableid\":100,\"extcol1\":30,\"extcol2\":\"扩展字段值\"}", + convert2.convertTo(table)); + // {"players":[{"cards":[11,12,13,14,15],"userid":1,"username":"玩家1"},{"cards":[21,22,23,24,25],"userid":2,"username":"玩家2"},{"cards":[31,32,33,34,35],"userid":3,"username":"玩家3"}],"tableid":100} + // {"players":[{"cards":[11,12,13,14,15],"userid":1,"username":"玩家1"},{"cards":[21,22,23,24,25],"userid":2,"username":"玩家2"},{"userid":3,"username":"玩家3"}],"tableid":100,"extcol1":30,"extcol2":"扩展字段值"} + } +} diff --git a/src/test/java/org/redkale/test/convert/BsonMainTest.java b/src/test/java/org/redkale/test/convert/BsonMainTest.java index da212141f..4fbc6459d 100644 --- a/src/test/java/org/redkale/test/convert/BsonMainTest.java +++ b/src/test/java/org/redkale/test/convert/BsonMainTest.java @@ -1,286 +1,286 @@ -/* - * 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.test.convert; - -import java.io.*; -import java.nio.ByteBuffer; -import java.util.*; -import org.junit.jupiter.api.*; -import org.redkale.annotation.ConstructorParameters; -import org.redkale.convert.bson.*; -import org.redkale.convert.json.JsonConvert; -import org.redkale.persistence.*; -import org.redkale.util.*; - -/** @author zhangjx */ -public class BsonMainTest { - - public static void main(String[] args) throws Throwable { - BsonMainTest test = new BsonMainTest(); - test.run1(); - test.run2(); - test.run3(); - test.run4(); - test.run5(); - test.run6(); - test.run7(); - test.run8(); - } - - @Test - public void run1() throws Throwable { - Serializable[] sers = new Serializable[] {"aaa", 4}; - final BsonConvert convert = BsonFactory.root().getConvert(); - byte[] bytes = convert.convertTo(sers); - Utility.println("---", bytes); - byte[] checks = new byte[] { - 0x00, 0x00, 0x00, 0x02, 0x7f, 0x01, 0x41, 0x00, 0x00, 0x00, 0x03, 0x61, 0x61, 0x61, 0x01, 0x69, 0x00, 0x00, - 0x00, 0x04 - }; - Assertions.assertArrayEquals(checks, bytes); - Serializable[] a = convert.convertFrom(Serializable[].class, bytes); - Assertions.assertEquals("[aaa, 4]", Arrays.toString(a)); - } - - @Test - public void run2() throws Exception { - final BsonConvert convert = BsonFactory.root().getConvert(); - SimpleChildEntity entry = SimpleChildEntity.create(); - byte[] bytes = convert.convertTo(SimpleEntity.class, entry); - System.out.println("长度: " + bytes.length); - Assertions.assertEquals(260, bytes.length); - BsonByteBufferWriter writer = convert.pollWriter(() -> ByteBuffer.allocate(1)); - convert.convertTo(writer, SimpleEntity.class, entry); - ByteBuffer[] buffers = writer.toBuffers(); - int len = 0; - ByteArrayOutputStream out = new ByteArrayOutputStream(); - for (ByteBuffer b : buffers) { - len += b.remaining(); - byte[] ts = new byte[b.remaining()]; - b.get(ts); - out.write(ts); - b.flip(); - } - System.out.println("长度: " + len); - Assertions.assertEquals(260, len); - SimpleChildEntity entry2 = convert.convertFrom(SimpleChildEntity.class, buffers); - System.out.println(entry); - Assertions.assertEquals(entry.toString(), entry2.toString()); - } - - @Test - public void run3() throws Exception { - final BsonConvert convert = BsonFactory.root().getConvert(); - SimpleChildEntity entry = SimpleChildEntity.create(); - byte[] bytes = convert.convertTo(SimpleEntity.class, entry); - Utility.println(null, bytes); - System.out.println(JsonConvert.root().convertTo(entry)); - SimpleEntity rs = convert.convertFrom(SimpleEntity.class, bytes); - Assertions.assertEquals(JsonConvert.root().convertTo(entry), rs.toString()); - - ComplextEntity bean = new ComplextEntity(); - byte[] bytes2 = convert.convertTo(Object.class, bean); - final int len = bytes2.length; - BsonByteBufferWriter writer = convert.pollWriter(() -> ByteBuffer.allocate(len / 2)); - convert.convertTo(writer, bean); - bytes2 = writer.toArray(); - System.out.println(convert.convertFrom(ComplextEntity.class, bytes2).toString()); - Assertions.assertEquals( - "{\"chname\":\"\",\"flag\":true,\"userid\":0}", - convert.convertFrom(ComplextEntity.class, bytes2).toString()); - } - - @Test - public void run4() throws Exception { - final BsonConvert convert = BsonFactory.root().getConvert(); - SimpleChildEntity entry = SimpleChildEntity.create(); - ByteArrayOutputStream out = new ByteArrayOutputStream(); - convert.convertTo(out, SimpleEntity.class, entry); - byte[] bytes = out.toByteArray(); - Utility.println(null, bytes); - SimpleEntity rs = convert.convertFrom(SimpleEntity.class, new ByteArrayInputStream(bytes)); - System.out.println(rs.toString()); - Assertions.assertEquals(JsonConvert.root().convertTo(entry), rs.toString()); - } - - @Test - public void run5() throws Exception { - final BsonConvert convert = BsonFactory.root().getConvert(); - - LinkedHashMap map = new LinkedHashMap(); - map.put("1", 1); - map.put("2", "a2"); - byte[] bs = convert.convertTo(Object.class, map); - Object mapobj = convert.convertFrom(Object.class, bs); - System.out.println(mapobj); - Assertions.assertEquals("{1=1, 2=a2}", mapobj.toString()); - } - - @Test - public void run6() throws Exception { - final BsonConvert convert = BsonFactory.root().getConvert(); - - Optional val = Optional.ofNullable("haha"); - byte[] bs = convert.convertTo(val); - Object obj = convert.convertFrom(Optional.class, bs); - System.out.println(obj); - Assertions.assertEquals("Optional[haha]", obj.toString()); - bs = convert.convertTo(Object.class, val); - obj = convert.convertFrom(Object.class, bs); - Assertions.assertEquals("Optional[haha]", obj.toString()); - bs = convert.convertTo(new TypeToken>() {}.getType(), val); - obj = convert.convertFrom(new TypeToken>() {}.getType(), bs); - Assertions.assertEquals("Optional[haha]", obj.toString()); - System.out.println(JsonConvert.root().convertTo(val)); - Assertions.assertEquals("\"haha\"", JsonConvert.root().convertTo(val)); - } - - @Test - public void run7() throws Throwable { - Two two = new Two(); - two.setKey("key111"); - two.setCode(12345); - List list = new ArrayList<>(); - list.add("haha"); - two.setList(list); - Map map = new HashMap<>(); - map.put("222", "333"); - two.setStringMap(map); - - List records = new ArrayList<>(); - records.add(ConvertRecord.createDefault()); - two.setRecords(records); - - Map rmap = new HashMap<>(); - rmap.put("222", ConvertRecord.createDefault()); - two.setRecordMap(rmap); - - byte[] bs = BsonFactory.root().getConvert().convertTo(two); - - One one = BsonFactory.root().getConvert().convertFrom(One.class, bs); - System.out.println(one); - Assertions.assertEquals( - "{\"bytes\":[3,4,5],\"code\":12345,\"ints\":[3000,4000,5000],\"key\":\"key111\"}", one.toString()); - } - - @Test - public void run8() throws Exception { - final JsonConvert jsonConvert = JsonConvert.root(); - final BsonConvert bsonConvert = BsonFactory.root().getConvert(); - ConstructorArgsEntity bean = new ConstructorArgsEntity(12345678, "哈哈"); - bean.setCreatetime(12345678901L); - String json = jsonConvert.convertTo(bean); - System.out.println(json); - Assertions.assertEquals("{\"createtime\":12345678901,\"name\":\"哈哈\",\"userid\":12345678}", json); - Assertions.assertEquals( - jsonConvert.convertFrom(ConstructorArgsEntity.class, json).toString(), json); - byte[] bytes = bsonConvert.convertTo(bean); - Assertions.assertEquals( - bsonConvert.convertFrom(ConstructorArgsEntity.class, bytes).toString(), json); - } - - public static class ComplextEntity { - - @Id - private int userid; - - private String chname = ""; - - @Transient - private boolean flag = true; - - @Transient - private List children; - - @Transient - private SimpleEntity user; - - public int getUserid() { - return userid; - } - - public void setUserid(int userid) { - this.userid = userid; - } - - public String getChname() { - return chname; - } - - public void setChname(String chname) { - this.chname = chname; - } - - public boolean isFlag() { - return flag; - } - - public void setFlag(boolean flag) { - this.flag = flag; - } - - public List getChildren() { - return children; - } - - public void setChildren(List children) { - this.children = children; - } - - public SimpleEntity getUser() { - return user; - } - - public void setUser(SimpleEntity user) { - this.user = user; - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } - } - - public static class ConstructorArgsEntity { - - private final int userid; - - private String name; - - private long createtime; - - @ConstructorParameters({"userid", "name"}) - public ConstructorArgsEntity(int userid, String name) { - this.userid = userid; - this.name = name; - } - - public int getUserid() { - return userid; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public long getCreatetime() { - return createtime; - } - - public void setCreatetime(long createtime) { - this.createtime = createtime; - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } - } -} +/* + * 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.test.convert; + +import java.io.*; +import java.nio.ByteBuffer; +import java.util.*; +import org.junit.jupiter.api.*; +import org.redkale.annotation.ConstructorParameters; +import org.redkale.convert.bson.*; +import org.redkale.convert.json.JsonConvert; +import org.redkale.persistence.*; +import org.redkale.util.*; + +/** @author zhangjx */ +public class BsonMainTest { + + public static void main(String[] args) throws Throwable { + BsonMainTest test = new BsonMainTest(); + test.run1(); + test.run2(); + test.run3(); + test.run4(); + test.run5(); + test.run6(); + test.run7(); + test.run8(); + } + + @Test + public void run1() throws Throwable { + Serializable[] sers = new Serializable[] {"aaa", 4}; + final BsonConvert convert = BsonFactory.root().getConvert(); + byte[] bytes = convert.convertTo(sers); + Utility.println("---", bytes); + byte[] checks = new byte[] { + 0x00, 0x00, 0x00, 0x02, 0x7f, 0x01, 0x41, 0x00, 0x00, 0x00, 0x03, 0x61, 0x61, 0x61, 0x01, 0x69, 0x00, 0x00, + 0x00, 0x04 + }; + Assertions.assertArrayEquals(checks, bytes); + Serializable[] a = convert.convertFrom(Serializable[].class, bytes); + Assertions.assertEquals("[aaa, 4]", Arrays.toString(a)); + } + + @Test + public void run2() throws Exception { + final BsonConvert convert = BsonFactory.root().getConvert(); + SimpleChildEntity entry = SimpleChildEntity.create(); + byte[] bytes = convert.convertTo(SimpleEntity.class, entry); + System.out.println("长度: " + bytes.length); + Assertions.assertEquals(260, bytes.length); + BsonByteBufferWriter writer = convert.pollWriter(() -> ByteBuffer.allocate(1)); + convert.convertTo(writer, SimpleEntity.class, entry); + ByteBuffer[] buffers = writer.toBuffers(); + int len = 0; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + for (ByteBuffer b : buffers) { + len += b.remaining(); + byte[] ts = new byte[b.remaining()]; + b.get(ts); + out.write(ts); + b.flip(); + } + System.out.println("长度: " + len); + Assertions.assertEquals(260, len); + SimpleChildEntity entry2 = convert.convertFrom(SimpleChildEntity.class, buffers); + System.out.println(entry); + Assertions.assertEquals(entry.toString(), entry2.toString()); + } + + @Test + public void run3() throws Exception { + final BsonConvert convert = BsonFactory.root().getConvert(); + SimpleChildEntity entry = SimpleChildEntity.create(); + byte[] bytes = convert.convertTo(SimpleEntity.class, entry); + Utility.println(null, bytes); + System.out.println(JsonConvert.root().convertTo(entry)); + SimpleEntity rs = convert.convertFrom(SimpleEntity.class, bytes); + Assertions.assertEquals(JsonConvert.root().convertTo(entry), rs.toString()); + + ComplextEntity bean = new ComplextEntity(); + byte[] bytes2 = convert.convertTo(Object.class, bean); + final int len = bytes2.length; + BsonByteBufferWriter writer = convert.pollWriter(() -> ByteBuffer.allocate(len / 2)); + convert.convertTo(writer, bean); + bytes2 = writer.toArray(); + System.out.println(convert.convertFrom(ComplextEntity.class, bytes2).toString()); + Assertions.assertEquals( + "{\"chname\":\"\",\"flag\":true,\"userid\":0}", + convert.convertFrom(ComplextEntity.class, bytes2).toString()); + } + + @Test + public void run4() throws Exception { + final BsonConvert convert = BsonFactory.root().getConvert(); + SimpleChildEntity entry = SimpleChildEntity.create(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + convert.convertTo(out, SimpleEntity.class, entry); + byte[] bytes = out.toByteArray(); + Utility.println(null, bytes); + SimpleEntity rs = convert.convertFrom(SimpleEntity.class, new ByteArrayInputStream(bytes)); + System.out.println(rs.toString()); + Assertions.assertEquals(JsonConvert.root().convertTo(entry), rs.toString()); + } + + @Test + public void run5() throws Exception { + final BsonConvert convert = BsonFactory.root().getConvert(); + + LinkedHashMap map = new LinkedHashMap(); + map.put("1", 1); + map.put("2", "a2"); + byte[] bs = convert.convertTo(Object.class, map); + Object mapobj = convert.convertFrom(Object.class, bs); + System.out.println(mapobj); + Assertions.assertEquals("{1=1, 2=a2}", mapobj.toString()); + } + + @Test + public void run6() throws Exception { + final BsonConvert convert = BsonFactory.root().getConvert(); + + Optional val = Optional.ofNullable("haha"); + byte[] bs = convert.convertTo(val); + Object obj = convert.convertFrom(Optional.class, bs); + System.out.println(obj); + Assertions.assertEquals("Optional[haha]", obj.toString()); + bs = convert.convertTo(Object.class, val); + obj = convert.convertFrom(Object.class, bs); + Assertions.assertEquals("Optional[haha]", obj.toString()); + bs = convert.convertTo(new TypeToken>() {}.getType(), val); + obj = convert.convertFrom(new TypeToken>() {}.getType(), bs); + Assertions.assertEquals("Optional[haha]", obj.toString()); + System.out.println(JsonConvert.root().convertTo(val)); + Assertions.assertEquals("\"haha\"", JsonConvert.root().convertTo(val)); + } + + @Test + public void run7() throws Throwable { + Two two = new Two(); + two.setKey("key111"); + two.setCode(12345); + List list = new ArrayList<>(); + list.add("haha"); + two.setList(list); + Map map = new HashMap<>(); + map.put("222", "333"); + two.setStringMap(map); + + List records = new ArrayList<>(); + records.add(ConvertRecord.createDefault()); + two.setRecords(records); + + Map rmap = new HashMap<>(); + rmap.put("222", ConvertRecord.createDefault()); + two.setRecordMap(rmap); + + byte[] bs = BsonFactory.root().getConvert().convertTo(two); + + One one = BsonFactory.root().getConvert().convertFrom(One.class, bs); + System.out.println(one); + Assertions.assertEquals( + "{\"bytes\":[3,4,5],\"code\":12345,\"ints\":[3000,4000,5000],\"key\":\"key111\"}", one.toString()); + } + + @Test + public void run8() throws Exception { + final JsonConvert jsonConvert = JsonConvert.root(); + final BsonConvert bsonConvert = BsonFactory.root().getConvert(); + ConstructorArgsEntity bean = new ConstructorArgsEntity(12345678, "哈哈"); + bean.setCreatetime(12345678901L); + String json = jsonConvert.convertTo(bean); + System.out.println(json); + Assertions.assertEquals("{\"createtime\":12345678901,\"name\":\"哈哈\",\"userid\":12345678}", json); + Assertions.assertEquals( + jsonConvert.convertFrom(ConstructorArgsEntity.class, json).toString(), json); + byte[] bytes = bsonConvert.convertTo(bean); + Assertions.assertEquals( + bsonConvert.convertFrom(ConstructorArgsEntity.class, bytes).toString(), json); + } + + public static class ComplextEntity { + + @Id + private int userid; + + private String chname = ""; + + @Transient + private boolean flag = true; + + @Transient + private List children; + + @Transient + private SimpleEntity user; + + public int getUserid() { + return userid; + } + + public void setUserid(int userid) { + this.userid = userid; + } + + public String getChname() { + return chname; + } + + public void setChname(String chname) { + this.chname = chname; + } + + public boolean isFlag() { + return flag; + } + + public void setFlag(boolean flag) { + this.flag = flag; + } + + public List getChildren() { + return children; + } + + public void setChildren(List children) { + this.children = children; + } + + public SimpleEntity getUser() { + return user; + } + + public void setUser(SimpleEntity user) { + this.user = user; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + } + + public static class ConstructorArgsEntity { + + private final int userid; + + private String name; + + private long createtime; + + @ConstructorParameters({"userid", "name"}) + public ConstructorArgsEntity(int userid, String name) { + this.userid = userid; + this.name = name; + } + + public int getUserid() { + return userid; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public long getCreatetime() { + return createtime; + } + + public void setCreatetime(long createtime) { + this.createtime = createtime; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + } +} diff --git a/src/test/java/org/redkale/test/convert/ConvertImplTest.java b/src/test/java/org/redkale/test/convert/ConvertImplTest.java index 5663fe461..189ec55b4 100644 --- a/src/test/java/org/redkale/test/convert/ConvertImplTest.java +++ b/src/test/java/org/redkale/test/convert/ConvertImplTest.java @@ -1,41 +1,41 @@ -/* - * 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.test.convert; - -import org.junit.jupiter.api.*; -import org.redkale.convert.ConvertImpl; -import org.redkale.convert.json.JsonConvert; - -/** @author zhangjx */ -public class ConvertImplTest { - - @Test - public void run1() throws Throwable { - String json = "{'name':'hellow'}"; - OneEntity one = JsonConvert.root().convertFrom(OneEntity.class, json); - Assertions.assertTrue(one instanceof OneImpl); - } - - @ConvertImpl(OneImpl.class) - public static interface OneEntity { - - public String getName(); - } - - public static class OneImpl implements OneEntity { - - private String name; - - @Override - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - } -} +/* + * 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.test.convert; + +import org.junit.jupiter.api.*; +import org.redkale.convert.ConvertImpl; +import org.redkale.convert.json.JsonConvert; + +/** @author zhangjx */ +public class ConvertImplTest { + + @Test + public void run1() throws Throwable { + String json = "{'name':'hellow'}"; + OneEntity one = JsonConvert.root().convertFrom(OneEntity.class, json); + Assertions.assertTrue(one instanceof OneImpl); + } + + @ConvertImpl(OneImpl.class) + public static interface OneEntity { + + public String getName(); + } + + public static class OneImpl implements OneEntity { + + private String name; + + @Override + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } +} diff --git a/src/test/java/org/redkale/test/convert/ConvertRecord.java b/src/test/java/org/redkale/test/convert/ConvertRecord.java index ee1d33360..6f2e76d93 100644 --- a/src/test/java/org/redkale/test/convert/ConvertRecord.java +++ b/src/test/java/org/redkale/test/convert/ConvertRecord.java @@ -1,155 +1,155 @@ -/* - * 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.test.convert; - -import java.util.*; - -/** @author redkale */ -public class ConvertRecord { - - private String aname; - - private String desc = ""; - - private int id = (int) System.currentTimeMillis(); - - private int[] integers; - - private long[] longs; - - private List strings; - - private Map map; - - public static ConvertRecord createDefault() { - ConvertRecord v = new ConvertRecord(); - v.setAname("this is name\n \"test"); - v.setId(1000000001); - v.setIntegers(new int[] {12, 34, 56, 78, 90, 123, 456, 789}); - v.setLongs(new long[] { - 10000012L, 10000034L, 10000056L, 10000078L, -10000090L, -100000123L, -100000456L, -100000789L - }); - List list = new ArrayList<>(); - list.add("str_a"); - list.add("str_b"); - list.add("str_c"); - v.setStrings(list); - Map map = new HashMap<>(); - map.put("key_a", 111); - map.put("key_b", 222); - map.put("key_c", 333); - v.setMap(map); - return v; - } - - public static void main(String[] args) throws Exception { - final ConvertRecord entry = ConvertRecord.createDefault(); - run(ConvertRecord.class, entry); - } - - public static void run(final Class type, final T entry) throws Exception { - /** - * final org.redkale.convert.json.JsonConvert convert = - * org.redkale.convert.json.JsonFactory.root().getConvert(); final String entryString = - * convert.convertTo(entry); convert.convertFrom(type, entryString); System.out.println("redkale-convert: " + - * convert.convertTo(entry)); - * - *

com.alibaba.fastjson.JSON.parseObject(entryString, type); System.out.println("fastjson 1.2.7: " + - * com.alibaba.fastjson.JSON.toJSONString(entry)); - * - *

final com.fasterxml.jackson.databind.ObjectMapper mapper = new - * com.fasterxml.jackson.databind.ObjectMapper(); mapper.readValue(entryString, type); - * System.out.println("jackson 2.7.2: " + mapper.writeValueAsString(entry)); - * - *

final com.google.gson.Gson gson = new com.google.gson.Gson(); gson.fromJson(entryString, type); - * System.out.println("google-gson 2.4: " + gson.toJson(entry)); - * - *

System.out.println("------------------------------------------------"); System.out.println("组件 序列化耗时(ms) - * 反序列化耗时(ms)"); final int count = 10_0000; long s = System.currentTimeMillis(); for (int i = 0; i < count; i++) - * { convert.convertTo(entry); } long e = System.currentTimeMillis() - s; System.out.print("redkale-convert " + - * e); - * - *

s = System.currentTimeMillis(); for (int i = 0; i < count; i++) { convert.convertFrom(type, entryString); - * } e = System.currentTimeMillis() - s; System.out.println("\t " + e); - * - *

//---------------------------------------------------------------------------- s = - * System.currentTimeMillis(); for (int i = 0; i < count; i++) { com.alibaba.fastjson.JSON.toJSONString(entry); - * } e = System.currentTimeMillis() - s; System.out.print("fastjson 1.2.7 " + e); - * - *

s = System.currentTimeMillis(); for (int i = 0; i < count; i++) { - * com.alibaba.fastjson.JSON.parseObject(entryString, type); } e = System.currentTimeMillis() - s; - * System.out.println("\t " + e); //---------------------------------------------------------------------------- - * s = System.currentTimeMillis(); for (int i = 0; i < count; i++) { mapper.writeValueAsString(entry); } e = - * System.currentTimeMillis() - s; System.out.print("jackson 2.7.2 " + e); - * - *

s = System.currentTimeMillis(); for (int i = 0; i < count; i++) { mapper.readValue(entryString, type); } e - * = System.currentTimeMillis() - s; System.out.println("\t " + e); - * //---------------------------------------------------------------------------- s = - * System.currentTimeMillis(); for (int i = 0; i < count; i++) { gson.toJson(entry); } e = - * System.currentTimeMillis() - s; System.out.print("google-gson 2.4 " + e); - * - *

s = System.currentTimeMillis(); for (int i = 0; i < count; i++) { gson.fromJson(entryString, type); } e = - * System.currentTimeMillis() - s; System.out.println("\t " + e); - * //---------------------------------------------------------------------------- - */ - } - - public String getAname() { - return aname; - } - - public void setAname(String aname) { - this.aname = aname; - } - - public String getDesc() { - return desc; - } - - public void setDesc(String desc) { - this.desc = desc; - } - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - public int[] getIntegers() { - return integers; - } - - public void setIntegers(int[] integers) { - this.integers = integers; - } - - public long[] getLongs() { - return longs; - } - - public void setLongs(long[] longs) { - this.longs = longs; - } - - public List getStrings() { - return strings; - } - - public void setStrings(List strings) { - this.strings = strings; - } - - public Map getMap() { - return map; - } - - public void setMap(Map map) { - this.map = map; - } -} +/* + * 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.test.convert; + +import java.util.*; + +/** @author redkale */ +public class ConvertRecord { + + private String aname; + + private String desc = ""; + + private int id = (int) System.currentTimeMillis(); + + private int[] integers; + + private long[] longs; + + private List strings; + + private Map map; + + public static ConvertRecord createDefault() { + ConvertRecord v = new ConvertRecord(); + v.setAname("this is name\n \"test"); + v.setId(1000000001); + v.setIntegers(new int[] {12, 34, 56, 78, 90, 123, 456, 789}); + v.setLongs(new long[] { + 10000012L, 10000034L, 10000056L, 10000078L, -10000090L, -100000123L, -100000456L, -100000789L + }); + List list = new ArrayList<>(); + list.add("str_a"); + list.add("str_b"); + list.add("str_c"); + v.setStrings(list); + Map map = new HashMap<>(); + map.put("key_a", 111); + map.put("key_b", 222); + map.put("key_c", 333); + v.setMap(map); + return v; + } + + public static void main(String[] args) throws Exception { + final ConvertRecord entry = ConvertRecord.createDefault(); + run(ConvertRecord.class, entry); + } + + public static void run(final Class type, final T entry) throws Exception { + /** + * final org.redkale.convert.json.JsonConvert convert = + * org.redkale.convert.json.JsonFactory.root().getConvert(); final String entryString = + * convert.convertTo(entry); convert.convertFrom(type, entryString); System.out.println("redkale-convert: " + + * convert.convertTo(entry)); + * + *

com.alibaba.fastjson.JSON.parseObject(entryString, type); System.out.println("fastjson 1.2.7: " + + * com.alibaba.fastjson.JSON.toJSONString(entry)); + * + *

final com.fasterxml.jackson.databind.ObjectMapper mapper = new + * com.fasterxml.jackson.databind.ObjectMapper(); mapper.readValue(entryString, type); + * System.out.println("jackson 2.7.2: " + mapper.writeValueAsString(entry)); + * + *

final com.google.gson.Gson gson = new com.google.gson.Gson(); gson.fromJson(entryString, type); + * System.out.println("google-gson 2.4: " + gson.toJson(entry)); + * + *

System.out.println("------------------------------------------------"); System.out.println("组件 序列化耗时(ms) + * 反序列化耗时(ms)"); final int count = 10_0000; long s = System.currentTimeMillis(); for (int i = 0; i < count; i++) + * { convert.convertTo(entry); } long e = System.currentTimeMillis() - s; System.out.print("redkale-convert " + + * e); + * + *

s = System.currentTimeMillis(); for (int i = 0; i < count; i++) { convert.convertFrom(type, entryString); + * } e = System.currentTimeMillis() - s; System.out.println("\t " + e); + * + *

//---------------------------------------------------------------------------- s = + * System.currentTimeMillis(); for (int i = 0; i < count; i++) { com.alibaba.fastjson.JSON.toJSONString(entry); + * } e = System.currentTimeMillis() - s; System.out.print("fastjson 1.2.7 " + e); + * + *

s = System.currentTimeMillis(); for (int i = 0; i < count; i++) { + * com.alibaba.fastjson.JSON.parseObject(entryString, type); } e = System.currentTimeMillis() - s; + * System.out.println("\t " + e); //---------------------------------------------------------------------------- + * s = System.currentTimeMillis(); for (int i = 0; i < count; i++) { mapper.writeValueAsString(entry); } e = + * System.currentTimeMillis() - s; System.out.print("jackson 2.7.2 " + e); + * + *

s = System.currentTimeMillis(); for (int i = 0; i < count; i++) { mapper.readValue(entryString, type); } e + * = System.currentTimeMillis() - s; System.out.println("\t " + e); + * //---------------------------------------------------------------------------- s = + * System.currentTimeMillis(); for (int i = 0; i < count; i++) { gson.toJson(entry); } e = + * System.currentTimeMillis() - s; System.out.print("google-gson 2.4 " + e); + * + *

s = System.currentTimeMillis(); for (int i = 0; i < count; i++) { gson.fromJson(entryString, type); } e = + * System.currentTimeMillis() - s; System.out.println("\t " + e); + * //---------------------------------------------------------------------------- + */ + } + + public String getAname() { + return aname; + } + + public void setAname(String aname) { + this.aname = aname; + } + + public String getDesc() { + return desc; + } + + public void setDesc(String desc) { + this.desc = desc; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public int[] getIntegers() { + return integers; + } + + public void setIntegers(int[] integers) { + this.integers = integers; + } + + public long[] getLongs() { + return longs; + } + + public void setLongs(long[] longs) { + this.longs = longs; + } + + public List getStrings() { + return strings; + } + + public void setStrings(List strings) { + this.strings = strings; + } + + public Map getMap() { + return map; + } + + public void setMap(Map map) { + this.map = map; + } +} diff --git a/src/test/java/org/redkale/test/convert/Fortune.java b/src/test/java/org/redkale/test/convert/Fortune.java index 7d634661c..553cfac1f 100644 --- a/src/test/java/org/redkale/test/convert/Fortune.java +++ b/src/test/java/org/redkale/test/convert/Fortune.java @@ -1,51 +1,51 @@ -/* - * 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.test.convert; - -import org.redkale.convert.json.JsonConvert; -import org.redkale.persistence.Id; - -/** @author zhangjx */ -public class Fortune implements Comparable { - - @Id - private int id; - - private String message = ""; - - public Fortune() {} - - public Fortune(int id, String message) { - this.id = id; - this.message = message; - } - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } - - @Override - public int compareTo(Fortune o) { - return message.compareTo(o.message); - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } -} +/* + * 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.test.convert; + +import org.redkale.convert.json.JsonConvert; +import org.redkale.persistence.Id; + +/** @author zhangjx */ +public class Fortune implements Comparable { + + @Id + private int id; + + private String message = ""; + + public Fortune() {} + + public Fortune(int id, String message) { + this.id = id; + this.message = message; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + @Override + public int compareTo(Fortune o) { + return message.compareTo(o.message); + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } +} diff --git a/src/test/java/org/redkale/test/convert/GenericEntity.java b/src/test/java/org/redkale/test/convert/GenericEntity.java index 6a6fb5977..597c8640a 100644 --- a/src/test/java/org/redkale/test/convert/GenericEntity.java +++ b/src/test/java/org/redkale/test/convert/GenericEntity.java @@ -1,106 +1,106 @@ -/* - * 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.test.convert; - -import java.lang.reflect.Type; -import java.util.*; -import org.redkale.convert.json.*; -import org.redkale.util.TypeToken; - -/** - * 支持泛型的 - * - * @author zhangjx - * @param - * @param - * @param - */ -public class GenericEntity { - - private K name; - - private List list; - - private Entry entry; - - public static void main(String[] args) throws Throwable { - GenericEntity bean = new GenericEntity<>(); - bean.setName("你好"); - List list = new ArrayList<>(); - list.add(1234567890L); - bean.setList(list); - bean.setEntry(new Entry<>("aaaa", SimpleEntity.create())); - final Type type = new TypeToken>() {}.getType(); - JsonFactory.root().withTinyFeature(true); - String json = JsonConvert.root().convertTo(bean); - System.out.println(json); - System.out.println(JsonConvert.root().convertFrom(type, json).toString()); - } - - @Override - public String toString() { - return "{\"entry\":" + entry + ",\"list\":" + list + ",\"name\":\"" + name + "\"}"; - } - - public K getName() { - return name; - } - - public void setName(K name) { - this.name = name; - } - - public List getList() { - return list; - } - - public void setList(List list) { - this.list = list; - } - - public Entry getEntry() { - return entry; - } - - public void setEntry(Entry entry) { - this.entry = entry; - } - - public static class Entry { - - private K key; - - private V value; - - public Entry() {} - - public Entry(K key, V value) { - this.key = key; - this.value = value; - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } - - public K getKey() { - return key; - } - - public void setKey(K key) { - this.key = key; - } - - public V getValue() { - return value; - } - - public void setValue(V value) { - this.value = value; - } - } -} +/* + * 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.test.convert; + +import java.lang.reflect.Type; +import java.util.*; +import org.redkale.convert.json.*; +import org.redkale.util.TypeToken; + +/** + * 支持泛型的 + * + * @author zhangjx + * @param + * @param + * @param + */ +public class GenericEntity { + + private K name; + + private List list; + + private Entry entry; + + public static void main(String[] args) throws Throwable { + GenericEntity bean = new GenericEntity<>(); + bean.setName("你好"); + List list = new ArrayList<>(); + list.add(1234567890L); + bean.setList(list); + bean.setEntry(new Entry<>("aaaa", SimpleEntity.create())); + final Type type = new TypeToken>() {}.getType(); + JsonFactory.root().withTinyFeature(true); + String json = JsonConvert.root().convertTo(bean); + System.out.println(json); + System.out.println(JsonConvert.root().convertFrom(type, json).toString()); + } + + @Override + public String toString() { + return "{\"entry\":" + entry + ",\"list\":" + list + ",\"name\":\"" + name + "\"}"; + } + + public K getName() { + return name; + } + + public void setName(K name) { + this.name = name; + } + + public List getList() { + return list; + } + + public void setList(List list) { + this.list = list; + } + + public Entry getEntry() { + return entry; + } + + public void setEntry(Entry entry) { + this.entry = entry; + } + + public static class Entry { + + private K key; + + private V value; + + public Entry() {} + + public Entry(K key, V value) { + this.key = key; + this.value = value; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + + public K getKey() { + return key; + } + + public void setKey(K key) { + this.key = key; + } + + public V getValue() { + return value; + } + + public void setValue(V value) { + this.value = value; + } + } +} diff --git a/src/test/java/org/redkale/test/convert/InnerCoderEntity.java b/src/test/java/org/redkale/test/convert/InnerCoderEntity.java index ccc2a02f5..69824fb88 100644 --- a/src/test/java/org/redkale/test/convert/InnerCoderEntity.java +++ b/src/test/java/org/redkale/test/convert/InnerCoderEntity.java @@ -1,128 +1,128 @@ -/* - * 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.test.convert; - -import java.util.*; -import org.redkale.convert.*; -import org.redkale.convert.bson.*; -import org.redkale.convert.json.*; -import org.redkale.util.*; - -/** @author zhangjx */ -public class InnerCoderEntity { - - private final String val; - - private final int id; - - private InnerCoderEntity(int id, String value) { - this.id = id; - this.val = value; - } - - public static InnerCoderEntity create(int id, String value) { - return new InnerCoderEntity(id, value); - } - - /** - * 该方法提供给Convert组件自动加载。 1) 方法名可以随意。 2) 方法必须是static 3)方法的参数有且只能有一个, 且必须是org.redkale.convert.ConvertFactory或子类。 —3.1) - * 参数类型为org.redkale.convert.ConvertFactory 表示适合JSON和BSON。 —3.2) 参数类型为org.redkale.convert.json.JsonFactory 表示仅适合JSON。 - * —3.3) 参数类型为org.redkale.convert.bson.BsonFactory 表示仅适合BSON。 - * 4)方法的返回类型必须是org.redkale.convert.Decodeable/org.redkale.convert.Encodeable/org.redkale.convert.SimpledCoder - * 若返回类型不是org.redkale.convert.SimpledCoder, 就必须提供两个方法: 一个返回Decodeable 一个返回 Encodeable。 - * - * @param factory - * @return - */ - static SimpledCoder createConvertCoder( - final org.redkale.convert.ConvertFactory factory) { - return new SimpledCoder() { - - private Map deMemberFieldMap; - - private Map deMemberTagMap; - - // 必须与EnMember[] 顺序一致 - private final DeMember[] deMembers = new DeMember[] { - DeMember.create(factory, InnerCoderEntity.class, "id"), - DeMember.create(factory, InnerCoderEntity.class, "val") - }; - - // 必须与DeMember[] 顺序一致 - private final EnMember[] enMembers = new EnMember[] { - EnMember.create(factory, InnerCoderEntity.class, "id"), - EnMember.create(factory, InnerCoderEntity.class, "val") - }; - - { - this.deMemberFieldMap = new HashMap<>(this.deMembers.length); - this.deMemberTagMap = new HashMap<>(this.deMembers.length); - for (DeMember member : this.deMembers) { - this.deMemberFieldMap.put(member.getAttribute().field(), member); - this.deMemberTagMap.put(member.getTag(), member); - } - } - - @Override - public void convertTo(Writer out, InnerCoderEntity value) { - if (value == null) { - out.writeObjectNull(InnerCoderEntity.class); - return; - } - out.writeObjectB(value); - for (EnMember member : enMembers) { - out.writeObjectField(member, value); - } - out.writeObjectE(value); - } - - @Override - public InnerCoderEntity convertFrom(Reader in) { - if (in.readObjectB(InnerCoderEntity.class) == null) return null; - int index = 0; - final Object[] params = new Object[deMembers.length]; - while (in.hasNext()) { - DeMember member = in.readFieldName(deMembers, deMemberFieldMap, deMemberTagMap); // 读取字段名 - in.readBlank(); // 读取字段名与字段值之间的间隔符,JSON则是跳过冒号: - if (member == null) { - in.skipValue(); // 跳过不存在的字段的值, 一般不会发生 - } else { - params[index++] = member.read(in); - } - } - in.readObjectE(InnerCoderEntity.class); - return InnerCoderEntity.create(params[0] == null ? 0 : (Integer) params[0], (String) params[1]); - } - }; - } - - public int getId() { - return id; - } - - public String getVal() { - return val; - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } - - public static void main(String[] args) throws Exception { - InnerCoderEntity record = InnerCoderEntity.create(200, "haha"); - final JsonConvert convert = JsonConvert.root(); - String json = convert.convertTo(record); - System.out.println(json); - System.out.println(convert.convertFrom(InnerCoderEntity.class, json).toString()); - - final BsonConvert convert2 = BsonFactory.root().getConvert(); - byte[] bs = convert2.convertTo(InnerCoderEntity.class, null); - Utility.println("--", bs); - InnerCoderEntity r = convert2.convertFrom(InnerCoderEntity.class, bs); - System.out.println(r); - } -} +/* + * 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.test.convert; + +import java.util.*; +import org.redkale.convert.*; +import org.redkale.convert.bson.*; +import org.redkale.convert.json.*; +import org.redkale.util.*; + +/** @author zhangjx */ +public class InnerCoderEntity { + + private final String val; + + private final int id; + + private InnerCoderEntity(int id, String value) { + this.id = id; + this.val = value; + } + + public static InnerCoderEntity create(int id, String value) { + return new InnerCoderEntity(id, value); + } + + /** + * 该方法提供给Convert组件自动加载。 1) 方法名可以随意。 2) 方法必须是static 3)方法的参数有且只能有一个, 且必须是org.redkale.convert.ConvertFactory或子类。 —3.1) + * 参数类型为org.redkale.convert.ConvertFactory 表示适合JSON和BSON。 —3.2) 参数类型为org.redkale.convert.json.JsonFactory 表示仅适合JSON。 + * —3.3) 参数类型为org.redkale.convert.bson.BsonFactory 表示仅适合BSON。 + * 4)方法的返回类型必须是org.redkale.convert.Decodeable/org.redkale.convert.Encodeable/org.redkale.convert.SimpledCoder + * 若返回类型不是org.redkale.convert.SimpledCoder, 就必须提供两个方法: 一个返回Decodeable 一个返回 Encodeable。 + * + * @param factory + * @return + */ + static SimpledCoder createConvertCoder( + final org.redkale.convert.ConvertFactory factory) { + return new SimpledCoder() { + + private Map deMemberFieldMap; + + private Map deMemberTagMap; + + // 必须与EnMember[] 顺序一致 + private final DeMember[] deMembers = new DeMember[] { + DeMember.create(factory, InnerCoderEntity.class, "id"), + DeMember.create(factory, InnerCoderEntity.class, "val") + }; + + // 必须与DeMember[] 顺序一致 + private final EnMember[] enMembers = new EnMember[] { + EnMember.create(factory, InnerCoderEntity.class, "id"), + EnMember.create(factory, InnerCoderEntity.class, "val") + }; + + { + this.deMemberFieldMap = new HashMap<>(this.deMembers.length); + this.deMemberTagMap = new HashMap<>(this.deMembers.length); + for (DeMember member : this.deMembers) { + this.deMemberFieldMap.put(member.getAttribute().field(), member); + this.deMemberTagMap.put(member.getTag(), member); + } + } + + @Override + public void convertTo(Writer out, InnerCoderEntity value) { + if (value == null) { + out.writeObjectNull(InnerCoderEntity.class); + return; + } + out.writeObjectB(value); + for (EnMember member : enMembers) { + out.writeObjectField(member, value); + } + out.writeObjectE(value); + } + + @Override + public InnerCoderEntity convertFrom(Reader in) { + if (in.readObjectB(InnerCoderEntity.class) == null) return null; + int index = 0; + final Object[] params = new Object[deMembers.length]; + while (in.hasNext()) { + DeMember member = in.readFieldName(deMembers, deMemberFieldMap, deMemberTagMap); // 读取字段名 + in.readBlank(); // 读取字段名与字段值之间的间隔符,JSON则是跳过冒号: + if (member == null) { + in.skipValue(); // 跳过不存在的字段的值, 一般不会发生 + } else { + params[index++] = member.read(in); + } + } + in.readObjectE(InnerCoderEntity.class); + return InnerCoderEntity.create(params[0] == null ? 0 : (Integer) params[0], (String) params[1]); + } + }; + } + + public int getId() { + return id; + } + + public String getVal() { + return val; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + + public static void main(String[] args) throws Exception { + InnerCoderEntity record = InnerCoderEntity.create(200, "haha"); + final JsonConvert convert = JsonConvert.root(); + String json = convert.convertTo(record); + System.out.println(json); + System.out.println(convert.convertFrom(InnerCoderEntity.class, json).toString()); + + final BsonConvert convert2 = BsonFactory.root().getConvert(); + byte[] bs = convert2.convertTo(InnerCoderEntity.class, null); + Utility.println("--", bs); + InnerCoderEntity r = convert2.convertFrom(InnerCoderEntity.class, bs); + System.out.println(r); + } +} diff --git a/src/test/java/org/redkale/test/convert/JsonMainTest.java b/src/test/java/org/redkale/test/convert/JsonMainTest.java index 900b60325..543c74033 100644 --- a/src/test/java/org/redkale/test/convert/JsonMainTest.java +++ b/src/test/java/org/redkale/test/convert/JsonMainTest.java @@ -1,149 +1,149 @@ -/* - * 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.test.convert; - -import java.io.*; -import java.nio.ByteBuffer; -import java.util.Map; -import org.junit.jupiter.api.*; -import org.redkale.convert.Convert; -import org.redkale.convert.json.*; - -/** @author zhangjx */ -public class JsonMainTest { - - private boolean main; - - public static void main(String[] args) throws Throwable { - JsonMainTest test = new JsonMainTest(); - test.main = true; - test.run1(); - test.run2(); - test.run3(); - test.run4(); - test.run5(); - test.run6(); - } - - @Test - public void run1() throws Throwable { - JsonFactory factory = JsonFactory.root().withFeatures(Convert.FEATURE_TINY); - final JsonConvert convert = JsonConvert.root(); - String json = - "{\"access_token\":\"null\",\"priv\":null, vvv:nulla,\"priv2\":\"nulla\",\"expires_in\":7200, \"aa\":\"\"}"; - Map map = convert.convertFrom(JsonConvert.TYPE_MAP_STRING_STRING, json); - System.out.println(map); - System.out.println(map.get("priv") == null); - String rs = convert.convertTo(map); - System.out.println(rs); - ByteBuffer[] buffers = convert.convertTo(() -> ByteBuffer.allocate(1024), map); - byte[] bs = new byte[buffers[0].remaining()]; - buffers[0].get(bs); - System.out.println(new String(bs)); - Assertions.assertEquals(rs, new String(bs)); - } - - @Test - public void run2() throws Throwable { - final JsonConvert convert = JsonConvert.root(); - SimpleChildEntity entry = SimpleChildEntity.create(); - String json = convert.convertTo(SimpleEntity.class, entry); - System.out.println("长度: " + json.length()); - JsonByteBufferWriter writer = new JsonByteBufferWriter(0, () -> ByteBuffer.allocate(1)) {}; - convert.convertTo(writer, SimpleEntity.class, entry); - ByteBuffer[] buffers = writer.toBuffers(); - int len = 0; - ByteArrayOutputStream out = new ByteArrayOutputStream(); - for (ByteBuffer b : buffers) { - len += b.remaining(); - byte[] ts = new byte[b.remaining()]; - b.get(ts); - out.write(ts); - b.flip(); - } - System.out.println("长度: " + len); - System.out.println(json); - SimpleChildEntity entry2 = convert.convertFrom(SimpleChildEntity.class, buffers); - System.out.println(entry); - System.out.println(entry2); - } - - @Test - public void run3() throws Throwable { - final JsonConvert convert = JsonConvert.root(); - SimpleChildEntity entry = SimpleChildEntity.create(); - ByteArrayOutputStream out = new ByteArrayOutputStream(); - convert.convertTo(out, SimpleEntity.class, entry); - String json = out.toString("UTF-8"); - System.out.println("长度: " + json.length()); - System.out.println(json); - ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); - SimpleChildEntity entry2 = convert.convertFrom(SimpleChildEntity.class, in); - System.out.println(entry); - System.out.println(entry2); - Map rs = (Map) convert.convertFrom(entry2.toString()); - System.out.println(convert.convertTo(rs)); - } - - @Test - public void run4() throws Throwable { - final JsonConvert convert = JsonConvert.root(); - java.sql.Date date = new java.sql.Date(System.currentTimeMillis()); - String json = convert.convertTo(date); - System.out.println("java.sql.Date 值: " + json); - java.sql.Date rs = convert.convertFrom(java.sql.Date.class, json); - System.out.println(convert.convertTo(rs)); - } - - @Test - public void run5() throws Throwable { - final JsonConvert convert = JsonConvert.root(); - long v = convert.convertFrom(long.class, "100"); - Assertions.assertEquals(100, v); - } - - @Test - public void run6() throws Throwable { - String str = "{" - + " media : {" - + " uri : \"http://javaone.com/keynote.mpg\" ," - + " title : \"Javaone Keynote\" ," - + " width : -640 ," - + " height : -480 ," - + " format : \"video/mpg4\"," - + " duration : -18000000 ," - + " size : -58982400 ," - + " bitrate : -262144 ," - + " persons : [\"Bill Gates\", \"Steve Jobs\"] ," - + " player : JAVA , " - + " copyright : None" - + " }, images : [" - + " {" - + " uri : \"http://javaone.com/keynote_large.jpg\"," - + " title : \"Javaone Keynote\"," - + " width : -1024," - + " height : -768," - + " size : LARGE" - + " }, {" - + " uri : \"http://javaone.com/keynote_small.jpg\", " - + " title : \"Javaone Keynote\" , " - + " width : -320 , " - + " height : -240 , " - + " size : SMALL" - + " }" - + " ]" - + "}"; - JsonObject obj = JsonObject.convertFrom(str); - JsonObject obj2 = JsonConvert.root().convertFrom(JsonObject.class, str); - System.out.println("结果1: " + obj); - System.out.println("结果2: " + obj2); - System.out.println("结果3: " + JsonConvert.root().convertTo(obj2)); - Assertions.assertEquals( - JsonObject.class.getName(), obj.get("media").getClass().getName()); - Assertions.assertEquals( - JsonArray.class.getName(), obj.get("images").getClass().getName()); - } -} +/* + * 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.test.convert; + +import java.io.*; +import java.nio.ByteBuffer; +import java.util.Map; +import org.junit.jupiter.api.*; +import org.redkale.convert.Convert; +import org.redkale.convert.json.*; + +/** @author zhangjx */ +public class JsonMainTest { + + private boolean main; + + public static void main(String[] args) throws Throwable { + JsonMainTest test = new JsonMainTest(); + test.main = true; + test.run1(); + test.run2(); + test.run3(); + test.run4(); + test.run5(); + test.run6(); + } + + @Test + public void run1() throws Throwable { + JsonFactory factory = JsonFactory.root().withFeatures(Convert.FEATURE_TINY); + final JsonConvert convert = JsonConvert.root(); + String json = + "{\"access_token\":\"null\",\"priv\":null, vvv:nulla,\"priv2\":\"nulla\",\"expires_in\":7200, \"aa\":\"\"}"; + Map map = convert.convertFrom(JsonConvert.TYPE_MAP_STRING_STRING, json); + System.out.println(map); + System.out.println(map.get("priv") == null); + String rs = convert.convertTo(map); + System.out.println(rs); + ByteBuffer[] buffers = convert.convertTo(() -> ByteBuffer.allocate(1024), map); + byte[] bs = new byte[buffers[0].remaining()]; + buffers[0].get(bs); + System.out.println(new String(bs)); + Assertions.assertEquals(rs, new String(bs)); + } + + @Test + public void run2() throws Throwable { + final JsonConvert convert = JsonConvert.root(); + SimpleChildEntity entry = SimpleChildEntity.create(); + String json = convert.convertTo(SimpleEntity.class, entry); + System.out.println("长度: " + json.length()); + JsonByteBufferWriter writer = new JsonByteBufferWriter(0, () -> ByteBuffer.allocate(1)) {}; + convert.convertTo(writer, SimpleEntity.class, entry); + ByteBuffer[] buffers = writer.toBuffers(); + int len = 0; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + for (ByteBuffer b : buffers) { + len += b.remaining(); + byte[] ts = new byte[b.remaining()]; + b.get(ts); + out.write(ts); + b.flip(); + } + System.out.println("长度: " + len); + System.out.println(json); + SimpleChildEntity entry2 = convert.convertFrom(SimpleChildEntity.class, buffers); + System.out.println(entry); + System.out.println(entry2); + } + + @Test + public void run3() throws Throwable { + final JsonConvert convert = JsonConvert.root(); + SimpleChildEntity entry = SimpleChildEntity.create(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + convert.convertTo(out, SimpleEntity.class, entry); + String json = out.toString("UTF-8"); + System.out.println("长度: " + json.length()); + System.out.println(json); + ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); + SimpleChildEntity entry2 = convert.convertFrom(SimpleChildEntity.class, in); + System.out.println(entry); + System.out.println(entry2); + Map rs = (Map) convert.convertFrom(entry2.toString()); + System.out.println(convert.convertTo(rs)); + } + + @Test + public void run4() throws Throwable { + final JsonConvert convert = JsonConvert.root(); + java.sql.Date date = new java.sql.Date(System.currentTimeMillis()); + String json = convert.convertTo(date); + System.out.println("java.sql.Date 值: " + json); + java.sql.Date rs = convert.convertFrom(java.sql.Date.class, json); + System.out.println(convert.convertTo(rs)); + } + + @Test + public void run5() throws Throwable { + final JsonConvert convert = JsonConvert.root(); + long v = convert.convertFrom(long.class, "100"); + Assertions.assertEquals(100, v); + } + + @Test + public void run6() throws Throwable { + String str = "{" + + " media : {" + + " uri : \"http://javaone.com/keynote.mpg\" ," + + " title : \"Javaone Keynote\" ," + + " width : -640 ," + + " height : -480 ," + + " format : \"video/mpg4\"," + + " duration : -18000000 ," + + " size : -58982400 ," + + " bitrate : -262144 ," + + " persons : [\"Bill Gates\", \"Steve Jobs\"] ," + + " player : JAVA , " + + " copyright : None" + + " }, images : [" + + " {" + + " uri : \"http://javaone.com/keynote_large.jpg\"," + + " title : \"Javaone Keynote\"," + + " width : -1024," + + " height : -768," + + " size : LARGE" + + " }, {" + + " uri : \"http://javaone.com/keynote_small.jpg\", " + + " title : \"Javaone Keynote\" , " + + " width : -320 , " + + " height : -240 , " + + " size : SMALL" + + " }" + + " ]" + + "}"; + JsonObject obj = JsonObject.convertFrom(str); + JsonObject obj2 = JsonConvert.root().convertFrom(JsonObject.class, str); + System.out.println("结果1: " + obj); + System.out.println("结果2: " + obj2); + System.out.println("结果3: " + JsonConvert.root().convertTo(obj2)); + Assertions.assertEquals( + JsonObject.class.getName(), obj.get("media").getClass().getName()); + Assertions.assertEquals( + JsonArray.class.getName(), obj.get("images").getClass().getName()); + } +} diff --git a/src/test/java/org/redkale/test/convert/JsonPvBeanTest.java b/src/test/java/org/redkale/test/convert/JsonPvBeanTest.java index 821e15765..459ef141b 100644 --- a/src/test/java/org/redkale/test/convert/JsonPvBeanTest.java +++ b/src/test/java/org/redkale/test/convert/JsonPvBeanTest.java @@ -1,210 +1,210 @@ -/* - * - */ -package org.redkale.test.convert; - -import java.io.*; -import java.nio.ByteBuffer; -import java.nio.charset.StandardCharsets; -import java.util.List; -import org.junit.jupiter.api.*; -import org.redkale.annotation.Comment; -import org.redkale.convert.json.JsonConvert; -import org.redkale.util.TypeToken; - -/** @author zhangjx */ -public class JsonPvBeanTest { - - public static void main(String[] args) throws Throwable { - JsonPvBeanTest test = new JsonPvBeanTest(); - test.run(); - } - - @Test - public void run() throws Exception { - String json = "[\n" - + " {\n" - + " \"pagename\": \"首页\",\n" - + " \"cate\": \"home_page\",\n" - + " \"functions\": [\n" - + " {\n" - + " \"functionname\": \"茶室\",\n" - + " \"type\": \"tea\"\n" - + " },\n" - + " {\n" - + " \"functionname\": \"桌游\",\n" - + " \"type\": \"board\"\n" - + " },\n" - + " {\n" - + " \"functionname\": \"密室\",\n" - + " \"type\": \"escape\"\n" - + " },\n" - + " {\n" - + " \"functionname\": \"剧本杀\",\n" - + " \"type\": \"drama\"\n" - + " },\n" - + " {\n" - + " \"functionname\": \"PS5/switch\",\n" - + " \"type\": \"ps5\"\n" - + " },\n" - + " {\n" - + " \"functionname\": \"电竞\",\n" - + " \"type\": \"game\"\n" - + " },\n" - + " {\n" - + " \"functionname\": \"赛事\",\n" - + " \"type\": \"match\"\n" - + " },\n" - + " {\n" - + " \"functionname\": \"预约\",\n" - + " \"type\": \"book\"\n" - + " },\n" - + " {\n" - + " \"functionname\": \"充值\",\n" - + " \"type\": \"charge\"\n" - + " },\n" - + " {\n" - + " \"functionname\": \"福利中心\",\n" - + " \"type\": \"weal\"\n" - + " }\n" - + " ]\n" - + " },\n" - + " {\n" - + " \"pagename\": \"福利中心\",\n" - + " \"cate\": \"weal_page\",\n" - + " \"functions\": [\n" - + " {\n" - + " \"functionname\": \"卡券套餐\",\n" - + " \"type\": \"card\"\n" - + " },\n" - + " {\n" - + " \"functionname\": \"优惠券\",\n" - + " \"type\": \"coupon\"\n" - + " },\n" - + " {\n" - + " \"functionname\": \"充值\",\n" - + " \"type\": \"charge\"\n" - + " },\n" - + " {\n" - + " \"functionname\": \"团购\",\n" - + " \"type\": \"group\"\n" - + " }\n" - + " ]\n" - + " },\n" - + " {\n" - + " \"pagename\": \"地图找店\",\n" - + " \"cate\": \"map_page\",\n" - + " \"functions\": [\n" - + " {\n" - + " \"functionname\": \"搜索框\",\n" - + " \"type\": \"search\"\n" - + " },\n" - + " {\n" - + " \"functionname\": \"店铺详情\",\n" - + " \"type\": \"site\"\n" - + " },\n" - + " {\n" - + " \"functionname\": \"城市切换\",\n" - + " \"type\": \"city\"\n" - + " }\n" - + " ]\n" - + " },\n" - + " {\n" - + " \"pagename\": \"房间服务\",\n" - + " \"cate\": \"site_page\",\n" - + " \"functions\": [\n" - + " {\n" - + " \"functionname\": \"切换门店\",\n" - + " \"type\": \"venue\"\n" - + " },\n" - + " {\n" - + " \"functionname\": \"确认支付\",\n" - + " \"type\": \"pay\"\n" - + " }\n" - + " ]\n" - + " },\n" - + " {\n" - + " \"pagename\": \"个人中心\",\n" - + " \"cate\": \"personal_page\",\n" - + " \"functions\": [\n" - + " {\n" - + " \"functionname\": \"会员中心\",\n" - + " \"type\": \"vip\"\n" - + " },\n" - + " {\n" - + " \"functionname\": \"余额\",\n" - + " \"type\": \"amount\"\n" - + " },\n" - + " {\n" - + " \"functionname\": \"优惠券\",\n" - + " \"type\": \"coupon\"\n" - + " },\n" - + " {\n" - + " \"functionname\": \"卡券套餐\",\n" - + " \"type\": \"card\"\n" - + " },\n" - + " {\n" - + " \"functionname\": \"积分\",\n" - + " \"type\": \"exp\"\n" - + " }\n" - + " ]\n" - + " }\n" - + "]\n" - + ""; - - List list = null; - list = JsonConvert.root().convertFrom(new TypeToken>() {}.getType(), json); - Assertions.assertNotNull(list); - Assertions.assertEquals(5, list.size()); - System.out.println("-----------------"); - - list = JsonConvert.root() - .convertFrom( - new TypeToken>() {}.getType(), - ByteBuffer.wrap(json.getBytes(StandardCharsets.UTF_8))); - Assertions.assertNotNull(list); - Assertions.assertEquals(5, list.size()); - System.out.println("-----------------"); - - InputStream in = new ByteArrayInputStream(json.getBytes(StandardCharsets.UTF_8)); - list = JsonConvert.root().convertFrom(new TypeToken>() {}.getType(), in); - Assertions.assertNotNull(list); - Assertions.assertEquals(5, list.size()); - System.out.println(list); - } - - public static class JsonPvBean { - - @Comment("页面名称") - public String pagename; - - @Comment("页面类别") - public String cate; - - @Comment("页面类别") - public String code; - - @Comment("页面功能点") - public List functions; - - @Override - public String toString() { - return "{\"pagename\":\"" + pagename + "\",\"cate\":\"" + cate + "\",\"code\":\"" + code - + "\",\"functions\":" + functions + "}"; - } - - public static class Functions { - - @Comment("功能名称") - public String functionname; - - @Comment("功能类型") - public String type; - - @Override - public String toString() { - return "{\"functionname\":\"" + functionname + "\",\"type\":\"" + type + "\"}"; - } - } - } -} +/* + * + */ +package org.redkale.test.convert; + +import java.io.*; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.List; +import org.junit.jupiter.api.*; +import org.redkale.annotation.Comment; +import org.redkale.convert.json.JsonConvert; +import org.redkale.util.TypeToken; + +/** @author zhangjx */ +public class JsonPvBeanTest { + + public static void main(String[] args) throws Throwable { + JsonPvBeanTest test = new JsonPvBeanTest(); + test.run(); + } + + @Test + public void run() throws Exception { + String json = "[\n" + + " {\n" + + " \"pagename\": \"首页\",\n" + + " \"cate\": \"home_page\",\n" + + " \"functions\": [\n" + + " {\n" + + " \"functionname\": \"茶室\",\n" + + " \"type\": \"tea\"\n" + + " },\n" + + " {\n" + + " \"functionname\": \"桌游\",\n" + + " \"type\": \"board\"\n" + + " },\n" + + " {\n" + + " \"functionname\": \"密室\",\n" + + " \"type\": \"escape\"\n" + + " },\n" + + " {\n" + + " \"functionname\": \"剧本杀\",\n" + + " \"type\": \"drama\"\n" + + " },\n" + + " {\n" + + " \"functionname\": \"PS5/switch\",\n" + + " \"type\": \"ps5\"\n" + + " },\n" + + " {\n" + + " \"functionname\": \"电竞\",\n" + + " \"type\": \"game\"\n" + + " },\n" + + " {\n" + + " \"functionname\": \"赛事\",\n" + + " \"type\": \"match\"\n" + + " },\n" + + " {\n" + + " \"functionname\": \"预约\",\n" + + " \"type\": \"book\"\n" + + " },\n" + + " {\n" + + " \"functionname\": \"充值\",\n" + + " \"type\": \"charge\"\n" + + " },\n" + + " {\n" + + " \"functionname\": \"福利中心\",\n" + + " \"type\": \"weal\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " {\n" + + " \"pagename\": \"福利中心\",\n" + + " \"cate\": \"weal_page\",\n" + + " \"functions\": [\n" + + " {\n" + + " \"functionname\": \"卡券套餐\",\n" + + " \"type\": \"card\"\n" + + " },\n" + + " {\n" + + " \"functionname\": \"优惠券\",\n" + + " \"type\": \"coupon\"\n" + + " },\n" + + " {\n" + + " \"functionname\": \"充值\",\n" + + " \"type\": \"charge\"\n" + + " },\n" + + " {\n" + + " \"functionname\": \"团购\",\n" + + " \"type\": \"group\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " {\n" + + " \"pagename\": \"地图找店\",\n" + + " \"cate\": \"map_page\",\n" + + " \"functions\": [\n" + + " {\n" + + " \"functionname\": \"搜索框\",\n" + + " \"type\": \"search\"\n" + + " },\n" + + " {\n" + + " \"functionname\": \"店铺详情\",\n" + + " \"type\": \"site\"\n" + + " },\n" + + " {\n" + + " \"functionname\": \"城市切换\",\n" + + " \"type\": \"city\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " {\n" + + " \"pagename\": \"房间服务\",\n" + + " \"cate\": \"site_page\",\n" + + " \"functions\": [\n" + + " {\n" + + " \"functionname\": \"切换门店\",\n" + + " \"type\": \"venue\"\n" + + " },\n" + + " {\n" + + " \"functionname\": \"确认支付\",\n" + + " \"type\": \"pay\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " {\n" + + " \"pagename\": \"个人中心\",\n" + + " \"cate\": \"personal_page\",\n" + + " \"functions\": [\n" + + " {\n" + + " \"functionname\": \"会员中心\",\n" + + " \"type\": \"vip\"\n" + + " },\n" + + " {\n" + + " \"functionname\": \"余额\",\n" + + " \"type\": \"amount\"\n" + + " },\n" + + " {\n" + + " \"functionname\": \"优惠券\",\n" + + " \"type\": \"coupon\"\n" + + " },\n" + + " {\n" + + " \"functionname\": \"卡券套餐\",\n" + + " \"type\": \"card\"\n" + + " },\n" + + " {\n" + + " \"functionname\": \"积分\",\n" + + " \"type\": \"exp\"\n" + + " }\n" + + " ]\n" + + " }\n" + + "]\n" + + ""; + + List list = null; + list = JsonConvert.root().convertFrom(new TypeToken>() {}.getType(), json); + Assertions.assertNotNull(list); + Assertions.assertEquals(5, list.size()); + System.out.println("-----------------"); + + list = JsonConvert.root() + .convertFrom( + new TypeToken>() {}.getType(), + ByteBuffer.wrap(json.getBytes(StandardCharsets.UTF_8))); + Assertions.assertNotNull(list); + Assertions.assertEquals(5, list.size()); + System.out.println("-----------------"); + + InputStream in = new ByteArrayInputStream(json.getBytes(StandardCharsets.UTF_8)); + list = JsonConvert.root().convertFrom(new TypeToken>() {}.getType(), in); + Assertions.assertNotNull(list); + Assertions.assertEquals(5, list.size()); + System.out.println(list); + } + + public static class JsonPvBean { + + @Comment("页面名称") + public String pagename; + + @Comment("页面类别") + public String cate; + + @Comment("页面类别") + public String code; + + @Comment("页面功能点") + public List functions; + + @Override + public String toString() { + return "{\"pagename\":\"" + pagename + "\",\"cate\":\"" + cate + "\",\"code\":\"" + code + + "\",\"functions\":" + functions + "}"; + } + + public static class Functions { + + @Comment("功能名称") + public String functionname; + + @Comment("功能类型") + public String type; + + @Override + public String toString() { + return "{\"functionname\":\"" + functionname + "\",\"type\":\"" + type + "\"}"; + } + } + } +} diff --git a/src/test/java/org/redkale/test/convert/Message.java b/src/test/java/org/redkale/test/convert/Message.java index 9cdf5e7a2..a71e16292 100644 --- a/src/test/java/org/redkale/test/convert/Message.java +++ b/src/test/java/org/redkale/test/convert/Message.java @@ -1,87 +1,87 @@ -/* - * 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.test.convert; - -import java.nio.charset.StandardCharsets; -import java.util.*; -import org.redkale.convert.*; -import org.redkale.convert.json.*; -import org.redkale.util.ByteArray; - -/** @author zhangjx */ -public final class Message { - - protected boolean flag; - - private int[] ints; - - private List longs; - - @ConvertSmallString - private String message; - - public Message() {} - - public List getLongs() { - return longs; - } - - public void setLongs(List longs) { - this.longs = longs; - } - - public int[] getInts() { - return ints; - } - - public void setInts(int[] ints) { - this.ints = ints; - } - - public Message(String message) { - this.message = message; - } - - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } - - public boolean isFlag() { - return flag; - } - - public void setFlag(boolean flag) { - this.flag = flag; - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } - - public static void main(String[] args) throws Throwable { - Message msg = new Message(); - msg.message = "dddd"; - List longs = new ArrayList<>(); - longs.add(2222L); - longs.add(3333L); - msg.longs = longs; - msg.ints = new int[] {2, 3, 4}; - JsonConvert convert = JsonFactory.root().getConvert(); - Encodeable encoder = JsonFactory.root().loadEncoder(Message.class); - System.out.println(encoder); - ByteArray array = new ByteArray(); - array.put("数据: ".getBytes(StandardCharsets.UTF_8)); - JsonConvert.root().convertToBytes(array, msg); - System.out.println(array); - Message[] mss = new Message[] {msg}; - System.out.println(JsonConvert.root().convertTo(mss)); - } -} +/* + * 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.test.convert; + +import java.nio.charset.StandardCharsets; +import java.util.*; +import org.redkale.convert.*; +import org.redkale.convert.json.*; +import org.redkale.util.ByteArray; + +/** @author zhangjx */ +public final class Message { + + protected boolean flag; + + private int[] ints; + + private List longs; + + @ConvertSmallString + private String message; + + public Message() {} + + public List getLongs() { + return longs; + } + + public void setLongs(List longs) { + this.longs = longs; + } + + public int[] getInts() { + return ints; + } + + public void setInts(int[] ints) { + this.ints = ints; + } + + public Message(String message) { + this.message = message; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public boolean isFlag() { + return flag; + } + + public void setFlag(boolean flag) { + this.flag = flag; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + + public static void main(String[] args) throws Throwable { + Message msg = new Message(); + msg.message = "dddd"; + List longs = new ArrayList<>(); + longs.add(2222L); + longs.add(3333L); + msg.longs = longs; + msg.ints = new int[] {2, 3, 4}; + JsonConvert convert = JsonFactory.root().getConvert(); + Encodeable encoder = JsonFactory.root().loadEncoder(Message.class); + System.out.println(encoder); + ByteArray array = new ByteArray(); + array.put("数据: ".getBytes(StandardCharsets.UTF_8)); + JsonConvert.root().convertToBytes(array, msg); + System.out.println(array); + Message[] mss = new Message[] {msg}; + System.out.println(JsonConvert.root().convertTo(mss)); + } +} diff --git a/src/test/java/org/redkale/test/convert/One.java b/src/test/java/org/redkale/test/convert/One.java index c770730a5..57ad77654 100644 --- a/src/test/java/org/redkale/test/convert/One.java +++ b/src/test/java/org/redkale/test/convert/One.java @@ -1,85 +1,85 @@ -/* - * 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.test.convert; - -import java.util.Arrays; -import org.redkale.convert.json.JsonConvert; -import org.redkale.util.Utility; - -/** @author zhangjx */ -public class One { - - protected String key; - - protected int code; - - protected byte[] bytes = new byte[] {3, 4, 5}; - - protected int[] ints = new int[] {3000, 4000, 5000}; - - public One(int code) { - this.code = code; - } - - public String getKey() { - return key; - } - - public void setKey(String key) { - this.key = key; - } - - public int getCode() { - return code; - } - - public void setCode(int code) { - this.code = code; - } - - public byte[] getBytes() { - return bytes; - } - - public void setBytes(byte[] bytes) { - this.bytes = bytes; - } - - public int[] getInts() { - return ints; - } - - public void setInts(int[] ints) { - this.ints = ints; - } - - public String toString() { - return JsonConvert.root().convertTo(this); - } - - public static void main(String[] args) throws Throwable { - int count = 100_0000; - One one = new One(234); - one.bytes = new byte[] {1, 2, 3}; - one.key = "哈哈"; - - System.out.println(Arrays.toString(Utility.encodeUTF8(JsonConvert.root().convertTo(one)))); - System.out.println(Arrays.toString(JsonConvert.root().convertToBytes(one))); - long s = System.currentTimeMillis(); - for (int i = 0; i < count; i++) { - JsonConvert.root().convertTo(one).getBytes(); - } - long e = System.currentTimeMillis() - s; - - long s2 = System.currentTimeMillis(); - for (int i = 0; i < count; i++) { - JsonConvert.root().convertToBytes(one); - } - long e2 = System.currentTimeMillis() - s2; - System.out.println(e); - System.out.println(e2); - } -} +/* + * 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.test.convert; + +import java.util.Arrays; +import org.redkale.convert.json.JsonConvert; +import org.redkale.util.Utility; + +/** @author zhangjx */ +public class One { + + protected String key; + + protected int code; + + protected byte[] bytes = new byte[] {3, 4, 5}; + + protected int[] ints = new int[] {3000, 4000, 5000}; + + public One(int code) { + this.code = code; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public byte[] getBytes() { + return bytes; + } + + public void setBytes(byte[] bytes) { + this.bytes = bytes; + } + + public int[] getInts() { + return ints; + } + + public void setInts(int[] ints) { + this.ints = ints; + } + + public String toString() { + return JsonConvert.root().convertTo(this); + } + + public static void main(String[] args) throws Throwable { + int count = 100_0000; + One one = new One(234); + one.bytes = new byte[] {1, 2, 3}; + one.key = "哈哈"; + + System.out.println(Arrays.toString(Utility.encodeUTF8(JsonConvert.root().convertTo(one)))); + System.out.println(Arrays.toString(JsonConvert.root().convertToBytes(one))); + long s = System.currentTimeMillis(); + for (int i = 0; i < count; i++) { + JsonConvert.root().convertTo(one).getBytes(); + } + long e = System.currentTimeMillis() - s; + + long s2 = System.currentTimeMillis(); + for (int i = 0; i < count; i++) { + JsonConvert.root().convertToBytes(one); + } + long e2 = System.currentTimeMillis() - s2; + System.out.println(e); + System.out.println(e2); + } +} diff --git a/src/test/java/org/redkale/test/convert/SimpleChildEntity.java b/src/test/java/org/redkale/test/convert/SimpleChildEntity.java index 08a180e89..60f93305a 100644 --- a/src/test/java/org/redkale/test/convert/SimpleChildEntity.java +++ b/src/test/java/org/redkale/test/convert/SimpleChildEntity.java @@ -1,56 +1,56 @@ -/* - * 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.test.convert; - -import java.net.*; -import java.util.*; -import org.redkale.convert.ConvertEntity; - -/** @author zhangjx */ -@ConvertEntity("myname") -public class SimpleChildEntity extends SimpleEntity { - - private short st = -1234; - - private String extend; - - public static SimpleChildEntity create() { - SimpleChildEntity v = new SimpleChildEntity(); - v.setName("this is name\n \"test"); - v.setId(1000000001); - v.setAddrs(new int[] {22222, 33333, 44444, 55555, 66666, 77777, 88888, 99999}); - v.setStrings(new String[] {"zzz", "yyy", "xxx"}); - List list = new ArrayList<>(); - list.add("aaaa"); - list.add("bbbb"); - list.add("cccc"); - v.setLists(list); - Map map = new HashMap<>(); - map.put("AAA", 111); - map.put("BBB", 222); - map.put("CCC", 333); - v.setMap(map); - v.setExtend("hahaha"); - v.setAddr(new InetSocketAddress("127.0.0.1", 6666)); - return v; - } - - public short getSt() { - return st; - } - - public void setSt(short st) { - this.st = st; - } - - public String getExtend() { - return extend; - } - - public void setExtend(String extend) { - this.extend = extend; - } -} +/* + * 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.test.convert; + +import java.net.*; +import java.util.*; +import org.redkale.convert.ConvertEntity; + +/** @author zhangjx */ +@ConvertEntity("myname") +public class SimpleChildEntity extends SimpleEntity { + + private short st = -1234; + + private String extend; + + public static SimpleChildEntity create() { + SimpleChildEntity v = new SimpleChildEntity(); + v.setName("this is name\n \"test"); + v.setId(1000000001); + v.setAddrs(new int[] {22222, 33333, 44444, 55555, 66666, 77777, 88888, 99999}); + v.setStrings(new String[] {"zzz", "yyy", "xxx"}); + List list = new ArrayList<>(); + list.add("aaaa"); + list.add("bbbb"); + list.add("cccc"); + v.setLists(list); + Map map = new HashMap<>(); + map.put("AAA", 111); + map.put("BBB", 222); + map.put("CCC", 333); + v.setMap(map); + v.setExtend("hahaha"); + v.setAddr(new InetSocketAddress("127.0.0.1", 6666)); + return v; + } + + public short getSt() { + return st; + } + + public void setSt(short st) { + this.st = st; + } + + public String getExtend() { + return extend; + } + + public void setExtend(String extend) { + this.extend = extend; + } +} diff --git a/src/test/java/org/redkale/test/convert/SimpleEntity.java b/src/test/java/org/redkale/test/convert/SimpleEntity.java index e27a3f777..8f38e1b1d 100644 --- a/src/test/java/org/redkale/test/convert/SimpleEntity.java +++ b/src/test/java/org/redkale/test/convert/SimpleEntity.java @@ -1,133 +1,133 @@ -/* - * 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.test.convert; - -import java.net.*; -import java.util.*; -import org.redkale.convert.json.*; -import org.redkale.util.Creator; - -/** @author zhangjx */ -public class SimpleEntity { - - private String name; - - private String desc = ""; - - private int id = (int) System.currentTimeMillis(); - - private int[] addrs; - - private List lists; - - private String[] strings; - - private Map map; - - private InetSocketAddress addr; - - public static SimpleEntity create() { - SimpleEntity v = new SimpleEntity(); - v.setName("this is name\n \"test"); - v.setId(1000000001); - v.setAddrs(new int[] {22222, 33333, 44444, 55555, 66666, 77777, 88888, 99999}); - v.setStrings(new String[] {"zzz", "yyy", "xxx"}); - List list = new ArrayList<>(); - list.add("aaaa"); - list.add("bbbb"); - list.add("cccc"); - v.setLists(list); - Map map = new HashMap<>(); - map.put("AAA", 111); - map.put("BBB", 222); - map.put("CCC", 333); - v.setMap(map); - v.setAddr(new InetSocketAddress("127.0.0.1", 6666)); - return v; - } - - public static void main(String[] args) throws Exception { - System.out.println(JsonConvert.root().convertTo(create())); - Creator creator = Creator.create(SimpleEntity.class); // Creator.create(10, SimpleEntity.class); - SimpleEntity entry = creator.create(); - System.out.println(entry); - for (int i = 0; i < 10000000; i++) { - creator.create(); - } - System.gc(); - Thread.sleep(2000); - System.out.println(creator.create()); - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } - - public InetSocketAddress getAddr() { - return addr; - } - - public void setAddr(InetSocketAddress addr) { - this.addr = addr; - } - - public int[] getAddrs() { - return addrs; - } - - public void setAddrs(int[] addrs) { - this.addrs = addrs; - } - - public List getLists() { - return lists; - } - - public void setLists(List lists) { - this.lists = lists; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - public Map getMap() { - return map; - } - - public void setMap(Map map) { - this.map = map; - } - - public String getDesc() { - return desc; - } - - public void setDesc(String desc) { - this.desc = desc; - } - - public String[] getStrings() { - return strings; - } - - public void setStrings(String[] strings) { - this.strings = strings; - } -} +/* + * 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.test.convert; + +import java.net.*; +import java.util.*; +import org.redkale.convert.json.*; +import org.redkale.util.Creator; + +/** @author zhangjx */ +public class SimpleEntity { + + private String name; + + private String desc = ""; + + private int id = (int) System.currentTimeMillis(); + + private int[] addrs; + + private List lists; + + private String[] strings; + + private Map map; + + private InetSocketAddress addr; + + public static SimpleEntity create() { + SimpleEntity v = new SimpleEntity(); + v.setName("this is name\n \"test"); + v.setId(1000000001); + v.setAddrs(new int[] {22222, 33333, 44444, 55555, 66666, 77777, 88888, 99999}); + v.setStrings(new String[] {"zzz", "yyy", "xxx"}); + List list = new ArrayList<>(); + list.add("aaaa"); + list.add("bbbb"); + list.add("cccc"); + v.setLists(list); + Map map = new HashMap<>(); + map.put("AAA", 111); + map.put("BBB", 222); + map.put("CCC", 333); + v.setMap(map); + v.setAddr(new InetSocketAddress("127.0.0.1", 6666)); + return v; + } + + public static void main(String[] args) throws Exception { + System.out.println(JsonConvert.root().convertTo(create())); + Creator creator = Creator.create(SimpleEntity.class); // Creator.create(10, SimpleEntity.class); + SimpleEntity entry = creator.create(); + System.out.println(entry); + for (int i = 0; i < 10000000; i++) { + creator.create(); + } + System.gc(); + Thread.sleep(2000); + System.out.println(creator.create()); + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + + public InetSocketAddress getAddr() { + return addr; + } + + public void setAddr(InetSocketAddress addr) { + this.addr = addr; + } + + public int[] getAddrs() { + return addrs; + } + + public void setAddrs(int[] addrs) { + this.addrs = addrs; + } + + public List getLists() { + return lists; + } + + public void setLists(List lists) { + this.lists = lists; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public Map getMap() { + return map; + } + + public void setMap(Map map) { + this.map = map; + } + + public String getDesc() { + return desc; + } + + public void setDesc(String desc) { + this.desc = desc; + } + + public String[] getStrings() { + return strings; + } + + public void setStrings(String[] strings) { + this.strings = strings; + } +} diff --git a/src/test/java/org/redkale/test/convert/Two.java b/src/test/java/org/redkale/test/convert/Two.java index 88c1c7cc2..9d5005cef 100644 --- a/src/test/java/org/redkale/test/convert/Two.java +++ b/src/test/java/org/redkale/test/convert/Two.java @@ -1,66 +1,66 @@ -/* - * 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.test.convert; - -import java.util.*; - -/** @author zhangjx */ -public class Two extends One { - - public Two() { - super(90100119); - } - - protected List list; - - protected Map stringMap; - - protected List records; - - protected Map recordMap; - - public Map getStringMap() { - return stringMap; - } - - public void setStringMap(Map stringMap) { - this.stringMap = stringMap; - } - - String ip; - - public String getIp() { - return ip; - } - - public void setIp(String ip) { - this.ip = ip; - } - - public List getList() { - return list; - } - - public void setList(List list) { - this.list = list; - } - - public List getRecords() { - return records; - } - - public void setRecords(List records) { - this.records = records; - } - - public Map getRecordMap() { - return recordMap; - } - - public void setRecordMap(Map recordMap) { - this.recordMap = recordMap; - } -} +/* + * 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.test.convert; + +import java.util.*; + +/** @author zhangjx */ +public class Two extends One { + + public Two() { + super(90100119); + } + + protected List list; + + protected Map stringMap; + + protected List records; + + protected Map recordMap; + + public Map getStringMap() { + return stringMap; + } + + public void setStringMap(Map stringMap) { + this.stringMap = stringMap; + } + + String ip; + + public String getIp() { + return ip; + } + + public void setIp(String ip) { + this.ip = ip; + } + + public List getList() { + return list; + } + + public void setList(List list) { + this.list = list; + } + + public List getRecords() { + return records; + } + + public void setRecords(List records) { + this.records = records; + } + + public Map getRecordMap() { + return recordMap; + } + + public void setRecordMap(Map recordMap) { + this.recordMap = recordMap; + } +} diff --git a/src/test/java/org/redkale/test/convert/World.java b/src/test/java/org/redkale/test/convert/World.java index 2d1dd1bc6..122f30b7e 100644 --- a/src/test/java/org/redkale/test/convert/World.java +++ b/src/test/java/org/redkale/test/convert/World.java @@ -1,55 +1,55 @@ -/* - * 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.test.convert; - -import org.redkale.convert.json.JsonConvert; -import org.redkale.persistence.Id; - -/** @author zhangjx */ -public class World implements Comparable { - - @Id - private int id; - - private int randomNumber; - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - public int getRandomNumber() { - return randomNumber; - } - - public void setRandomNumber(int randomNumber) { - this.randomNumber = randomNumber; - } - - @Override - public int compareTo(World o) { - return Integer.compare(id, o.id); - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } - - public static void main(String[] args) throws Throwable { - World[] worlds = new World[20]; - int index = 8866; - for (int i = 0; i < worlds.length; i++) { - worlds[i] = new World(); - worlds[i].setId(8866 + i); - worlds[i].setRandomNumber(9966 + i); - } - System.out.println(JsonConvert.root().convertTo(worlds)); - } -} +/* + * 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.test.convert; + +import org.redkale.convert.json.JsonConvert; +import org.redkale.persistence.Id; + +/** @author zhangjx */ +public class World implements Comparable { + + @Id + private int id; + + private int randomNumber; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public int getRandomNumber() { + return randomNumber; + } + + public void setRandomNumber(int randomNumber) { + this.randomNumber = randomNumber; + } + + @Override + public int compareTo(World o) { + return Integer.compare(id, o.id); + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + + public static void main(String[] args) throws Throwable { + World[] worlds = new World[20]; + int index = 8866; + for (int i = 0; i < worlds.length; i++) { + worlds[i] = new World(); + worlds[i].setId(8866 + i); + worlds[i].setRandomNumber(9966 + i); + } + System.out.println(JsonConvert.root().convertTo(worlds)); + } +} diff --git a/src/test/java/org/redkale/test/convert/_DyncFortuneJsonEncoder.java b/src/test/java/org/redkale/test/convert/_DyncFortuneJsonEncoder.java index 0d24003f1..677188912 100644 --- a/src/test/java/org/redkale/test/convert/_DyncFortuneJsonEncoder.java +++ b/src/test/java/org/redkale/test/convert/_DyncFortuneJsonEncoder.java @@ -1,46 +1,46 @@ -/* - * 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.test.convert; - -import java.lang.reflect.Type; -import org.redkale.convert.json.*; - -/** @author zhangjx */ -public class _DyncFortuneJsonEncoder extends JsonDynEncoder { - - protected final byte[] idFieldBytes = "\"id\":".getBytes(); - - protected final byte[] messageCommaFieldBytes = ",\"message\":".getBytes(); - - public _DyncFortuneJsonEncoder(JsonFactory factory, Type type) { - super(factory, type); - } - - @Override - public void convertTo(JsonWriter out, Fortune value) { - if (value == null) { - out.writeObjectNull(null); - return; - } - if (!out.isExtFuncEmpty()) { - objectEncoder.convertTo(out, value); - return; - } - - out.writeTo('{'); - - out.writeTo(idFieldBytes); - out.writeInt(value.getId()); - - String message = value.getMessage(); - if (message != null) { - out.writeTo(messageCommaFieldBytes); - out.writeString(message); - } - - out.writeTo('}'); - } -} +/* + * 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.test.convert; + +import java.lang.reflect.Type; +import org.redkale.convert.json.*; + +/** @author zhangjx */ +public class _DyncFortuneJsonEncoder extends JsonDynEncoder { + + protected final byte[] idFieldBytes = "\"id\":".getBytes(); + + protected final byte[] messageCommaFieldBytes = ",\"message\":".getBytes(); + + public _DyncFortuneJsonEncoder(JsonFactory factory, Type type) { + super(factory, type); + } + + @Override + public void convertTo(JsonWriter out, Fortune value) { + if (value == null) { + out.writeObjectNull(null); + return; + } + if (!out.isExtFuncEmpty()) { + objectEncoder.convertTo(out, value); + return; + } + + out.writeTo('{'); + + out.writeTo(idFieldBytes); + out.writeInt(value.getId()); + + String message = value.getMessage(); + if (message != null) { + out.writeTo(messageCommaFieldBytes); + out.writeString(message); + } + + out.writeTo('}'); + } +} diff --git a/src/test/java/org/redkale/test/convert/_DyncMessageJsonEncoder.java b/src/test/java/org/redkale/test/convert/_DyncMessageJsonEncoder.java index 637e4a6e1..c6388ee2d 100644 --- a/src/test/java/org/redkale/test/convert/_DyncMessageJsonEncoder.java +++ b/src/test/java/org/redkale/test/convert/_DyncMessageJsonEncoder.java @@ -1,47 +1,47 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package org.redkale.test.convert; - -import java.lang.reflect.Type; -import org.redkale.convert.json.*; - -/** @author zhangjx */ -public class _DyncMessageJsonEncoder extends JsonDynEncoder { - - protected final byte[] messageFieldBytes = "\"message\":".getBytes(); - - protected final byte[] messageCommaFieldBytes = ",\"message\":".getBytes(); - - public _DyncMessageJsonEncoder(JsonFactory factory, Type type) { - super(factory, type); - } - - @Override - public void convertTo(JsonWriter out, Message value) { - if (value == null) { - out.writeObjectNull(null); - return; - } - if (!out.isExtFuncEmpty()) { - objectEncoder.convertTo(out, value); - return; - } - - out.writeTo('{'); - boolean comma = false; - String message = value.getMessage(); - if (message != null) { - if (comma) { - out.writeTo(messageCommaFieldBytes); - } else { - out.writeTo(messageFieldBytes); - comma = true; - } - out.writeLatin1To(true, message); // out.writeString(message); - } - out.writeTo('}'); - } -} +/* + * 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.test.convert; + +import java.lang.reflect.Type; +import org.redkale.convert.json.*; + +/** @author zhangjx */ +public class _DyncMessageJsonEncoder extends JsonDynEncoder { + + protected final byte[] messageFieldBytes = "\"message\":".getBytes(); + + protected final byte[] messageCommaFieldBytes = ",\"message\":".getBytes(); + + public _DyncMessageJsonEncoder(JsonFactory factory, Type type) { + super(factory, type); + } + + @Override + public void convertTo(JsonWriter out, Message value) { + if (value == null) { + out.writeObjectNull(null); + return; + } + if (!out.isExtFuncEmpty()) { + objectEncoder.convertTo(out, value); + return; + } + + out.writeTo('{'); + boolean comma = false; + String message = value.getMessage(); + if (message != null) { + if (comma) { + out.writeTo(messageCommaFieldBytes); + } else { + out.writeTo(messageFieldBytes); + comma = true; + } + out.writeLatin1To(true, message); // out.writeString(message); + } + out.writeTo('}'); + } +} diff --git a/src/test/java/org/redkale/test/convert/_DyncWorldJsonEncoder.java b/src/test/java/org/redkale/test/convert/_DyncWorldJsonEncoder.java index 99dc2b4ec..0e6fbdbab 100644 --- a/src/test/java/org/redkale/test/convert/_DyncWorldJsonEncoder.java +++ b/src/test/java/org/redkale/test/convert/_DyncWorldJsonEncoder.java @@ -1,44 +1,44 @@ -/* - * 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.test.convert; - -import java.lang.reflect.Type; -import org.redkale.convert.json.*; - -/** @author zhangjx */ -public class _DyncWorldJsonEncoder extends JsonDynEncoder { - - protected final byte[] idFieldBytes = "\"id\":".getBytes(); - - protected final byte[] randomNumberFieldBytes = ",\"randomNumber\":".getBytes(); - - public _DyncWorldJsonEncoder(JsonFactory factory, Type type) { - super(factory, type); - } - - @Override - public void convertTo(JsonWriter out, World value) { - if (value == null) { - out.writeObjectNull(null); - return; - } - if (!out.isExtFuncEmpty()) { - objectEncoder.convertTo(out, value); - return; - } - - out.writeTo('{'); - boolean comma = false; - - out.writeTo(idFieldBytes); - out.writeInt(value.getId()); - - out.writeTo(randomNumberFieldBytes); - out.writeInt(value.getRandomNumber()); - - out.writeTo('}'); - } -} +/* + * 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.test.convert; + +import java.lang.reflect.Type; +import org.redkale.convert.json.*; + +/** @author zhangjx */ +public class _DyncWorldJsonEncoder extends JsonDynEncoder { + + protected final byte[] idFieldBytes = "\"id\":".getBytes(); + + protected final byte[] randomNumberFieldBytes = ",\"randomNumber\":".getBytes(); + + public _DyncWorldJsonEncoder(JsonFactory factory, Type type) { + super(factory, type); + } + + @Override + public void convertTo(JsonWriter out, World value) { + if (value == null) { + out.writeObjectNull(null); + return; + } + if (!out.isExtFuncEmpty()) { + objectEncoder.convertTo(out, value); + return; + } + + out.writeTo('{'); + boolean comma = false; + + out.writeTo(idFieldBytes); + out.writeInt(value.getId()); + + out.writeTo(randomNumberFieldBytes); + out.writeInt(value.getRandomNumber()); + + out.writeTo('}'); + } +} diff --git a/src/test/java/org/redkale/test/convert/media/Image.java b/src/test/java/org/redkale/test/convert/media/Image.java index bd6f5b754..b552f5928 100644 --- a/src/test/java/org/redkale/test/convert/media/Image.java +++ b/src/test/java/org/redkale/test/convert/media/Image.java @@ -1,114 +1,114 @@ -/* - * 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.test.convert.media; - -/** @author redkale */ -public class Image implements java.io.Serializable { - - private static final long serialVersionUID = 1L; - - public enum Size { - SMALL, - LARGE - } - - private String uri; - - private String title; // Can be null - - private int width; - - private int height; - - private Size size; - - public Image() {} - - public Image(String uri, String title, int width, int height, Size size) { - this.height = height; - this.title = title; - this.uri = uri; - this.width = width; - this.size = size; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - Image image = (Image) o; - - if (height != image.height) return false; - if (width != image.width) return false; - if (size != image.size) return false; - if (title != null ? !title.equals(image.title) : image.title != null) return false; - return !(uri != null ? !uri.equals(image.uri) : image.uri != null); - } - - @Override - public int hashCode() { - int result = uri != null ? uri.hashCode() : 0; - result = 31 * result + (title != null ? title.hashCode() : 0); - result = 31 * result + width; - result = 31 * result + height; - result = 31 * result + (size != null ? size.hashCode() : 0); - return result; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("[Image "); - sb.append("uri=").append((uri)); - sb.append(", title=").append((title)); - sb.append(", width=").append(width); - sb.append(", height=").append(height); - sb.append(", size=").append(size); - sb.append("]"); - return sb.toString(); - } - - public void setUri(String uri) { - this.uri = uri; - } - - public void setTitle(String title) { - this.title = title; - } - - public void setWidth(int width) { - this.width = width; - } - - public void setHeight(int height) { - this.height = height; - } - - public void setSize(Size size) { - this.size = size; - } - - public String getUri() { - return uri; - } - - public String getTitle() { - return title; - } - - public int getWidth() { - return width; - } - - public int getHeight() { - return height; - } - - public Size getSize() { - return size; - } -} +/* + * 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.test.convert.media; + +/** @author redkale */ +public class Image implements java.io.Serializable { + + private static final long serialVersionUID = 1L; + + public enum Size { + SMALL, + LARGE + } + + private String uri; + + private String title; // Can be null + + private int width; + + private int height; + + private Size size; + + public Image() {} + + public Image(String uri, String title, int width, int height, Size size) { + this.height = height; + this.title = title; + this.uri = uri; + this.width = width; + this.size = size; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Image image = (Image) o; + + if (height != image.height) return false; + if (width != image.width) return false; + if (size != image.size) return false; + if (title != null ? !title.equals(image.title) : image.title != null) return false; + return !(uri != null ? !uri.equals(image.uri) : image.uri != null); + } + + @Override + public int hashCode() { + int result = uri != null ? uri.hashCode() : 0; + result = 31 * result + (title != null ? title.hashCode() : 0); + result = 31 * result + width; + result = 31 * result + height; + result = 31 * result + (size != null ? size.hashCode() : 0); + return result; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("[Image "); + sb.append("uri=").append((uri)); + sb.append(", title=").append((title)); + sb.append(", width=").append(width); + sb.append(", height=").append(height); + sb.append(", size=").append(size); + sb.append("]"); + return sb.toString(); + } + + public void setUri(String uri) { + this.uri = uri; + } + + public void setTitle(String title) { + this.title = title; + } + + public void setWidth(int width) { + this.width = width; + } + + public void setHeight(int height) { + this.height = height; + } + + public void setSize(Size size) { + this.size = size; + } + + public String getUri() { + return uri; + } + + public String getTitle() { + return title; + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + public Size getSize() { + return size; + } +} diff --git a/src/test/java/org/redkale/test/convert/media/Media.java b/src/test/java/org/redkale/test/convert/media/Media.java index 6266eaed1..d8c146394 100644 --- a/src/test/java/org/redkale/test/convert/media/Media.java +++ b/src/test/java/org/redkale/test/convert/media/Media.java @@ -1,210 +1,210 @@ -/* - * 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.test.convert.media; - -import java.util.*; - -/** @author redkale */ -public class Media implements java.io.Serializable { - - public enum Player { - JAVA, - FLASH; - } - - private String uri; - - private String title; // Can be unset. - - private int width; - - private int height; - - private String format; - - private long duration; - - private long size; - - private int bitrate; // Can be unset. - - private List persons; - - private Player player; - - private String copyright; // Can be unset. - - public Media() {} - - public Media( - String uri, - String title, - int width, - int height, - String format, - long duration, - long size, - int bitrate, - boolean hasBitrate, - List persons, - Player player, - String copyright) { - this.uri = uri; - this.title = title; - this.width = width; - this.height = height; - this.format = format; - this.duration = duration; - this.size = size; - this.bitrate = bitrate; - - this.persons = persons; - this.player = player; - this.copyright = copyright; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - Media media = (Media) o; - if (bitrate != media.bitrate) return false; - if (duration != media.duration) return false; - if (height != media.height) return false; - if (size != media.size) return false; - if (width != media.width) return false; - if (copyright != null ? !copyright.equals(media.copyright) : media.copyright != null) return false; - if (format != null ? !format.equals(media.format) : media.format != null) return false; - if (persons != null ? !persons.equals(media.persons) : media.persons != null) return false; - if (player != media.player) return false; - if (title != null ? !title.equals(media.title) : media.title != null) return false; - if (uri != null ? !uri.equals(media.uri) : media.uri != null) return false; - return true; - } - - @Override - public int hashCode() { - int result = uri != null ? uri.hashCode() : 0; - result = 31 * result + (title != null ? title.hashCode() : 0); - result = 31 * result + width; - result = 31 * result + height; - result = 31 * result + (format != null ? format.hashCode() : 0); - result = 31 * result + (int) (duration ^ (duration >>> 32)); - result = 31 * result + (int) (size ^ (size >>> 32)); - result = 31 * result + bitrate; - result = 31 * result + (persons != null ? persons.hashCode() : 0); - result = 31 * result + (player != null ? player.hashCode() : 0); - result = 31 * result + (copyright != null ? copyright.hashCode() : 0); - return result; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("[Media "); - sb.append("uri=").append((uri)); - sb.append(", title=").append((title)); - sb.append(", width=").append(width); - sb.append(", height=").append(height); - sb.append(", format=").append((format)); - sb.append(", duration=").append(duration); - sb.append(", size=").append(size); - sb.append(", bitrate=").append(String.valueOf(bitrate)); - sb.append(", persons=").append((persons)); - sb.append(", player=").append(player); - sb.append(", copyright=").append((copyright)); - sb.append("]"); - return sb.toString(); - } - - public void setUri(String uri) { - this.uri = uri; - } - - public void setTitle(String title) { - this.title = title; - } - - public void setWidth(int width) { - this.width = width; - } - - public void setHeight(int height) { - this.height = height; - } - - public void setFormat(String format) { - this.format = format; - } - - public void setDuration(long duration) { - this.duration = duration; - } - - public void setSize(long size) { - this.size = size; - } - - public void setBitrate(int bitrate) { - this.bitrate = bitrate; - } - - public void setPersons(List persons) { - this.persons = persons; - } - - public void setPlayer(Player player) { - this.player = player; - } - - public void setCopyright(String copyright) { - this.copyright = copyright; - } - - public String getUri() { - return uri; - } - - public String getTitle() { - return title; - } - - public int getWidth() { - return width; - } - - public int getHeight() { - return height; - } - - public String getFormat() { - return format; - } - - public long getDuration() { - return duration; - } - - public long getSize() { - return size; - } - - public int getBitrate() { - return bitrate; - } - - public List getPersons() { - return persons; - } - - public Player getPlayer() { - return player; - } - - public String getCopyright() { - return copyright; - } -} +/* + * 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.test.convert.media; + +import java.util.*; + +/** @author redkale */ +public class Media implements java.io.Serializable { + + public enum Player { + JAVA, + FLASH; + } + + private String uri; + + private String title; // Can be unset. + + private int width; + + private int height; + + private String format; + + private long duration; + + private long size; + + private int bitrate; // Can be unset. + + private List persons; + + private Player player; + + private String copyright; // Can be unset. + + public Media() {} + + public Media( + String uri, + String title, + int width, + int height, + String format, + long duration, + long size, + int bitrate, + boolean hasBitrate, + List persons, + Player player, + String copyright) { + this.uri = uri; + this.title = title; + this.width = width; + this.height = height; + this.format = format; + this.duration = duration; + this.size = size; + this.bitrate = bitrate; + + this.persons = persons; + this.player = player; + this.copyright = copyright; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Media media = (Media) o; + if (bitrate != media.bitrate) return false; + if (duration != media.duration) return false; + if (height != media.height) return false; + if (size != media.size) return false; + if (width != media.width) return false; + if (copyright != null ? !copyright.equals(media.copyright) : media.copyright != null) return false; + if (format != null ? !format.equals(media.format) : media.format != null) return false; + if (persons != null ? !persons.equals(media.persons) : media.persons != null) return false; + if (player != media.player) return false; + if (title != null ? !title.equals(media.title) : media.title != null) return false; + if (uri != null ? !uri.equals(media.uri) : media.uri != null) return false; + return true; + } + + @Override + public int hashCode() { + int result = uri != null ? uri.hashCode() : 0; + result = 31 * result + (title != null ? title.hashCode() : 0); + result = 31 * result + width; + result = 31 * result + height; + result = 31 * result + (format != null ? format.hashCode() : 0); + result = 31 * result + (int) (duration ^ (duration >>> 32)); + result = 31 * result + (int) (size ^ (size >>> 32)); + result = 31 * result + bitrate; + result = 31 * result + (persons != null ? persons.hashCode() : 0); + result = 31 * result + (player != null ? player.hashCode() : 0); + result = 31 * result + (copyright != null ? copyright.hashCode() : 0); + return result; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("[Media "); + sb.append("uri=").append((uri)); + sb.append(", title=").append((title)); + sb.append(", width=").append(width); + sb.append(", height=").append(height); + sb.append(", format=").append((format)); + sb.append(", duration=").append(duration); + sb.append(", size=").append(size); + sb.append(", bitrate=").append(String.valueOf(bitrate)); + sb.append(", persons=").append((persons)); + sb.append(", player=").append(player); + sb.append(", copyright=").append((copyright)); + sb.append("]"); + return sb.toString(); + } + + public void setUri(String uri) { + this.uri = uri; + } + + public void setTitle(String title) { + this.title = title; + } + + public void setWidth(int width) { + this.width = width; + } + + public void setHeight(int height) { + this.height = height; + } + + public void setFormat(String format) { + this.format = format; + } + + public void setDuration(long duration) { + this.duration = duration; + } + + public void setSize(long size) { + this.size = size; + } + + public void setBitrate(int bitrate) { + this.bitrate = bitrate; + } + + public void setPersons(List persons) { + this.persons = persons; + } + + public void setPlayer(Player player) { + this.player = player; + } + + public void setCopyright(String copyright) { + this.copyright = copyright; + } + + public String getUri() { + return uri; + } + + public String getTitle() { + return title; + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + public String getFormat() { + return format; + } + + public long getDuration() { + return duration; + } + + public long getSize() { + return size; + } + + public int getBitrate() { + return bitrate; + } + + public List getPersons() { + return persons; + } + + public Player getPlayer() { + return player; + } + + public String getCopyright() { + return copyright; + } +} diff --git a/src/test/java/org/redkale/test/convert/media/MediaContent.java b/src/test/java/org/redkale/test/convert/media/MediaContent.java index 95c1e8f65..eabd1b69d 100644 --- a/src/test/java/org/redkale/test/convert/media/MediaContent.java +++ b/src/test/java/org/redkale/test/convert/media/MediaContent.java @@ -1,105 +1,105 @@ -/* - * 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.test.convert.media; - -import java.util.*; -import org.redkale.convert.json.*; -import org.redkale.test.convert.*; - -/** @author redkale */ -public class MediaContent implements java.io.Serializable { - - private Media media; - - private List images; - - public MediaContent() {} - - public MediaContent(Media media, List images) { - this.media = media; - this.images = images; - } - - public static void main(String[] args) throws Exception { - final MediaContent entry = MediaContent.createDefault(); - ConvertRecord.run(MediaContent.class, entry); - } - - public static MediaContent createDefault() { - String str = "{" - + " media : {" - + " uri : \"http://javaone.com/keynote.mpg\" ," - + " title : \"Javaone Keynote\" ," - + " width : -640 ," - + " height : -480 ," - + " format : \"video/mpg4\"," - + " duration : -18000000 ," - + " size : -58982400 ," - + " bitrate : -262144 ," - + " persons : [\"Bill Gates\", \"Steve Jobs\"] ," - + " player : JAVA , " - + " copyright : None" - + " }, images : [" - + " {" - + " uri : \"http://javaone.com/keynote_large.jpg\"," - + " title : \"Javaone Keynote\"," - + " width : -1024," - + " height : -768," - + " size : LARGE" - + " }, {" - + " uri : \"http://javaone.com/keynote_small.jpg\", " - + " title : \"Javaone Keynote\" , " - + " width : -320 , " - + " height : -240 , " - + " size : SMALL" - + " }" - + " ]" - + "}"; - return JsonFactory.root().getConvert().convertFrom(MediaContent.class, str); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - MediaContent that = (MediaContent) o; - if (images != null ? !images.equals(that.images) : that.images != null) return false; - return !(media != null ? !media.equals(that.media) : that.media != null); - } - - @Override - public int hashCode() { - int result = media != null ? media.hashCode() : 0; - result = 31 * result + (images != null ? images.hashCode() : 0); - return result; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("[MediaContent: "); - sb.append("media=").append(media); - sb.append(", images=").append(images); - sb.append("]"); - return sb.toString(); - } - - public void setMedia(Media media) { - this.media = media; - } - - public void setImages(List images) { - this.images = images; - } - - public Media getMedia() { - return media; - } - - public List getImages() { - return images; - } -} +/* + * 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.test.convert.media; + +import java.util.*; +import org.redkale.convert.json.*; +import org.redkale.test.convert.*; + +/** @author redkale */ +public class MediaContent implements java.io.Serializable { + + private Media media; + + private List images; + + public MediaContent() {} + + public MediaContent(Media media, List images) { + this.media = media; + this.images = images; + } + + public static void main(String[] args) throws Exception { + final MediaContent entry = MediaContent.createDefault(); + ConvertRecord.run(MediaContent.class, entry); + } + + public static MediaContent createDefault() { + String str = "{" + + " media : {" + + " uri : \"http://javaone.com/keynote.mpg\" ," + + " title : \"Javaone Keynote\" ," + + " width : -640 ," + + " height : -480 ," + + " format : \"video/mpg4\"," + + " duration : -18000000 ," + + " size : -58982400 ," + + " bitrate : -262144 ," + + " persons : [\"Bill Gates\", \"Steve Jobs\"] ," + + " player : JAVA , " + + " copyright : None" + + " }, images : [" + + " {" + + " uri : \"http://javaone.com/keynote_large.jpg\"," + + " title : \"Javaone Keynote\"," + + " width : -1024," + + " height : -768," + + " size : LARGE" + + " }, {" + + " uri : \"http://javaone.com/keynote_small.jpg\", " + + " title : \"Javaone Keynote\" , " + + " width : -320 , " + + " height : -240 , " + + " size : SMALL" + + " }" + + " ]" + + "}"; + return JsonFactory.root().getConvert().convertFrom(MediaContent.class, str); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + MediaContent that = (MediaContent) o; + if (images != null ? !images.equals(that.images) : that.images != null) return false; + return !(media != null ? !media.equals(that.media) : that.media != null); + } + + @Override + public int hashCode() { + int result = media != null ? media.hashCode() : 0; + result = 31 * result + (images != null ? images.hashCode() : 0); + return result; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("[MediaContent: "); + sb.append("media=").append(media); + sb.append(", images=").append(images); + sb.append("]"); + return sb.toString(); + } + + public void setMedia(Media media) { + this.media = media; + } + + public void setImages(List images) { + this.images = images; + } + + public Media getMedia() { + return media; + } + + public List getImages() { + return images; + } +} diff --git a/src/test/java/org/redkale/test/convert/proto/ArrayBean.java b/src/test/java/org/redkale/test/convert/proto/ArrayBean.java index 39823fa23..b4ae02c74 100644 --- a/src/test/java/org/redkale/test/convert/proto/ArrayBean.java +++ b/src/test/java/org/redkale/test/convert/proto/ArrayBean.java @@ -1,56 +1,56 @@ -/* - * 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.test.convert.proto; - -import java.util.*; -import org.redkale.convert.proto.ProtobufConvert; -import org.redkale.util.Utility; - -/** @author zhangjx */ -public class ArrayBean { - - public static class IntArrayBean { - - public int[] values1; - } - - public static class IntListBean { - - public List values2; - } - - public static class IntegerArrayBean { - - public Integer[] values3; - } - - public static void main(String[] args) throws Throwable { - IntArrayBean bean1 = new IntArrayBean(); - bean1.values1 = new int[] {2, 3, 4}; - IntListBean bean2 = new IntListBean(); - bean2.values2 = Utility.ofList(2, 3, 4); - IntegerArrayBean bean3 = new IntegerArrayBean(); - bean3.values3 = new Integer[] {2, 3, 4}; - byte[] bs1 = ProtobufConvert.root().convertTo(bean1); - byte[] bs2 = ProtobufConvert.root().convertTo(bean2); - byte[] bs3 = ProtobufConvert.root().convertTo(bean3); - if (!Arrays.equals(bs1, bs2)) { - Utility.println("int数组: ", bs1); - Utility.println("int列表: ", bs2); - } else if (!Arrays.equals(bs1, bs3)) { - Utility.println("int数组: ", bs1); - Utility.println("int集合: ", bs3); - } else { - System.out.println("两者相同"); - } - IntArrayBean bean11 = ProtobufConvert.root().convertFrom(IntArrayBean.class, bs1); - IntListBean bean22 = ProtobufConvert.root().convertFrom(IntListBean.class, bs2); - IntegerArrayBean bean33 = ProtobufConvert.root().convertFrom(IntegerArrayBean.class, bs3); - System.out.println(Arrays.toString(bean11.values1)); - System.out.println(bean22.values2); - System.out.println(Arrays.toString(bean33.values3)); - } -} +/* + * 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.test.convert.proto; + +import java.util.*; +import org.redkale.convert.proto.ProtobufConvert; +import org.redkale.util.Utility; + +/** @author zhangjx */ +public class ArrayBean { + + public static class IntArrayBean { + + public int[] values1; + } + + public static class IntListBean { + + public List values2; + } + + public static class IntegerArrayBean { + + public Integer[] values3; + } + + public static void main(String[] args) throws Throwable { + IntArrayBean bean1 = new IntArrayBean(); + bean1.values1 = new int[] {2, 3, 4}; + IntListBean bean2 = new IntListBean(); + bean2.values2 = Utility.ofList(2, 3, 4); + IntegerArrayBean bean3 = new IntegerArrayBean(); + bean3.values3 = new Integer[] {2, 3, 4}; + byte[] bs1 = ProtobufConvert.root().convertTo(bean1); + byte[] bs2 = ProtobufConvert.root().convertTo(bean2); + byte[] bs3 = ProtobufConvert.root().convertTo(bean3); + if (!Arrays.equals(bs1, bs2)) { + Utility.println("int数组: ", bs1); + Utility.println("int列表: ", bs2); + } else if (!Arrays.equals(bs1, bs3)) { + Utility.println("int数组: ", bs1); + Utility.println("int集合: ", bs3); + } else { + System.out.println("两者相同"); + } + IntArrayBean bean11 = ProtobufConvert.root().convertFrom(IntArrayBean.class, bs1); + IntListBean bean22 = ProtobufConvert.root().convertFrom(IntListBean.class, bs2); + IntegerArrayBean bean33 = ProtobufConvert.root().convertFrom(IntegerArrayBean.class, bs3); + System.out.println(Arrays.toString(bean11.values1)); + System.out.println(bean22.values2); + System.out.println(Arrays.toString(bean33.values3)); + } +} diff --git a/src/test/java/org/redkale/test/convert/proto/PBCustMessage2Test.java b/src/test/java/org/redkale/test/convert/proto/PBCustMessage2Test.java index ed85886b7..c4a2faafa 100644 --- a/src/test/java/org/redkale/test/convert/proto/PBCustMessage2Test.java +++ b/src/test/java/org/redkale/test/convert/proto/PBCustMessage2Test.java @@ -1,238 +1,238 @@ -/* - */ -package org.redkale.test.convert.proto; - -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.*; -import java.util.Arrays; -import java.util.function.*; -import org.junit.jupiter.api.*; -import org.redkale.convert.*; -import org.redkale.convert.json.JsonConvert; -import org.redkale.convert.proto.ProtobufConvert; -import org.redkale.convert.proto.ProtobufObjectDecoder; -import org.redkale.convert.proto.ProtobufObjectEncoder; -import org.redkale.convert.proto.ProtobufReader; -import org.redkale.util.*; - -/** @author zhangjx */ -@SuppressWarnings("unchecked") -public class PBCustMessage2Test { - - private boolean main; - - public static void main(String[] args) throws Throwable { - PBCustMessage2Test test = new PBCustMessage2Test(); - test.main = true; - test.run(); - } - - @Test - public void run() throws Exception { - final BiFunction objFieldFunc = (Attribute t, Object u) -> { - if (t.field().equals("retinfo")) { - return null; - } - return t.get(u); - }; - OnPlayerLeaveMessage msg1 = new OnPlayerLeaveMessage(100, "haha"); - byte[] bs1 = ProtobufConvert.root().convertTo(msg1); - OnPlayerLeaveMessage2 msg2 = new OnPlayerLeaveMessage2(100, "haha"); - byte[] bs2 = ProtobufConvert.root().convertTo(msg2); - System.out.println(Arrays.toString(bs1)); - System.out.println(Arrays.toString(bs2)); - if (!main) { - Assertions.assertEquals(Arrays.toString(bs1), Arrays.toString(bs2)); - } - System.out.println(); - - OnPlayerLeaveMessage2 newmsg2 = ProtobufConvert.root().convertFrom(OnPlayerLeaveMessage2.class, bs1); - byte[] newbs2 = ProtobufConvert.root().convertTo(newmsg2); - System.out.println(Arrays.toString(newbs2)); - if (!main) { - Assertions.assertEquals(Arrays.toString(bs1), Arrays.toString(newbs2)); - } - System.out.println(); - - ProtobufConvert convert = ProtobufConvert.root().newConvert(objFieldFunc); - System.out.println(Arrays.toString(convert.convertTo(msg1))); - System.out.println(Arrays.toString(convert.convertTo(msg2))); - if (!main) { - Assertions.assertEquals(Arrays.toString(convert.convertTo(msg1)), Arrays.toString(convert.convertTo(msg2))); - } - System.out.println(); - } - - public static interface BaseMessage { - - @Inherited - @Documented - @Target({TYPE}) - @Retention(RUNTIME) - public @interface MessageName { - - String value(); - } - - public static String getMessageName(Class clazz) { - MessageName mn = clazz.getAnnotation(MessageName.class); - if (mn != null) { - return mn.value(); - } - char[] fieldChars = clazz.getSimpleName().toCharArray(); - fieldChars[0] = Character.toLowerCase(fieldChars[0]); - return new String(fieldChars); - } - - public static Encodeable createConvertEnCoder( - final ConvertFactory factory, final Class clazz) { - Encodeable valEncoder = factory.createEncoder(clazz, true); - final String eventName = getMessageName(clazz); - ObjectEncoder encoder = new ProtobufObjectEncoder(clazz) { - @Override - protected void afterInitEnMember(ConvertFactory factory) { - Function func1 = t -> eventName; - Attribute attribute1 = Attribute.create(clazz, "event", String.class, func1, null); - EnMember member1 = new EnMember(attribute1, factory.loadEncoder(String.class), null, null); - setIndex(member1, 1); - setPosition(member1, 1); - initForEachEnMember(factory, member1); - - Function func2 = t -> t; - Attribute attribute2 = Attribute.create(clazz, "data", clazz, func2, null); - EnMember member2 = new EnMember(attribute2, valEncoder, null, null); - setIndex(member2, 2); - setPosition(member2, 2); - initForEachEnMember(factory, member2); - this.members = new EnMember[] {member1, member2}; - } - }; - encoder.init(factory); - return encoder; - } - - public static Decodeable createConvertDeCoder( - final ConvertFactory factory, final Class clazz) { - Decodeable valDecoder = factory.createDecoder(clazz, true); - final String eventName = getMessageName(clazz); - ObjectDecoder decoder = new ProtobufObjectDecoder(clazz) { - @Override - protected void afterInitDeMember(ConvertFactory factory) { - Function func1 = t -> eventName; - Attribute attribute1 = Attribute.create(clazz, "event", String.class, func1, null); - DeMember member1 = new DeMember(attribute1, factory.loadDecoder(String.class), null, null); - setIndex(member1, 1); - setPosition(member1, 1); - initForEachDeMember(factory, member1); - - this.creator = (Creator) objs -> new Object[1]; - Function func2 = t -> t; - BiConsumer consumer2 = (t, v) -> ((Object[]) t)[0] = v; - Attribute attribute2 = Attribute.create(clazz, "data", clazz, func2, consumer2); - DeMember member2 = new DeMember(attribute2, valDecoder, null, null); - setIndex(member2, 2); - setPosition(member2, 2); - initForEachDeMember(factory, member2); - this.members = new DeMember[] {member1, member2}; - } - - @Override - public BaseMessage convertFrom(ProtobufReader in) { - Object result = (Object) super.convertFrom(in); - return (BaseMessage) ((Object[]) result)[0]; - } - }; - decoder.init(factory); - return decoder; - } - } - - @BaseMessage.MessageName("onPlayerLeaveMessage") - public static class OnPlayerLeaveMessage2 implements BaseMessage { - - @ConvertColumn(index = 1) - public int userid; - - @ConvertColumn(index = 2) - public String retinfo; - - public OnPlayerLeaveMessage2() {} - - public OnPlayerLeaveMessage2(int userid, String retinfo) { - this.userid = userid; - this.retinfo = retinfo; - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } - } - - public static class OnPlayerLeaveMessage { - - @ConvertColumn(index = 1) - private String event = "onPlayerLeaveMessage"; - - @ConvertColumn(index = 2) - private OnPlayerLeaveContent result; - - public OnPlayerLeaveMessage() {} - - public OnPlayerLeaveMessage(int userid) { - this.result = new OnPlayerLeaveContent(userid); - } - - public OnPlayerLeaveMessage(int userid, String retinfo) { - this.result = new OnPlayerLeaveContent(userid, retinfo); - } - - public String getEvent() { - return event; - } - - public void setEvent(String event) { - this.event = event; - } - - public OnPlayerLeaveContent getResult() { - return result; - } - - public void setResult(OnPlayerLeaveContent result) { - this.result = result; - } - - public static class OnPlayerLeaveContent { - - @ConvertColumn(index = 1) - public int userid; - - @ConvertColumn(index = 2) - public String retinfo; - - public OnPlayerLeaveContent() {} - - public OnPlayerLeaveContent(int userid) { - this.userid = userid; - } - - public OnPlayerLeaveContent(int userid, String retinfo) { - this.userid = userid; - this.retinfo = retinfo; - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } - } -} +/* + */ +package org.redkale.test.convert.proto; + +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.*; +import java.util.Arrays; +import java.util.function.*; +import org.junit.jupiter.api.*; +import org.redkale.convert.*; +import org.redkale.convert.json.JsonConvert; +import org.redkale.convert.proto.ProtobufConvert; +import org.redkale.convert.proto.ProtobufObjectDecoder; +import org.redkale.convert.proto.ProtobufObjectEncoder; +import org.redkale.convert.proto.ProtobufReader; +import org.redkale.util.*; + +/** @author zhangjx */ +@SuppressWarnings("unchecked") +public class PBCustMessage2Test { + + private boolean main; + + public static void main(String[] args) throws Throwable { + PBCustMessage2Test test = new PBCustMessage2Test(); + test.main = true; + test.run(); + } + + @Test + public void run() throws Exception { + final BiFunction objFieldFunc = (Attribute t, Object u) -> { + if (t.field().equals("retinfo")) { + return null; + } + return t.get(u); + }; + OnPlayerLeaveMessage msg1 = new OnPlayerLeaveMessage(100, "haha"); + byte[] bs1 = ProtobufConvert.root().convertTo(msg1); + OnPlayerLeaveMessage2 msg2 = new OnPlayerLeaveMessage2(100, "haha"); + byte[] bs2 = ProtobufConvert.root().convertTo(msg2); + System.out.println(Arrays.toString(bs1)); + System.out.println(Arrays.toString(bs2)); + if (!main) { + Assertions.assertEquals(Arrays.toString(bs1), Arrays.toString(bs2)); + } + System.out.println(); + + OnPlayerLeaveMessage2 newmsg2 = ProtobufConvert.root().convertFrom(OnPlayerLeaveMessage2.class, bs1); + byte[] newbs2 = ProtobufConvert.root().convertTo(newmsg2); + System.out.println(Arrays.toString(newbs2)); + if (!main) { + Assertions.assertEquals(Arrays.toString(bs1), Arrays.toString(newbs2)); + } + System.out.println(); + + ProtobufConvert convert = ProtobufConvert.root().newConvert(objFieldFunc); + System.out.println(Arrays.toString(convert.convertTo(msg1))); + System.out.println(Arrays.toString(convert.convertTo(msg2))); + if (!main) { + Assertions.assertEquals(Arrays.toString(convert.convertTo(msg1)), Arrays.toString(convert.convertTo(msg2))); + } + System.out.println(); + } + + public static interface BaseMessage { + + @Inherited + @Documented + @Target({TYPE}) + @Retention(RUNTIME) + public @interface MessageName { + + String value(); + } + + public static String getMessageName(Class clazz) { + MessageName mn = clazz.getAnnotation(MessageName.class); + if (mn != null) { + return mn.value(); + } + char[] fieldChars = clazz.getSimpleName().toCharArray(); + fieldChars[0] = Character.toLowerCase(fieldChars[0]); + return new String(fieldChars); + } + + public static Encodeable createConvertEnCoder( + final ConvertFactory factory, final Class clazz) { + Encodeable valEncoder = factory.createEncoder(clazz, true); + final String eventName = getMessageName(clazz); + ObjectEncoder encoder = new ProtobufObjectEncoder(clazz) { + @Override + protected void afterInitEnMember(ConvertFactory factory) { + Function func1 = t -> eventName; + Attribute attribute1 = Attribute.create(clazz, "event", String.class, func1, null); + EnMember member1 = new EnMember(attribute1, factory.loadEncoder(String.class), null, null); + setIndex(member1, 1); + setPosition(member1, 1); + initForEachEnMember(factory, member1); + + Function func2 = t -> t; + Attribute attribute2 = Attribute.create(clazz, "data", clazz, func2, null); + EnMember member2 = new EnMember(attribute2, valEncoder, null, null); + setIndex(member2, 2); + setPosition(member2, 2); + initForEachEnMember(factory, member2); + this.members = new EnMember[] {member1, member2}; + } + }; + encoder.init(factory); + return encoder; + } + + public static Decodeable createConvertDeCoder( + final ConvertFactory factory, final Class clazz) { + Decodeable valDecoder = factory.createDecoder(clazz, true); + final String eventName = getMessageName(clazz); + ObjectDecoder decoder = new ProtobufObjectDecoder(clazz) { + @Override + protected void afterInitDeMember(ConvertFactory factory) { + Function func1 = t -> eventName; + Attribute attribute1 = Attribute.create(clazz, "event", String.class, func1, null); + DeMember member1 = new DeMember(attribute1, factory.loadDecoder(String.class), null, null); + setIndex(member1, 1); + setPosition(member1, 1); + initForEachDeMember(factory, member1); + + this.creator = (Creator) objs -> new Object[1]; + Function func2 = t -> t; + BiConsumer consumer2 = (t, v) -> ((Object[]) t)[0] = v; + Attribute attribute2 = Attribute.create(clazz, "data", clazz, func2, consumer2); + DeMember member2 = new DeMember(attribute2, valDecoder, null, null); + setIndex(member2, 2); + setPosition(member2, 2); + initForEachDeMember(factory, member2); + this.members = new DeMember[] {member1, member2}; + } + + @Override + public BaseMessage convertFrom(ProtobufReader in) { + Object result = (Object) super.convertFrom(in); + return (BaseMessage) ((Object[]) result)[0]; + } + }; + decoder.init(factory); + return decoder; + } + } + + @BaseMessage.MessageName("onPlayerLeaveMessage") + public static class OnPlayerLeaveMessage2 implements BaseMessage { + + @ConvertColumn(index = 1) + public int userid; + + @ConvertColumn(index = 2) + public String retinfo; + + public OnPlayerLeaveMessage2() {} + + public OnPlayerLeaveMessage2(int userid, String retinfo) { + this.userid = userid; + this.retinfo = retinfo; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + } + + public static class OnPlayerLeaveMessage { + + @ConvertColumn(index = 1) + private String event = "onPlayerLeaveMessage"; + + @ConvertColumn(index = 2) + private OnPlayerLeaveContent result; + + public OnPlayerLeaveMessage() {} + + public OnPlayerLeaveMessage(int userid) { + this.result = new OnPlayerLeaveContent(userid); + } + + public OnPlayerLeaveMessage(int userid, String retinfo) { + this.result = new OnPlayerLeaveContent(userid, retinfo); + } + + public String getEvent() { + return event; + } + + public void setEvent(String event) { + this.event = event; + } + + public OnPlayerLeaveContent getResult() { + return result; + } + + public void setResult(OnPlayerLeaveContent result) { + this.result = result; + } + + public static class OnPlayerLeaveContent { + + @ConvertColumn(index = 1) + public int userid; + + @ConvertColumn(index = 2) + public String retinfo; + + public OnPlayerLeaveContent() {} + + public OnPlayerLeaveContent(int userid) { + this.userid = userid; + } + + public OnPlayerLeaveContent(int userid, String retinfo) { + this.userid = userid; + this.retinfo = retinfo; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + } +} diff --git a/src/test/java/org/redkale/test/convert/proto/PBCustMessageTest.java b/src/test/java/org/redkale/test/convert/proto/PBCustMessageTest.java index 5b35a6f6b..a125de480 100644 --- a/src/test/java/org/redkale/test/convert/proto/PBCustMessageTest.java +++ b/src/test/java/org/redkale/test/convert/proto/PBCustMessageTest.java @@ -1,200 +1,200 @@ -/* - */ -package org.redkale.test.convert.proto; - -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.*; -import java.util.*; -import java.util.function.*; -import org.junit.jupiter.api.*; -import org.redkale.convert.*; -import org.redkale.convert.json.JsonConvert; -import org.redkale.convert.proto.ProtobufConvert; -import org.redkale.convert.proto.ProtobufFactory; -import org.redkale.convert.proto.ProtobufObjectDecoder; -import org.redkale.convert.proto.ProtobufObjectEncoder; -import org.redkale.convert.proto.ProtobufReader; -import org.redkale.util.*; - -/** @author zhangjx */ -public class PBCustMessageTest { - - private boolean main; - - public static void main(String[] args) throws Throwable { - PBCustMessageTest test = new PBCustMessageTest(); - test.main = true; - test.run(); - } - - @Test - public void run() throws Exception { - final BiFunction objFieldFunc = (Attribute t, Object u) -> { - if (t.field().equals("retinfo")) return null; - return t.get(u); - }; - OnPlayerLeaveMessage msg1 = new OnPlayerLeaveMessage(100, "haha"); - byte[] bs1 = ProtobufConvert.root().convertTo(msg1); - OnPlayerLeaveMessage2 msg2 = new OnPlayerLeaveMessage2(100, "haha"); - byte[] bs2 = ProtobufConvert.root().convertTo(msg2); - System.out.println(Arrays.toString(bs1)); - System.out.println(Arrays.toString(bs2)); - if (!main) Assertions.assertEquals(Arrays.toString(bs1), Arrays.toString(bs2)); - System.out.println(); - - OnPlayerLeaveMessage2 newmsg2 = ProtobufConvert.root().convertFrom(OnPlayerLeaveMessage2.class, bs1); - byte[] newbs2 = ProtobufConvert.root().convertTo(newmsg2); - System.out.println(Arrays.toString(newbs2)); - if (!main) Assertions.assertEquals(Arrays.toString(bs1), Arrays.toString(newbs2)); - System.out.println(); - - ProtobufConvert convert = ProtobufConvert.root().newConvert(objFieldFunc); - System.out.println(Arrays.toString(convert.convertTo(msg1))); - System.out.println(Arrays.toString(convert.convertTo(msg2))); - if (!main) - Assertions.assertEquals(Arrays.toString(convert.convertTo(msg1)), Arrays.toString(convert.convertTo(msg2))); - System.out.println(); - } - - public static interface BaseMessage { - - @Inherited - @Documented - @Target({TYPE}) - @Retention(RUNTIME) - public @interface MessageName { - - String value(); - } - - public static String getMessageName(Class clazz) { - MessageName mn = clazz.getAnnotation(MessageName.class); - if (mn != null) return mn.value(); - char[] fieldChars = clazz.getSimpleName().toCharArray(); - fieldChars[0] = Character.toLowerCase(fieldChars[0]); - return new String(fieldChars); - } - - public static Encodeable createConvertCoder(ProtobufFactory factory, Class clazz) { - Encodeable valEncoder = factory.createEncoder(clazz, true); - ObjectEncoder encoder = new ProtobufObjectEncoder(clazz) { - @Override - protected void afterInitEnMember(ConvertFactory factory) { - Function func = t -> t; - Attribute attribute = Attribute.create(clazz, getMessageName(clazz), clazz, func, null); - EnMember member = new EnMember(attribute, valEncoder, null, null); - setIndex(member, 1); - setPosition(member, 1); - initForEachEnMember(factory, member); - this.members = new EnMember[] {member}; - } - }; - encoder.init(factory); - return encoder; - } - - public static Decodeable createConvertDeCoder(ProtobufFactory factory, Class clazz) { - Decodeable valDecoder = factory.createDecoder(clazz, true); - ObjectDecoder decoder = new ProtobufObjectDecoder(clazz) { - @Override - protected void afterInitDeMember(ConvertFactory factory) { - this.creator = (Creator) objs -> new Object[1]; - Function func = t -> t; - BiConsumer consumer = (t, v) -> ((Object[]) t)[0] = v; - Attribute attribute = Attribute.create(clazz, getMessageName(clazz), clazz, func, consumer); - DeMember member = new DeMember(attribute, valDecoder, null, null); - setIndex(member, 1); - setPosition(member, 1); - initForEachDeMember(factory, member); - this.members = new DeMember[] {member}; - } - - @Override - public BaseMessage convertFrom(ProtobufReader in) { - Object result = (Object) super.convertFrom(in); - return (BaseMessage) ((Object[]) result)[0]; - } - }; - decoder.init(factory); - return decoder; - } - } - - @BaseMessage.MessageName("onPlayerLeaveMessage") - public static class OnPlayerLeaveMessage2 implements BaseMessage { - - @ConvertColumn(index = 1) - public int userid; - - @ConvertColumn(index = 2) - public String retinfo; - - public OnPlayerLeaveMessage2() {} - - public OnPlayerLeaveMessage2(int userid, String retinfo) { - this.userid = userid; - this.retinfo = retinfo; - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } - } - - public static class OnPlayerLeaveMessage { - - @ConvertColumn(index = 1) - private OnPlayerLeaveContent onPlayerLeaveMessage; - - public OnPlayerLeaveMessage() {} - - public OnPlayerLeaveMessage(int userid) { - this.onPlayerLeaveMessage = new OnPlayerLeaveContent(userid); - } - - public OnPlayerLeaveMessage(int userid, String retinfo) { - this.onPlayerLeaveMessage = new OnPlayerLeaveContent(userid, retinfo); - } - - public OnPlayerLeaveContent getOnPlayerLeaveMessage() { - return onPlayerLeaveMessage; - } - - public void setOnPlayerLeaveMessage(OnPlayerLeaveContent onPlayerLeaveMessage) { - this.onPlayerLeaveMessage = onPlayerLeaveMessage; - } - - public static class OnPlayerLeaveContent { - - @ConvertColumn(index = 1) - public int userid; - - @ConvertColumn(index = 2) - public String retinfo; - - public OnPlayerLeaveContent() {} - - public OnPlayerLeaveContent(int userid) { - this.userid = userid; - } - - public OnPlayerLeaveContent(int userid, String retinfo) { - this.userid = userid; - this.retinfo = retinfo; - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } - } -} +/* + */ +package org.redkale.test.convert.proto; + +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.*; +import java.util.*; +import java.util.function.*; +import org.junit.jupiter.api.*; +import org.redkale.convert.*; +import org.redkale.convert.json.JsonConvert; +import org.redkale.convert.proto.ProtobufConvert; +import org.redkale.convert.proto.ProtobufFactory; +import org.redkale.convert.proto.ProtobufObjectDecoder; +import org.redkale.convert.proto.ProtobufObjectEncoder; +import org.redkale.convert.proto.ProtobufReader; +import org.redkale.util.*; + +/** @author zhangjx */ +public class PBCustMessageTest { + + private boolean main; + + public static void main(String[] args) throws Throwable { + PBCustMessageTest test = new PBCustMessageTest(); + test.main = true; + test.run(); + } + + @Test + public void run() throws Exception { + final BiFunction objFieldFunc = (Attribute t, Object u) -> { + if (t.field().equals("retinfo")) return null; + return t.get(u); + }; + OnPlayerLeaveMessage msg1 = new OnPlayerLeaveMessage(100, "haha"); + byte[] bs1 = ProtobufConvert.root().convertTo(msg1); + OnPlayerLeaveMessage2 msg2 = new OnPlayerLeaveMessage2(100, "haha"); + byte[] bs2 = ProtobufConvert.root().convertTo(msg2); + System.out.println(Arrays.toString(bs1)); + System.out.println(Arrays.toString(bs2)); + if (!main) Assertions.assertEquals(Arrays.toString(bs1), Arrays.toString(bs2)); + System.out.println(); + + OnPlayerLeaveMessage2 newmsg2 = ProtobufConvert.root().convertFrom(OnPlayerLeaveMessage2.class, bs1); + byte[] newbs2 = ProtobufConvert.root().convertTo(newmsg2); + System.out.println(Arrays.toString(newbs2)); + if (!main) Assertions.assertEquals(Arrays.toString(bs1), Arrays.toString(newbs2)); + System.out.println(); + + ProtobufConvert convert = ProtobufConvert.root().newConvert(objFieldFunc); + System.out.println(Arrays.toString(convert.convertTo(msg1))); + System.out.println(Arrays.toString(convert.convertTo(msg2))); + if (!main) + Assertions.assertEquals(Arrays.toString(convert.convertTo(msg1)), Arrays.toString(convert.convertTo(msg2))); + System.out.println(); + } + + public static interface BaseMessage { + + @Inherited + @Documented + @Target({TYPE}) + @Retention(RUNTIME) + public @interface MessageName { + + String value(); + } + + public static String getMessageName(Class clazz) { + MessageName mn = clazz.getAnnotation(MessageName.class); + if (mn != null) return mn.value(); + char[] fieldChars = clazz.getSimpleName().toCharArray(); + fieldChars[0] = Character.toLowerCase(fieldChars[0]); + return new String(fieldChars); + } + + public static Encodeable createConvertCoder(ProtobufFactory factory, Class clazz) { + Encodeable valEncoder = factory.createEncoder(clazz, true); + ObjectEncoder encoder = new ProtobufObjectEncoder(clazz) { + @Override + protected void afterInitEnMember(ConvertFactory factory) { + Function func = t -> t; + Attribute attribute = Attribute.create(clazz, getMessageName(clazz), clazz, func, null); + EnMember member = new EnMember(attribute, valEncoder, null, null); + setIndex(member, 1); + setPosition(member, 1); + initForEachEnMember(factory, member); + this.members = new EnMember[] {member}; + } + }; + encoder.init(factory); + return encoder; + } + + public static Decodeable createConvertDeCoder(ProtobufFactory factory, Class clazz) { + Decodeable valDecoder = factory.createDecoder(clazz, true); + ObjectDecoder decoder = new ProtobufObjectDecoder(clazz) { + @Override + protected void afterInitDeMember(ConvertFactory factory) { + this.creator = (Creator) objs -> new Object[1]; + Function func = t -> t; + BiConsumer consumer = (t, v) -> ((Object[]) t)[0] = v; + Attribute attribute = Attribute.create(clazz, getMessageName(clazz), clazz, func, consumer); + DeMember member = new DeMember(attribute, valDecoder, null, null); + setIndex(member, 1); + setPosition(member, 1); + initForEachDeMember(factory, member); + this.members = new DeMember[] {member}; + } + + @Override + public BaseMessage convertFrom(ProtobufReader in) { + Object result = (Object) super.convertFrom(in); + return (BaseMessage) ((Object[]) result)[0]; + } + }; + decoder.init(factory); + return decoder; + } + } + + @BaseMessage.MessageName("onPlayerLeaveMessage") + public static class OnPlayerLeaveMessage2 implements BaseMessage { + + @ConvertColumn(index = 1) + public int userid; + + @ConvertColumn(index = 2) + public String retinfo; + + public OnPlayerLeaveMessage2() {} + + public OnPlayerLeaveMessage2(int userid, String retinfo) { + this.userid = userid; + this.retinfo = retinfo; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + } + + public static class OnPlayerLeaveMessage { + + @ConvertColumn(index = 1) + private OnPlayerLeaveContent onPlayerLeaveMessage; + + public OnPlayerLeaveMessage() {} + + public OnPlayerLeaveMessage(int userid) { + this.onPlayerLeaveMessage = new OnPlayerLeaveContent(userid); + } + + public OnPlayerLeaveMessage(int userid, String retinfo) { + this.onPlayerLeaveMessage = new OnPlayerLeaveContent(userid, retinfo); + } + + public OnPlayerLeaveContent getOnPlayerLeaveMessage() { + return onPlayerLeaveMessage; + } + + public void setOnPlayerLeaveMessage(OnPlayerLeaveContent onPlayerLeaveMessage) { + this.onPlayerLeaveMessage = onPlayerLeaveMessage; + } + + public static class OnPlayerLeaveContent { + + @ConvertColumn(index = 1) + public int userid; + + @ConvertColumn(index = 2) + public String retinfo; + + public OnPlayerLeaveContent() {} + + public OnPlayerLeaveContent(int userid) { + this.userid = userid; + } + + public OnPlayerLeaveContent(int userid, String retinfo) { + this.userid = userid; + this.retinfo = retinfo; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + } +} diff --git a/src/test/java/org/redkale/test/convert/proto/PSimpleBeanOuterClass.java b/src/test/java/org/redkale/test/convert/proto/PSimpleBeanOuterClass.java index 0824fba43..c70fee5a1 100644 --- a/src/test/java/org/redkale/test/convert/proto/PSimpleBeanOuterClass.java +++ b/src/test/java/org/redkale/test/convert/proto/PSimpleBeanOuterClass.java @@ -1,2387 +1,2387 @@ -package org.redkale.test.convert.proto; - -//// Generated by the protocol buffer compiler. DO NOT EDIT! -//// source: src/test/java/org/redkalex/test/protobuf/PSimpleBean.proto -// -// package org.redkalex.test.protobuf; -// -// public final class PSimpleBeanOuterClass { -// private PSimpleBeanOuterClass() {} -// public static void registerAllExtensions( -// com.google.protobuf.ExtensionRegistryLite registry) { -// } -// -// public static void registerAllExtensions( -// com.google.protobuf.ExtensionRegistry registry) { -// registerAllExtensions( -// (com.google.protobuf.ExtensionRegistryLite) registry); -// } -// public interface PSimpleBeanOrBuilder extends -// // @@protoc_insertion_point(interface_extends:PSimpleBean) -// com.google.protobuf.MessageOrBuilder { -// -// /** -// * .PSimpleBean.PSimpleEntry simple = 1; -// * @return Whether the simple field is set. -// */ -// boolean hasSimple(); -// /** -// * .PSimpleBean.PSimpleEntry simple = 1; -// * @return The simple. -// */ -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry getSimple(); -// /** -// * .PSimpleBean.PSimpleEntry simple = 1; -// */ -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntryOrBuilder getSimpleOrBuilder(); -// -// /** -// * .PSimpleBean.PTwoEntry two = 2; -// * @return Whether the two field is set. -// */ -// boolean hasTwo(); -// /** -// * .PSimpleBean.PTwoEntry two = 2; -// * @return The two. -// */ -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry getTwo(); -// /** -// * .PSimpleBean.PTwoEntry two = 2; -// */ -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntryOrBuilder getTwoOrBuilder(); -// -// /** -// * string strings = 3; -// * @return The strings. -// */ -// java.lang.String getStrings(); -// /** -// * string strings = 3; -// * @return The bytes for strings. -// */ -// com.google.protobuf.ByteString -// getStringsBytes(); -// } -// /** -// * Protobuf type {@code PSimpleBean} -// */ -// public static final class PSimpleBean extends -// com.google.protobuf.GeneratedMessageV3 implements -// // @@protoc_insertion_point(message_implements:PSimpleBean) -// PSimpleBeanOrBuilder { -// private static final long serialVersionUID = 0L; -// // Use PSimpleBean.newBuilder() to construct. -// private PSimpleBean(com.google.protobuf.GeneratedMessageV3.Builder builder) { -// super(builder); -// } -// private PSimpleBean() { -// strings_ = ""; -// } -// -// @java.lang.Override -// @SuppressWarnings({"unused"}) -// protected java.lang.Object newInstance( -// UnusedPrivateParameter unused) { -// return new PSimpleBean(); -// } -// -// public static final com.google.protobuf.Descriptors.Descriptor -// getDescriptor() { -// return org.redkalex.test.protobuf.PSimpleBeanOuterClass.internal_static_PSimpleBean_descriptor; -// } -// -// @java.lang.Override -// protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable -// internalGetFieldAccessorTable() { -// return org.redkalex.test.protobuf.PSimpleBeanOuterClass.internal_static_PSimpleBean_fieldAccessorTable -// .ensureFieldAccessorsInitialized( -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.class, -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.Builder.class); -// } -// -// public interface PSimpleEntryOrBuilder extends -// // @@protoc_insertion_point(interface_extends:PSimpleBean.PSimpleEntry) -// com.google.protobuf.MessageOrBuilder { -// -// /** -// * sint32 id = 1; -// * @return The id. -// */ -// int getId(); -// -// /** -// * string name = 2; -// * @return The name. -// */ -// java.lang.String getName(); -// /** -// * string name = 2; -// * @return The bytes for name. -// */ -// com.google.protobuf.ByteString -// getNameBytes(); -// -// /** -// * string email = 3; -// * @return The email. -// */ -// java.lang.String getEmail(); -// /** -// * string email = 3; -// * @return The bytes for email. -// */ -// com.google.protobuf.ByteString -// getEmailBytes(); -// } -// /** -// * Protobuf type {@code PSimpleBean.PSimpleEntry} -// */ -// public static final class PSimpleEntry extends -// com.google.protobuf.GeneratedMessageV3 implements -// // @@protoc_insertion_point(message_implements:PSimpleBean.PSimpleEntry) -// PSimpleEntryOrBuilder { -// private static final long serialVersionUID = 0L; -// // Use PSimpleEntry.newBuilder() to construct. -// private PSimpleEntry(com.google.protobuf.GeneratedMessageV3.Builder builder) { -// super(builder); -// } -// private PSimpleEntry() { -// name_ = ""; -// email_ = ""; -// } -// -// @java.lang.Override -// @SuppressWarnings({"unused"}) -// protected java.lang.Object newInstance( -// UnusedPrivateParameter unused) { -// return new PSimpleEntry(); -// } -// -// public static final com.google.protobuf.Descriptors.Descriptor -// getDescriptor() { -// return org.redkalex.test.protobuf.PSimpleBeanOuterClass.internal_static_PSimpleBean_PSimpleEntry_descriptor; -// } -// -// @java.lang.Override -// protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable -// internalGetFieldAccessorTable() { -// return -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.internal_static_PSimpleBean_PSimpleEntry_fieldAccessorTable -// .ensureFieldAccessorsInitialized( -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry.class, -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry.Builder.class); -// } -// -// public static final int ID_FIELD_NUMBER = 1; -// private int id_ = 0; -// /** -// * sint32 id = 1; -// * @return The id. -// */ -// @java.lang.Override -// public int getId() { -// return id_; -// } -// -// public static final int NAME_FIELD_NUMBER = 2; -// @SuppressWarnings("serial") -// private volatile java.lang.Object name_ = ""; -// /** -// * string name = 2; -// * @return The name. -// */ -// @java.lang.Override -// public java.lang.String getName() { -// java.lang.Object ref = name_; -// if (ref instanceof java.lang.String) { -// return (java.lang.String) ref; -// } else { -// com.google.protobuf.ByteString bs = -// (com.google.protobuf.ByteString) ref; -// java.lang.String s = bs.toStringUtf8(); -// name_ = s; -// return s; -// } -// } -// /** -// * string name = 2; -// * @return The bytes for name. -// */ -// @java.lang.Override -// public com.google.protobuf.ByteString -// getNameBytes() { -// java.lang.Object ref = name_; -// if (ref instanceof java.lang.String) { -// com.google.protobuf.ByteString b = -// com.google.protobuf.ByteString.copyFromUtf8( -// (java.lang.String) ref); -// name_ = b; -// return b; -// } else { -// return (com.google.protobuf.ByteString) ref; -// } -// } -// -// public static final int EMAIL_FIELD_NUMBER = 3; -// @SuppressWarnings("serial") -// private volatile java.lang.Object email_ = ""; -// /** -// * string email = 3; -// * @return The email. -// */ -// @java.lang.Override -// public java.lang.String getEmail() { -// java.lang.Object ref = email_; -// if (ref instanceof java.lang.String) { -// return (java.lang.String) ref; -// } else { -// com.google.protobuf.ByteString bs = -// (com.google.protobuf.ByteString) ref; -// java.lang.String s = bs.toStringUtf8(); -// email_ = s; -// return s; -// } -// } -// /** -// * string email = 3; -// * @return The bytes for email. -// */ -// @java.lang.Override -// public com.google.protobuf.ByteString -// getEmailBytes() { -// java.lang.Object ref = email_; -// if (ref instanceof java.lang.String) { -// com.google.protobuf.ByteString b = -// com.google.protobuf.ByteString.copyFromUtf8( -// (java.lang.String) ref); -// email_ = b; -// return b; -// } else { -// return (com.google.protobuf.ByteString) ref; -// } -// } -// -// private byte memoizedIsInitialized = -1; -// @java.lang.Override -// public final boolean isInitialized() { -// byte isInitialized = memoizedIsInitialized; -// if (isInitialized == 1) return true; -// if (isInitialized == 0) return false; -// -// memoizedIsInitialized = 1; -// return true; -// } -// -// @java.lang.Override -// public void writeTo(com.google.protobuf.CodedOutputStream output) -// throws java.io.IOException { -// if (id_ != 0) { -// output.writeSInt32(1, id_); -// } -// if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(name_)) { -// com.google.protobuf.GeneratedMessageV3.writeString(output, 2, name_); -// } -// if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(email_)) { -// com.google.protobuf.GeneratedMessageV3.writeString(output, 3, email_); -// } -// getUnknownFields().writeTo(output); -// } -// -// @java.lang.Override -// public int getSerializedSize() { -// int size = memoizedSize; -// if (size != -1) return size; -// -// size = 0; -// if (id_ != 0) { -// size += com.google.protobuf.CodedOutputStream -// .computeSInt32Size(1, id_); -// } -// if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(name_)) { -// size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, name_); -// } -// if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(email_)) { -// size += com.google.protobuf.GeneratedMessageV3.computeStringSize(3, email_); -// } -// size += getUnknownFields().getSerializedSize(); -// memoizedSize = size; -// return size; -// } -// -// @java.lang.Override -// public boolean equals(final java.lang.Object obj) { -// if (obj == this) { -// return true; -// } -// if (!(obj instanceof org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry)) { -// return super.equals(obj); -// } -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry other = -// (org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry) obj; -// -// if (getId() -// != other.getId()) return false; -// if (!getName() -// .equals(other.getName())) return false; -// if (!getEmail() -// .equals(other.getEmail())) return false; -// if (!getUnknownFields().equals(other.getUnknownFields())) return false; -// return true; -// } -// -// @java.lang.Override -// public int hashCode() { -// if (memoizedHashCode != 0) { -// return memoizedHashCode; -// } -// int hash = 41; -// hash = (19 * hash) + getDescriptor().hashCode(); -// hash = (37 * hash) + ID_FIELD_NUMBER; -// hash = (53 * hash) + getId(); -// hash = (37 * hash) + NAME_FIELD_NUMBER; -// hash = (53 * hash) + getName().hashCode(); -// hash = (37 * hash) + EMAIL_FIELD_NUMBER; -// hash = (53 * hash) + getEmail().hashCode(); -// hash = (29 * hash) + getUnknownFields().hashCode(); -// memoizedHashCode = hash; -// return hash; -// } -// -// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry parseFrom( -// java.nio.ByteBuffer data) -// throws com.google.protobuf.InvalidProtocolBufferException { -// return PARSER.parseFrom(data); -// } -// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry parseFrom( -// java.nio.ByteBuffer data, -// com.google.protobuf.ExtensionRegistryLite extensionRegistry) -// throws com.google.protobuf.InvalidProtocolBufferException { -// return PARSER.parseFrom(data, extensionRegistry); -// } -// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry parseFrom( -// com.google.protobuf.ByteString data) -// throws com.google.protobuf.InvalidProtocolBufferException { -// return PARSER.parseFrom(data); -// } -// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry parseFrom( -// com.google.protobuf.ByteString data, -// com.google.protobuf.ExtensionRegistryLite extensionRegistry) -// throws com.google.protobuf.InvalidProtocolBufferException { -// return PARSER.parseFrom(data, extensionRegistry); -// } -// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry parseFrom(byte[] data) -// throws com.google.protobuf.InvalidProtocolBufferException { -// return PARSER.parseFrom(data); -// } -// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry parseFrom( -// byte[] data, -// com.google.protobuf.ExtensionRegistryLite extensionRegistry) -// throws com.google.protobuf.InvalidProtocolBufferException { -// return PARSER.parseFrom(data, extensionRegistry); -// } -// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry -// parseFrom(java.io.InputStream input) -// throws java.io.IOException { -// return com.google.protobuf.GeneratedMessageV3 -// .parseWithIOException(PARSER, input); -// } -// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry parseFrom( -// java.io.InputStream input, -// com.google.protobuf.ExtensionRegistryLite extensionRegistry) -// throws java.io.IOException { -// return com.google.protobuf.GeneratedMessageV3 -// .parseWithIOException(PARSER, input, extensionRegistry); -// } -// -// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry -// parseDelimitedFrom(java.io.InputStream input) -// throws java.io.IOException { -// return com.google.protobuf.GeneratedMessageV3 -// .parseDelimitedWithIOException(PARSER, input); -// } -// -// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry parseDelimitedFrom( -// java.io.InputStream input, -// com.google.protobuf.ExtensionRegistryLite extensionRegistry) -// throws java.io.IOException { -// return com.google.protobuf.GeneratedMessageV3 -// .parseDelimitedWithIOException(PARSER, input, extensionRegistry); -// } -// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry parseFrom( -// com.google.protobuf.CodedInputStream input) -// throws java.io.IOException { -// return com.google.protobuf.GeneratedMessageV3 -// .parseWithIOException(PARSER, input); -// } -// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry parseFrom( -// com.google.protobuf.CodedInputStream input, -// com.google.protobuf.ExtensionRegistryLite extensionRegistry) -// throws java.io.IOException { -// return com.google.protobuf.GeneratedMessageV3 -// .parseWithIOException(PARSER, input, extensionRegistry); -// } -// -// @java.lang.Override -// public Builder newBuilderForType() { return newBuilder(); } -// public static Builder newBuilder() { -// return DEFAULT_INSTANCE.toBuilder(); -// } -// public static Builder newBuilder(org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry -// prototype) { -// return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); -// } -// @java.lang.Override -// public Builder toBuilder() { -// return this == DEFAULT_INSTANCE -// ? new Builder() : new Builder().mergeFrom(this); -// } -// -// @java.lang.Override -// protected Builder newBuilderForType( -// com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { -// Builder builder = new Builder(parent); -// return builder; -// } -// /** -// * Protobuf type {@code PSimpleBean.PSimpleEntry} -// */ -// public static final class Builder extends -// com.google.protobuf.GeneratedMessageV3.Builder implements -// // @@protoc_insertion_point(builder_implements:PSimpleBean.PSimpleEntry) -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntryOrBuilder { -// public static final com.google.protobuf.Descriptors.Descriptor -// getDescriptor() { -// return org.redkalex.test.protobuf.PSimpleBeanOuterClass.internal_static_PSimpleBean_PSimpleEntry_descriptor; -// } -// -// @java.lang.Override -// protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable -// internalGetFieldAccessorTable() { -// return -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.internal_static_PSimpleBean_PSimpleEntry_fieldAccessorTable -// .ensureFieldAccessorsInitialized( -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry.class, -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry.Builder.class); -// } -// -// // Construct using org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry.newBuilder() -// private Builder() { -// -// } -// -// private Builder( -// com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { -// super(parent); -// -// } -// @java.lang.Override -// public Builder clear() { -// super.clear(); -// bitField0_ = 0; -// id_ = 0; -// name_ = ""; -// email_ = ""; -// return this; -// } -// -// @java.lang.Override -// public com.google.protobuf.Descriptors.Descriptor -// getDescriptorForType() { -// return org.redkalex.test.protobuf.PSimpleBeanOuterClass.internal_static_PSimpleBean_PSimpleEntry_descriptor; -// } -// -// @java.lang.Override -// public org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry getDefaultInstanceForType() { -// return org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry.getDefaultInstance(); -// } -// -// @java.lang.Override -// public org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry build() { -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry result = buildPartial(); -// if (!result.isInitialized()) { -// throw newUninitializedMessageException(result); -// } -// return result; -// } -// -// @java.lang.Override -// public org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry buildPartial() { -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry result = new -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry(this); -// if (bitField0_ != 0) { buildPartial0(result); } -// onBuilt(); -// return result; -// } -// -// private void buildPartial0(org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry result) { -// int from_bitField0_ = bitField0_; -// if (((from_bitField0_ & 0x00000001) != 0)) { -// result.id_ = id_; -// } -// if (((from_bitField0_ & 0x00000002) != 0)) { -// result.name_ = name_; -// } -// if (((from_bitField0_ & 0x00000004) != 0)) { -// result.email_ = email_; -// } -// } -// -// @java.lang.Override -// public Builder clone() { -// return super.clone(); -// } -// @java.lang.Override -// public Builder setField( -// com.google.protobuf.Descriptors.FieldDescriptor field, -// java.lang.Object value) { -// return super.setField(field, value); -// } -// @java.lang.Override -// public Builder clearField( -// com.google.protobuf.Descriptors.FieldDescriptor field) { -// return super.clearField(field); -// } -// @java.lang.Override -// public Builder clearOneof( -// com.google.protobuf.Descriptors.OneofDescriptor oneof) { -// return super.clearOneof(oneof); -// } -// @java.lang.Override -// public Builder setRepeatedField( -// com.google.protobuf.Descriptors.FieldDescriptor field, -// int index, java.lang.Object value) { -// return super.setRepeatedField(field, index, value); -// } -// @java.lang.Override -// public Builder addRepeatedField( -// com.google.protobuf.Descriptors.FieldDescriptor field, -// java.lang.Object value) { -// return super.addRepeatedField(field, value); -// } -// @java.lang.Override -// public Builder mergeFrom(com.google.protobuf.Message other) { -// if (other instanceof org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry) { -// return mergeFrom((org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry)other); -// } else { -// super.mergeFrom(other); -// return this; -// } -// } -// -// public Builder mergeFrom(org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry other) { -// if (other == org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry.getDefaultInstance()) -// return this; -// if (other.getId() != 0) { -// setId(other.getId()); -// } -// if (!other.getName().isEmpty()) { -// name_ = other.name_; -// bitField0_ |= 0x00000002; -// onChanged(); -// } -// if (!other.getEmail().isEmpty()) { -// email_ = other.email_; -// bitField0_ |= 0x00000004; -// onChanged(); -// } -// this.mergeUnknownFields(other.getUnknownFields()); -// onChanged(); -// return this; -// } -// -// @java.lang.Override -// public final boolean isInitialized() { -// return true; -// } -// -// @java.lang.Override -// public Builder mergeFrom( -// com.google.protobuf.CodedInputStream input, -// com.google.protobuf.ExtensionRegistryLite extensionRegistry) -// throws java.io.IOException { -// if (extensionRegistry == null) { -// throw new java.lang.NullPointerException(); -// } -// try { -// boolean done = false; -// while (!done) { -// int tag = input.readTag(); -// switch (tag) { -// case 0: -// done = true; -// break; -// case 8: { -// id_ = input.readSInt32(); -// bitField0_ |= 0x00000001; -// break; -// } // case 8 -// case 18: { -// name_ = input.readStringRequireUtf8(); -// bitField0_ |= 0x00000002; -// break; -// } // case 18 -// case 26: { -// email_ = input.readStringRequireUtf8(); -// bitField0_ |= 0x00000004; -// break; -// } // case 26 -// default: { -// if (!super.parseUnknownField(input, extensionRegistry, tag)) { -// done = true; // was an endgroup tag -// } -// break; -// } // default: -// } // switch (tag) -// } // while (!done) -// } catch (com.google.protobuf.InvalidProtocolBufferException e) { -// throw e.unwrapIOException(); -// } finally { -// onChanged(); -// } // finally -// return this; -// } -// private int bitField0_; -// -// private int id_ ; -// /** -// * sint32 id = 1; -// * @return The id. -// */ -// @java.lang.Override -// public int getId() { -// return id_; -// } -// /** -// * sint32 id = 1; -// * @param value The id to set. -// * @return This builder for chaining. -// */ -// public Builder setId(int value) { -// -// id_ = value; -// bitField0_ |= 0x00000001; -// onChanged(); -// return this; -// } -// /** -// * sint32 id = 1; -// * @return This builder for chaining. -// */ -// public Builder clearId() { -// bitField0_ = (bitField0_ & ~0x00000001); -// id_ = 0; -// onChanged(); -// return this; -// } -// -// private java.lang.Object name_ = ""; -// /** -// * string name = 2; -// * @return The name. -// */ -// public java.lang.String getName() { -// java.lang.Object ref = name_; -// if (!(ref instanceof java.lang.String)) { -// com.google.protobuf.ByteString bs = -// (com.google.protobuf.ByteString) ref; -// java.lang.String s = bs.toStringUtf8(); -// name_ = s; -// return s; -// } else { -// return (java.lang.String) ref; -// } -// } -// /** -// * string name = 2; -// * @return The bytes for name. -// */ -// public com.google.protobuf.ByteString -// getNameBytes() { -// java.lang.Object ref = name_; -// if (ref instanceof String) { -// com.google.protobuf.ByteString b = -// com.google.protobuf.ByteString.copyFromUtf8( -// (java.lang.String) ref); -// name_ = b; -// return b; -// } else { -// return (com.google.protobuf.ByteString) ref; -// } -// } -// /** -// * string name = 2; -// * @param value The name to set. -// * @return This builder for chaining. -// */ -// public Builder setName( -// java.lang.String value) { -// if (value == null) { throw new NullPointerException(); } -// name_ = value; -// bitField0_ |= 0x00000002; -// onChanged(); -// return this; -// } -// /** -// * string name = 2; -// * @return This builder for chaining. -// */ -// public Builder clearName() { -// name_ = getDefaultInstance().getName(); -// bitField0_ = (bitField0_ & ~0x00000002); -// onChanged(); -// return this; -// } -// /** -// * string name = 2; -// * @param value The bytes for name to set. -// * @return This builder for chaining. -// */ -// public Builder setNameBytes( -// com.google.protobuf.ByteString value) { -// if (value == null) { throw new NullPointerException(); } -// checkByteStringIsUtf8(value); -// name_ = value; -// bitField0_ |= 0x00000002; -// onChanged(); -// return this; -// } -// -// private java.lang.Object email_ = ""; -// /** -// * string email = 3; -// * @return The email. -// */ -// public java.lang.String getEmail() { -// java.lang.Object ref = email_; -// if (!(ref instanceof java.lang.String)) { -// com.google.protobuf.ByteString bs = -// (com.google.protobuf.ByteString) ref; -// java.lang.String s = bs.toStringUtf8(); -// email_ = s; -// return s; -// } else { -// return (java.lang.String) ref; -// } -// } -// /** -// * string email = 3; -// * @return The bytes for email. -// */ -// public com.google.protobuf.ByteString -// getEmailBytes() { -// java.lang.Object ref = email_; -// if (ref instanceof String) { -// com.google.protobuf.ByteString b = -// com.google.protobuf.ByteString.copyFromUtf8( -// (java.lang.String) ref); -// email_ = b; -// return b; -// } else { -// return (com.google.protobuf.ByteString) ref; -// } -// } -// /** -// * string email = 3; -// * @param value The email to set. -// * @return This builder for chaining. -// */ -// public Builder setEmail( -// java.lang.String value) { -// if (value == null) { throw new NullPointerException(); } -// email_ = value; -// bitField0_ |= 0x00000004; -// onChanged(); -// return this; -// } -// /** -// * string email = 3; -// * @return This builder for chaining. -// */ -// public Builder clearEmail() { -// email_ = getDefaultInstance().getEmail(); -// bitField0_ = (bitField0_ & ~0x00000004); -// onChanged(); -// return this; -// } -// /** -// * string email = 3; -// * @param value The bytes for email to set. -// * @return This builder for chaining. -// */ -// public Builder setEmailBytes( -// com.google.protobuf.ByteString value) { -// if (value == null) { throw new NullPointerException(); } -// checkByteStringIsUtf8(value); -// email_ = value; -// bitField0_ |= 0x00000004; -// onChanged(); -// return this; -// } -// @java.lang.Override -// public final Builder setUnknownFields( -// final com.google.protobuf.UnknownFieldSet unknownFields) { -// return super.setUnknownFields(unknownFields); -// } -// -// @java.lang.Override -// public final Builder mergeUnknownFields( -// final com.google.protobuf.UnknownFieldSet unknownFields) { -// return super.mergeUnknownFields(unknownFields); -// } -// -// -// // @@protoc_insertion_point(builder_scope:PSimpleBean.PSimpleEntry) -// } -// -// // @@protoc_insertion_point(class_scope:PSimpleBean.PSimpleEntry) -// private static final org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry DEFAULT_INSTANCE; -// static { -// DEFAULT_INSTANCE = new org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry(); -// } -// -// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry getDefaultInstance() { -// return DEFAULT_INSTANCE; -// } -// -// private static final com.google.protobuf.Parser -// PARSER = new com.google.protobuf.AbstractParser() { -// @java.lang.Override -// public PSimpleEntry parsePartialFrom( -// com.google.protobuf.CodedInputStream input, -// com.google.protobuf.ExtensionRegistryLite extensionRegistry) -// throws com.google.protobuf.InvalidProtocolBufferException { -// Builder builder = newBuilder(); -// try { -// builder.mergeFrom(input, extensionRegistry); -// } catch (com.google.protobuf.InvalidProtocolBufferException e) { -// throw e.setUnfinishedMessage(builder.buildPartial()); -// } catch (com.google.protobuf.UninitializedMessageException e) { -// throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); -// } catch (java.io.IOException e) { -// throw new com.google.protobuf.InvalidProtocolBufferException(e) -// .setUnfinishedMessage(builder.buildPartial()); -// } -// return builder.buildPartial(); -// } -// }; -// -// public static com.google.protobuf.Parser parser() { -// return PARSER; -// } -// -// @java.lang.Override -// public com.google.protobuf.Parser getParserForType() { -// return PARSER; -// } -// -// @java.lang.Override -// public org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry getDefaultInstanceForType() { -// return DEFAULT_INSTANCE; -// } -// -// } -// -// public interface PTwoEntryOrBuilder extends -// // @@protoc_insertion_point(interface_extends:PSimpleBean.PTwoEntry) -// com.google.protobuf.MessageOrBuilder { -// -// /** -// * sint32 status = 1; -// * @return The status. -// */ -// int getStatus(); -// -// /** -// * sint64 createtime = 2; -// * @return The createtime. -// */ -// long getCreatetime(); -// } -// /** -// * Protobuf type {@code PSimpleBean.PTwoEntry} -// */ -// public static final class PTwoEntry extends -// com.google.protobuf.GeneratedMessageV3 implements -// // @@protoc_insertion_point(message_implements:PSimpleBean.PTwoEntry) -// PTwoEntryOrBuilder { -// private static final long serialVersionUID = 0L; -// // Use PTwoEntry.newBuilder() to construct. -// private PTwoEntry(com.google.protobuf.GeneratedMessageV3.Builder builder) { -// super(builder); -// } -// private PTwoEntry() { -// } -// -// @java.lang.Override -// @SuppressWarnings({"unused"}) -// protected java.lang.Object newInstance( -// UnusedPrivateParameter unused) { -// return new PTwoEntry(); -// } -// -// public static final com.google.protobuf.Descriptors.Descriptor -// getDescriptor() { -// return org.redkalex.test.protobuf.PSimpleBeanOuterClass.internal_static_PSimpleBean_PTwoEntry_descriptor; -// } -// -// @java.lang.Override -// protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable -// internalGetFieldAccessorTable() { -// return -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.internal_static_PSimpleBean_PTwoEntry_fieldAccessorTable -// .ensureFieldAccessorsInitialized( -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry.class, -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry.Builder.class); -// } -// -// public static final int STATUS_FIELD_NUMBER = 1; -// private int status_ = 0; -// /** -// * sint32 status = 1; -// * @return The status. -// */ -// @java.lang.Override -// public int getStatus() { -// return status_; -// } -// -// public static final int CREATETIME_FIELD_NUMBER = 2; -// private long createtime_ = 0L; -// /** -// * sint64 createtime = 2; -// * @return The createtime. -// */ -// @java.lang.Override -// public long getCreatetime() { -// return createtime_; -// } -// -// private byte memoizedIsInitialized = -1; -// @java.lang.Override -// public final boolean isInitialized() { -// byte isInitialized = memoizedIsInitialized; -// if (isInitialized == 1) return true; -// if (isInitialized == 0) return false; -// -// memoizedIsInitialized = 1; -// return true; -// } -// -// @java.lang.Override -// public void writeTo(com.google.protobuf.CodedOutputStream output) -// throws java.io.IOException { -// if (status_ != 0) { -// output.writeSInt32(1, status_); -// } -// if (createtime_ != 0L) { -// output.writeSInt64(2, createtime_); -// } -// getUnknownFields().writeTo(output); -// } -// -// @java.lang.Override -// public int getSerializedSize() { -// int size = memoizedSize; -// if (size != -1) return size; -// -// size = 0; -// if (status_ != 0) { -// size += com.google.protobuf.CodedOutputStream -// .computeSInt32Size(1, status_); -// } -// if (createtime_ != 0L) { -// size += com.google.protobuf.CodedOutputStream -// .computeSInt64Size(2, createtime_); -// } -// size += getUnknownFields().getSerializedSize(); -// memoizedSize = size; -// return size; -// } -// -// @java.lang.Override -// public boolean equals(final java.lang.Object obj) { -// if (obj == this) { -// return true; -// } -// if (!(obj instanceof org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry)) { -// return super.equals(obj); -// } -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry other = -// (org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry) obj; -// -// if (getStatus() -// != other.getStatus()) return false; -// if (getCreatetime() -// != other.getCreatetime()) return false; -// if (!getUnknownFields().equals(other.getUnknownFields())) return false; -// return true; -// } -// -// @java.lang.Override -// public int hashCode() { -// if (memoizedHashCode != 0) { -// return memoizedHashCode; -// } -// int hash = 41; -// hash = (19 * hash) + getDescriptor().hashCode(); -// hash = (37 * hash) + STATUS_FIELD_NUMBER; -// hash = (53 * hash) + getStatus(); -// hash = (37 * hash) + CREATETIME_FIELD_NUMBER; -// hash = (53 * hash) + com.google.protobuf.Internal.hashLong( -// getCreatetime()); -// hash = (29 * hash) + getUnknownFields().hashCode(); -// memoizedHashCode = hash; -// return hash; -// } -// -// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry parseFrom( -// java.nio.ByteBuffer data) -// throws com.google.protobuf.InvalidProtocolBufferException { -// return PARSER.parseFrom(data); -// } -// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry parseFrom( -// java.nio.ByteBuffer data, -// com.google.protobuf.ExtensionRegistryLite extensionRegistry) -// throws com.google.protobuf.InvalidProtocolBufferException { -// return PARSER.parseFrom(data, extensionRegistry); -// } -// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry parseFrom( -// com.google.protobuf.ByteString data) -// throws com.google.protobuf.InvalidProtocolBufferException { -// return PARSER.parseFrom(data); -// } -// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry parseFrom( -// com.google.protobuf.ByteString data, -// com.google.protobuf.ExtensionRegistryLite extensionRegistry) -// throws com.google.protobuf.InvalidProtocolBufferException { -// return PARSER.parseFrom(data, extensionRegistry); -// } -// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry parseFrom(byte[] data) -// throws com.google.protobuf.InvalidProtocolBufferException { -// return PARSER.parseFrom(data); -// } -// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry parseFrom( -// byte[] data, -// com.google.protobuf.ExtensionRegistryLite extensionRegistry) -// throws com.google.protobuf.InvalidProtocolBufferException { -// return PARSER.parseFrom(data, extensionRegistry); -// } -// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry -// parseFrom(java.io.InputStream input) -// throws java.io.IOException { -// return com.google.protobuf.GeneratedMessageV3 -// .parseWithIOException(PARSER, input); -// } -// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry parseFrom( -// java.io.InputStream input, -// com.google.protobuf.ExtensionRegistryLite extensionRegistry) -// throws java.io.IOException { -// return com.google.protobuf.GeneratedMessageV3 -// .parseWithIOException(PARSER, input, extensionRegistry); -// } -// -// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry -// parseDelimitedFrom(java.io.InputStream input) -// throws java.io.IOException { -// return com.google.protobuf.GeneratedMessageV3 -// .parseDelimitedWithIOException(PARSER, input); -// } -// -// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry parseDelimitedFrom( -// java.io.InputStream input, -// com.google.protobuf.ExtensionRegistryLite extensionRegistry) -// throws java.io.IOException { -// return com.google.protobuf.GeneratedMessageV3 -// .parseDelimitedWithIOException(PARSER, input, extensionRegistry); -// } -// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry parseFrom( -// com.google.protobuf.CodedInputStream input) -// throws java.io.IOException { -// return com.google.protobuf.GeneratedMessageV3 -// .parseWithIOException(PARSER, input); -// } -// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry parseFrom( -// com.google.protobuf.CodedInputStream input, -// com.google.protobuf.ExtensionRegistryLite extensionRegistry) -// throws java.io.IOException { -// return com.google.protobuf.GeneratedMessageV3 -// .parseWithIOException(PARSER, input, extensionRegistry); -// } -// -// @java.lang.Override -// public Builder newBuilderForType() { return newBuilder(); } -// public static Builder newBuilder() { -// return DEFAULT_INSTANCE.toBuilder(); -// } -// public static Builder newBuilder(org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry -// prototype) { -// return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); -// } -// @java.lang.Override -// public Builder toBuilder() { -// return this == DEFAULT_INSTANCE -// ? new Builder() : new Builder().mergeFrom(this); -// } -// -// @java.lang.Override -// protected Builder newBuilderForType( -// com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { -// Builder builder = new Builder(parent); -// return builder; -// } -// /** -// * Protobuf type {@code PSimpleBean.PTwoEntry} -// */ -// public static final class Builder extends -// com.google.protobuf.GeneratedMessageV3.Builder implements -// // @@protoc_insertion_point(builder_implements:PSimpleBean.PTwoEntry) -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntryOrBuilder { -// public static final com.google.protobuf.Descriptors.Descriptor -// getDescriptor() { -// return org.redkalex.test.protobuf.PSimpleBeanOuterClass.internal_static_PSimpleBean_PTwoEntry_descriptor; -// } -// -// @java.lang.Override -// protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable -// internalGetFieldAccessorTable() { -// return -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.internal_static_PSimpleBean_PTwoEntry_fieldAccessorTable -// .ensureFieldAccessorsInitialized( -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry.class, -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry.Builder.class); -// } -// -// // Construct using org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry.newBuilder() -// private Builder() { -// -// } -// -// private Builder( -// com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { -// super(parent); -// -// } -// @java.lang.Override -// public Builder clear() { -// super.clear(); -// bitField0_ = 0; -// status_ = 0; -// createtime_ = 0L; -// return this; -// } -// -// @java.lang.Override -// public com.google.protobuf.Descriptors.Descriptor -// getDescriptorForType() { -// return org.redkalex.test.protobuf.PSimpleBeanOuterClass.internal_static_PSimpleBean_PTwoEntry_descriptor; -// } -// -// @java.lang.Override -// public org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry getDefaultInstanceForType() { -// return org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry.getDefaultInstance(); -// } -// -// @java.lang.Override -// public org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry build() { -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry result = buildPartial(); -// if (!result.isInitialized()) { -// throw newUninitializedMessageException(result); -// } -// return result; -// } -// -// @java.lang.Override -// public org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry buildPartial() { -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry result = new -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry(this); -// if (bitField0_ != 0) { buildPartial0(result); } -// onBuilt(); -// return result; -// } -// -// private void buildPartial0(org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry result) { -// int from_bitField0_ = bitField0_; -// if (((from_bitField0_ & 0x00000001) != 0)) { -// result.status_ = status_; -// } -// if (((from_bitField0_ & 0x00000002) != 0)) { -// result.createtime_ = createtime_; -// } -// } -// -// @java.lang.Override -// public Builder clone() { -// return super.clone(); -// } -// @java.lang.Override -// public Builder setField( -// com.google.protobuf.Descriptors.FieldDescriptor field, -// java.lang.Object value) { -// return super.setField(field, value); -// } -// @java.lang.Override -// public Builder clearField( -// com.google.protobuf.Descriptors.FieldDescriptor field) { -// return super.clearField(field); -// } -// @java.lang.Override -// public Builder clearOneof( -// com.google.protobuf.Descriptors.OneofDescriptor oneof) { -// return super.clearOneof(oneof); -// } -// @java.lang.Override -// public Builder setRepeatedField( -// com.google.protobuf.Descriptors.FieldDescriptor field, -// int index, java.lang.Object value) { -// return super.setRepeatedField(field, index, value); -// } -// @java.lang.Override -// public Builder addRepeatedField( -// com.google.protobuf.Descriptors.FieldDescriptor field, -// java.lang.Object value) { -// return super.addRepeatedField(field, value); -// } -// @java.lang.Override -// public Builder mergeFrom(com.google.protobuf.Message other) { -// if (other instanceof org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry) { -// return mergeFrom((org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry)other); -// } else { -// super.mergeFrom(other); -// return this; -// } -// } -// -// public Builder mergeFrom(org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry other) { -// if (other == org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry.getDefaultInstance()) -// return this; -// if (other.getStatus() != 0) { -// setStatus(other.getStatus()); -// } -// if (other.getCreatetime() != 0L) { -// setCreatetime(other.getCreatetime()); -// } -// this.mergeUnknownFields(other.getUnknownFields()); -// onChanged(); -// return this; -// } -// -// @java.lang.Override -// public final boolean isInitialized() { -// return true; -// } -// -// @java.lang.Override -// public Builder mergeFrom( -// com.google.protobuf.CodedInputStream input, -// com.google.protobuf.ExtensionRegistryLite extensionRegistry) -// throws java.io.IOException { -// if (extensionRegistry == null) { -// throw new java.lang.NullPointerException(); -// } -// try { -// boolean done = false; -// while (!done) { -// int tag = input.readTag(); -// switch (tag) { -// case 0: -// done = true; -// break; -// case 8: { -// status_ = input.readSInt32(); -// bitField0_ |= 0x00000001; -// break; -// } // case 8 -// case 16: { -// createtime_ = input.readSInt64(); -// bitField0_ |= 0x00000002; -// break; -// } // case 16 -// default: { -// if (!super.parseUnknownField(input, extensionRegistry, tag)) { -// done = true; // was an endgroup tag -// } -// break; -// } // default: -// } // switch (tag) -// } // while (!done) -// } catch (com.google.protobuf.InvalidProtocolBufferException e) { -// throw e.unwrapIOException(); -// } finally { -// onChanged(); -// } // finally -// return this; -// } -// private int bitField0_; -// -// private int status_ ; -// /** -// * sint32 status = 1; -// * @return The status. -// */ -// @java.lang.Override -// public int getStatus() { -// return status_; -// } -// /** -// * sint32 status = 1; -// * @param value The status to set. -// * @return This builder for chaining. -// */ -// public Builder setStatus(int value) { -// -// status_ = value; -// bitField0_ |= 0x00000001; -// onChanged(); -// return this; -// } -// /** -// * sint32 status = 1; -// * @return This builder for chaining. -// */ -// public Builder clearStatus() { -// bitField0_ = (bitField0_ & ~0x00000001); -// status_ = 0; -// onChanged(); -// return this; -// } -// -// private long createtime_ ; -// /** -// * sint64 createtime = 2; -// * @return The createtime. -// */ -// @java.lang.Override -// public long getCreatetime() { -// return createtime_; -// } -// /** -// * sint64 createtime = 2; -// * @param value The createtime to set. -// * @return This builder for chaining. -// */ -// public Builder setCreatetime(long value) { -// -// createtime_ = value; -// bitField0_ |= 0x00000002; -// onChanged(); -// return this; -// } -// /** -// * sint64 createtime = 2; -// * @return This builder for chaining. -// */ -// public Builder clearCreatetime() { -// bitField0_ = (bitField0_ & ~0x00000002); -// createtime_ = 0L; -// onChanged(); -// return this; -// } -// @java.lang.Override -// public final Builder setUnknownFields( -// final com.google.protobuf.UnknownFieldSet unknownFields) { -// return super.setUnknownFields(unknownFields); -// } -// -// @java.lang.Override -// public final Builder mergeUnknownFields( -// final com.google.protobuf.UnknownFieldSet unknownFields) { -// return super.mergeUnknownFields(unknownFields); -// } -// -// -// // @@protoc_insertion_point(builder_scope:PSimpleBean.PTwoEntry) -// } -// -// // @@protoc_insertion_point(class_scope:PSimpleBean.PTwoEntry) -// private static final org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry DEFAULT_INSTANCE; -// static { -// DEFAULT_INSTANCE = new org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry(); -// } -// -// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry getDefaultInstance() { -// return DEFAULT_INSTANCE; -// } -// -// private static final com.google.protobuf.Parser -// PARSER = new com.google.protobuf.AbstractParser() { -// @java.lang.Override -// public PTwoEntry parsePartialFrom( -// com.google.protobuf.CodedInputStream input, -// com.google.protobuf.ExtensionRegistryLite extensionRegistry) -// throws com.google.protobuf.InvalidProtocolBufferException { -// Builder builder = newBuilder(); -// try { -// builder.mergeFrom(input, extensionRegistry); -// } catch (com.google.protobuf.InvalidProtocolBufferException e) { -// throw e.setUnfinishedMessage(builder.buildPartial()); -// } catch (com.google.protobuf.UninitializedMessageException e) { -// throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); -// } catch (java.io.IOException e) { -// throw new com.google.protobuf.InvalidProtocolBufferException(e) -// .setUnfinishedMessage(builder.buildPartial()); -// } -// return builder.buildPartial(); -// } -// }; -// -// public static com.google.protobuf.Parser parser() { -// return PARSER; -// } -// -// @java.lang.Override -// public com.google.protobuf.Parser getParserForType() { -// return PARSER; -// } -// -// @java.lang.Override -// public org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry getDefaultInstanceForType() { -// return DEFAULT_INSTANCE; -// } -// -// } -// -// public static final int SIMPLE_FIELD_NUMBER = 1; -// private org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry simple_; -// /** -// * .PSimpleBean.PSimpleEntry simple = 1; -// * @return Whether the simple field is set. -// */ -// @java.lang.Override -// public boolean hasSimple() { -// return simple_ != null; -// } -// /** -// * .PSimpleBean.PSimpleEntry simple = 1; -// * @return The simple. -// */ -// @java.lang.Override -// public org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry getSimple() { -// return simple_ == null ? -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry.getDefaultInstance() : simple_; -// } -// /** -// * .PSimpleBean.PSimpleEntry simple = 1; -// */ -// @java.lang.Override -// public org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntryOrBuilder getSimpleOrBuilder() { -// return simple_ == null ? -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry.getDefaultInstance() : simple_; -// } -// -// public static final int TWO_FIELD_NUMBER = 2; -// private org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry two_; -// /** -// * .PSimpleBean.PTwoEntry two = 2; -// * @return Whether the two field is set. -// */ -// @java.lang.Override -// public boolean hasTwo() { -// return two_ != null; -// } -// /** -// * .PSimpleBean.PTwoEntry two = 2; -// * @return The two. -// */ -// @java.lang.Override -// public org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry getTwo() { -// return two_ == null ? -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry.getDefaultInstance() : two_; -// } -// /** -// * .PSimpleBean.PTwoEntry two = 2; -// */ -// @java.lang.Override -// public org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntryOrBuilder getTwoOrBuilder() { -// return two_ == null ? -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry.getDefaultInstance() : two_; -// } -// -// public static final int STRINGS_FIELD_NUMBER = 3; -// @SuppressWarnings("serial") -// private volatile java.lang.Object strings_ = ""; -// /** -// * string strings = 3; -// * @return The strings. -// */ -// @java.lang.Override -// public java.lang.String getStrings() { -// java.lang.Object ref = strings_; -// if (ref instanceof java.lang.String) { -// return (java.lang.String) ref; -// } else { -// com.google.protobuf.ByteString bs = -// (com.google.protobuf.ByteString) ref; -// java.lang.String s = bs.toStringUtf8(); -// strings_ = s; -// return s; -// } -// } -// /** -// * string strings = 3; -// * @return The bytes for strings. -// */ -// @java.lang.Override -// public com.google.protobuf.ByteString -// getStringsBytes() { -// java.lang.Object ref = strings_; -// if (ref instanceof java.lang.String) { -// com.google.protobuf.ByteString b = -// com.google.protobuf.ByteString.copyFromUtf8( -// (java.lang.String) ref); -// strings_ = b; -// return b; -// } else { -// return (com.google.protobuf.ByteString) ref; -// } -// } -// -// private byte memoizedIsInitialized = -1; -// @java.lang.Override -// public final boolean isInitialized() { -// byte isInitialized = memoizedIsInitialized; -// if (isInitialized == 1) return true; -// if (isInitialized == 0) return false; -// -// memoizedIsInitialized = 1; -// return true; -// } -// -// @java.lang.Override -// public void writeTo(com.google.protobuf.CodedOutputStream output) -// throws java.io.IOException { -// if (simple_ != null) { -// output.writeMessage(1, getSimple()); -// } -// if (two_ != null) { -// output.writeMessage(2, getTwo()); -// } -// if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(strings_)) { -// com.google.protobuf.GeneratedMessageV3.writeString(output, 3, strings_); -// } -// getUnknownFields().writeTo(output); -// } -// -// @java.lang.Override -// public int getSerializedSize() { -// int size = memoizedSize; -// if (size != -1) return size; -// -// size = 0; -// if (simple_ != null) { -// size += com.google.protobuf.CodedOutputStream -// .computeMessageSize(1, getSimple()); -// } -// if (two_ != null) { -// size += com.google.protobuf.CodedOutputStream -// .computeMessageSize(2, getTwo()); -// } -// if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(strings_)) { -// size += com.google.protobuf.GeneratedMessageV3.computeStringSize(3, strings_); -// } -// size += getUnknownFields().getSerializedSize(); -// memoizedSize = size; -// return size; -// } -// -// @java.lang.Override -// public boolean equals(final java.lang.Object obj) { -// if (obj == this) { -// return true; -// } -// if (!(obj instanceof org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean)) { -// return super.equals(obj); -// } -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean other = -// (org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean) obj; -// -// if (hasSimple() != other.hasSimple()) return false; -// if (hasSimple()) { -// if (!getSimple() -// .equals(other.getSimple())) return false; -// } -// if (hasTwo() != other.hasTwo()) return false; -// if (hasTwo()) { -// if (!getTwo() -// .equals(other.getTwo())) return false; -// } -// if (!getStrings() -// .equals(other.getStrings())) return false; -// if (!getUnknownFields().equals(other.getUnknownFields())) return false; -// return true; -// } -// -// @java.lang.Override -// public int hashCode() { -// if (memoizedHashCode != 0) { -// return memoizedHashCode; -// } -// int hash = 41; -// hash = (19 * hash) + getDescriptor().hashCode(); -// if (hasSimple()) { -// hash = (37 * hash) + SIMPLE_FIELD_NUMBER; -// hash = (53 * hash) + getSimple().hashCode(); -// } -// if (hasTwo()) { -// hash = (37 * hash) + TWO_FIELD_NUMBER; -// hash = (53 * hash) + getTwo().hashCode(); -// } -// hash = (37 * hash) + STRINGS_FIELD_NUMBER; -// hash = (53 * hash) + getStrings().hashCode(); -// hash = (29 * hash) + getUnknownFields().hashCode(); -// memoizedHashCode = hash; -// return hash; -// } -// -// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean parseFrom( -// java.nio.ByteBuffer data) -// throws com.google.protobuf.InvalidProtocolBufferException { -// return PARSER.parseFrom(data); -// } -// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean parseFrom( -// java.nio.ByteBuffer data, -// com.google.protobuf.ExtensionRegistryLite extensionRegistry) -// throws com.google.protobuf.InvalidProtocolBufferException { -// return PARSER.parseFrom(data, extensionRegistry); -// } -// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean parseFrom( -// com.google.protobuf.ByteString data) -// throws com.google.protobuf.InvalidProtocolBufferException { -// return PARSER.parseFrom(data); -// } -// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean parseFrom( -// com.google.protobuf.ByteString data, -// com.google.protobuf.ExtensionRegistryLite extensionRegistry) -// throws com.google.protobuf.InvalidProtocolBufferException { -// return PARSER.parseFrom(data, extensionRegistry); -// } -// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean parseFrom(byte[] data) -// throws com.google.protobuf.InvalidProtocolBufferException { -// return PARSER.parseFrom(data); -// } -// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean parseFrom( -// byte[] data, -// com.google.protobuf.ExtensionRegistryLite extensionRegistry) -// throws com.google.protobuf.InvalidProtocolBufferException { -// return PARSER.parseFrom(data, extensionRegistry); -// } -// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean parseFrom(java.io.InputStream input) -// throws java.io.IOException { -// return com.google.protobuf.GeneratedMessageV3 -// .parseWithIOException(PARSER, input); -// } -// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean parseFrom( -// java.io.InputStream input, -// com.google.protobuf.ExtensionRegistryLite extensionRegistry) -// throws java.io.IOException { -// return com.google.protobuf.GeneratedMessageV3 -// .parseWithIOException(PARSER, input, extensionRegistry); -// } -// -// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean parseDelimitedFrom(java.io.InputStream -// input) -// throws java.io.IOException { -// return com.google.protobuf.GeneratedMessageV3 -// .parseDelimitedWithIOException(PARSER, input); -// } -// -// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean parseDelimitedFrom( -// java.io.InputStream input, -// com.google.protobuf.ExtensionRegistryLite extensionRegistry) -// throws java.io.IOException { -// return com.google.protobuf.GeneratedMessageV3 -// .parseDelimitedWithIOException(PARSER, input, extensionRegistry); -// } -// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean parseFrom( -// com.google.protobuf.CodedInputStream input) -// throws java.io.IOException { -// return com.google.protobuf.GeneratedMessageV3 -// .parseWithIOException(PARSER, input); -// } -// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean parseFrom( -// com.google.protobuf.CodedInputStream input, -// com.google.protobuf.ExtensionRegistryLite extensionRegistry) -// throws java.io.IOException { -// return com.google.protobuf.GeneratedMessageV3 -// .parseWithIOException(PARSER, input, extensionRegistry); -// } -// -// @java.lang.Override -// public Builder newBuilderForType() { return newBuilder(); } -// public static Builder newBuilder() { -// return DEFAULT_INSTANCE.toBuilder(); -// } -// public static Builder newBuilder(org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean prototype) { -// return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); -// } -// @java.lang.Override -// public Builder toBuilder() { -// return this == DEFAULT_INSTANCE -// ? new Builder() : new Builder().mergeFrom(this); -// } -// -// @java.lang.Override -// protected Builder newBuilderForType( -// com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { -// Builder builder = new Builder(parent); -// return builder; -// } -// /** -// * Protobuf type {@code PSimpleBean} -// */ -// public static final class Builder extends -// com.google.protobuf.GeneratedMessageV3.Builder implements -// // @@protoc_insertion_point(builder_implements:PSimpleBean) -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBeanOrBuilder { -// public static final com.google.protobuf.Descriptors.Descriptor -// getDescriptor() { -// return org.redkalex.test.protobuf.PSimpleBeanOuterClass.internal_static_PSimpleBean_descriptor; -// } -// -// @java.lang.Override -// protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable -// internalGetFieldAccessorTable() { -// return org.redkalex.test.protobuf.PSimpleBeanOuterClass.internal_static_PSimpleBean_fieldAccessorTable -// .ensureFieldAccessorsInitialized( -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.class, -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.Builder.class); -// } -// -// // Construct using org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.newBuilder() -// private Builder() { -// -// } -// -// private Builder( -// com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { -// super(parent); -// -// } -// @java.lang.Override -// public Builder clear() { -// super.clear(); -// bitField0_ = 0; -// simple_ = null; -// if (simpleBuilder_ != null) { -// simpleBuilder_.dispose(); -// simpleBuilder_ = null; -// } -// two_ = null; -// if (twoBuilder_ != null) { -// twoBuilder_.dispose(); -// twoBuilder_ = null; -// } -// strings_ = ""; -// return this; -// } -// -// @java.lang.Override -// public com.google.protobuf.Descriptors.Descriptor -// getDescriptorForType() { -// return org.redkalex.test.protobuf.PSimpleBeanOuterClass.internal_static_PSimpleBean_descriptor; -// } -// -// @java.lang.Override -// public org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean getDefaultInstanceForType() { -// return org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.getDefaultInstance(); -// } -// -// @java.lang.Override -// public org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean build() { -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean result = buildPartial(); -// if (!result.isInitialized()) { -// throw newUninitializedMessageException(result); -// } -// return result; -// } -// -// @java.lang.Override -// public org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean buildPartial() { -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean result = new -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean(this); -// if (bitField0_ != 0) { buildPartial0(result); } -// onBuilt(); -// return result; -// } -// -// private void buildPartial0(org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean result) { -// int from_bitField0_ = bitField0_; -// if (((from_bitField0_ & 0x00000001) != 0)) { -// result.simple_ = simpleBuilder_ == null -// ? simple_ -// : simpleBuilder_.build(); -// } -// if (((from_bitField0_ & 0x00000002) != 0)) { -// result.two_ = twoBuilder_ == null -// ? two_ -// : twoBuilder_.build(); -// } -// if (((from_bitField0_ & 0x00000004) != 0)) { -// result.strings_ = strings_; -// } -// } -// -// @java.lang.Override -// public Builder clone() { -// return super.clone(); -// } -// @java.lang.Override -// public Builder setField( -// com.google.protobuf.Descriptors.FieldDescriptor field, -// java.lang.Object value) { -// return super.setField(field, value); -// } -// @java.lang.Override -// public Builder clearField( -// com.google.protobuf.Descriptors.FieldDescriptor field) { -// return super.clearField(field); -// } -// @java.lang.Override -// public Builder clearOneof( -// com.google.protobuf.Descriptors.OneofDescriptor oneof) { -// return super.clearOneof(oneof); -// } -// @java.lang.Override -// public Builder setRepeatedField( -// com.google.protobuf.Descriptors.FieldDescriptor field, -// int index, java.lang.Object value) { -// return super.setRepeatedField(field, index, value); -// } -// @java.lang.Override -// public Builder addRepeatedField( -// com.google.protobuf.Descriptors.FieldDescriptor field, -// java.lang.Object value) { -// return super.addRepeatedField(field, value); -// } -// @java.lang.Override -// public Builder mergeFrom(com.google.protobuf.Message other) { -// if (other instanceof org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean) { -// return mergeFrom((org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean)other); -// } else { -// super.mergeFrom(other); -// return this; -// } -// } -// -// public Builder mergeFrom(org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean other) { -// if (other == org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.getDefaultInstance()) return this; -// if (other.hasSimple()) { -// mergeSimple(other.getSimple()); -// } -// if (other.hasTwo()) { -// mergeTwo(other.getTwo()); -// } -// if (!other.getStrings().isEmpty()) { -// strings_ = other.strings_; -// bitField0_ |= 0x00000004; -// onChanged(); -// } -// this.mergeUnknownFields(other.getUnknownFields()); -// onChanged(); -// return this; -// } -// -// @java.lang.Override -// public final boolean isInitialized() { -// return true; -// } -// -// @java.lang.Override -// public Builder mergeFrom( -// com.google.protobuf.CodedInputStream input, -// com.google.protobuf.ExtensionRegistryLite extensionRegistry) -// throws java.io.IOException { -// if (extensionRegistry == null) { -// throw new java.lang.NullPointerException(); -// } -// try { -// boolean done = false; -// while (!done) { -// int tag = input.readTag(); -// switch (tag) { -// case 0: -// done = true; -// break; -// case 10: { -// input.readMessage( -// getSimpleFieldBuilder().getBuilder(), -// extensionRegistry); -// bitField0_ |= 0x00000001; -// break; -// } // case 10 -// case 18: { -// input.readMessage( -// getTwoFieldBuilder().getBuilder(), -// extensionRegistry); -// bitField0_ |= 0x00000002; -// break; -// } // case 18 -// case 26: { -// strings_ = input.readStringRequireUtf8(); -// bitField0_ |= 0x00000004; -// break; -// } // case 26 -// default: { -// if (!super.parseUnknownField(input, extensionRegistry, tag)) { -// done = true; // was an endgroup tag -// } -// break; -// } // default: -// } // switch (tag) -// } // while (!done) -// } catch (com.google.protobuf.InvalidProtocolBufferException e) { -// throw e.unwrapIOException(); -// } finally { -// onChanged(); -// } // finally -// return this; -// } -// private int bitField0_; -// -// private org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry simple_; -// private com.google.protobuf.SingleFieldBuilderV3< -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry, -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry.Builder, -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntryOrBuilder> simpleBuilder_; -// /** -// * .PSimpleBean.PSimpleEntry simple = 1; -// * @return Whether the simple field is set. -// */ -// public boolean hasSimple() { -// return ((bitField0_ & 0x00000001) != 0); -// } -// /** -// * .PSimpleBean.PSimpleEntry simple = 1; -// * @return The simple. -// */ -// public org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry getSimple() { -// if (simpleBuilder_ == null) { -// return simple_ == null ? -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry.getDefaultInstance() : simple_; -// } else { -// return simpleBuilder_.getMessage(); -// } -// } -// /** -// * .PSimpleBean.PSimpleEntry simple = 1; -// */ -// public Builder setSimple(org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry value) { -// if (simpleBuilder_ == null) { -// if (value == null) { -// throw new NullPointerException(); -// } -// simple_ = value; -// } else { -// simpleBuilder_.setMessage(value); -// } -// bitField0_ |= 0x00000001; -// onChanged(); -// return this; -// } -// /** -// * .PSimpleBean.PSimpleEntry simple = 1; -// */ -// public Builder setSimple( -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry.Builder builderForValue) { -// if (simpleBuilder_ == null) { -// simple_ = builderForValue.build(); -// } else { -// simpleBuilder_.setMessage(builderForValue.build()); -// } -// bitField0_ |= 0x00000001; -// onChanged(); -// return this; -// } -// /** -// * .PSimpleBean.PSimpleEntry simple = 1; -// */ -// public Builder mergeSimple(org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry value) { -// if (simpleBuilder_ == null) { -// if (((bitField0_ & 0x00000001) != 0) && -// simple_ != null && -// simple_ != org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry.getDefaultInstance()) -// { -// getSimpleBuilder().mergeFrom(value); -// } else { -// simple_ = value; -// } -// } else { -// simpleBuilder_.mergeFrom(value); -// } -// bitField0_ |= 0x00000001; -// onChanged(); -// return this; -// } -// /** -// * .PSimpleBean.PSimpleEntry simple = 1; -// */ -// public Builder clearSimple() { -// bitField0_ = (bitField0_ & ~0x00000001); -// simple_ = null; -// if (simpleBuilder_ != null) { -// simpleBuilder_.dispose(); -// simpleBuilder_ = null; -// } -// onChanged(); -// return this; -// } -// /** -// * .PSimpleBean.PSimpleEntry simple = 1; -// */ -// public org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry.Builder getSimpleBuilder() { -// bitField0_ |= 0x00000001; -// onChanged(); -// return getSimpleFieldBuilder().getBuilder(); -// } -// /** -// * .PSimpleBean.PSimpleEntry simple = 1; -// */ -// public org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntryOrBuilder getSimpleOrBuilder() { -// if (simpleBuilder_ != null) { -// return simpleBuilder_.getMessageOrBuilder(); -// } else { -// return simple_ == null ? -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry.getDefaultInstance() : -// simple_; -// } -// } -// /** -// * .PSimpleBean.PSimpleEntry simple = 1; -// */ -// private com.google.protobuf.SingleFieldBuilderV3< -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry, -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry.Builder, -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntryOrBuilder> -// getSimpleFieldBuilder() { -// if (simpleBuilder_ == null) { -// simpleBuilder_ = new com.google.protobuf.SingleFieldBuilderV3< -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry, -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry.Builder, -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntryOrBuilder>( -// getSimple(), -// getParentForChildren(), -// isClean()); -// simple_ = null; -// } -// return simpleBuilder_; -// } -// -// private org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry two_; -// private com.google.protobuf.SingleFieldBuilderV3< -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry, -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry.Builder, -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntryOrBuilder> twoBuilder_; -// /** -// * .PSimpleBean.PTwoEntry two = 2; -// * @return Whether the two field is set. -// */ -// public boolean hasTwo() { -// return ((bitField0_ & 0x00000002) != 0); -// } -// /** -// * .PSimpleBean.PTwoEntry two = 2; -// * @return The two. -// */ -// public org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry getTwo() { -// if (twoBuilder_ == null) { -// return two_ == null ? -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry.getDefaultInstance() : two_; -// } else { -// return twoBuilder_.getMessage(); -// } -// } -// /** -// * .PSimpleBean.PTwoEntry two = 2; -// */ -// public Builder setTwo(org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry value) { -// if (twoBuilder_ == null) { -// if (value == null) { -// throw new NullPointerException(); -// } -// two_ = value; -// } else { -// twoBuilder_.setMessage(value); -// } -// bitField0_ |= 0x00000002; -// onChanged(); -// return this; -// } -// /** -// * .PSimpleBean.PTwoEntry two = 2; -// */ -// public Builder setTwo( -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry.Builder builderForValue) { -// if (twoBuilder_ == null) { -// two_ = builderForValue.build(); -// } else { -// twoBuilder_.setMessage(builderForValue.build()); -// } -// bitField0_ |= 0x00000002; -// onChanged(); -// return this; -// } -// /** -// * .PSimpleBean.PTwoEntry two = 2; -// */ -// public Builder mergeTwo(org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry value) { -// if (twoBuilder_ == null) { -// if (((bitField0_ & 0x00000002) != 0) && -// two_ != null && -// two_ != org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry.getDefaultInstance()) { -// getTwoBuilder().mergeFrom(value); -// } else { -// two_ = value; -// } -// } else { -// twoBuilder_.mergeFrom(value); -// } -// bitField0_ |= 0x00000002; -// onChanged(); -// return this; -// } -// /** -// * .PSimpleBean.PTwoEntry two = 2; -// */ -// public Builder clearTwo() { -// bitField0_ = (bitField0_ & ~0x00000002); -// two_ = null; -// if (twoBuilder_ != null) { -// twoBuilder_.dispose(); -// twoBuilder_ = null; -// } -// onChanged(); -// return this; -// } -// /** -// * .PSimpleBean.PTwoEntry two = 2; -// */ -// public org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry.Builder getTwoBuilder() { -// bitField0_ |= 0x00000002; -// onChanged(); -// return getTwoFieldBuilder().getBuilder(); -// } -// /** -// * .PSimpleBean.PTwoEntry two = 2; -// */ -// public org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntryOrBuilder getTwoOrBuilder() { -// if (twoBuilder_ != null) { -// return twoBuilder_.getMessageOrBuilder(); -// } else { -// return two_ == null ? -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry.getDefaultInstance() : two_; -// } -// } -// /** -// * .PSimpleBean.PTwoEntry two = 2; -// */ -// private com.google.protobuf.SingleFieldBuilderV3< -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry, -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry.Builder, -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntryOrBuilder> -// getTwoFieldBuilder() { -// if (twoBuilder_ == null) { -// twoBuilder_ = new com.google.protobuf.SingleFieldBuilderV3< -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry, -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry.Builder, -// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntryOrBuilder>( -// getTwo(), -// getParentForChildren(), -// isClean()); -// two_ = null; -// } -// return twoBuilder_; -// } -// -// private java.lang.Object strings_ = ""; -// /** -// * string strings = 3; -// * @return The strings. -// */ -// public java.lang.String getStrings() { -// java.lang.Object ref = strings_; -// if (!(ref instanceof java.lang.String)) { -// com.google.protobuf.ByteString bs = -// (com.google.protobuf.ByteString) ref; -// java.lang.String s = bs.toStringUtf8(); -// strings_ = s; -// return s; -// } else { -// return (java.lang.String) ref; -// } -// } -// /** -// * string strings = 3; -// * @return The bytes for strings. -// */ -// public com.google.protobuf.ByteString -// getStringsBytes() { -// java.lang.Object ref = strings_; -// if (ref instanceof String) { -// com.google.protobuf.ByteString b = -// com.google.protobuf.ByteString.copyFromUtf8( -// (java.lang.String) ref); -// strings_ = b; -// return b; -// } else { -// return (com.google.protobuf.ByteString) ref; -// } -// } -// /** -// * string strings = 3; -// * @param value The strings to set. -// * @return This builder for chaining. -// */ -// public Builder setStrings( -// java.lang.String value) { -// if (value == null) { throw new NullPointerException(); } -// strings_ = value; -// bitField0_ |= 0x00000004; -// onChanged(); -// return this; -// } -// /** -// * string strings = 3; -// * @return This builder for chaining. -// */ -// public Builder clearStrings() { -// strings_ = getDefaultInstance().getStrings(); -// bitField0_ = (bitField0_ & ~0x00000004); -// onChanged(); -// return this; -// } -// /** -// * string strings = 3; -// * @param value The bytes for strings to set. -// * @return This builder for chaining. -// */ -// public Builder setStringsBytes( -// com.google.protobuf.ByteString value) { -// if (value == null) { throw new NullPointerException(); } -// checkByteStringIsUtf8(value); -// strings_ = value; -// bitField0_ |= 0x00000004; -// onChanged(); -// return this; -// } -// @java.lang.Override -// public final Builder setUnknownFields( -// final com.google.protobuf.UnknownFieldSet unknownFields) { -// return super.setUnknownFields(unknownFields); -// } -// -// @java.lang.Override -// public final Builder mergeUnknownFields( -// final com.google.protobuf.UnknownFieldSet unknownFields) { -// return super.mergeUnknownFields(unknownFields); -// } -// -// -// // @@protoc_insertion_point(builder_scope:PSimpleBean) -// } -// -// // @@protoc_insertion_point(class_scope:PSimpleBean) -// private static final org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean DEFAULT_INSTANCE; -// static { -// DEFAULT_INSTANCE = new org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean(); -// } -// -// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean getDefaultInstance() { -// return DEFAULT_INSTANCE; -// } -// -// private static final com.google.protobuf.Parser -// PARSER = new com.google.protobuf.AbstractParser() { -// @java.lang.Override -// public PSimpleBean parsePartialFrom( -// com.google.protobuf.CodedInputStream input, -// com.google.protobuf.ExtensionRegistryLite extensionRegistry) -// throws com.google.protobuf.InvalidProtocolBufferException { -// Builder builder = newBuilder(); -// try { -// builder.mergeFrom(input, extensionRegistry); -// } catch (com.google.protobuf.InvalidProtocolBufferException e) { -// throw e.setUnfinishedMessage(builder.buildPartial()); -// } catch (com.google.protobuf.UninitializedMessageException e) { -// throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); -// } catch (java.io.IOException e) { -// throw new com.google.protobuf.InvalidProtocolBufferException(e) -// .setUnfinishedMessage(builder.buildPartial()); -// } -// return builder.buildPartial(); -// } -// }; -// -// public static com.google.protobuf.Parser parser() { -// return PARSER; -// } -// -// @java.lang.Override -// public com.google.protobuf.Parser getParserForType() { -// return PARSER; -// } -// -// @java.lang.Override -// public org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean getDefaultInstanceForType() { -// return DEFAULT_INSTANCE; -// } -// -// } -// -// private static final com.google.protobuf.Descriptors.Descriptor -// internal_static_PSimpleBean_descriptor; -// private static final -// com.google.protobuf.GeneratedMessageV3.FieldAccessorTable -// internal_static_PSimpleBean_fieldAccessorTable; -// private static final com.google.protobuf.Descriptors.Descriptor -// internal_static_PSimpleBean_PSimpleEntry_descriptor; -// private static final -// com.google.protobuf.GeneratedMessageV3.FieldAccessorTable -// internal_static_PSimpleBean_PSimpleEntry_fieldAccessorTable; -// private static final com.google.protobuf.Descriptors.Descriptor -// internal_static_PSimpleBean_PTwoEntry_descriptor; -// private static final -// com.google.protobuf.GeneratedMessageV3.FieldAccessorTable -// internal_static_PSimpleBean_PTwoEntry_fieldAccessorTable; -// -// public static com.google.protobuf.Descriptors.FileDescriptor -// getDescriptor() { -// return descriptor; -// } -// private static com.google.protobuf.Descriptors.FileDescriptor -// descriptor; -// static { -// java.lang.String[] descriptorData = { -// "\n:src/test/java/org/redkalex/test/protob" + -// "uf/PSimpleBean.proto\"\330\001\n\013PSimpleBean\022)\n\006" + -// "simple\030\001 \001(\0132\031.PSimpleBean.PSimpleEntry\022" + -// "#\n\003two\030\002 \001(\0132\026.PSimpleBean.PTwoEntry\022\017\n\007" + -// "strings\030\003 \001(\t\0327\n\014PSimpleEntry\022\n\n\002id\030\001 \001(" + -// "\021\022\014\n\004name\030\002 \001(\t\022\r\n\005email\030\003 \001(\t\032/\n\tPTwoEn" + -// "try\022\016\n\006status\030\001 \001(\021\022\022\n\ncreatetime\030\002 \001(\022B" + -// "\034\n\032org.redkalex.test.protobufb\006proto3" -// }; -// descriptor = com.google.protobuf.Descriptors.FileDescriptor -// .internalBuildGeneratedFileFrom(descriptorData, -// new com.google.protobuf.Descriptors.FileDescriptor[] { -// }); -// internal_static_PSimpleBean_descriptor = -// getDescriptor().getMessageTypes().get(0); -// internal_static_PSimpleBean_fieldAccessorTable = new -// com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( -// internal_static_PSimpleBean_descriptor, -// new java.lang.String[] { "Simple", "Two", "Strings", }); -// internal_static_PSimpleBean_PSimpleEntry_descriptor = -// internal_static_PSimpleBean_descriptor.getNestedTypes().get(0); -// internal_static_PSimpleBean_PSimpleEntry_fieldAccessorTable = new -// com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( -// internal_static_PSimpleBean_PSimpleEntry_descriptor, -// new java.lang.String[] { "Id", "Name", "Email", }); -// internal_static_PSimpleBean_PTwoEntry_descriptor = -// internal_static_PSimpleBean_descriptor.getNestedTypes().get(1); -// internal_static_PSimpleBean_PTwoEntry_fieldAccessorTable = new -// com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( -// internal_static_PSimpleBean_PTwoEntry_descriptor, -// new java.lang.String[] { "Status", "Createtime", }); -// } -// -// // @@protoc_insertion_point(outer_class_scope) -// } +package org.redkale.test.convert.proto; + +//// Generated by the protocol buffer compiler. DO NOT EDIT! +//// source: src/test/java/org/redkalex/test/protobuf/PSimpleBean.proto +// +// package org.redkalex.test.protobuf; +// +// public final class PSimpleBeanOuterClass { +// private PSimpleBeanOuterClass() {} +// public static void registerAllExtensions( +// com.google.protobuf.ExtensionRegistryLite registry) { +// } +// +// public static void registerAllExtensions( +// com.google.protobuf.ExtensionRegistry registry) { +// registerAllExtensions( +// (com.google.protobuf.ExtensionRegistryLite) registry); +// } +// public interface PSimpleBeanOrBuilder extends +// // @@protoc_insertion_point(interface_extends:PSimpleBean) +// com.google.protobuf.MessageOrBuilder { +// +// /** +// * .PSimpleBean.PSimpleEntry simple = 1; +// * @return Whether the simple field is set. +// */ +// boolean hasSimple(); +// /** +// * .PSimpleBean.PSimpleEntry simple = 1; +// * @return The simple. +// */ +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry getSimple(); +// /** +// * .PSimpleBean.PSimpleEntry simple = 1; +// */ +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntryOrBuilder getSimpleOrBuilder(); +// +// /** +// * .PSimpleBean.PTwoEntry two = 2; +// * @return Whether the two field is set. +// */ +// boolean hasTwo(); +// /** +// * .PSimpleBean.PTwoEntry two = 2; +// * @return The two. +// */ +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry getTwo(); +// /** +// * .PSimpleBean.PTwoEntry two = 2; +// */ +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntryOrBuilder getTwoOrBuilder(); +// +// /** +// * string strings = 3; +// * @return The strings. +// */ +// java.lang.String getStrings(); +// /** +// * string strings = 3; +// * @return The bytes for strings. +// */ +// com.google.protobuf.ByteString +// getStringsBytes(); +// } +// /** +// * Protobuf type {@code PSimpleBean} +// */ +// public static final class PSimpleBean extends +// com.google.protobuf.GeneratedMessageV3 implements +// // @@protoc_insertion_point(message_implements:PSimpleBean) +// PSimpleBeanOrBuilder { +// private static final long serialVersionUID = 0L; +// // Use PSimpleBean.newBuilder() to construct. +// private PSimpleBean(com.google.protobuf.GeneratedMessageV3.Builder builder) { +// super(builder); +// } +// private PSimpleBean() { +// strings_ = ""; +// } +// +// @java.lang.Override +// @SuppressWarnings({"unused"}) +// protected java.lang.Object newInstance( +// UnusedPrivateParameter unused) { +// return new PSimpleBean(); +// } +// +// public static final com.google.protobuf.Descriptors.Descriptor +// getDescriptor() { +// return org.redkalex.test.protobuf.PSimpleBeanOuterClass.internal_static_PSimpleBean_descriptor; +// } +// +// @java.lang.Override +// protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable +// internalGetFieldAccessorTable() { +// return org.redkalex.test.protobuf.PSimpleBeanOuterClass.internal_static_PSimpleBean_fieldAccessorTable +// .ensureFieldAccessorsInitialized( +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.class, +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.Builder.class); +// } +// +// public interface PSimpleEntryOrBuilder extends +// // @@protoc_insertion_point(interface_extends:PSimpleBean.PSimpleEntry) +// com.google.protobuf.MessageOrBuilder { +// +// /** +// * sint32 id = 1; +// * @return The id. +// */ +// int getId(); +// +// /** +// * string name = 2; +// * @return The name. +// */ +// java.lang.String getName(); +// /** +// * string name = 2; +// * @return The bytes for name. +// */ +// com.google.protobuf.ByteString +// getNameBytes(); +// +// /** +// * string email = 3; +// * @return The email. +// */ +// java.lang.String getEmail(); +// /** +// * string email = 3; +// * @return The bytes for email. +// */ +// com.google.protobuf.ByteString +// getEmailBytes(); +// } +// /** +// * Protobuf type {@code PSimpleBean.PSimpleEntry} +// */ +// public static final class PSimpleEntry extends +// com.google.protobuf.GeneratedMessageV3 implements +// // @@protoc_insertion_point(message_implements:PSimpleBean.PSimpleEntry) +// PSimpleEntryOrBuilder { +// private static final long serialVersionUID = 0L; +// // Use PSimpleEntry.newBuilder() to construct. +// private PSimpleEntry(com.google.protobuf.GeneratedMessageV3.Builder builder) { +// super(builder); +// } +// private PSimpleEntry() { +// name_ = ""; +// email_ = ""; +// } +// +// @java.lang.Override +// @SuppressWarnings({"unused"}) +// protected java.lang.Object newInstance( +// UnusedPrivateParameter unused) { +// return new PSimpleEntry(); +// } +// +// public static final com.google.protobuf.Descriptors.Descriptor +// getDescriptor() { +// return org.redkalex.test.protobuf.PSimpleBeanOuterClass.internal_static_PSimpleBean_PSimpleEntry_descriptor; +// } +// +// @java.lang.Override +// protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable +// internalGetFieldAccessorTable() { +// return +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.internal_static_PSimpleBean_PSimpleEntry_fieldAccessorTable +// .ensureFieldAccessorsInitialized( +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry.class, +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry.Builder.class); +// } +// +// public static final int ID_FIELD_NUMBER = 1; +// private int id_ = 0; +// /** +// * sint32 id = 1; +// * @return The id. +// */ +// @java.lang.Override +// public int getId() { +// return id_; +// } +// +// public static final int NAME_FIELD_NUMBER = 2; +// @SuppressWarnings("serial") +// private volatile java.lang.Object name_ = ""; +// /** +// * string name = 2; +// * @return The name. +// */ +// @java.lang.Override +// public java.lang.String getName() { +// java.lang.Object ref = name_; +// if (ref instanceof java.lang.String) { +// return (java.lang.String) ref; +// } else { +// com.google.protobuf.ByteString bs = +// (com.google.protobuf.ByteString) ref; +// java.lang.String s = bs.toStringUtf8(); +// name_ = s; +// return s; +// } +// } +// /** +// * string name = 2; +// * @return The bytes for name. +// */ +// @java.lang.Override +// public com.google.protobuf.ByteString +// getNameBytes() { +// java.lang.Object ref = name_; +// if (ref instanceof java.lang.String) { +// com.google.protobuf.ByteString b = +// com.google.protobuf.ByteString.copyFromUtf8( +// (java.lang.String) ref); +// name_ = b; +// return b; +// } else { +// return (com.google.protobuf.ByteString) ref; +// } +// } +// +// public static final int EMAIL_FIELD_NUMBER = 3; +// @SuppressWarnings("serial") +// private volatile java.lang.Object email_ = ""; +// /** +// * string email = 3; +// * @return The email. +// */ +// @java.lang.Override +// public java.lang.String getEmail() { +// java.lang.Object ref = email_; +// if (ref instanceof java.lang.String) { +// return (java.lang.String) ref; +// } else { +// com.google.protobuf.ByteString bs = +// (com.google.protobuf.ByteString) ref; +// java.lang.String s = bs.toStringUtf8(); +// email_ = s; +// return s; +// } +// } +// /** +// * string email = 3; +// * @return The bytes for email. +// */ +// @java.lang.Override +// public com.google.protobuf.ByteString +// getEmailBytes() { +// java.lang.Object ref = email_; +// if (ref instanceof java.lang.String) { +// com.google.protobuf.ByteString b = +// com.google.protobuf.ByteString.copyFromUtf8( +// (java.lang.String) ref); +// email_ = b; +// return b; +// } else { +// return (com.google.protobuf.ByteString) ref; +// } +// } +// +// private byte memoizedIsInitialized = -1; +// @java.lang.Override +// public final boolean isInitialized() { +// byte isInitialized = memoizedIsInitialized; +// if (isInitialized == 1) return true; +// if (isInitialized == 0) return false; +// +// memoizedIsInitialized = 1; +// return true; +// } +// +// @java.lang.Override +// public void writeTo(com.google.protobuf.CodedOutputStream output) +// throws java.io.IOException { +// if (id_ != 0) { +// output.writeSInt32(1, id_); +// } +// if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(name_)) { +// com.google.protobuf.GeneratedMessageV3.writeString(output, 2, name_); +// } +// if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(email_)) { +// com.google.protobuf.GeneratedMessageV3.writeString(output, 3, email_); +// } +// getUnknownFields().writeTo(output); +// } +// +// @java.lang.Override +// public int getSerializedSize() { +// int size = memoizedSize; +// if (size != -1) return size; +// +// size = 0; +// if (id_ != 0) { +// size += com.google.protobuf.CodedOutputStream +// .computeSInt32Size(1, id_); +// } +// if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(name_)) { +// size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, name_); +// } +// if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(email_)) { +// size += com.google.protobuf.GeneratedMessageV3.computeStringSize(3, email_); +// } +// size += getUnknownFields().getSerializedSize(); +// memoizedSize = size; +// return size; +// } +// +// @java.lang.Override +// public boolean equals(final java.lang.Object obj) { +// if (obj == this) { +// return true; +// } +// if (!(obj instanceof org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry)) { +// return super.equals(obj); +// } +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry other = +// (org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry) obj; +// +// if (getId() +// != other.getId()) return false; +// if (!getName() +// .equals(other.getName())) return false; +// if (!getEmail() +// .equals(other.getEmail())) return false; +// if (!getUnknownFields().equals(other.getUnknownFields())) return false; +// return true; +// } +// +// @java.lang.Override +// public int hashCode() { +// if (memoizedHashCode != 0) { +// return memoizedHashCode; +// } +// int hash = 41; +// hash = (19 * hash) + getDescriptor().hashCode(); +// hash = (37 * hash) + ID_FIELD_NUMBER; +// hash = (53 * hash) + getId(); +// hash = (37 * hash) + NAME_FIELD_NUMBER; +// hash = (53 * hash) + getName().hashCode(); +// hash = (37 * hash) + EMAIL_FIELD_NUMBER; +// hash = (53 * hash) + getEmail().hashCode(); +// hash = (29 * hash) + getUnknownFields().hashCode(); +// memoizedHashCode = hash; +// return hash; +// } +// +// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry parseFrom( +// java.nio.ByteBuffer data) +// throws com.google.protobuf.InvalidProtocolBufferException { +// return PARSER.parseFrom(data); +// } +// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry parseFrom( +// java.nio.ByteBuffer data, +// com.google.protobuf.ExtensionRegistryLite extensionRegistry) +// throws com.google.protobuf.InvalidProtocolBufferException { +// return PARSER.parseFrom(data, extensionRegistry); +// } +// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry parseFrom( +// com.google.protobuf.ByteString data) +// throws com.google.protobuf.InvalidProtocolBufferException { +// return PARSER.parseFrom(data); +// } +// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry parseFrom( +// com.google.protobuf.ByteString data, +// com.google.protobuf.ExtensionRegistryLite extensionRegistry) +// throws com.google.protobuf.InvalidProtocolBufferException { +// return PARSER.parseFrom(data, extensionRegistry); +// } +// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry parseFrom(byte[] data) +// throws com.google.protobuf.InvalidProtocolBufferException { +// return PARSER.parseFrom(data); +// } +// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry parseFrom( +// byte[] data, +// com.google.protobuf.ExtensionRegistryLite extensionRegistry) +// throws com.google.protobuf.InvalidProtocolBufferException { +// return PARSER.parseFrom(data, extensionRegistry); +// } +// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry +// parseFrom(java.io.InputStream input) +// throws java.io.IOException { +// return com.google.protobuf.GeneratedMessageV3 +// .parseWithIOException(PARSER, input); +// } +// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry parseFrom( +// java.io.InputStream input, +// com.google.protobuf.ExtensionRegistryLite extensionRegistry) +// throws java.io.IOException { +// return com.google.protobuf.GeneratedMessageV3 +// .parseWithIOException(PARSER, input, extensionRegistry); +// } +// +// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry +// parseDelimitedFrom(java.io.InputStream input) +// throws java.io.IOException { +// return com.google.protobuf.GeneratedMessageV3 +// .parseDelimitedWithIOException(PARSER, input); +// } +// +// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry parseDelimitedFrom( +// java.io.InputStream input, +// com.google.protobuf.ExtensionRegistryLite extensionRegistry) +// throws java.io.IOException { +// return com.google.protobuf.GeneratedMessageV3 +// .parseDelimitedWithIOException(PARSER, input, extensionRegistry); +// } +// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry parseFrom( +// com.google.protobuf.CodedInputStream input) +// throws java.io.IOException { +// return com.google.protobuf.GeneratedMessageV3 +// .parseWithIOException(PARSER, input); +// } +// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry parseFrom( +// com.google.protobuf.CodedInputStream input, +// com.google.protobuf.ExtensionRegistryLite extensionRegistry) +// throws java.io.IOException { +// return com.google.protobuf.GeneratedMessageV3 +// .parseWithIOException(PARSER, input, extensionRegistry); +// } +// +// @java.lang.Override +// public Builder newBuilderForType() { return newBuilder(); } +// public static Builder newBuilder() { +// return DEFAULT_INSTANCE.toBuilder(); +// } +// public static Builder newBuilder(org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry +// prototype) { +// return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); +// } +// @java.lang.Override +// public Builder toBuilder() { +// return this == DEFAULT_INSTANCE +// ? new Builder() : new Builder().mergeFrom(this); +// } +// +// @java.lang.Override +// protected Builder newBuilderForType( +// com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { +// Builder builder = new Builder(parent); +// return builder; +// } +// /** +// * Protobuf type {@code PSimpleBean.PSimpleEntry} +// */ +// public static final class Builder extends +// com.google.protobuf.GeneratedMessageV3.Builder implements +// // @@protoc_insertion_point(builder_implements:PSimpleBean.PSimpleEntry) +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntryOrBuilder { +// public static final com.google.protobuf.Descriptors.Descriptor +// getDescriptor() { +// return org.redkalex.test.protobuf.PSimpleBeanOuterClass.internal_static_PSimpleBean_PSimpleEntry_descriptor; +// } +// +// @java.lang.Override +// protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable +// internalGetFieldAccessorTable() { +// return +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.internal_static_PSimpleBean_PSimpleEntry_fieldAccessorTable +// .ensureFieldAccessorsInitialized( +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry.class, +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry.Builder.class); +// } +// +// // Construct using org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry.newBuilder() +// private Builder() { +// +// } +// +// private Builder( +// com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { +// super(parent); +// +// } +// @java.lang.Override +// public Builder clear() { +// super.clear(); +// bitField0_ = 0; +// id_ = 0; +// name_ = ""; +// email_ = ""; +// return this; +// } +// +// @java.lang.Override +// public com.google.protobuf.Descriptors.Descriptor +// getDescriptorForType() { +// return org.redkalex.test.protobuf.PSimpleBeanOuterClass.internal_static_PSimpleBean_PSimpleEntry_descriptor; +// } +// +// @java.lang.Override +// public org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry getDefaultInstanceForType() { +// return org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry.getDefaultInstance(); +// } +// +// @java.lang.Override +// public org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry build() { +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry result = buildPartial(); +// if (!result.isInitialized()) { +// throw newUninitializedMessageException(result); +// } +// return result; +// } +// +// @java.lang.Override +// public org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry buildPartial() { +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry result = new +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry(this); +// if (bitField0_ != 0) { buildPartial0(result); } +// onBuilt(); +// return result; +// } +// +// private void buildPartial0(org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry result) { +// int from_bitField0_ = bitField0_; +// if (((from_bitField0_ & 0x00000001) != 0)) { +// result.id_ = id_; +// } +// if (((from_bitField0_ & 0x00000002) != 0)) { +// result.name_ = name_; +// } +// if (((from_bitField0_ & 0x00000004) != 0)) { +// result.email_ = email_; +// } +// } +// +// @java.lang.Override +// public Builder clone() { +// return super.clone(); +// } +// @java.lang.Override +// public Builder setField( +// com.google.protobuf.Descriptors.FieldDescriptor field, +// java.lang.Object value) { +// return super.setField(field, value); +// } +// @java.lang.Override +// public Builder clearField( +// com.google.protobuf.Descriptors.FieldDescriptor field) { +// return super.clearField(field); +// } +// @java.lang.Override +// public Builder clearOneof( +// com.google.protobuf.Descriptors.OneofDescriptor oneof) { +// return super.clearOneof(oneof); +// } +// @java.lang.Override +// public Builder setRepeatedField( +// com.google.protobuf.Descriptors.FieldDescriptor field, +// int index, java.lang.Object value) { +// return super.setRepeatedField(field, index, value); +// } +// @java.lang.Override +// public Builder addRepeatedField( +// com.google.protobuf.Descriptors.FieldDescriptor field, +// java.lang.Object value) { +// return super.addRepeatedField(field, value); +// } +// @java.lang.Override +// public Builder mergeFrom(com.google.protobuf.Message other) { +// if (other instanceof org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry) { +// return mergeFrom((org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry)other); +// } else { +// super.mergeFrom(other); +// return this; +// } +// } +// +// public Builder mergeFrom(org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry other) { +// if (other == org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry.getDefaultInstance()) +// return this; +// if (other.getId() != 0) { +// setId(other.getId()); +// } +// if (!other.getName().isEmpty()) { +// name_ = other.name_; +// bitField0_ |= 0x00000002; +// onChanged(); +// } +// if (!other.getEmail().isEmpty()) { +// email_ = other.email_; +// bitField0_ |= 0x00000004; +// onChanged(); +// } +// this.mergeUnknownFields(other.getUnknownFields()); +// onChanged(); +// return this; +// } +// +// @java.lang.Override +// public final boolean isInitialized() { +// return true; +// } +// +// @java.lang.Override +// public Builder mergeFrom( +// com.google.protobuf.CodedInputStream input, +// com.google.protobuf.ExtensionRegistryLite extensionRegistry) +// throws java.io.IOException { +// if (extensionRegistry == null) { +// throw new java.lang.NullPointerException(); +// } +// try { +// boolean done = false; +// while (!done) { +// int tag = input.readTag(); +// switch (tag) { +// case 0: +// done = true; +// break; +// case 8: { +// id_ = input.readSInt32(); +// bitField0_ |= 0x00000001; +// break; +// } // case 8 +// case 18: { +// name_ = input.readStringRequireUtf8(); +// bitField0_ |= 0x00000002; +// break; +// } // case 18 +// case 26: { +// email_ = input.readStringRequireUtf8(); +// bitField0_ |= 0x00000004; +// break; +// } // case 26 +// default: { +// if (!super.parseUnknownField(input, extensionRegistry, tag)) { +// done = true; // was an endgroup tag +// } +// break; +// } // default: +// } // switch (tag) +// } // while (!done) +// } catch (com.google.protobuf.InvalidProtocolBufferException e) { +// throw e.unwrapIOException(); +// } finally { +// onChanged(); +// } // finally +// return this; +// } +// private int bitField0_; +// +// private int id_ ; +// /** +// * sint32 id = 1; +// * @return The id. +// */ +// @java.lang.Override +// public int getId() { +// return id_; +// } +// /** +// * sint32 id = 1; +// * @param value The id to set. +// * @return This builder for chaining. +// */ +// public Builder setId(int value) { +// +// id_ = value; +// bitField0_ |= 0x00000001; +// onChanged(); +// return this; +// } +// /** +// * sint32 id = 1; +// * @return This builder for chaining. +// */ +// public Builder clearId() { +// bitField0_ = (bitField0_ & ~0x00000001); +// id_ = 0; +// onChanged(); +// return this; +// } +// +// private java.lang.Object name_ = ""; +// /** +// * string name = 2; +// * @return The name. +// */ +// public java.lang.String getName() { +// java.lang.Object ref = name_; +// if (!(ref instanceof java.lang.String)) { +// com.google.protobuf.ByteString bs = +// (com.google.protobuf.ByteString) ref; +// java.lang.String s = bs.toStringUtf8(); +// name_ = s; +// return s; +// } else { +// return (java.lang.String) ref; +// } +// } +// /** +// * string name = 2; +// * @return The bytes for name. +// */ +// public com.google.protobuf.ByteString +// getNameBytes() { +// java.lang.Object ref = name_; +// if (ref instanceof String) { +// com.google.protobuf.ByteString b = +// com.google.protobuf.ByteString.copyFromUtf8( +// (java.lang.String) ref); +// name_ = b; +// return b; +// } else { +// return (com.google.protobuf.ByteString) ref; +// } +// } +// /** +// * string name = 2; +// * @param value The name to set. +// * @return This builder for chaining. +// */ +// public Builder setName( +// java.lang.String value) { +// if (value == null) { throw new NullPointerException(); } +// name_ = value; +// bitField0_ |= 0x00000002; +// onChanged(); +// return this; +// } +// /** +// * string name = 2; +// * @return This builder for chaining. +// */ +// public Builder clearName() { +// name_ = getDefaultInstance().getName(); +// bitField0_ = (bitField0_ & ~0x00000002); +// onChanged(); +// return this; +// } +// /** +// * string name = 2; +// * @param value The bytes for name to set. +// * @return This builder for chaining. +// */ +// public Builder setNameBytes( +// com.google.protobuf.ByteString value) { +// if (value == null) { throw new NullPointerException(); } +// checkByteStringIsUtf8(value); +// name_ = value; +// bitField0_ |= 0x00000002; +// onChanged(); +// return this; +// } +// +// private java.lang.Object email_ = ""; +// /** +// * string email = 3; +// * @return The email. +// */ +// public java.lang.String getEmail() { +// java.lang.Object ref = email_; +// if (!(ref instanceof java.lang.String)) { +// com.google.protobuf.ByteString bs = +// (com.google.protobuf.ByteString) ref; +// java.lang.String s = bs.toStringUtf8(); +// email_ = s; +// return s; +// } else { +// return (java.lang.String) ref; +// } +// } +// /** +// * string email = 3; +// * @return The bytes for email. +// */ +// public com.google.protobuf.ByteString +// getEmailBytes() { +// java.lang.Object ref = email_; +// if (ref instanceof String) { +// com.google.protobuf.ByteString b = +// com.google.protobuf.ByteString.copyFromUtf8( +// (java.lang.String) ref); +// email_ = b; +// return b; +// } else { +// return (com.google.protobuf.ByteString) ref; +// } +// } +// /** +// * string email = 3; +// * @param value The email to set. +// * @return This builder for chaining. +// */ +// public Builder setEmail( +// java.lang.String value) { +// if (value == null) { throw new NullPointerException(); } +// email_ = value; +// bitField0_ |= 0x00000004; +// onChanged(); +// return this; +// } +// /** +// * string email = 3; +// * @return This builder for chaining. +// */ +// public Builder clearEmail() { +// email_ = getDefaultInstance().getEmail(); +// bitField0_ = (bitField0_ & ~0x00000004); +// onChanged(); +// return this; +// } +// /** +// * string email = 3; +// * @param value The bytes for email to set. +// * @return This builder for chaining. +// */ +// public Builder setEmailBytes( +// com.google.protobuf.ByteString value) { +// if (value == null) { throw new NullPointerException(); } +// checkByteStringIsUtf8(value); +// email_ = value; +// bitField0_ |= 0x00000004; +// onChanged(); +// return this; +// } +// @java.lang.Override +// public final Builder setUnknownFields( +// final com.google.protobuf.UnknownFieldSet unknownFields) { +// return super.setUnknownFields(unknownFields); +// } +// +// @java.lang.Override +// public final Builder mergeUnknownFields( +// final com.google.protobuf.UnknownFieldSet unknownFields) { +// return super.mergeUnknownFields(unknownFields); +// } +// +// +// // @@protoc_insertion_point(builder_scope:PSimpleBean.PSimpleEntry) +// } +// +// // @@protoc_insertion_point(class_scope:PSimpleBean.PSimpleEntry) +// private static final org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry DEFAULT_INSTANCE; +// static { +// DEFAULT_INSTANCE = new org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry(); +// } +// +// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry getDefaultInstance() { +// return DEFAULT_INSTANCE; +// } +// +// private static final com.google.protobuf.Parser +// PARSER = new com.google.protobuf.AbstractParser() { +// @java.lang.Override +// public PSimpleEntry parsePartialFrom( +// com.google.protobuf.CodedInputStream input, +// com.google.protobuf.ExtensionRegistryLite extensionRegistry) +// throws com.google.protobuf.InvalidProtocolBufferException { +// Builder builder = newBuilder(); +// try { +// builder.mergeFrom(input, extensionRegistry); +// } catch (com.google.protobuf.InvalidProtocolBufferException e) { +// throw e.setUnfinishedMessage(builder.buildPartial()); +// } catch (com.google.protobuf.UninitializedMessageException e) { +// throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); +// } catch (java.io.IOException e) { +// throw new com.google.protobuf.InvalidProtocolBufferException(e) +// .setUnfinishedMessage(builder.buildPartial()); +// } +// return builder.buildPartial(); +// } +// }; +// +// public static com.google.protobuf.Parser parser() { +// return PARSER; +// } +// +// @java.lang.Override +// public com.google.protobuf.Parser getParserForType() { +// return PARSER; +// } +// +// @java.lang.Override +// public org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry getDefaultInstanceForType() { +// return DEFAULT_INSTANCE; +// } +// +// } +// +// public interface PTwoEntryOrBuilder extends +// // @@protoc_insertion_point(interface_extends:PSimpleBean.PTwoEntry) +// com.google.protobuf.MessageOrBuilder { +// +// /** +// * sint32 status = 1; +// * @return The status. +// */ +// int getStatus(); +// +// /** +// * sint64 createtime = 2; +// * @return The createtime. +// */ +// long getCreatetime(); +// } +// /** +// * Protobuf type {@code PSimpleBean.PTwoEntry} +// */ +// public static final class PTwoEntry extends +// com.google.protobuf.GeneratedMessageV3 implements +// // @@protoc_insertion_point(message_implements:PSimpleBean.PTwoEntry) +// PTwoEntryOrBuilder { +// private static final long serialVersionUID = 0L; +// // Use PTwoEntry.newBuilder() to construct. +// private PTwoEntry(com.google.protobuf.GeneratedMessageV3.Builder builder) { +// super(builder); +// } +// private PTwoEntry() { +// } +// +// @java.lang.Override +// @SuppressWarnings({"unused"}) +// protected java.lang.Object newInstance( +// UnusedPrivateParameter unused) { +// return new PTwoEntry(); +// } +// +// public static final com.google.protobuf.Descriptors.Descriptor +// getDescriptor() { +// return org.redkalex.test.protobuf.PSimpleBeanOuterClass.internal_static_PSimpleBean_PTwoEntry_descriptor; +// } +// +// @java.lang.Override +// protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable +// internalGetFieldAccessorTable() { +// return +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.internal_static_PSimpleBean_PTwoEntry_fieldAccessorTable +// .ensureFieldAccessorsInitialized( +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry.class, +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry.Builder.class); +// } +// +// public static final int STATUS_FIELD_NUMBER = 1; +// private int status_ = 0; +// /** +// * sint32 status = 1; +// * @return The status. +// */ +// @java.lang.Override +// public int getStatus() { +// return status_; +// } +// +// public static final int CREATETIME_FIELD_NUMBER = 2; +// private long createtime_ = 0L; +// /** +// * sint64 createtime = 2; +// * @return The createtime. +// */ +// @java.lang.Override +// public long getCreatetime() { +// return createtime_; +// } +// +// private byte memoizedIsInitialized = -1; +// @java.lang.Override +// public final boolean isInitialized() { +// byte isInitialized = memoizedIsInitialized; +// if (isInitialized == 1) return true; +// if (isInitialized == 0) return false; +// +// memoizedIsInitialized = 1; +// return true; +// } +// +// @java.lang.Override +// public void writeTo(com.google.protobuf.CodedOutputStream output) +// throws java.io.IOException { +// if (status_ != 0) { +// output.writeSInt32(1, status_); +// } +// if (createtime_ != 0L) { +// output.writeSInt64(2, createtime_); +// } +// getUnknownFields().writeTo(output); +// } +// +// @java.lang.Override +// public int getSerializedSize() { +// int size = memoizedSize; +// if (size != -1) return size; +// +// size = 0; +// if (status_ != 0) { +// size += com.google.protobuf.CodedOutputStream +// .computeSInt32Size(1, status_); +// } +// if (createtime_ != 0L) { +// size += com.google.protobuf.CodedOutputStream +// .computeSInt64Size(2, createtime_); +// } +// size += getUnknownFields().getSerializedSize(); +// memoizedSize = size; +// return size; +// } +// +// @java.lang.Override +// public boolean equals(final java.lang.Object obj) { +// if (obj == this) { +// return true; +// } +// if (!(obj instanceof org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry)) { +// return super.equals(obj); +// } +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry other = +// (org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry) obj; +// +// if (getStatus() +// != other.getStatus()) return false; +// if (getCreatetime() +// != other.getCreatetime()) return false; +// if (!getUnknownFields().equals(other.getUnknownFields())) return false; +// return true; +// } +// +// @java.lang.Override +// public int hashCode() { +// if (memoizedHashCode != 0) { +// return memoizedHashCode; +// } +// int hash = 41; +// hash = (19 * hash) + getDescriptor().hashCode(); +// hash = (37 * hash) + STATUS_FIELD_NUMBER; +// hash = (53 * hash) + getStatus(); +// hash = (37 * hash) + CREATETIME_FIELD_NUMBER; +// hash = (53 * hash) + com.google.protobuf.Internal.hashLong( +// getCreatetime()); +// hash = (29 * hash) + getUnknownFields().hashCode(); +// memoizedHashCode = hash; +// return hash; +// } +// +// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry parseFrom( +// java.nio.ByteBuffer data) +// throws com.google.protobuf.InvalidProtocolBufferException { +// return PARSER.parseFrom(data); +// } +// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry parseFrom( +// java.nio.ByteBuffer data, +// com.google.protobuf.ExtensionRegistryLite extensionRegistry) +// throws com.google.protobuf.InvalidProtocolBufferException { +// return PARSER.parseFrom(data, extensionRegistry); +// } +// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry parseFrom( +// com.google.protobuf.ByteString data) +// throws com.google.protobuf.InvalidProtocolBufferException { +// return PARSER.parseFrom(data); +// } +// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry parseFrom( +// com.google.protobuf.ByteString data, +// com.google.protobuf.ExtensionRegistryLite extensionRegistry) +// throws com.google.protobuf.InvalidProtocolBufferException { +// return PARSER.parseFrom(data, extensionRegistry); +// } +// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry parseFrom(byte[] data) +// throws com.google.protobuf.InvalidProtocolBufferException { +// return PARSER.parseFrom(data); +// } +// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry parseFrom( +// byte[] data, +// com.google.protobuf.ExtensionRegistryLite extensionRegistry) +// throws com.google.protobuf.InvalidProtocolBufferException { +// return PARSER.parseFrom(data, extensionRegistry); +// } +// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry +// parseFrom(java.io.InputStream input) +// throws java.io.IOException { +// return com.google.protobuf.GeneratedMessageV3 +// .parseWithIOException(PARSER, input); +// } +// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry parseFrom( +// java.io.InputStream input, +// com.google.protobuf.ExtensionRegistryLite extensionRegistry) +// throws java.io.IOException { +// return com.google.protobuf.GeneratedMessageV3 +// .parseWithIOException(PARSER, input, extensionRegistry); +// } +// +// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry +// parseDelimitedFrom(java.io.InputStream input) +// throws java.io.IOException { +// return com.google.protobuf.GeneratedMessageV3 +// .parseDelimitedWithIOException(PARSER, input); +// } +// +// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry parseDelimitedFrom( +// java.io.InputStream input, +// com.google.protobuf.ExtensionRegistryLite extensionRegistry) +// throws java.io.IOException { +// return com.google.protobuf.GeneratedMessageV3 +// .parseDelimitedWithIOException(PARSER, input, extensionRegistry); +// } +// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry parseFrom( +// com.google.protobuf.CodedInputStream input) +// throws java.io.IOException { +// return com.google.protobuf.GeneratedMessageV3 +// .parseWithIOException(PARSER, input); +// } +// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry parseFrom( +// com.google.protobuf.CodedInputStream input, +// com.google.protobuf.ExtensionRegistryLite extensionRegistry) +// throws java.io.IOException { +// return com.google.protobuf.GeneratedMessageV3 +// .parseWithIOException(PARSER, input, extensionRegistry); +// } +// +// @java.lang.Override +// public Builder newBuilderForType() { return newBuilder(); } +// public static Builder newBuilder() { +// return DEFAULT_INSTANCE.toBuilder(); +// } +// public static Builder newBuilder(org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry +// prototype) { +// return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); +// } +// @java.lang.Override +// public Builder toBuilder() { +// return this == DEFAULT_INSTANCE +// ? new Builder() : new Builder().mergeFrom(this); +// } +// +// @java.lang.Override +// protected Builder newBuilderForType( +// com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { +// Builder builder = new Builder(parent); +// return builder; +// } +// /** +// * Protobuf type {@code PSimpleBean.PTwoEntry} +// */ +// public static final class Builder extends +// com.google.protobuf.GeneratedMessageV3.Builder implements +// // @@protoc_insertion_point(builder_implements:PSimpleBean.PTwoEntry) +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntryOrBuilder { +// public static final com.google.protobuf.Descriptors.Descriptor +// getDescriptor() { +// return org.redkalex.test.protobuf.PSimpleBeanOuterClass.internal_static_PSimpleBean_PTwoEntry_descriptor; +// } +// +// @java.lang.Override +// protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable +// internalGetFieldAccessorTable() { +// return +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.internal_static_PSimpleBean_PTwoEntry_fieldAccessorTable +// .ensureFieldAccessorsInitialized( +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry.class, +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry.Builder.class); +// } +// +// // Construct using org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry.newBuilder() +// private Builder() { +// +// } +// +// private Builder( +// com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { +// super(parent); +// +// } +// @java.lang.Override +// public Builder clear() { +// super.clear(); +// bitField0_ = 0; +// status_ = 0; +// createtime_ = 0L; +// return this; +// } +// +// @java.lang.Override +// public com.google.protobuf.Descriptors.Descriptor +// getDescriptorForType() { +// return org.redkalex.test.protobuf.PSimpleBeanOuterClass.internal_static_PSimpleBean_PTwoEntry_descriptor; +// } +// +// @java.lang.Override +// public org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry getDefaultInstanceForType() { +// return org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry.getDefaultInstance(); +// } +// +// @java.lang.Override +// public org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry build() { +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry result = buildPartial(); +// if (!result.isInitialized()) { +// throw newUninitializedMessageException(result); +// } +// return result; +// } +// +// @java.lang.Override +// public org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry buildPartial() { +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry result = new +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry(this); +// if (bitField0_ != 0) { buildPartial0(result); } +// onBuilt(); +// return result; +// } +// +// private void buildPartial0(org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry result) { +// int from_bitField0_ = bitField0_; +// if (((from_bitField0_ & 0x00000001) != 0)) { +// result.status_ = status_; +// } +// if (((from_bitField0_ & 0x00000002) != 0)) { +// result.createtime_ = createtime_; +// } +// } +// +// @java.lang.Override +// public Builder clone() { +// return super.clone(); +// } +// @java.lang.Override +// public Builder setField( +// com.google.protobuf.Descriptors.FieldDescriptor field, +// java.lang.Object value) { +// return super.setField(field, value); +// } +// @java.lang.Override +// public Builder clearField( +// com.google.protobuf.Descriptors.FieldDescriptor field) { +// return super.clearField(field); +// } +// @java.lang.Override +// public Builder clearOneof( +// com.google.protobuf.Descriptors.OneofDescriptor oneof) { +// return super.clearOneof(oneof); +// } +// @java.lang.Override +// public Builder setRepeatedField( +// com.google.protobuf.Descriptors.FieldDescriptor field, +// int index, java.lang.Object value) { +// return super.setRepeatedField(field, index, value); +// } +// @java.lang.Override +// public Builder addRepeatedField( +// com.google.protobuf.Descriptors.FieldDescriptor field, +// java.lang.Object value) { +// return super.addRepeatedField(field, value); +// } +// @java.lang.Override +// public Builder mergeFrom(com.google.protobuf.Message other) { +// if (other instanceof org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry) { +// return mergeFrom((org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry)other); +// } else { +// super.mergeFrom(other); +// return this; +// } +// } +// +// public Builder mergeFrom(org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry other) { +// if (other == org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry.getDefaultInstance()) +// return this; +// if (other.getStatus() != 0) { +// setStatus(other.getStatus()); +// } +// if (other.getCreatetime() != 0L) { +// setCreatetime(other.getCreatetime()); +// } +// this.mergeUnknownFields(other.getUnknownFields()); +// onChanged(); +// return this; +// } +// +// @java.lang.Override +// public final boolean isInitialized() { +// return true; +// } +// +// @java.lang.Override +// public Builder mergeFrom( +// com.google.protobuf.CodedInputStream input, +// com.google.protobuf.ExtensionRegistryLite extensionRegistry) +// throws java.io.IOException { +// if (extensionRegistry == null) { +// throw new java.lang.NullPointerException(); +// } +// try { +// boolean done = false; +// while (!done) { +// int tag = input.readTag(); +// switch (tag) { +// case 0: +// done = true; +// break; +// case 8: { +// status_ = input.readSInt32(); +// bitField0_ |= 0x00000001; +// break; +// } // case 8 +// case 16: { +// createtime_ = input.readSInt64(); +// bitField0_ |= 0x00000002; +// break; +// } // case 16 +// default: { +// if (!super.parseUnknownField(input, extensionRegistry, tag)) { +// done = true; // was an endgroup tag +// } +// break; +// } // default: +// } // switch (tag) +// } // while (!done) +// } catch (com.google.protobuf.InvalidProtocolBufferException e) { +// throw e.unwrapIOException(); +// } finally { +// onChanged(); +// } // finally +// return this; +// } +// private int bitField0_; +// +// private int status_ ; +// /** +// * sint32 status = 1; +// * @return The status. +// */ +// @java.lang.Override +// public int getStatus() { +// return status_; +// } +// /** +// * sint32 status = 1; +// * @param value The status to set. +// * @return This builder for chaining. +// */ +// public Builder setStatus(int value) { +// +// status_ = value; +// bitField0_ |= 0x00000001; +// onChanged(); +// return this; +// } +// /** +// * sint32 status = 1; +// * @return This builder for chaining. +// */ +// public Builder clearStatus() { +// bitField0_ = (bitField0_ & ~0x00000001); +// status_ = 0; +// onChanged(); +// return this; +// } +// +// private long createtime_ ; +// /** +// * sint64 createtime = 2; +// * @return The createtime. +// */ +// @java.lang.Override +// public long getCreatetime() { +// return createtime_; +// } +// /** +// * sint64 createtime = 2; +// * @param value The createtime to set. +// * @return This builder for chaining. +// */ +// public Builder setCreatetime(long value) { +// +// createtime_ = value; +// bitField0_ |= 0x00000002; +// onChanged(); +// return this; +// } +// /** +// * sint64 createtime = 2; +// * @return This builder for chaining. +// */ +// public Builder clearCreatetime() { +// bitField0_ = (bitField0_ & ~0x00000002); +// createtime_ = 0L; +// onChanged(); +// return this; +// } +// @java.lang.Override +// public final Builder setUnknownFields( +// final com.google.protobuf.UnknownFieldSet unknownFields) { +// return super.setUnknownFields(unknownFields); +// } +// +// @java.lang.Override +// public final Builder mergeUnknownFields( +// final com.google.protobuf.UnknownFieldSet unknownFields) { +// return super.mergeUnknownFields(unknownFields); +// } +// +// +// // @@protoc_insertion_point(builder_scope:PSimpleBean.PTwoEntry) +// } +// +// // @@protoc_insertion_point(class_scope:PSimpleBean.PTwoEntry) +// private static final org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry DEFAULT_INSTANCE; +// static { +// DEFAULT_INSTANCE = new org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry(); +// } +// +// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry getDefaultInstance() { +// return DEFAULT_INSTANCE; +// } +// +// private static final com.google.protobuf.Parser +// PARSER = new com.google.protobuf.AbstractParser() { +// @java.lang.Override +// public PTwoEntry parsePartialFrom( +// com.google.protobuf.CodedInputStream input, +// com.google.protobuf.ExtensionRegistryLite extensionRegistry) +// throws com.google.protobuf.InvalidProtocolBufferException { +// Builder builder = newBuilder(); +// try { +// builder.mergeFrom(input, extensionRegistry); +// } catch (com.google.protobuf.InvalidProtocolBufferException e) { +// throw e.setUnfinishedMessage(builder.buildPartial()); +// } catch (com.google.protobuf.UninitializedMessageException e) { +// throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); +// } catch (java.io.IOException e) { +// throw new com.google.protobuf.InvalidProtocolBufferException(e) +// .setUnfinishedMessage(builder.buildPartial()); +// } +// return builder.buildPartial(); +// } +// }; +// +// public static com.google.protobuf.Parser parser() { +// return PARSER; +// } +// +// @java.lang.Override +// public com.google.protobuf.Parser getParserForType() { +// return PARSER; +// } +// +// @java.lang.Override +// public org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry getDefaultInstanceForType() { +// return DEFAULT_INSTANCE; +// } +// +// } +// +// public static final int SIMPLE_FIELD_NUMBER = 1; +// private org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry simple_; +// /** +// * .PSimpleBean.PSimpleEntry simple = 1; +// * @return Whether the simple field is set. +// */ +// @java.lang.Override +// public boolean hasSimple() { +// return simple_ != null; +// } +// /** +// * .PSimpleBean.PSimpleEntry simple = 1; +// * @return The simple. +// */ +// @java.lang.Override +// public org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry getSimple() { +// return simple_ == null ? +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry.getDefaultInstance() : simple_; +// } +// /** +// * .PSimpleBean.PSimpleEntry simple = 1; +// */ +// @java.lang.Override +// public org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntryOrBuilder getSimpleOrBuilder() { +// return simple_ == null ? +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry.getDefaultInstance() : simple_; +// } +// +// public static final int TWO_FIELD_NUMBER = 2; +// private org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry two_; +// /** +// * .PSimpleBean.PTwoEntry two = 2; +// * @return Whether the two field is set. +// */ +// @java.lang.Override +// public boolean hasTwo() { +// return two_ != null; +// } +// /** +// * .PSimpleBean.PTwoEntry two = 2; +// * @return The two. +// */ +// @java.lang.Override +// public org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry getTwo() { +// return two_ == null ? +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry.getDefaultInstance() : two_; +// } +// /** +// * .PSimpleBean.PTwoEntry two = 2; +// */ +// @java.lang.Override +// public org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntryOrBuilder getTwoOrBuilder() { +// return two_ == null ? +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry.getDefaultInstance() : two_; +// } +// +// public static final int STRINGS_FIELD_NUMBER = 3; +// @SuppressWarnings("serial") +// private volatile java.lang.Object strings_ = ""; +// /** +// * string strings = 3; +// * @return The strings. +// */ +// @java.lang.Override +// public java.lang.String getStrings() { +// java.lang.Object ref = strings_; +// if (ref instanceof java.lang.String) { +// return (java.lang.String) ref; +// } else { +// com.google.protobuf.ByteString bs = +// (com.google.protobuf.ByteString) ref; +// java.lang.String s = bs.toStringUtf8(); +// strings_ = s; +// return s; +// } +// } +// /** +// * string strings = 3; +// * @return The bytes for strings. +// */ +// @java.lang.Override +// public com.google.protobuf.ByteString +// getStringsBytes() { +// java.lang.Object ref = strings_; +// if (ref instanceof java.lang.String) { +// com.google.protobuf.ByteString b = +// com.google.protobuf.ByteString.copyFromUtf8( +// (java.lang.String) ref); +// strings_ = b; +// return b; +// } else { +// return (com.google.protobuf.ByteString) ref; +// } +// } +// +// private byte memoizedIsInitialized = -1; +// @java.lang.Override +// public final boolean isInitialized() { +// byte isInitialized = memoizedIsInitialized; +// if (isInitialized == 1) return true; +// if (isInitialized == 0) return false; +// +// memoizedIsInitialized = 1; +// return true; +// } +// +// @java.lang.Override +// public void writeTo(com.google.protobuf.CodedOutputStream output) +// throws java.io.IOException { +// if (simple_ != null) { +// output.writeMessage(1, getSimple()); +// } +// if (two_ != null) { +// output.writeMessage(2, getTwo()); +// } +// if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(strings_)) { +// com.google.protobuf.GeneratedMessageV3.writeString(output, 3, strings_); +// } +// getUnknownFields().writeTo(output); +// } +// +// @java.lang.Override +// public int getSerializedSize() { +// int size = memoizedSize; +// if (size != -1) return size; +// +// size = 0; +// if (simple_ != null) { +// size += com.google.protobuf.CodedOutputStream +// .computeMessageSize(1, getSimple()); +// } +// if (two_ != null) { +// size += com.google.protobuf.CodedOutputStream +// .computeMessageSize(2, getTwo()); +// } +// if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(strings_)) { +// size += com.google.protobuf.GeneratedMessageV3.computeStringSize(3, strings_); +// } +// size += getUnknownFields().getSerializedSize(); +// memoizedSize = size; +// return size; +// } +// +// @java.lang.Override +// public boolean equals(final java.lang.Object obj) { +// if (obj == this) { +// return true; +// } +// if (!(obj instanceof org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean)) { +// return super.equals(obj); +// } +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean other = +// (org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean) obj; +// +// if (hasSimple() != other.hasSimple()) return false; +// if (hasSimple()) { +// if (!getSimple() +// .equals(other.getSimple())) return false; +// } +// if (hasTwo() != other.hasTwo()) return false; +// if (hasTwo()) { +// if (!getTwo() +// .equals(other.getTwo())) return false; +// } +// if (!getStrings() +// .equals(other.getStrings())) return false; +// if (!getUnknownFields().equals(other.getUnknownFields())) return false; +// return true; +// } +// +// @java.lang.Override +// public int hashCode() { +// if (memoizedHashCode != 0) { +// return memoizedHashCode; +// } +// int hash = 41; +// hash = (19 * hash) + getDescriptor().hashCode(); +// if (hasSimple()) { +// hash = (37 * hash) + SIMPLE_FIELD_NUMBER; +// hash = (53 * hash) + getSimple().hashCode(); +// } +// if (hasTwo()) { +// hash = (37 * hash) + TWO_FIELD_NUMBER; +// hash = (53 * hash) + getTwo().hashCode(); +// } +// hash = (37 * hash) + STRINGS_FIELD_NUMBER; +// hash = (53 * hash) + getStrings().hashCode(); +// hash = (29 * hash) + getUnknownFields().hashCode(); +// memoizedHashCode = hash; +// return hash; +// } +// +// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean parseFrom( +// java.nio.ByteBuffer data) +// throws com.google.protobuf.InvalidProtocolBufferException { +// return PARSER.parseFrom(data); +// } +// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean parseFrom( +// java.nio.ByteBuffer data, +// com.google.protobuf.ExtensionRegistryLite extensionRegistry) +// throws com.google.protobuf.InvalidProtocolBufferException { +// return PARSER.parseFrom(data, extensionRegistry); +// } +// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean parseFrom( +// com.google.protobuf.ByteString data) +// throws com.google.protobuf.InvalidProtocolBufferException { +// return PARSER.parseFrom(data); +// } +// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean parseFrom( +// com.google.protobuf.ByteString data, +// com.google.protobuf.ExtensionRegistryLite extensionRegistry) +// throws com.google.protobuf.InvalidProtocolBufferException { +// return PARSER.parseFrom(data, extensionRegistry); +// } +// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean parseFrom(byte[] data) +// throws com.google.protobuf.InvalidProtocolBufferException { +// return PARSER.parseFrom(data); +// } +// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean parseFrom( +// byte[] data, +// com.google.protobuf.ExtensionRegistryLite extensionRegistry) +// throws com.google.protobuf.InvalidProtocolBufferException { +// return PARSER.parseFrom(data, extensionRegistry); +// } +// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean parseFrom(java.io.InputStream input) +// throws java.io.IOException { +// return com.google.protobuf.GeneratedMessageV3 +// .parseWithIOException(PARSER, input); +// } +// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean parseFrom( +// java.io.InputStream input, +// com.google.protobuf.ExtensionRegistryLite extensionRegistry) +// throws java.io.IOException { +// return com.google.protobuf.GeneratedMessageV3 +// .parseWithIOException(PARSER, input, extensionRegistry); +// } +// +// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean parseDelimitedFrom(java.io.InputStream +// input) +// throws java.io.IOException { +// return com.google.protobuf.GeneratedMessageV3 +// .parseDelimitedWithIOException(PARSER, input); +// } +// +// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean parseDelimitedFrom( +// java.io.InputStream input, +// com.google.protobuf.ExtensionRegistryLite extensionRegistry) +// throws java.io.IOException { +// return com.google.protobuf.GeneratedMessageV3 +// .parseDelimitedWithIOException(PARSER, input, extensionRegistry); +// } +// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean parseFrom( +// com.google.protobuf.CodedInputStream input) +// throws java.io.IOException { +// return com.google.protobuf.GeneratedMessageV3 +// .parseWithIOException(PARSER, input); +// } +// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean parseFrom( +// com.google.protobuf.CodedInputStream input, +// com.google.protobuf.ExtensionRegistryLite extensionRegistry) +// throws java.io.IOException { +// return com.google.protobuf.GeneratedMessageV3 +// .parseWithIOException(PARSER, input, extensionRegistry); +// } +// +// @java.lang.Override +// public Builder newBuilderForType() { return newBuilder(); } +// public static Builder newBuilder() { +// return DEFAULT_INSTANCE.toBuilder(); +// } +// public static Builder newBuilder(org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean prototype) { +// return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); +// } +// @java.lang.Override +// public Builder toBuilder() { +// return this == DEFAULT_INSTANCE +// ? new Builder() : new Builder().mergeFrom(this); +// } +// +// @java.lang.Override +// protected Builder newBuilderForType( +// com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { +// Builder builder = new Builder(parent); +// return builder; +// } +// /** +// * Protobuf type {@code PSimpleBean} +// */ +// public static final class Builder extends +// com.google.protobuf.GeneratedMessageV3.Builder implements +// // @@protoc_insertion_point(builder_implements:PSimpleBean) +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBeanOrBuilder { +// public static final com.google.protobuf.Descriptors.Descriptor +// getDescriptor() { +// return org.redkalex.test.protobuf.PSimpleBeanOuterClass.internal_static_PSimpleBean_descriptor; +// } +// +// @java.lang.Override +// protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable +// internalGetFieldAccessorTable() { +// return org.redkalex.test.protobuf.PSimpleBeanOuterClass.internal_static_PSimpleBean_fieldAccessorTable +// .ensureFieldAccessorsInitialized( +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.class, +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.Builder.class); +// } +// +// // Construct using org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.newBuilder() +// private Builder() { +// +// } +// +// private Builder( +// com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { +// super(parent); +// +// } +// @java.lang.Override +// public Builder clear() { +// super.clear(); +// bitField0_ = 0; +// simple_ = null; +// if (simpleBuilder_ != null) { +// simpleBuilder_.dispose(); +// simpleBuilder_ = null; +// } +// two_ = null; +// if (twoBuilder_ != null) { +// twoBuilder_.dispose(); +// twoBuilder_ = null; +// } +// strings_ = ""; +// return this; +// } +// +// @java.lang.Override +// public com.google.protobuf.Descriptors.Descriptor +// getDescriptorForType() { +// return org.redkalex.test.protobuf.PSimpleBeanOuterClass.internal_static_PSimpleBean_descriptor; +// } +// +// @java.lang.Override +// public org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean getDefaultInstanceForType() { +// return org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.getDefaultInstance(); +// } +// +// @java.lang.Override +// public org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean build() { +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean result = buildPartial(); +// if (!result.isInitialized()) { +// throw newUninitializedMessageException(result); +// } +// return result; +// } +// +// @java.lang.Override +// public org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean buildPartial() { +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean result = new +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean(this); +// if (bitField0_ != 0) { buildPartial0(result); } +// onBuilt(); +// return result; +// } +// +// private void buildPartial0(org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean result) { +// int from_bitField0_ = bitField0_; +// if (((from_bitField0_ & 0x00000001) != 0)) { +// result.simple_ = simpleBuilder_ == null +// ? simple_ +// : simpleBuilder_.build(); +// } +// if (((from_bitField0_ & 0x00000002) != 0)) { +// result.two_ = twoBuilder_ == null +// ? two_ +// : twoBuilder_.build(); +// } +// if (((from_bitField0_ & 0x00000004) != 0)) { +// result.strings_ = strings_; +// } +// } +// +// @java.lang.Override +// public Builder clone() { +// return super.clone(); +// } +// @java.lang.Override +// public Builder setField( +// com.google.protobuf.Descriptors.FieldDescriptor field, +// java.lang.Object value) { +// return super.setField(field, value); +// } +// @java.lang.Override +// public Builder clearField( +// com.google.protobuf.Descriptors.FieldDescriptor field) { +// return super.clearField(field); +// } +// @java.lang.Override +// public Builder clearOneof( +// com.google.protobuf.Descriptors.OneofDescriptor oneof) { +// return super.clearOneof(oneof); +// } +// @java.lang.Override +// public Builder setRepeatedField( +// com.google.protobuf.Descriptors.FieldDescriptor field, +// int index, java.lang.Object value) { +// return super.setRepeatedField(field, index, value); +// } +// @java.lang.Override +// public Builder addRepeatedField( +// com.google.protobuf.Descriptors.FieldDescriptor field, +// java.lang.Object value) { +// return super.addRepeatedField(field, value); +// } +// @java.lang.Override +// public Builder mergeFrom(com.google.protobuf.Message other) { +// if (other instanceof org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean) { +// return mergeFrom((org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean)other); +// } else { +// super.mergeFrom(other); +// return this; +// } +// } +// +// public Builder mergeFrom(org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean other) { +// if (other == org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.getDefaultInstance()) return this; +// if (other.hasSimple()) { +// mergeSimple(other.getSimple()); +// } +// if (other.hasTwo()) { +// mergeTwo(other.getTwo()); +// } +// if (!other.getStrings().isEmpty()) { +// strings_ = other.strings_; +// bitField0_ |= 0x00000004; +// onChanged(); +// } +// this.mergeUnknownFields(other.getUnknownFields()); +// onChanged(); +// return this; +// } +// +// @java.lang.Override +// public final boolean isInitialized() { +// return true; +// } +// +// @java.lang.Override +// public Builder mergeFrom( +// com.google.protobuf.CodedInputStream input, +// com.google.protobuf.ExtensionRegistryLite extensionRegistry) +// throws java.io.IOException { +// if (extensionRegistry == null) { +// throw new java.lang.NullPointerException(); +// } +// try { +// boolean done = false; +// while (!done) { +// int tag = input.readTag(); +// switch (tag) { +// case 0: +// done = true; +// break; +// case 10: { +// input.readMessage( +// getSimpleFieldBuilder().getBuilder(), +// extensionRegistry); +// bitField0_ |= 0x00000001; +// break; +// } // case 10 +// case 18: { +// input.readMessage( +// getTwoFieldBuilder().getBuilder(), +// extensionRegistry); +// bitField0_ |= 0x00000002; +// break; +// } // case 18 +// case 26: { +// strings_ = input.readStringRequireUtf8(); +// bitField0_ |= 0x00000004; +// break; +// } // case 26 +// default: { +// if (!super.parseUnknownField(input, extensionRegistry, tag)) { +// done = true; // was an endgroup tag +// } +// break; +// } // default: +// } // switch (tag) +// } // while (!done) +// } catch (com.google.protobuf.InvalidProtocolBufferException e) { +// throw e.unwrapIOException(); +// } finally { +// onChanged(); +// } // finally +// return this; +// } +// private int bitField0_; +// +// private org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry simple_; +// private com.google.protobuf.SingleFieldBuilderV3< +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry, +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry.Builder, +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntryOrBuilder> simpleBuilder_; +// /** +// * .PSimpleBean.PSimpleEntry simple = 1; +// * @return Whether the simple field is set. +// */ +// public boolean hasSimple() { +// return ((bitField0_ & 0x00000001) != 0); +// } +// /** +// * .PSimpleBean.PSimpleEntry simple = 1; +// * @return The simple. +// */ +// public org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry getSimple() { +// if (simpleBuilder_ == null) { +// return simple_ == null ? +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry.getDefaultInstance() : simple_; +// } else { +// return simpleBuilder_.getMessage(); +// } +// } +// /** +// * .PSimpleBean.PSimpleEntry simple = 1; +// */ +// public Builder setSimple(org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry value) { +// if (simpleBuilder_ == null) { +// if (value == null) { +// throw new NullPointerException(); +// } +// simple_ = value; +// } else { +// simpleBuilder_.setMessage(value); +// } +// bitField0_ |= 0x00000001; +// onChanged(); +// return this; +// } +// /** +// * .PSimpleBean.PSimpleEntry simple = 1; +// */ +// public Builder setSimple( +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry.Builder builderForValue) { +// if (simpleBuilder_ == null) { +// simple_ = builderForValue.build(); +// } else { +// simpleBuilder_.setMessage(builderForValue.build()); +// } +// bitField0_ |= 0x00000001; +// onChanged(); +// return this; +// } +// /** +// * .PSimpleBean.PSimpleEntry simple = 1; +// */ +// public Builder mergeSimple(org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry value) { +// if (simpleBuilder_ == null) { +// if (((bitField0_ & 0x00000001) != 0) && +// simple_ != null && +// simple_ != org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry.getDefaultInstance()) +// { +// getSimpleBuilder().mergeFrom(value); +// } else { +// simple_ = value; +// } +// } else { +// simpleBuilder_.mergeFrom(value); +// } +// bitField0_ |= 0x00000001; +// onChanged(); +// return this; +// } +// /** +// * .PSimpleBean.PSimpleEntry simple = 1; +// */ +// public Builder clearSimple() { +// bitField0_ = (bitField0_ & ~0x00000001); +// simple_ = null; +// if (simpleBuilder_ != null) { +// simpleBuilder_.dispose(); +// simpleBuilder_ = null; +// } +// onChanged(); +// return this; +// } +// /** +// * .PSimpleBean.PSimpleEntry simple = 1; +// */ +// public org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry.Builder getSimpleBuilder() { +// bitField0_ |= 0x00000001; +// onChanged(); +// return getSimpleFieldBuilder().getBuilder(); +// } +// /** +// * .PSimpleBean.PSimpleEntry simple = 1; +// */ +// public org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntryOrBuilder getSimpleOrBuilder() { +// if (simpleBuilder_ != null) { +// return simpleBuilder_.getMessageOrBuilder(); +// } else { +// return simple_ == null ? +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry.getDefaultInstance() : +// simple_; +// } +// } +// /** +// * .PSimpleBean.PSimpleEntry simple = 1; +// */ +// private com.google.protobuf.SingleFieldBuilderV3< +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry, +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry.Builder, +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntryOrBuilder> +// getSimpleFieldBuilder() { +// if (simpleBuilder_ == null) { +// simpleBuilder_ = new com.google.protobuf.SingleFieldBuilderV3< +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry, +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry.Builder, +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PSimpleEntryOrBuilder>( +// getSimple(), +// getParentForChildren(), +// isClean()); +// simple_ = null; +// } +// return simpleBuilder_; +// } +// +// private org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry two_; +// private com.google.protobuf.SingleFieldBuilderV3< +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry, +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry.Builder, +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntryOrBuilder> twoBuilder_; +// /** +// * .PSimpleBean.PTwoEntry two = 2; +// * @return Whether the two field is set. +// */ +// public boolean hasTwo() { +// return ((bitField0_ & 0x00000002) != 0); +// } +// /** +// * .PSimpleBean.PTwoEntry two = 2; +// * @return The two. +// */ +// public org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry getTwo() { +// if (twoBuilder_ == null) { +// return two_ == null ? +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry.getDefaultInstance() : two_; +// } else { +// return twoBuilder_.getMessage(); +// } +// } +// /** +// * .PSimpleBean.PTwoEntry two = 2; +// */ +// public Builder setTwo(org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry value) { +// if (twoBuilder_ == null) { +// if (value == null) { +// throw new NullPointerException(); +// } +// two_ = value; +// } else { +// twoBuilder_.setMessage(value); +// } +// bitField0_ |= 0x00000002; +// onChanged(); +// return this; +// } +// /** +// * .PSimpleBean.PTwoEntry two = 2; +// */ +// public Builder setTwo( +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry.Builder builderForValue) { +// if (twoBuilder_ == null) { +// two_ = builderForValue.build(); +// } else { +// twoBuilder_.setMessage(builderForValue.build()); +// } +// bitField0_ |= 0x00000002; +// onChanged(); +// return this; +// } +// /** +// * .PSimpleBean.PTwoEntry two = 2; +// */ +// public Builder mergeTwo(org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry value) { +// if (twoBuilder_ == null) { +// if (((bitField0_ & 0x00000002) != 0) && +// two_ != null && +// two_ != org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry.getDefaultInstance()) { +// getTwoBuilder().mergeFrom(value); +// } else { +// two_ = value; +// } +// } else { +// twoBuilder_.mergeFrom(value); +// } +// bitField0_ |= 0x00000002; +// onChanged(); +// return this; +// } +// /** +// * .PSimpleBean.PTwoEntry two = 2; +// */ +// public Builder clearTwo() { +// bitField0_ = (bitField0_ & ~0x00000002); +// two_ = null; +// if (twoBuilder_ != null) { +// twoBuilder_.dispose(); +// twoBuilder_ = null; +// } +// onChanged(); +// return this; +// } +// /** +// * .PSimpleBean.PTwoEntry two = 2; +// */ +// public org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry.Builder getTwoBuilder() { +// bitField0_ |= 0x00000002; +// onChanged(); +// return getTwoFieldBuilder().getBuilder(); +// } +// /** +// * .PSimpleBean.PTwoEntry two = 2; +// */ +// public org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntryOrBuilder getTwoOrBuilder() { +// if (twoBuilder_ != null) { +// return twoBuilder_.getMessageOrBuilder(); +// } else { +// return two_ == null ? +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry.getDefaultInstance() : two_; +// } +// } +// /** +// * .PSimpleBean.PTwoEntry two = 2; +// */ +// private com.google.protobuf.SingleFieldBuilderV3< +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry, +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry.Builder, +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntryOrBuilder> +// getTwoFieldBuilder() { +// if (twoBuilder_ == null) { +// twoBuilder_ = new com.google.protobuf.SingleFieldBuilderV3< +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry, +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntry.Builder, +// org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean.PTwoEntryOrBuilder>( +// getTwo(), +// getParentForChildren(), +// isClean()); +// two_ = null; +// } +// return twoBuilder_; +// } +// +// private java.lang.Object strings_ = ""; +// /** +// * string strings = 3; +// * @return The strings. +// */ +// public java.lang.String getStrings() { +// java.lang.Object ref = strings_; +// if (!(ref instanceof java.lang.String)) { +// com.google.protobuf.ByteString bs = +// (com.google.protobuf.ByteString) ref; +// java.lang.String s = bs.toStringUtf8(); +// strings_ = s; +// return s; +// } else { +// return (java.lang.String) ref; +// } +// } +// /** +// * string strings = 3; +// * @return The bytes for strings. +// */ +// public com.google.protobuf.ByteString +// getStringsBytes() { +// java.lang.Object ref = strings_; +// if (ref instanceof String) { +// com.google.protobuf.ByteString b = +// com.google.protobuf.ByteString.copyFromUtf8( +// (java.lang.String) ref); +// strings_ = b; +// return b; +// } else { +// return (com.google.protobuf.ByteString) ref; +// } +// } +// /** +// * string strings = 3; +// * @param value The strings to set. +// * @return This builder for chaining. +// */ +// public Builder setStrings( +// java.lang.String value) { +// if (value == null) { throw new NullPointerException(); } +// strings_ = value; +// bitField0_ |= 0x00000004; +// onChanged(); +// return this; +// } +// /** +// * string strings = 3; +// * @return This builder for chaining. +// */ +// public Builder clearStrings() { +// strings_ = getDefaultInstance().getStrings(); +// bitField0_ = (bitField0_ & ~0x00000004); +// onChanged(); +// return this; +// } +// /** +// * string strings = 3; +// * @param value The bytes for strings to set. +// * @return This builder for chaining. +// */ +// public Builder setStringsBytes( +// com.google.protobuf.ByteString value) { +// if (value == null) { throw new NullPointerException(); } +// checkByteStringIsUtf8(value); +// strings_ = value; +// bitField0_ |= 0x00000004; +// onChanged(); +// return this; +// } +// @java.lang.Override +// public final Builder setUnknownFields( +// final com.google.protobuf.UnknownFieldSet unknownFields) { +// return super.setUnknownFields(unknownFields); +// } +// +// @java.lang.Override +// public final Builder mergeUnknownFields( +// final com.google.protobuf.UnknownFieldSet unknownFields) { +// return super.mergeUnknownFields(unknownFields); +// } +// +// +// // @@protoc_insertion_point(builder_scope:PSimpleBean) +// } +// +// // @@protoc_insertion_point(class_scope:PSimpleBean) +// private static final org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean DEFAULT_INSTANCE; +// static { +// DEFAULT_INSTANCE = new org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean(); +// } +// +// public static org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean getDefaultInstance() { +// return DEFAULT_INSTANCE; +// } +// +// private static final com.google.protobuf.Parser +// PARSER = new com.google.protobuf.AbstractParser() { +// @java.lang.Override +// public PSimpleBean parsePartialFrom( +// com.google.protobuf.CodedInputStream input, +// com.google.protobuf.ExtensionRegistryLite extensionRegistry) +// throws com.google.protobuf.InvalidProtocolBufferException { +// Builder builder = newBuilder(); +// try { +// builder.mergeFrom(input, extensionRegistry); +// } catch (com.google.protobuf.InvalidProtocolBufferException e) { +// throw e.setUnfinishedMessage(builder.buildPartial()); +// } catch (com.google.protobuf.UninitializedMessageException e) { +// throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); +// } catch (java.io.IOException e) { +// throw new com.google.protobuf.InvalidProtocolBufferException(e) +// .setUnfinishedMessage(builder.buildPartial()); +// } +// return builder.buildPartial(); +// } +// }; +// +// public static com.google.protobuf.Parser parser() { +// return PARSER; +// } +// +// @java.lang.Override +// public com.google.protobuf.Parser getParserForType() { +// return PARSER; +// } +// +// @java.lang.Override +// public org.redkalex.test.protobuf.PSimpleBeanOuterClass.PSimpleBean getDefaultInstanceForType() { +// return DEFAULT_INSTANCE; +// } +// +// } +// +// private static final com.google.protobuf.Descriptors.Descriptor +// internal_static_PSimpleBean_descriptor; +// private static final +// com.google.protobuf.GeneratedMessageV3.FieldAccessorTable +// internal_static_PSimpleBean_fieldAccessorTable; +// private static final com.google.protobuf.Descriptors.Descriptor +// internal_static_PSimpleBean_PSimpleEntry_descriptor; +// private static final +// com.google.protobuf.GeneratedMessageV3.FieldAccessorTable +// internal_static_PSimpleBean_PSimpleEntry_fieldAccessorTable; +// private static final com.google.protobuf.Descriptors.Descriptor +// internal_static_PSimpleBean_PTwoEntry_descriptor; +// private static final +// com.google.protobuf.GeneratedMessageV3.FieldAccessorTable +// internal_static_PSimpleBean_PTwoEntry_fieldAccessorTable; +// +// public static com.google.protobuf.Descriptors.FileDescriptor +// getDescriptor() { +// return descriptor; +// } +// private static com.google.protobuf.Descriptors.FileDescriptor +// descriptor; +// static { +// java.lang.String[] descriptorData = { +// "\n:src/test/java/org/redkalex/test/protob" + +// "uf/PSimpleBean.proto\"\330\001\n\013PSimpleBean\022)\n\006" + +// "simple\030\001 \001(\0132\031.PSimpleBean.PSimpleEntry\022" + +// "#\n\003two\030\002 \001(\0132\026.PSimpleBean.PTwoEntry\022\017\n\007" + +// "strings\030\003 \001(\t\0327\n\014PSimpleEntry\022\n\n\002id\030\001 \001(" + +// "\021\022\014\n\004name\030\002 \001(\t\022\r\n\005email\030\003 \001(\t\032/\n\tPTwoEn" + +// "try\022\016\n\006status\030\001 \001(\021\022\022\n\ncreatetime\030\002 \001(\022B" + +// "\034\n\032org.redkalex.test.protobufb\006proto3" +// }; +// descriptor = com.google.protobuf.Descriptors.FileDescriptor +// .internalBuildGeneratedFileFrom(descriptorData, +// new com.google.protobuf.Descriptors.FileDescriptor[] { +// }); +// internal_static_PSimpleBean_descriptor = +// getDescriptor().getMessageTypes().get(0); +// internal_static_PSimpleBean_fieldAccessorTable = new +// com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( +// internal_static_PSimpleBean_descriptor, +// new java.lang.String[] { "Simple", "Two", "Strings", }); +// internal_static_PSimpleBean_PSimpleEntry_descriptor = +// internal_static_PSimpleBean_descriptor.getNestedTypes().get(0); +// internal_static_PSimpleBean_PSimpleEntry_fieldAccessorTable = new +// com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( +// internal_static_PSimpleBean_PSimpleEntry_descriptor, +// new java.lang.String[] { "Id", "Name", "Email", }); +// internal_static_PSimpleBean_PTwoEntry_descriptor = +// internal_static_PSimpleBean_descriptor.getNestedTypes().get(1); +// internal_static_PSimpleBean_PTwoEntry_fieldAccessorTable = new +// com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( +// internal_static_PSimpleBean_PTwoEntry_descriptor, +// new java.lang.String[] { "Status", "Createtime", }); +// } +// +// // @@protoc_insertion_point(outer_class_scope) +// } diff --git a/src/test/java/org/redkale/test/convert/proto/PTestBeanOuterClass.java b/src/test/java/org/redkale/test/convert/proto/PTestBeanOuterClass.java index fb92102e7..ddf21f99e 100644 --- a/src/test/java/org/redkale/test/convert/proto/PTestBeanOuterClass.java +++ b/src/test/java/org/redkale/test/convert/proto/PTestBeanOuterClass.java @@ -1,4564 +1,4564 @@ -package org.redkale.test.convert.proto; - -//// Generated by the protocol buffer compiler. DO NOT EDIT! -//// source: src/test/java/org/redkalex/test/protobuf/PTestBean.proto -// -// package org.redkalex.test.protobuf; -// -// public final class PTestBeanOuterClass { -// private PTestBeanOuterClass() {} -// public static void registerAllExtensions( -// com.google.protobuf.ExtensionRegistryLite registry) { -// } -// -// public static void registerAllExtensions( -// com.google.protobuf.ExtensionRegistry registry) { -// registerAllExtensions( -// (com.google.protobuf.ExtensionRegistryLite) registry); -// } -// public interface PTestBeanOrBuilder extends -// // @@protoc_insertion_point(interface_extends:PTestBean) -// com.google.protobuf.MessageOrBuilder { -// -// /** -// * repeated bool bools = 1; -// * @return A list containing the bools. -// */ -// java.util.List getBoolsList(); -// /** -// * repeated bool bools = 1; -// * @return The count of bools. -// */ -// int getBoolsCount(); -// /** -// * repeated bool bools = 1; -// * @param index The index of the element to return. -// * @return The bools at the given index. -// */ -// boolean getBools(int index); -// -// /** -// * repeated bytes bytes = 2; -// * @return A list containing the bytes. -// */ -// java.util.List getBytesList(); -// /** -// * repeated bytes bytes = 2; -// * @return The count of bytes. -// */ -// int getBytesCount(); -// /** -// * repeated bytes bytes = 2; -// * @param index The index of the element to return. -// * @return The bytes at the given index. -// */ -// com.google.protobuf.ByteString getBytes(int index); -// -// /** -// * repeated sint32 chars = 3; -// * @return A list containing the chars. -// */ -// java.util.List getCharsList(); -// /** -// * repeated sint32 chars = 3; -// * @return The count of chars. -// */ -// int getCharsCount(); -// /** -// * repeated sint32 chars = 3; -// * @param index The index of the element to return. -// * @return The chars at the given index. -// */ -// int getChars(int index); -// -// /** -// * repeated .PTestBean.PTestEntry entrys = 4; -// */ -// java.util.List -// getEntrysList(); -// /** -// * repeated .PTestBean.PTestEntry entrys = 4; -// */ -// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry getEntrys(int index); -// /** -// * repeated .PTestBean.PTestEntry entrys = 4; -// */ -// int getEntrysCount(); -// /** -// * repeated .PTestBean.PTestEntry entrys = 4; -// */ -// java.util.List -// getEntrysOrBuilderList(); -// /** -// * repeated .PTestBean.PTestEntry entrys = 4; -// */ -// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntryOrBuilder getEntrysOrBuilder( -// int index); -// -// /** -// * repeated sint32 ints = 5; -// * @return A list containing the ints. -// */ -// java.util.List getIntsList(); -// /** -// * repeated sint32 ints = 5; -// * @return The count of ints. -// */ -// int getIntsCount(); -// /** -// * repeated sint32 ints = 5; -// * @param index The index of the element to return. -// * @return The ints at the given index. -// */ -// int getInts(int index); -// -// /** -// * repeated float floats = 6; -// * @return A list containing the floats. -// */ -// java.util.List getFloatsList(); -// /** -// * repeated float floats = 6; -// * @return The count of floats. -// */ -// int getFloatsCount(); -// /** -// * repeated float floats = 6; -// * @param index The index of the element to return. -// * @return The floats at the given index. -// */ -// float getFloats(int index); -// -// /** -// * repeated sint64 longs = 7; -// * @return A list containing the longs. -// */ -// java.util.List getLongsList(); -// /** -// * repeated sint64 longs = 7; -// * @return The count of longs. -// */ -// int getLongsCount(); -// /** -// * repeated sint64 longs = 7; -// * @param index The index of the element to return. -// * @return The longs at the given index. -// */ -// long getLongs(int index); -// -// /** -// * repeated double doubles = 8; -// * @return A list containing the doubles. -// */ -// java.util.List getDoublesList(); -// /** -// * repeated double doubles = 8; -// * @return The count of doubles. -// */ -// int getDoublesCount(); -// /** -// * repeated double doubles = 8; -// * @param index The index of the element to return. -// * @return The doubles at the given index. -// */ -// double getDoubles(int index); -// -// /** -// * repeated string strings = 9; -// * @return A list containing the strings. -// */ -// java.util.List -// getStringsList(); -// /** -// * repeated string strings = 9; -// * @return The count of strings. -// */ -// int getStringsCount(); -// /** -// * repeated string strings = 9; -// * @param index The index of the element to return. -// * @return The strings at the given index. -// */ -// java.lang.String getStrings(int index); -// /** -// * repeated string strings = 9; -// * @param index The index of the value to return. -// * @return The bytes of the strings at the given index. -// */ -// com.google.protobuf.ByteString -// getStringsBytes(int index); -// -// /** -// * sint32 id = 10; -// * @return The id. -// */ -// int getId(); -// -// /** -// * string name = 11; -// * @return The name. -// */ -// java.lang.String getName(); -// /** -// * string name = 11; -// * @return The bytes for name. -// */ -// com.google.protobuf.ByteString -// getNameBytes(); -// -// /** -// * string email = 12; -// * @return The email. -// */ -// java.lang.String getEmail(); -// /** -// * string email = 12; -// * @return The bytes for email. -// */ -// com.google.protobuf.ByteString -// getEmailBytes(); -// -// /** -// * .PTestBean.Kind kind = 13; -// * @return The enum numeric value on the wire for kind. -// */ -// int getKindValue(); -// /** -// * .PTestBean.Kind kind = 13; -// * @return The kind. -// */ -// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.Kind getKind(); -// -// /** -// * map<string, sint32> map = 14; -// */ -// int getMapCount(); -// /** -// * map<string, sint32> map = 14; -// */ -// boolean containsMap( -// java.lang.String key); -// /** -// * Use {@link #getMapMap()} instead. -// */ -// @java.lang.Deprecated -// java.util.Map -// getMap(); -// /** -// * map<string, sint32> map = 14; -// */ -// java.util.Map -// getMapMap(); -// /** -// * map<string, sint32> map = 14; -// */ -// int getMapOrDefault( -// java.lang.String key, -// int defaultValue); -// /** -// * map<string, sint32> map = 14; -// */ -// int getMapOrThrow( -// java.lang.String key); -// -// /** -// * string end = 15; -// * @return The end. -// */ -// java.lang.String getEnd(); -// /** -// * string end = 15; -// * @return The bytes for end. -// */ -// com.google.protobuf.ByteString -// getEndBytes(); -// } -// /** -// * Protobuf type {@code PTestBean} -// */ -// public static final class PTestBean extends -// com.google.protobuf.GeneratedMessageV3 implements -// // @@protoc_insertion_point(message_implements:PTestBean) -// PTestBeanOrBuilder { -// private static final long serialVersionUID = 0L; -// // Use PTestBean.newBuilder() to construct. -// private PTestBean(com.google.protobuf.GeneratedMessageV3.Builder builder) { -// super(builder); -// } -// private PTestBean() { -// bools_ = emptyBooleanList(); -// bytes_ = java.util.Collections.emptyList(); -// chars_ = emptyIntList(); -// entrys_ = java.util.Collections.emptyList(); -// ints_ = emptyIntList(); -// floats_ = emptyFloatList(); -// longs_ = emptyLongList(); -// doubles_ = emptyDoubleList(); -// strings_ = -// com.google.protobuf.LazyStringArrayList.emptyList(); -// name_ = ""; -// email_ = ""; -// kind_ = 0; -// end_ = ""; -// } -// -// @java.lang.Override -// @SuppressWarnings({"unused"}) -// protected java.lang.Object newInstance( -// UnusedPrivateParameter unused) { -// return new PTestBean(); -// } -// -// public static final com.google.protobuf.Descriptors.Descriptor -// getDescriptor() { -// return org.redkalex.test.protobuf.PTestBeanOuterClass.internal_static_PTestBean_descriptor; -// } -// -// @SuppressWarnings({"rawtypes"}) -// @java.lang.Override -// protected com.google.protobuf.MapField internalGetMapField( -// int number) { -// switch (number) { -// case 14: -// return internalGetMap(); -// default: -// throw new RuntimeException( -// "Invalid map field number: " + number); -// } -// } -// @java.lang.Override -// protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable -// internalGetFieldAccessorTable() { -// return org.redkalex.test.protobuf.PTestBeanOuterClass.internal_static_PTestBean_fieldAccessorTable -// .ensureFieldAccessorsInitialized( -// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.class, -// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.Builder.class); -// } -// -// /** -// * Protobuf enum {@code PTestBean.Kind} -// */ -// public enum Kind -// implements com.google.protobuf.ProtocolMessageEnum { -// /** -// * ONE = 0; -// */ -// ONE(0), -// /** -// * TWO = 1; -// */ -// TWO(1), -// /** -// * THREE = 2; -// */ -// THREE(2), -// UNRECOGNIZED(-1), -// ; -// -// /** -// * ONE = 0; -// */ -// public static final int ONE_VALUE = 0; -// /** -// * TWO = 1; -// */ -// public static final int TWO_VALUE = 1; -// /** -// * THREE = 2; -// */ -// public static final int THREE_VALUE = 2; -// -// -// public final int getNumber() { -// if (this == UNRECOGNIZED) { -// throw new java.lang.IllegalArgumentException( -// "Can't get the number of an unknown enum value."); -// } -// return value; -// } -// -// /** -// * @param value The numeric wire value of the corresponding enum entry. -// * @return The enum associated with the given numeric wire value. -// * @deprecated Use {@link #forNumber(int)} instead. -// */ -// @java.lang.Deprecated -// public static Kind valueOf(int value) { -// return forNumber(value); -// } -// -// /** -// * @param value The numeric wire value of the corresponding enum entry. -// * @return The enum associated with the given numeric wire value. -// */ -// public static Kind forNumber(int value) { -// switch (value) { -// case 0: return ONE; -// case 1: return TWO; -// case 2: return THREE; -// default: return null; -// } -// } -// -// public static com.google.protobuf.Internal.EnumLiteMap -// internalGetValueMap() { -// return internalValueMap; -// } -// private static final com.google.protobuf.Internal.EnumLiteMap< -// Kind> internalValueMap = -// new com.google.protobuf.Internal.EnumLiteMap() { -// public Kind findValueByNumber(int number) { -// return Kind.forNumber(number); -// } -// }; -// -// public final com.google.protobuf.Descriptors.EnumValueDescriptor -// getValueDescriptor() { -// if (this == UNRECOGNIZED) { -// throw new java.lang.IllegalStateException( -// "Can't get the descriptor of an unrecognized enum value."); -// } -// return getDescriptor().getValues().get(ordinal()); -// } -// public final com.google.protobuf.Descriptors.EnumDescriptor -// getDescriptorForType() { -// return getDescriptor(); -// } -// public static final com.google.protobuf.Descriptors.EnumDescriptor -// getDescriptor() { -// return org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.getDescriptor().getEnumTypes().get(0); -// } -// -// private static final Kind[] VALUES = values(); -// -// public static Kind valueOf( -// com.google.protobuf.Descriptors.EnumValueDescriptor desc) { -// if (desc.getType() != getDescriptor()) { -// throw new java.lang.IllegalArgumentException( -// "EnumValueDescriptor is not for this type."); -// } -// if (desc.getIndex() == -1) { -// return UNRECOGNIZED; -// } -// return VALUES[desc.getIndex()]; -// } -// -// private final int value; -// -// private Kind(int value) { -// this.value = value; -// } -// -// // @@protoc_insertion_point(enum_scope:PTestBean.Kind) -// } -// -// public interface PTestEntryOrBuilder extends -// // @@protoc_insertion_point(interface_extends:PTestBean.PTestEntry) -// com.google.protobuf.MessageOrBuilder { -// -// /** -// * repeated bool bools = 1; -// * @return A list containing the bools. -// */ -// java.util.List getBoolsList(); -// /** -// * repeated bool bools = 1; -// * @return The count of bools. -// */ -// int getBoolsCount(); -// /** -// * repeated bool bools = 1; -// * @param index The index of the element to return. -// * @return The bools at the given index. -// */ -// boolean getBools(int index); -// -// /** -// * repeated bytes bytes = 2; -// * @return A list containing the bytes. -// */ -// java.util.List getBytesList(); -// /** -// * repeated bytes bytes = 2; -// * @return The count of bytes. -// */ -// int getBytesCount(); -// /** -// * repeated bytes bytes = 2; -// * @param index The index of the element to return. -// * @return The bytes at the given index. -// */ -// com.google.protobuf.ByteString getBytes(int index); -// -// /** -// * repeated sint32 chars = 3; -// * @return A list containing the chars. -// */ -// java.util.List getCharsList(); -// /** -// * repeated sint32 chars = 3; -// * @return The count of chars. -// */ -// int getCharsCount(); -// /** -// * repeated sint32 chars = 3; -// * @param index The index of the element to return. -// * @return The chars at the given index. -// */ -// int getChars(int index); -// -// /** -// * repeated sint32 shorts = 4; -// * @return A list containing the shorts. -// */ -// java.util.List getShortsList(); -// /** -// * repeated sint32 shorts = 4; -// * @return The count of shorts. -// */ -// int getShortsCount(); -// /** -// * repeated sint32 shorts = 4; -// * @param index The index of the element to return. -// * @return The shorts at the given index. -// */ -// int getShorts(int index); -// } -// /** -// * Protobuf type {@code PTestBean.PTestEntry} -// */ -// public static final class PTestEntry extends -// com.google.protobuf.GeneratedMessageV3 implements -// // @@protoc_insertion_point(message_implements:PTestBean.PTestEntry) -// PTestEntryOrBuilder { -// private static final long serialVersionUID = 0L; -// // Use PTestEntry.newBuilder() to construct. -// private PTestEntry(com.google.protobuf.GeneratedMessageV3.Builder builder) { -// super(builder); -// } -// private PTestEntry() { -// bools_ = emptyBooleanList(); -// bytes_ = java.util.Collections.emptyList(); -// chars_ = emptyIntList(); -// shorts_ = emptyIntList(); -// } -// -// @java.lang.Override -// @SuppressWarnings({"unused"}) -// protected java.lang.Object newInstance( -// UnusedPrivateParameter unused) { -// return new PTestEntry(); -// } -// -// public static final com.google.protobuf.Descriptors.Descriptor -// getDescriptor() { -// return org.redkalex.test.protobuf.PTestBeanOuterClass.internal_static_PTestBean_PTestEntry_descriptor; -// } -// -// @java.lang.Override -// protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable -// internalGetFieldAccessorTable() { -// return org.redkalex.test.protobuf.PTestBeanOuterClass.internal_static_PTestBean_PTestEntry_fieldAccessorTable -// .ensureFieldAccessorsInitialized( -// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry.class, -// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry.Builder.class); -// } -// -// public static final int BOOLS_FIELD_NUMBER = 1; -// @SuppressWarnings("serial") -// private com.google.protobuf.Internal.BooleanList bools_; -// /** -// * repeated bool bools = 1; -// * @return A list containing the bools. -// */ -// @java.lang.Override -// public java.util.List -// getBoolsList() { -// return bools_; -// } -// /** -// * repeated bool bools = 1; -// * @return The count of bools. -// */ -// public int getBoolsCount() { -// return bools_.size(); -// } -// /** -// * repeated bool bools = 1; -// * @param index The index of the element to return. -// * @return The bools at the given index. -// */ -// public boolean getBools(int index) { -// return bools_.getBoolean(index); -// } -// private int boolsMemoizedSerializedSize = -1; -// -// public static final int BYTES_FIELD_NUMBER = 2; -// @SuppressWarnings("serial") -// private java.util.List bytes_; -// /** -// * repeated bytes bytes = 2; -// * @return A list containing the bytes. -// */ -// @java.lang.Override -// public java.util.List -// getBytesList() { -// return bytes_; -// } -// /** -// * repeated bytes bytes = 2; -// * @return The count of bytes. -// */ -// public int getBytesCount() { -// return bytes_.size(); -// } -// /** -// * repeated bytes bytes = 2; -// * @param index The index of the element to return. -// * @return The bytes at the given index. -// */ -// public com.google.protobuf.ByteString getBytes(int index) { -// return bytes_.get(index); -// } -// -// public static final int CHARS_FIELD_NUMBER = 3; -// @SuppressWarnings("serial") -// private com.google.protobuf.Internal.IntList chars_; -// /** -// * repeated sint32 chars = 3; -// * @return A list containing the chars. -// */ -// @java.lang.Override -// public java.util.List -// getCharsList() { -// return chars_; -// } -// /** -// * repeated sint32 chars = 3; -// * @return The count of chars. -// */ -// public int getCharsCount() { -// return chars_.size(); -// } -// /** -// * repeated sint32 chars = 3; -// * @param index The index of the element to return. -// * @return The chars at the given index. -// */ -// public int getChars(int index) { -// return chars_.getInt(index); -// } -// private int charsMemoizedSerializedSize = -1; -// -// public static final int SHORTS_FIELD_NUMBER = 4; -// @SuppressWarnings("serial") -// private com.google.protobuf.Internal.IntList shorts_; -// /** -// * repeated sint32 shorts = 4; -// * @return A list containing the shorts. -// */ -// @java.lang.Override -// public java.util.List -// getShortsList() { -// return shorts_; -// } -// /** -// * repeated sint32 shorts = 4; -// * @return The count of shorts. -// */ -// public int getShortsCount() { -// return shorts_.size(); -// } -// /** -// * repeated sint32 shorts = 4; -// * @param index The index of the element to return. -// * @return The shorts at the given index. -// */ -// public int getShorts(int index) { -// return shorts_.getInt(index); -// } -// private int shortsMemoizedSerializedSize = -1; -// -// private byte memoizedIsInitialized = -1; -// @java.lang.Override -// public final boolean isInitialized() { -// byte isInitialized = memoizedIsInitialized; -// if (isInitialized == 1) return true; -// if (isInitialized == 0) return false; -// -// memoizedIsInitialized = 1; -// return true; -// } -// -// @java.lang.Override -// public void writeTo(com.google.protobuf.CodedOutputStream output) -// throws java.io.IOException { -// getSerializedSize(); -// if (getBoolsList().size() > 0) { -// output.writeUInt32NoTag(10); -// output.writeUInt32NoTag(boolsMemoizedSerializedSize); -// } -// for (int i = 0; i < bools_.size(); i++) { -// output.writeBoolNoTag(bools_.getBoolean(i)); -// } -// for (int i = 0; i < bytes_.size(); i++) { -// output.writeBytes(2, bytes_.get(i)); -// } -// if (getCharsList().size() > 0) { -// output.writeUInt32NoTag(26); -// output.writeUInt32NoTag(charsMemoizedSerializedSize); -// } -// for (int i = 0; i < chars_.size(); i++) { -// output.writeSInt32NoTag(chars_.getInt(i)); -// } -// if (getShortsList().size() > 0) { -// output.writeUInt32NoTag(34); -// output.writeUInt32NoTag(shortsMemoizedSerializedSize); -// } -// for (int i = 0; i < shorts_.size(); i++) { -// output.writeSInt32NoTag(shorts_.getInt(i)); -// } -// getUnknownFields().writeTo(output); -// } -// -// @java.lang.Override -// public int getSerializedSize() { -// int size = memoizedSize; -// if (size != -1) return size; -// -// size = 0; -// { -// int dataSize = 0; -// dataSize = 1 * getBoolsList().size(); -// size += dataSize; -// if (!getBoolsList().isEmpty()) { -// size += 1; -// size += com.google.protobuf.CodedOutputStream -// .computeInt32SizeNoTag(dataSize); -// } -// boolsMemoizedSerializedSize = dataSize; -// } -// { -// int dataSize = 0; -// for (int i = 0; i < bytes_.size(); i++) { -// dataSize += com.google.protobuf.CodedOutputStream -// .computeBytesSizeNoTag(bytes_.get(i)); -// } -// size += dataSize; -// size += 1 * getBytesList().size(); -// } -// { -// int dataSize = 0; -// for (int i = 0; i < chars_.size(); i++) { -// dataSize += com.google.protobuf.CodedOutputStream -// .computeSInt32SizeNoTag(chars_.getInt(i)); -// } -// size += dataSize; -// if (!getCharsList().isEmpty()) { -// size += 1; -// size += com.google.protobuf.CodedOutputStream -// .computeInt32SizeNoTag(dataSize); -// } -// charsMemoizedSerializedSize = dataSize; -// } -// { -// int dataSize = 0; -// for (int i = 0; i < shorts_.size(); i++) { -// dataSize += com.google.protobuf.CodedOutputStream -// .computeSInt32SizeNoTag(shorts_.getInt(i)); -// } -// size += dataSize; -// if (!getShortsList().isEmpty()) { -// size += 1; -// size += com.google.protobuf.CodedOutputStream -// .computeInt32SizeNoTag(dataSize); -// } -// shortsMemoizedSerializedSize = dataSize; -// } -// size += getUnknownFields().getSerializedSize(); -// memoizedSize = size; -// return size; -// } -// -// @java.lang.Override -// public boolean equals(final java.lang.Object obj) { -// if (obj == this) { -// return true; -// } -// if (!(obj instanceof org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry)) { -// return super.equals(obj); -// } -// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry other = -// (org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry) obj; -// -// if (!getBoolsList() -// .equals(other.getBoolsList())) return false; -// if (!getBytesList() -// .equals(other.getBytesList())) return false; -// if (!getCharsList() -// .equals(other.getCharsList())) return false; -// if (!getShortsList() -// .equals(other.getShortsList())) return false; -// if (!getUnknownFields().equals(other.getUnknownFields())) return false; -// return true; -// } -// -// @java.lang.Override -// public int hashCode() { -// if (memoizedHashCode != 0) { -// return memoizedHashCode; -// } -// int hash = 41; -// hash = (19 * hash) + getDescriptor().hashCode(); -// if (getBoolsCount() > 0) { -// hash = (37 * hash) + BOOLS_FIELD_NUMBER; -// hash = (53 * hash) + getBoolsList().hashCode(); -// } -// if (getBytesCount() > 0) { -// hash = (37 * hash) + BYTES_FIELD_NUMBER; -// hash = (53 * hash) + getBytesList().hashCode(); -// } -// if (getCharsCount() > 0) { -// hash = (37 * hash) + CHARS_FIELD_NUMBER; -// hash = (53 * hash) + getCharsList().hashCode(); -// } -// if (getShortsCount() > 0) { -// hash = (37 * hash) + SHORTS_FIELD_NUMBER; -// hash = (53 * hash) + getShortsList().hashCode(); -// } -// hash = (29 * hash) + getUnknownFields().hashCode(); -// memoizedHashCode = hash; -// return hash; -// } -// -// public static org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry parseFrom( -// java.nio.ByteBuffer data) -// throws com.google.protobuf.InvalidProtocolBufferException { -// return PARSER.parseFrom(data); -// } -// public static org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry parseFrom( -// java.nio.ByteBuffer data, -// com.google.protobuf.ExtensionRegistryLite extensionRegistry) -// throws com.google.protobuf.InvalidProtocolBufferException { -// return PARSER.parseFrom(data, extensionRegistry); -// } -// public static org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry parseFrom( -// com.google.protobuf.ByteString data) -// throws com.google.protobuf.InvalidProtocolBufferException { -// return PARSER.parseFrom(data); -// } -// public static org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry parseFrom( -// com.google.protobuf.ByteString data, -// com.google.protobuf.ExtensionRegistryLite extensionRegistry) -// throws com.google.protobuf.InvalidProtocolBufferException { -// return PARSER.parseFrom(data, extensionRegistry); -// } -// public static org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry parseFrom(byte[] data) -// throws com.google.protobuf.InvalidProtocolBufferException { -// return PARSER.parseFrom(data); -// } -// public static org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry parseFrom( -// byte[] data, -// com.google.protobuf.ExtensionRegistryLite extensionRegistry) -// throws com.google.protobuf.InvalidProtocolBufferException { -// return PARSER.parseFrom(data, extensionRegistry); -// } -// public static org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry parseFrom(java.io.InputStream -// input) -// throws java.io.IOException { -// return com.google.protobuf.GeneratedMessageV3 -// .parseWithIOException(PARSER, input); -// } -// public static org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry parseFrom( -// java.io.InputStream input, -// com.google.protobuf.ExtensionRegistryLite extensionRegistry) -// throws java.io.IOException { -// return com.google.protobuf.GeneratedMessageV3 -// .parseWithIOException(PARSER, input, extensionRegistry); -// } -// -// public static org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry -// parseDelimitedFrom(java.io.InputStream input) -// throws java.io.IOException { -// return com.google.protobuf.GeneratedMessageV3 -// .parseDelimitedWithIOException(PARSER, input); -// } -// -// public static org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry parseDelimitedFrom( -// java.io.InputStream input, -// com.google.protobuf.ExtensionRegistryLite extensionRegistry) -// throws java.io.IOException { -// return com.google.protobuf.GeneratedMessageV3 -// .parseDelimitedWithIOException(PARSER, input, extensionRegistry); -// } -// public static org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry parseFrom( -// com.google.protobuf.CodedInputStream input) -// throws java.io.IOException { -// return com.google.protobuf.GeneratedMessageV3 -// .parseWithIOException(PARSER, input); -// } -// public static org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry parseFrom( -// com.google.protobuf.CodedInputStream input, -// com.google.protobuf.ExtensionRegistryLite extensionRegistry) -// throws java.io.IOException { -// return com.google.protobuf.GeneratedMessageV3 -// .parseWithIOException(PARSER, input, extensionRegistry); -// } -// -// @java.lang.Override -// public Builder newBuilderForType() { return newBuilder(); } -// public static Builder newBuilder() { -// return DEFAULT_INSTANCE.toBuilder(); -// } -// public static Builder newBuilder(org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry prototype) -// { -// return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); -// } -// @java.lang.Override -// public Builder toBuilder() { -// return this == DEFAULT_INSTANCE -// ? new Builder() : new Builder().mergeFrom(this); -// } -// -// @java.lang.Override -// protected Builder newBuilderForType( -// com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { -// Builder builder = new Builder(parent); -// return builder; -// } -// /** -// * Protobuf type {@code PTestBean.PTestEntry} -// */ -// public static final class Builder extends -// com.google.protobuf.GeneratedMessageV3.Builder implements -// // @@protoc_insertion_point(builder_implements:PTestBean.PTestEntry) -// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntryOrBuilder { -// public static final com.google.protobuf.Descriptors.Descriptor -// getDescriptor() { -// return org.redkalex.test.protobuf.PTestBeanOuterClass.internal_static_PTestBean_PTestEntry_descriptor; -// } -// -// @java.lang.Override -// protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable -// internalGetFieldAccessorTable() { -// return -// org.redkalex.test.protobuf.PTestBeanOuterClass.internal_static_PTestBean_PTestEntry_fieldAccessorTable -// .ensureFieldAccessorsInitialized( -// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry.class, -// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry.Builder.class); -// } -// -// // Construct using org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry.newBuilder() -// private Builder() { -// -// } -// -// private Builder( -// com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { -// super(parent); -// -// } -// @java.lang.Override -// public Builder clear() { -// super.clear(); -// bitField0_ = 0; -// bools_ = emptyBooleanList(); -// bytes_ = java.util.Collections.emptyList(); -// chars_ = emptyIntList(); -// shorts_ = emptyIntList(); -// return this; -// } -// -// @java.lang.Override -// public com.google.protobuf.Descriptors.Descriptor -// getDescriptorForType() { -// return org.redkalex.test.protobuf.PTestBeanOuterClass.internal_static_PTestBean_PTestEntry_descriptor; -// } -// -// @java.lang.Override -// public org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry getDefaultInstanceForType() { -// return org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry.getDefaultInstance(); -// } -// -// @java.lang.Override -// public org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry build() { -// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry result = buildPartial(); -// if (!result.isInitialized()) { -// throw newUninitializedMessageException(result); -// } -// return result; -// } -// -// @java.lang.Override -// public org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry buildPartial() { -// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry result = new -// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry(this); -// buildPartialRepeatedFields(result); -// if (bitField0_ != 0) { buildPartial0(result); } -// onBuilt(); -// return result; -// } -// -// private void buildPartialRepeatedFields(org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry -// result) { -// if (((bitField0_ & 0x00000001) != 0)) { -// bools_.makeImmutable(); -// bitField0_ = (bitField0_ & ~0x00000001); -// } -// result.bools_ = bools_; -// if (((bitField0_ & 0x00000002) != 0)) { -// bytes_ = java.util.Collections.unmodifiableList(bytes_); -// bitField0_ = (bitField0_ & ~0x00000002); -// } -// result.bytes_ = bytes_; -// if (((bitField0_ & 0x00000004) != 0)) { -// chars_.makeImmutable(); -// bitField0_ = (bitField0_ & ~0x00000004); -// } -// result.chars_ = chars_; -// if (((bitField0_ & 0x00000008) != 0)) { -// shorts_.makeImmutable(); -// bitField0_ = (bitField0_ & ~0x00000008); -// } -// result.shorts_ = shorts_; -// } -// -// private void buildPartial0(org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry result) { -// int from_bitField0_ = bitField0_; -// } -// -// @java.lang.Override -// public Builder clone() { -// return super.clone(); -// } -// @java.lang.Override -// public Builder setField( -// com.google.protobuf.Descriptors.FieldDescriptor field, -// java.lang.Object value) { -// return super.setField(field, value); -// } -// @java.lang.Override -// public Builder clearField( -// com.google.protobuf.Descriptors.FieldDescriptor field) { -// return super.clearField(field); -// } -// @java.lang.Override -// public Builder clearOneof( -// com.google.protobuf.Descriptors.OneofDescriptor oneof) { -// return super.clearOneof(oneof); -// } -// @java.lang.Override -// public Builder setRepeatedField( -// com.google.protobuf.Descriptors.FieldDescriptor field, -// int index, java.lang.Object value) { -// return super.setRepeatedField(field, index, value); -// } -// @java.lang.Override -// public Builder addRepeatedField( -// com.google.protobuf.Descriptors.FieldDescriptor field, -// java.lang.Object value) { -// return super.addRepeatedField(field, value); -// } -// @java.lang.Override -// public Builder mergeFrom(com.google.protobuf.Message other) { -// if (other instanceof org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry) { -// return mergeFrom((org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry)other); -// } else { -// super.mergeFrom(other); -// return this; -// } -// } -// -// public Builder mergeFrom(org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry other) { -// if (other == org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry.getDefaultInstance()) -// return this; -// if (!other.bools_.isEmpty()) { -// if (bools_.isEmpty()) { -// bools_ = other.bools_; -// bitField0_ = (bitField0_ & ~0x00000001); -// } else { -// ensureBoolsIsMutable(); -// bools_.addAll(other.bools_); -// } -// onChanged(); -// } -// if (!other.bytes_.isEmpty()) { -// if (bytes_.isEmpty()) { -// bytes_ = other.bytes_; -// bitField0_ = (bitField0_ & ~0x00000002); -// } else { -// ensureBytesIsMutable(); -// bytes_.addAll(other.bytes_); -// } -// onChanged(); -// } -// if (!other.chars_.isEmpty()) { -// if (chars_.isEmpty()) { -// chars_ = other.chars_; -// bitField0_ = (bitField0_ & ~0x00000004); -// } else { -// ensureCharsIsMutable(); -// chars_.addAll(other.chars_); -// } -// onChanged(); -// } -// if (!other.shorts_.isEmpty()) { -// if (shorts_.isEmpty()) { -// shorts_ = other.shorts_; -// bitField0_ = (bitField0_ & ~0x00000008); -// } else { -// ensureShortsIsMutable(); -// shorts_.addAll(other.shorts_); -// } -// onChanged(); -// } -// this.mergeUnknownFields(other.getUnknownFields()); -// onChanged(); -// return this; -// } -// -// @java.lang.Override -// public final boolean isInitialized() { -// return true; -// } -// -// @java.lang.Override -// public Builder mergeFrom( -// com.google.protobuf.CodedInputStream input, -// com.google.protobuf.ExtensionRegistryLite extensionRegistry) -// throws java.io.IOException { -// if (extensionRegistry == null) { -// throw new java.lang.NullPointerException(); -// } -// try { -// boolean done = false; -// while (!done) { -// int tag = input.readTag(); -// switch (tag) { -// case 0: -// done = true; -// break; -// case 8: { -// boolean v = input.readBool(); -// ensureBoolsIsMutable(); -// bools_.addBoolean(v); -// break; -// } // case 8 -// case 10: { -// int length = input.readRawVarint32(); -// int limit = input.pushLimit(length); -// ensureBoolsIsMutable(); -// while (input.getBytesUntilLimit() > 0) { -// bools_.addBoolean(input.readBool()); -// } -// input.popLimit(limit); -// break; -// } // case 10 -// case 18: { -// com.google.protobuf.ByteString v = input.readBytes(); -// ensureBytesIsMutable(); -// bytes_.add(v); -// break; -// } // case 18 -// case 24: { -// int v = input.readSInt32(); -// ensureCharsIsMutable(); -// chars_.addInt(v); -// break; -// } // case 24 -// case 26: { -// int length = input.readRawVarint32(); -// int limit = input.pushLimit(length); -// ensureCharsIsMutable(); -// while (input.getBytesUntilLimit() > 0) { -// chars_.addInt(input.readSInt32()); -// } -// input.popLimit(limit); -// break; -// } // case 26 -// case 32: { -// int v = input.readSInt32(); -// ensureShortsIsMutable(); -// shorts_.addInt(v); -// break; -// } // case 32 -// case 34: { -// int length = input.readRawVarint32(); -// int limit = input.pushLimit(length); -// ensureShortsIsMutable(); -// while (input.getBytesUntilLimit() > 0) { -// shorts_.addInt(input.readSInt32()); -// } -// input.popLimit(limit); -// break; -// } // case 34 -// default: { -// if (!super.parseUnknownField(input, extensionRegistry, tag)) { -// done = true; // was an endgroup tag -// } -// break; -// } // default: -// } // switch (tag) -// } // while (!done) -// } catch (com.google.protobuf.InvalidProtocolBufferException e) { -// throw e.unwrapIOException(); -// } finally { -// onChanged(); -// } // finally -// return this; -// } -// private int bitField0_; -// -// private com.google.protobuf.Internal.BooleanList bools_ = emptyBooleanList(); -// private void ensureBoolsIsMutable() { -// if (!((bitField0_ & 0x00000001) != 0)) { -// bools_ = mutableCopy(bools_); -// bitField0_ |= 0x00000001; -// } -// } -// /** -// * repeated bool bools = 1; -// * @return A list containing the bools. -// */ -// public java.util.List -// getBoolsList() { -// return ((bitField0_ & 0x00000001) != 0) ? -// java.util.Collections.unmodifiableList(bools_) : bools_; -// } -// /** -// * repeated bool bools = 1; -// * @return The count of bools. -// */ -// public int getBoolsCount() { -// return bools_.size(); -// } -// /** -// * repeated bool bools = 1; -// * @param index The index of the element to return. -// * @return The bools at the given index. -// */ -// public boolean getBools(int index) { -// return bools_.getBoolean(index); -// } -// /** -// * repeated bool bools = 1; -// * @param index The index to set the value at. -// * @param value The bools to set. -// * @return This builder for chaining. -// */ -// public Builder setBools( -// int index, boolean value) { -// -// ensureBoolsIsMutable(); -// bools_.setBoolean(index, value); -// onChanged(); -// return this; -// } -// /** -// * repeated bool bools = 1; -// * @param value The bools to add. -// * @return This builder for chaining. -// */ -// public Builder addBools(boolean value) { -// -// ensureBoolsIsMutable(); -// bools_.addBoolean(value); -// onChanged(); -// return this; -// } -// /** -// * repeated bool bools = 1; -// * @param values The bools to add. -// * @return This builder for chaining. -// */ -// public Builder addAllBools( -// java.lang.Iterable values) { -// ensureBoolsIsMutable(); -// com.google.protobuf.AbstractMessageLite.Builder.addAll( -// values, bools_); -// onChanged(); -// return this; -// } -// /** -// * repeated bool bools = 1; -// * @return This builder for chaining. -// */ -// public Builder clearBools() { -// bools_ = emptyBooleanList(); -// bitField0_ = (bitField0_ & ~0x00000001); -// onChanged(); -// return this; -// } -// -// private java.util.List bytes_ = java.util.Collections.emptyList(); -// private void ensureBytesIsMutable() { -// if (!((bitField0_ & 0x00000002) != 0)) { -// bytes_ = new java.util.ArrayList(bytes_); -// bitField0_ |= 0x00000002; -// } -// } -// /** -// * repeated bytes bytes = 2; -// * @return A list containing the bytes. -// */ -// public java.util.List -// getBytesList() { -// return ((bitField0_ & 0x00000002) != 0) ? -// java.util.Collections.unmodifiableList(bytes_) : bytes_; -// } -// /** -// * repeated bytes bytes = 2; -// * @return The count of bytes. -// */ -// public int getBytesCount() { -// return bytes_.size(); -// } -// /** -// * repeated bytes bytes = 2; -// * @param index The index of the element to return. -// * @return The bytes at the given index. -// */ -// public com.google.protobuf.ByteString getBytes(int index) { -// return bytes_.get(index); -// } -// /** -// * repeated bytes bytes = 2; -// * @param index The index to set the value at. -// * @param value The bytes to set. -// * @return This builder for chaining. -// */ -// public Builder setBytes( -// int index, com.google.protobuf.ByteString value) { -// if (value == null) { throw new NullPointerException(); } -// ensureBytesIsMutable(); -// bytes_.set(index, value); -// onChanged(); -// return this; -// } -// /** -// * repeated bytes bytes = 2; -// * @param value The bytes to add. -// * @return This builder for chaining. -// */ -// public Builder addBytes(com.google.protobuf.ByteString value) { -// if (value == null) { throw new NullPointerException(); } -// ensureBytesIsMutable(); -// bytes_.add(value); -// onChanged(); -// return this; -// } -// /** -// * repeated bytes bytes = 2; -// * @param values The bytes to add. -// * @return This builder for chaining. -// */ -// public Builder addAllBytes( -// java.lang.Iterable values) { -// ensureBytesIsMutable(); -// com.google.protobuf.AbstractMessageLite.Builder.addAll( -// values, bytes_); -// onChanged(); -// return this; -// } -// /** -// * repeated bytes bytes = 2; -// * @return This builder for chaining. -// */ -// public Builder clearBytes() { -// bytes_ = java.util.Collections.emptyList(); -// bitField0_ = (bitField0_ & ~0x00000002); -// onChanged(); -// return this; -// } -// -// private com.google.protobuf.Internal.IntList chars_ = emptyIntList(); -// private void ensureCharsIsMutable() { -// if (!((bitField0_ & 0x00000004) != 0)) { -// chars_ = mutableCopy(chars_); -// bitField0_ |= 0x00000004; -// } -// } -// /** -// * repeated sint32 chars = 3; -// * @return A list containing the chars. -// */ -// public java.util.List -// getCharsList() { -// return ((bitField0_ & 0x00000004) != 0) ? -// java.util.Collections.unmodifiableList(chars_) : chars_; -// } -// /** -// * repeated sint32 chars = 3; -// * @return The count of chars. -// */ -// public int getCharsCount() { -// return chars_.size(); -// } -// /** -// * repeated sint32 chars = 3; -// * @param index The index of the element to return. -// * @return The chars at the given index. -// */ -// public int getChars(int index) { -// return chars_.getInt(index); -// } -// /** -// * repeated sint32 chars = 3; -// * @param index The index to set the value at. -// * @param value The chars to set. -// * @return This builder for chaining. -// */ -// public Builder setChars( -// int index, int value) { -// -// ensureCharsIsMutable(); -// chars_.setInt(index, value); -// onChanged(); -// return this; -// } -// /** -// * repeated sint32 chars = 3; -// * @param value The chars to add. -// * @return This builder for chaining. -// */ -// public Builder addChars(int value) { -// -// ensureCharsIsMutable(); -// chars_.addInt(value); -// onChanged(); -// return this; -// } -// /** -// * repeated sint32 chars = 3; -// * @param values The chars to add. -// * @return This builder for chaining. -// */ -// public Builder addAllChars( -// java.lang.Iterable values) { -// ensureCharsIsMutable(); -// com.google.protobuf.AbstractMessageLite.Builder.addAll( -// values, chars_); -// onChanged(); -// return this; -// } -// /** -// * repeated sint32 chars = 3; -// * @return This builder for chaining. -// */ -// public Builder clearChars() { -// chars_ = emptyIntList(); -// bitField0_ = (bitField0_ & ~0x00000004); -// onChanged(); -// return this; -// } -// -// private com.google.protobuf.Internal.IntList shorts_ = emptyIntList(); -// private void ensureShortsIsMutable() { -// if (!((bitField0_ & 0x00000008) != 0)) { -// shorts_ = mutableCopy(shorts_); -// bitField0_ |= 0x00000008; -// } -// } -// /** -// * repeated sint32 shorts = 4; -// * @return A list containing the shorts. -// */ -// public java.util.List -// getShortsList() { -// return ((bitField0_ & 0x00000008) != 0) ? -// java.util.Collections.unmodifiableList(shorts_) : shorts_; -// } -// /** -// * repeated sint32 shorts = 4; -// * @return The count of shorts. -// */ -// public int getShortsCount() { -// return shorts_.size(); -// } -// /** -// * repeated sint32 shorts = 4; -// * @param index The index of the element to return. -// * @return The shorts at the given index. -// */ -// public int getShorts(int index) { -// return shorts_.getInt(index); -// } -// /** -// * repeated sint32 shorts = 4; -// * @param index The index to set the value at. -// * @param value The shorts to set. -// * @return This builder for chaining. -// */ -// public Builder setShorts( -// int index, int value) { -// -// ensureShortsIsMutable(); -// shorts_.setInt(index, value); -// onChanged(); -// return this; -// } -// /** -// * repeated sint32 shorts = 4; -// * @param value The shorts to add. -// * @return This builder for chaining. -// */ -// public Builder addShorts(int value) { -// -// ensureShortsIsMutable(); -// shorts_.addInt(value); -// onChanged(); -// return this; -// } -// /** -// * repeated sint32 shorts = 4; -// * @param values The shorts to add. -// * @return This builder for chaining. -// */ -// public Builder addAllShorts( -// java.lang.Iterable values) { -// ensureShortsIsMutable(); -// com.google.protobuf.AbstractMessageLite.Builder.addAll( -// values, shorts_); -// onChanged(); -// return this; -// } -// /** -// * repeated sint32 shorts = 4; -// * @return This builder for chaining. -// */ -// public Builder clearShorts() { -// shorts_ = emptyIntList(); -// bitField0_ = (bitField0_ & ~0x00000008); -// onChanged(); -// return this; -// } -// @java.lang.Override -// public final Builder setUnknownFields( -// final com.google.protobuf.UnknownFieldSet unknownFields) { -// return super.setUnknownFields(unknownFields); -// } -// -// @java.lang.Override -// public final Builder mergeUnknownFields( -// final com.google.protobuf.UnknownFieldSet unknownFields) { -// return super.mergeUnknownFields(unknownFields); -// } -// -// -// // @@protoc_insertion_point(builder_scope:PTestBean.PTestEntry) -// } -// -// // @@protoc_insertion_point(class_scope:PTestBean.PTestEntry) -// private static final org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry DEFAULT_INSTANCE; -// static { -// DEFAULT_INSTANCE = new org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry(); -// } -// -// public static org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry getDefaultInstance() { -// return DEFAULT_INSTANCE; -// } -// -// private static final com.google.protobuf.Parser -// PARSER = new com.google.protobuf.AbstractParser() { -// @java.lang.Override -// public PTestEntry parsePartialFrom( -// com.google.protobuf.CodedInputStream input, -// com.google.protobuf.ExtensionRegistryLite extensionRegistry) -// throws com.google.protobuf.InvalidProtocolBufferException { -// Builder builder = newBuilder(); -// try { -// builder.mergeFrom(input, extensionRegistry); -// } catch (com.google.protobuf.InvalidProtocolBufferException e) { -// throw e.setUnfinishedMessage(builder.buildPartial()); -// } catch (com.google.protobuf.UninitializedMessageException e) { -// throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); -// } catch (java.io.IOException e) { -// throw new com.google.protobuf.InvalidProtocolBufferException(e) -// .setUnfinishedMessage(builder.buildPartial()); -// } -// return builder.buildPartial(); -// } -// }; -// -// public static com.google.protobuf.Parser parser() { -// return PARSER; -// } -// -// @java.lang.Override -// public com.google.protobuf.Parser getParserForType() { -// return PARSER; -// } -// -// @java.lang.Override -// public org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry getDefaultInstanceForType() { -// return DEFAULT_INSTANCE; -// } -// -// } -// -// public static final int BOOLS_FIELD_NUMBER = 1; -// @SuppressWarnings("serial") -// private com.google.protobuf.Internal.BooleanList bools_; -// /** -// * repeated bool bools = 1; -// * @return A list containing the bools. -// */ -// @java.lang.Override -// public java.util.List -// getBoolsList() { -// return bools_; -// } -// /** -// * repeated bool bools = 1; -// * @return The count of bools. -// */ -// public int getBoolsCount() { -// return bools_.size(); -// } -// /** -// * repeated bool bools = 1; -// * @param index The index of the element to return. -// * @return The bools at the given index. -// */ -// public boolean getBools(int index) { -// return bools_.getBoolean(index); -// } -// private int boolsMemoizedSerializedSize = -1; -// -// public static final int BYTES_FIELD_NUMBER = 2; -// @SuppressWarnings("serial") -// private java.util.List bytes_; -// /** -// * repeated bytes bytes = 2; -// * @return A list containing the bytes. -// */ -// @java.lang.Override -// public java.util.List -// getBytesList() { -// return bytes_; -// } -// /** -// * repeated bytes bytes = 2; -// * @return The count of bytes. -// */ -// public int getBytesCount() { -// return bytes_.size(); -// } -// /** -// * repeated bytes bytes = 2; -// * @param index The index of the element to return. -// * @return The bytes at the given index. -// */ -// public com.google.protobuf.ByteString getBytes(int index) { -// return bytes_.get(index); -// } -// -// public static final int CHARS_FIELD_NUMBER = 3; -// @SuppressWarnings("serial") -// private com.google.protobuf.Internal.IntList chars_; -// /** -// * repeated sint32 chars = 3; -// * @return A list containing the chars. -// */ -// @java.lang.Override -// public java.util.List -// getCharsList() { -// return chars_; -// } -// /** -// * repeated sint32 chars = 3; -// * @return The count of chars. -// */ -// public int getCharsCount() { -// return chars_.size(); -// } -// /** -// * repeated sint32 chars = 3; -// * @param index The index of the element to return. -// * @return The chars at the given index. -// */ -// public int getChars(int index) { -// return chars_.getInt(index); -// } -// private int charsMemoizedSerializedSize = -1; -// -// public static final int ENTRYS_FIELD_NUMBER = 4; -// @SuppressWarnings("serial") -// private java.util.List entrys_; -// /** -// * repeated .PTestBean.PTestEntry entrys = 4; -// */ -// @java.lang.Override -// public java.util.List getEntrysList() { -// return entrys_; -// } -// /** -// * repeated .PTestBean.PTestEntry entrys = 4; -// */ -// @java.lang.Override -// public java.util.List -// getEntrysOrBuilderList() { -// return entrys_; -// } -// /** -// * repeated .PTestBean.PTestEntry entrys = 4; -// */ -// @java.lang.Override -// public int getEntrysCount() { -// return entrys_.size(); -// } -// /** -// * repeated .PTestBean.PTestEntry entrys = 4; -// */ -// @java.lang.Override -// public org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry getEntrys(int index) { -// return entrys_.get(index); -// } -// /** -// * repeated .PTestBean.PTestEntry entrys = 4; -// */ -// @java.lang.Override -// public org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntryOrBuilder getEntrysOrBuilder( -// int index) { -// return entrys_.get(index); -// } -// -// public static final int INTS_FIELD_NUMBER = 5; -// @SuppressWarnings("serial") -// private com.google.protobuf.Internal.IntList ints_; -// /** -// * repeated sint32 ints = 5; -// * @return A list containing the ints. -// */ -// @java.lang.Override -// public java.util.List -// getIntsList() { -// return ints_; -// } -// /** -// * repeated sint32 ints = 5; -// * @return The count of ints. -// */ -// public int getIntsCount() { -// return ints_.size(); -// } -// /** -// * repeated sint32 ints = 5; -// * @param index The index of the element to return. -// * @return The ints at the given index. -// */ -// public int getInts(int index) { -// return ints_.getInt(index); -// } -// private int intsMemoizedSerializedSize = -1; -// -// public static final int FLOATS_FIELD_NUMBER = 6; -// @SuppressWarnings("serial") -// private com.google.protobuf.Internal.FloatList floats_; -// /** -// * repeated float floats = 6; -// * @return A list containing the floats. -// */ -// @java.lang.Override -// public java.util.List -// getFloatsList() { -// return floats_; -// } -// /** -// * repeated float floats = 6; -// * @return The count of floats. -// */ -// public int getFloatsCount() { -// return floats_.size(); -// } -// /** -// * repeated float floats = 6; -// * @param index The index of the element to return. -// * @return The floats at the given index. -// */ -// public float getFloats(int index) { -// return floats_.getFloat(index); -// } -// private int floatsMemoizedSerializedSize = -1; -// -// public static final int LONGS_FIELD_NUMBER = 7; -// @SuppressWarnings("serial") -// private com.google.protobuf.Internal.LongList longs_; -// /** -// * repeated sint64 longs = 7; -// * @return A list containing the longs. -// */ -// @java.lang.Override -// public java.util.List -// getLongsList() { -// return longs_; -// } -// /** -// * repeated sint64 longs = 7; -// * @return The count of longs. -// */ -// public int getLongsCount() { -// return longs_.size(); -// } -// /** -// * repeated sint64 longs = 7; -// * @param index The index of the element to return. -// * @return The longs at the given index. -// */ -// public long getLongs(int index) { -// return longs_.getLong(index); -// } -// private int longsMemoizedSerializedSize = -1; -// -// public static final int DOUBLES_FIELD_NUMBER = 8; -// @SuppressWarnings("serial") -// private com.google.protobuf.Internal.DoubleList doubles_; -// /** -// * repeated double doubles = 8; -// * @return A list containing the doubles. -// */ -// @java.lang.Override -// public java.util.List -// getDoublesList() { -// return doubles_; -// } -// /** -// * repeated double doubles = 8; -// * @return The count of doubles. -// */ -// public int getDoublesCount() { -// return doubles_.size(); -// } -// /** -// * repeated double doubles = 8; -// * @param index The index of the element to return. -// * @return The doubles at the given index. -// */ -// public double getDoubles(int index) { -// return doubles_.getDouble(index); -// } -// private int doublesMemoizedSerializedSize = -1; -// -// public static final int STRINGS_FIELD_NUMBER = 9; -// @SuppressWarnings("serial") -// private com.google.protobuf.LazyStringArrayList strings_ = -// com.google.protobuf.LazyStringArrayList.emptyList(); -// /** -// * repeated string strings = 9; -// * @return A list containing the strings. -// */ -// public com.google.protobuf.ProtocolStringList -// getStringsList() { -// return strings_; -// } -// /** -// * repeated string strings = 9; -// * @return The count of strings. -// */ -// public int getStringsCount() { -// return strings_.size(); -// } -// /** -// * repeated string strings = 9; -// * @param index The index of the element to return. -// * @return The strings at the given index. -// */ -// public java.lang.String getStrings(int index) { -// return strings_.get(index); -// } -// /** -// * repeated string strings = 9; -// * @param index The index of the value to return. -// * @return The bytes of the strings at the given index. -// */ -// public com.google.protobuf.ByteString -// getStringsBytes(int index) { -// return strings_.getByteString(index); -// } -// -// public static final int ID_FIELD_NUMBER = 10; -// private int id_ = 0; -// /** -// * sint32 id = 10; -// * @return The id. -// */ -// @java.lang.Override -// public int getId() { -// return id_; -// } -// -// public static final int NAME_FIELD_NUMBER = 11; -// @SuppressWarnings("serial") -// private volatile java.lang.Object name_ = ""; -// /** -// * string name = 11; -// * @return The name. -// */ -// @java.lang.Override -// public java.lang.String getName() { -// java.lang.Object ref = name_; -// if (ref instanceof java.lang.String) { -// return (java.lang.String) ref; -// } else { -// com.google.protobuf.ByteString bs = -// (com.google.protobuf.ByteString) ref; -// java.lang.String s = bs.toStringUtf8(); -// name_ = s; -// return s; -// } -// } -// /** -// * string name = 11; -// * @return The bytes for name. -// */ -// @java.lang.Override -// public com.google.protobuf.ByteString -// getNameBytes() { -// java.lang.Object ref = name_; -// if (ref instanceof java.lang.String) { -// com.google.protobuf.ByteString b = -// com.google.protobuf.ByteString.copyFromUtf8( -// (java.lang.String) ref); -// name_ = b; -// return b; -// } else { -// return (com.google.protobuf.ByteString) ref; -// } -// } -// -// public static final int EMAIL_FIELD_NUMBER = 12; -// @SuppressWarnings("serial") -// private volatile java.lang.Object email_ = ""; -// /** -// * string email = 12; -// * @return The email. -// */ -// @java.lang.Override -// public java.lang.String getEmail() { -// java.lang.Object ref = email_; -// if (ref instanceof java.lang.String) { -// return (java.lang.String) ref; -// } else { -// com.google.protobuf.ByteString bs = -// (com.google.protobuf.ByteString) ref; -// java.lang.String s = bs.toStringUtf8(); -// email_ = s; -// return s; -// } -// } -// /** -// * string email = 12; -// * @return The bytes for email. -// */ -// @java.lang.Override -// public com.google.protobuf.ByteString -// getEmailBytes() { -// java.lang.Object ref = email_; -// if (ref instanceof java.lang.String) { -// com.google.protobuf.ByteString b = -// com.google.protobuf.ByteString.copyFromUtf8( -// (java.lang.String) ref); -// email_ = b; -// return b; -// } else { -// return (com.google.protobuf.ByteString) ref; -// } -// } -// -// public static final int KIND_FIELD_NUMBER = 13; -// private int kind_ = 0; -// /** -// * .PTestBean.Kind kind = 13; -// * @return The enum numeric value on the wire for kind. -// */ -// @java.lang.Override public int getKindValue() { -// return kind_; -// } -// /** -// * .PTestBean.Kind kind = 13; -// * @return The kind. -// */ -// @java.lang.Override public org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.Kind getKind() { -// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.Kind result = -// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.Kind.forNumber(kind_); -// return result == null ? org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.Kind.UNRECOGNIZED : result; -// } -// -// public static final int MAP_FIELD_NUMBER = 14; -// private static final class MapDefaultEntryHolder { -// static final com.google.protobuf.MapEntry< -// java.lang.String, java.lang.Integer> defaultEntry = -// com.google.protobuf.MapEntry -// .newDefaultInstance( -// org.redkalex.test.protobuf.PTestBeanOuterClass.internal_static_PTestBean_MapEntry_descriptor, -// com.google.protobuf.WireFormat.FieldType.STRING, -// "", -// com.google.protobuf.WireFormat.FieldType.SINT32, -// 0); -// } -// @SuppressWarnings("serial") -// private com.google.protobuf.MapField< -// java.lang.String, java.lang.Integer> map_; -// private com.google.protobuf.MapField -// internalGetMap() { -// if (map_ == null) { -// return com.google.protobuf.MapField.emptyMapField( -// MapDefaultEntryHolder.defaultEntry); -// } -// return map_; -// } -// public int getMapCount() { -// return internalGetMap().getMap().size(); -// } -// /** -// * map<string, sint32> map = 14; -// */ -// @java.lang.Override -// public boolean containsMap( -// java.lang.String key) { -// if (key == null) { throw new NullPointerException("map key"); } -// return internalGetMap().getMap().containsKey(key); -// } -// /** -// * Use {@link #getMapMap()} instead. -// */ -// @java.lang.Override -// @java.lang.Deprecated -// public java.util.Map getMap() { -// return getMapMap(); -// } -// /** -// * map<string, sint32> map = 14; -// */ -// @java.lang.Override -// public java.util.Map getMapMap() { -// return internalGetMap().getMap(); -// } -// /** -// * map<string, sint32> map = 14; -// */ -// @java.lang.Override -// public int getMapOrDefault( -// java.lang.String key, -// int defaultValue) { -// if (key == null) { throw new NullPointerException("map key"); } -// java.util.Map map = -// internalGetMap().getMap(); -// return map.containsKey(key) ? map.get(key) : defaultValue; -// } -// /** -// * map<string, sint32> map = 14; -// */ -// @java.lang.Override -// public int getMapOrThrow( -// java.lang.String key) { -// if (key == null) { throw new NullPointerException("map key"); } -// java.util.Map map = -// internalGetMap().getMap(); -// if (!map.containsKey(key)) { -// throw new java.lang.IllegalArgumentException(); -// } -// return map.get(key); -// } -// -// public static final int END_FIELD_NUMBER = 15; -// @SuppressWarnings("serial") -// private volatile java.lang.Object end_ = ""; -// /** -// * string end = 15; -// * @return The end. -// */ -// @java.lang.Override -// public java.lang.String getEnd() { -// java.lang.Object ref = end_; -// if (ref instanceof java.lang.String) { -// return (java.lang.String) ref; -// } else { -// com.google.protobuf.ByteString bs = -// (com.google.protobuf.ByteString) ref; -// java.lang.String s = bs.toStringUtf8(); -// end_ = s; -// return s; -// } -// } -// /** -// * string end = 15; -// * @return The bytes for end. -// */ -// @java.lang.Override -// public com.google.protobuf.ByteString -// getEndBytes() { -// java.lang.Object ref = end_; -// if (ref instanceof java.lang.String) { -// com.google.protobuf.ByteString b = -// com.google.protobuf.ByteString.copyFromUtf8( -// (java.lang.String) ref); -// end_ = b; -// return b; -// } else { -// return (com.google.protobuf.ByteString) ref; -// } -// } -// -// private byte memoizedIsInitialized = -1; -// @java.lang.Override -// public final boolean isInitialized() { -// byte isInitialized = memoizedIsInitialized; -// if (isInitialized == 1) return true; -// if (isInitialized == 0) return false; -// -// memoizedIsInitialized = 1; -// return true; -// } -// -// @java.lang.Override -// public void writeTo(com.google.protobuf.CodedOutputStream output) -// throws java.io.IOException { -// getSerializedSize(); -// if (getBoolsList().size() > 0) { -// output.writeUInt32NoTag(10); -// output.writeUInt32NoTag(boolsMemoizedSerializedSize); -// } -// for (int i = 0; i < bools_.size(); i++) { -// output.writeBoolNoTag(bools_.getBoolean(i)); -// } -// for (int i = 0; i < bytes_.size(); i++) { -// output.writeBytes(2, bytes_.get(i)); -// } -// if (getCharsList().size() > 0) { -// output.writeUInt32NoTag(26); -// output.writeUInt32NoTag(charsMemoizedSerializedSize); -// } -// for (int i = 0; i < chars_.size(); i++) { -// output.writeSInt32NoTag(chars_.getInt(i)); -// } -// for (int i = 0; i < entrys_.size(); i++) { -// output.writeMessage(4, entrys_.get(i)); -// } -// if (getIntsList().size() > 0) { -// output.writeUInt32NoTag(42); -// output.writeUInt32NoTag(intsMemoizedSerializedSize); -// } -// for (int i = 0; i < ints_.size(); i++) { -// output.writeSInt32NoTag(ints_.getInt(i)); -// } -// if (getFloatsList().size() > 0) { -// output.writeUInt32NoTag(50); -// output.writeUInt32NoTag(floatsMemoizedSerializedSize); -// } -// for (int i = 0; i < floats_.size(); i++) { -// output.writeFloatNoTag(floats_.getFloat(i)); -// } -// if (getLongsList().size() > 0) { -// output.writeUInt32NoTag(58); -// output.writeUInt32NoTag(longsMemoizedSerializedSize); -// } -// for (int i = 0; i < longs_.size(); i++) { -// output.writeSInt64NoTag(longs_.getLong(i)); -// } -// if (getDoublesList().size() > 0) { -// output.writeUInt32NoTag(66); -// output.writeUInt32NoTag(doublesMemoizedSerializedSize); -// } -// for (int i = 0; i < doubles_.size(); i++) { -// output.writeDoubleNoTag(doubles_.getDouble(i)); -// } -// for (int i = 0; i < strings_.size(); i++) { -// com.google.protobuf.GeneratedMessageV3.writeString(output, 9, strings_.getRaw(i)); -// } -// if (id_ != 0) { -// output.writeSInt32(10, id_); -// } -// if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(name_)) { -// com.google.protobuf.GeneratedMessageV3.writeString(output, 11, name_); -// } -// if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(email_)) { -// com.google.protobuf.GeneratedMessageV3.writeString(output, 12, email_); -// } -// if (kind_ != org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.Kind.ONE.getNumber()) { -// output.writeEnum(13, kind_); -// } -// com.google.protobuf.GeneratedMessageV3 -// .serializeStringMapTo( -// output, -// internalGetMap(), -// MapDefaultEntryHolder.defaultEntry, -// 14); -// if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(end_)) { -// com.google.protobuf.GeneratedMessageV3.writeString(output, 15, end_); -// } -// getUnknownFields().writeTo(output); -// } -// -// @java.lang.Override -// public int getSerializedSize() { -// int size = memoizedSize; -// if (size != -1) return size; -// -// size = 0; -// { -// int dataSize = 0; -// dataSize = 1 * getBoolsList().size(); -// size += dataSize; -// if (!getBoolsList().isEmpty()) { -// size += 1; -// size += com.google.protobuf.CodedOutputStream -// .computeInt32SizeNoTag(dataSize); -// } -// boolsMemoizedSerializedSize = dataSize; -// } -// { -// int dataSize = 0; -// for (int i = 0; i < bytes_.size(); i++) { -// dataSize += com.google.protobuf.CodedOutputStream -// .computeBytesSizeNoTag(bytes_.get(i)); -// } -// size += dataSize; -// size += 1 * getBytesList().size(); -// } -// { -// int dataSize = 0; -// for (int i = 0; i < chars_.size(); i++) { -// dataSize += com.google.protobuf.CodedOutputStream -// .computeSInt32SizeNoTag(chars_.getInt(i)); -// } -// size += dataSize; -// if (!getCharsList().isEmpty()) { -// size += 1; -// size += com.google.protobuf.CodedOutputStream -// .computeInt32SizeNoTag(dataSize); -// } -// charsMemoizedSerializedSize = dataSize; -// } -// for (int i = 0; i < entrys_.size(); i++) { -// size += com.google.protobuf.CodedOutputStream -// .computeMessageSize(4, entrys_.get(i)); -// } -// { -// int dataSize = 0; -// for (int i = 0; i < ints_.size(); i++) { -// dataSize += com.google.protobuf.CodedOutputStream -// .computeSInt32SizeNoTag(ints_.getInt(i)); -// } -// size += dataSize; -// if (!getIntsList().isEmpty()) { -// size += 1; -// size += com.google.protobuf.CodedOutputStream -// .computeInt32SizeNoTag(dataSize); -// } -// intsMemoizedSerializedSize = dataSize; -// } -// { -// int dataSize = 0; -// dataSize = 4 * getFloatsList().size(); -// size += dataSize; -// if (!getFloatsList().isEmpty()) { -// size += 1; -// size += com.google.protobuf.CodedOutputStream -// .computeInt32SizeNoTag(dataSize); -// } -// floatsMemoizedSerializedSize = dataSize; -// } -// { -// int dataSize = 0; -// for (int i = 0; i < longs_.size(); i++) { -// dataSize += com.google.protobuf.CodedOutputStream -// .computeSInt64SizeNoTag(longs_.getLong(i)); -// } -// size += dataSize; -// if (!getLongsList().isEmpty()) { -// size += 1; -// size += com.google.protobuf.CodedOutputStream -// .computeInt32SizeNoTag(dataSize); -// } -// longsMemoizedSerializedSize = dataSize; -// } -// { -// int dataSize = 0; -// dataSize = 8 * getDoublesList().size(); -// size += dataSize; -// if (!getDoublesList().isEmpty()) { -// size += 1; -// size += com.google.protobuf.CodedOutputStream -// .computeInt32SizeNoTag(dataSize); -// } -// doublesMemoizedSerializedSize = dataSize; -// } -// { -// int dataSize = 0; -// for (int i = 0; i < strings_.size(); i++) { -// dataSize += computeStringSizeNoTag(strings_.getRaw(i)); -// } -// size += dataSize; -// size += 1 * getStringsList().size(); -// } -// if (id_ != 0) { -// size += com.google.protobuf.CodedOutputStream -// .computeSInt32Size(10, id_); -// } -// if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(name_)) { -// size += com.google.protobuf.GeneratedMessageV3.computeStringSize(11, name_); -// } -// if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(email_)) { -// size += com.google.protobuf.GeneratedMessageV3.computeStringSize(12, email_); -// } -// if (kind_ != org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.Kind.ONE.getNumber()) { -// size += com.google.protobuf.CodedOutputStream -// .computeEnumSize(13, kind_); -// } -// for (java.util.Map.Entry entry -// : internalGetMap().getMap().entrySet()) { -// com.google.protobuf.MapEntry -// map__ = MapDefaultEntryHolder.defaultEntry.newBuilderForType() -// .setKey(entry.getKey()) -// .setValue(entry.getValue()) -// .build(); -// size += com.google.protobuf.CodedOutputStream -// .computeMessageSize(14, map__); -// } -// if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(end_)) { -// size += com.google.protobuf.GeneratedMessageV3.computeStringSize(15, end_); -// } -// size += getUnknownFields().getSerializedSize(); -// memoizedSize = size; -// return size; -// } -// -// @java.lang.Override -// public boolean equals(final java.lang.Object obj) { -// if (obj == this) { -// return true; -// } -// if (!(obj instanceof org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean)) { -// return super.equals(obj); -// } -// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean other = -// (org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean) obj; -// -// if (!getBoolsList() -// .equals(other.getBoolsList())) return false; -// if (!getBytesList() -// .equals(other.getBytesList())) return false; -// if (!getCharsList() -// .equals(other.getCharsList())) return false; -// if (!getEntrysList() -// .equals(other.getEntrysList())) return false; -// if (!getIntsList() -// .equals(other.getIntsList())) return false; -// if (!getFloatsList() -// .equals(other.getFloatsList())) return false; -// if (!getLongsList() -// .equals(other.getLongsList())) return false; -// if (!getDoublesList() -// .equals(other.getDoublesList())) return false; -// if (!getStringsList() -// .equals(other.getStringsList())) return false; -// if (getId() -// != other.getId()) return false; -// if (!getName() -// .equals(other.getName())) return false; -// if (!getEmail() -// .equals(other.getEmail())) return false; -// if (kind_ != other.kind_) return false; -// if (!internalGetMap().equals( -// other.internalGetMap())) return false; -// if (!getEnd() -// .equals(other.getEnd())) return false; -// if (!getUnknownFields().equals(other.getUnknownFields())) return false; -// return true; -// } -// -// @java.lang.Override -// public int hashCode() { -// if (memoizedHashCode != 0) { -// return memoizedHashCode; -// } -// int hash = 41; -// hash = (19 * hash) + getDescriptor().hashCode(); -// if (getBoolsCount() > 0) { -// hash = (37 * hash) + BOOLS_FIELD_NUMBER; -// hash = (53 * hash) + getBoolsList().hashCode(); -// } -// if (getBytesCount() > 0) { -// hash = (37 * hash) + BYTES_FIELD_NUMBER; -// hash = (53 * hash) + getBytesList().hashCode(); -// } -// if (getCharsCount() > 0) { -// hash = (37 * hash) + CHARS_FIELD_NUMBER; -// hash = (53 * hash) + getCharsList().hashCode(); -// } -// if (getEntrysCount() > 0) { -// hash = (37 * hash) + ENTRYS_FIELD_NUMBER; -// hash = (53 * hash) + getEntrysList().hashCode(); -// } -// if (getIntsCount() > 0) { -// hash = (37 * hash) + INTS_FIELD_NUMBER; -// hash = (53 * hash) + getIntsList().hashCode(); -// } -// if (getFloatsCount() > 0) { -// hash = (37 * hash) + FLOATS_FIELD_NUMBER; -// hash = (53 * hash) + getFloatsList().hashCode(); -// } -// if (getLongsCount() > 0) { -// hash = (37 * hash) + LONGS_FIELD_NUMBER; -// hash = (53 * hash) + getLongsList().hashCode(); -// } -// if (getDoublesCount() > 0) { -// hash = (37 * hash) + DOUBLES_FIELD_NUMBER; -// hash = (53 * hash) + getDoublesList().hashCode(); -// } -// if (getStringsCount() > 0) { -// hash = (37 * hash) + STRINGS_FIELD_NUMBER; -// hash = (53 * hash) + getStringsList().hashCode(); -// } -// hash = (37 * hash) + ID_FIELD_NUMBER; -// hash = (53 * hash) + getId(); -// hash = (37 * hash) + NAME_FIELD_NUMBER; -// hash = (53 * hash) + getName().hashCode(); -// hash = (37 * hash) + EMAIL_FIELD_NUMBER; -// hash = (53 * hash) + getEmail().hashCode(); -// hash = (37 * hash) + KIND_FIELD_NUMBER; -// hash = (53 * hash) + kind_; -// if (!internalGetMap().getMap().isEmpty()) { -// hash = (37 * hash) + MAP_FIELD_NUMBER; -// hash = (53 * hash) + internalGetMap().hashCode(); -// } -// hash = (37 * hash) + END_FIELD_NUMBER; -// hash = (53 * hash) + getEnd().hashCode(); -// hash = (29 * hash) + getUnknownFields().hashCode(); -// memoizedHashCode = hash; -// return hash; -// } -// -// public static org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean parseFrom( -// java.nio.ByteBuffer data) -// throws com.google.protobuf.InvalidProtocolBufferException { -// return PARSER.parseFrom(data); -// } -// public static org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean parseFrom( -// java.nio.ByteBuffer data, -// com.google.protobuf.ExtensionRegistryLite extensionRegistry) -// throws com.google.protobuf.InvalidProtocolBufferException { -// return PARSER.parseFrom(data, extensionRegistry); -// } -// public static org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean parseFrom( -// com.google.protobuf.ByteString data) -// throws com.google.protobuf.InvalidProtocolBufferException { -// return PARSER.parseFrom(data); -// } -// public static org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean parseFrom( -// com.google.protobuf.ByteString data, -// com.google.protobuf.ExtensionRegistryLite extensionRegistry) -// throws com.google.protobuf.InvalidProtocolBufferException { -// return PARSER.parseFrom(data, extensionRegistry); -// } -// public static org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean parseFrom(byte[] data) -// throws com.google.protobuf.InvalidProtocolBufferException { -// return PARSER.parseFrom(data); -// } -// public static org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean parseFrom( -// byte[] data, -// com.google.protobuf.ExtensionRegistryLite extensionRegistry) -// throws com.google.protobuf.InvalidProtocolBufferException { -// return PARSER.parseFrom(data, extensionRegistry); -// } -// public static org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean parseFrom(java.io.InputStream input) -// throws java.io.IOException { -// return com.google.protobuf.GeneratedMessageV3 -// .parseWithIOException(PARSER, input); -// } -// public static org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean parseFrom( -// java.io.InputStream input, -// com.google.protobuf.ExtensionRegistryLite extensionRegistry) -// throws java.io.IOException { -// return com.google.protobuf.GeneratedMessageV3 -// .parseWithIOException(PARSER, input, extensionRegistry); -// } -// -// public static org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean parseDelimitedFrom(java.io.InputStream -// input) -// throws java.io.IOException { -// return com.google.protobuf.GeneratedMessageV3 -// .parseDelimitedWithIOException(PARSER, input); -// } -// -// public static org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean parseDelimitedFrom( -// java.io.InputStream input, -// com.google.protobuf.ExtensionRegistryLite extensionRegistry) -// throws java.io.IOException { -// return com.google.protobuf.GeneratedMessageV3 -// .parseDelimitedWithIOException(PARSER, input, extensionRegistry); -// } -// public static org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean parseFrom( -// com.google.protobuf.CodedInputStream input) -// throws java.io.IOException { -// return com.google.protobuf.GeneratedMessageV3 -// .parseWithIOException(PARSER, input); -// } -// public static org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean parseFrom( -// com.google.protobuf.CodedInputStream input, -// com.google.protobuf.ExtensionRegistryLite extensionRegistry) -// throws java.io.IOException { -// return com.google.protobuf.GeneratedMessageV3 -// .parseWithIOException(PARSER, input, extensionRegistry); -// } -// -// @java.lang.Override -// public Builder newBuilderForType() { return newBuilder(); } -// public static Builder newBuilder() { -// return DEFAULT_INSTANCE.toBuilder(); -// } -// public static Builder newBuilder(org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean prototype) { -// return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); -// } -// @java.lang.Override -// public Builder toBuilder() { -// return this == DEFAULT_INSTANCE -// ? new Builder() : new Builder().mergeFrom(this); -// } -// -// @java.lang.Override -// protected Builder newBuilderForType( -// com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { -// Builder builder = new Builder(parent); -// return builder; -// } -// /** -// * Protobuf type {@code PTestBean} -// */ -// public static final class Builder extends -// com.google.protobuf.GeneratedMessageV3.Builder implements -// // @@protoc_insertion_point(builder_implements:PTestBean) -// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBeanOrBuilder { -// public static final com.google.protobuf.Descriptors.Descriptor -// getDescriptor() { -// return org.redkalex.test.protobuf.PTestBeanOuterClass.internal_static_PTestBean_descriptor; -// } -// -// @SuppressWarnings({"rawtypes"}) -// protected com.google.protobuf.MapField internalGetMapField( -// int number) { -// switch (number) { -// case 14: -// return internalGetMap(); -// default: -// throw new RuntimeException( -// "Invalid map field number: " + number); -// } -// } -// @SuppressWarnings({"rawtypes"}) -// protected com.google.protobuf.MapField internalGetMutableMapField( -// int number) { -// switch (number) { -// case 14: -// return internalGetMutableMap(); -// default: -// throw new RuntimeException( -// "Invalid map field number: " + number); -// } -// } -// @java.lang.Override -// protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable -// internalGetFieldAccessorTable() { -// return org.redkalex.test.protobuf.PTestBeanOuterClass.internal_static_PTestBean_fieldAccessorTable -// .ensureFieldAccessorsInitialized( -// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.class, -// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.Builder.class); -// } -// -// // Construct using org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.newBuilder() -// private Builder() { -// -// } -// -// private Builder( -// com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { -// super(parent); -// -// } -// @java.lang.Override -// public Builder clear() { -// super.clear(); -// bitField0_ = 0; -// bools_ = emptyBooleanList(); -// bytes_ = java.util.Collections.emptyList(); -// chars_ = emptyIntList(); -// if (entrysBuilder_ == null) { -// entrys_ = java.util.Collections.emptyList(); -// } else { -// entrys_ = null; -// entrysBuilder_.clear(); -// } -// bitField0_ = (bitField0_ & ~0x00000008); -// ints_ = emptyIntList(); -// floats_ = emptyFloatList(); -// longs_ = emptyLongList(); -// doubles_ = emptyDoubleList(); -// strings_ = -// com.google.protobuf.LazyStringArrayList.emptyList(); -// id_ = 0; -// name_ = ""; -// email_ = ""; -// kind_ = 0; -// internalGetMutableMap().clear(); -// end_ = ""; -// return this; -// } -// -// @java.lang.Override -// public com.google.protobuf.Descriptors.Descriptor -// getDescriptorForType() { -// return org.redkalex.test.protobuf.PTestBeanOuterClass.internal_static_PTestBean_descriptor; -// } -// -// @java.lang.Override -// public org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean getDefaultInstanceForType() { -// return org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.getDefaultInstance(); -// } -// -// @java.lang.Override -// public org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean build() { -// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean result = buildPartial(); -// if (!result.isInitialized()) { -// throw newUninitializedMessageException(result); -// } -// return result; -// } -// -// @java.lang.Override -// public org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean buildPartial() { -// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean result = new -// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean(this); -// buildPartialRepeatedFields(result); -// if (bitField0_ != 0) { buildPartial0(result); } -// onBuilt(); -// return result; -// } -// -// private void buildPartialRepeatedFields(org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean result) { -// if (((bitField0_ & 0x00000001) != 0)) { -// bools_.makeImmutable(); -// bitField0_ = (bitField0_ & ~0x00000001); -// } -// result.bools_ = bools_; -// if (((bitField0_ & 0x00000002) != 0)) { -// bytes_ = java.util.Collections.unmodifiableList(bytes_); -// bitField0_ = (bitField0_ & ~0x00000002); -// } -// result.bytes_ = bytes_; -// if (((bitField0_ & 0x00000004) != 0)) { -// chars_.makeImmutable(); -// bitField0_ = (bitField0_ & ~0x00000004); -// } -// result.chars_ = chars_; -// if (entrysBuilder_ == null) { -// if (((bitField0_ & 0x00000008) != 0)) { -// entrys_ = java.util.Collections.unmodifiableList(entrys_); -// bitField0_ = (bitField0_ & ~0x00000008); -// } -// result.entrys_ = entrys_; -// } else { -// result.entrys_ = entrysBuilder_.build(); -// } -// if (((bitField0_ & 0x00000010) != 0)) { -// ints_.makeImmutable(); -// bitField0_ = (bitField0_ & ~0x00000010); -// } -// result.ints_ = ints_; -// if (((bitField0_ & 0x00000020) != 0)) { -// floats_.makeImmutable(); -// bitField0_ = (bitField0_ & ~0x00000020); -// } -// result.floats_ = floats_; -// if (((bitField0_ & 0x00000040) != 0)) { -// longs_.makeImmutable(); -// bitField0_ = (bitField0_ & ~0x00000040); -// } -// result.longs_ = longs_; -// if (((bitField0_ & 0x00000080) != 0)) { -// doubles_.makeImmutable(); -// bitField0_ = (bitField0_ & ~0x00000080); -// } -// result.doubles_ = doubles_; -// } -// -// private void buildPartial0(org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean result) { -// int from_bitField0_ = bitField0_; -// if (((from_bitField0_ & 0x00000100) != 0)) { -// strings_.makeImmutable(); -// result.strings_ = strings_; -// } -// if (((from_bitField0_ & 0x00000200) != 0)) { -// result.id_ = id_; -// } -// if (((from_bitField0_ & 0x00000400) != 0)) { -// result.name_ = name_; -// } -// if (((from_bitField0_ & 0x00000800) != 0)) { -// result.email_ = email_; -// } -// if (((from_bitField0_ & 0x00001000) != 0)) { -// result.kind_ = kind_; -// } -// if (((from_bitField0_ & 0x00002000) != 0)) { -// result.map_ = internalGetMap(); -// result.map_.makeImmutable(); -// } -// if (((from_bitField0_ & 0x00004000) != 0)) { -// result.end_ = end_; -// } -// } -// -// @java.lang.Override -// public Builder clone() { -// return super.clone(); -// } -// @java.lang.Override -// public Builder setField( -// com.google.protobuf.Descriptors.FieldDescriptor field, -// java.lang.Object value) { -// return super.setField(field, value); -// } -// @java.lang.Override -// public Builder clearField( -// com.google.protobuf.Descriptors.FieldDescriptor field) { -// return super.clearField(field); -// } -// @java.lang.Override -// public Builder clearOneof( -// com.google.protobuf.Descriptors.OneofDescriptor oneof) { -// return super.clearOneof(oneof); -// } -// @java.lang.Override -// public Builder setRepeatedField( -// com.google.protobuf.Descriptors.FieldDescriptor field, -// int index, java.lang.Object value) { -// return super.setRepeatedField(field, index, value); -// } -// @java.lang.Override -// public Builder addRepeatedField( -// com.google.protobuf.Descriptors.FieldDescriptor field, -// java.lang.Object value) { -// return super.addRepeatedField(field, value); -// } -// @java.lang.Override -// public Builder mergeFrom(com.google.protobuf.Message other) { -// if (other instanceof org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean) { -// return mergeFrom((org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean)other); -// } else { -// super.mergeFrom(other); -// return this; -// } -// } -// -// public Builder mergeFrom(org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean other) { -// if (other == org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.getDefaultInstance()) return this; -// if (!other.bools_.isEmpty()) { -// if (bools_.isEmpty()) { -// bools_ = other.bools_; -// bitField0_ = (bitField0_ & ~0x00000001); -// } else { -// ensureBoolsIsMutable(); -// bools_.addAll(other.bools_); -// } -// onChanged(); -// } -// if (!other.bytes_.isEmpty()) { -// if (bytes_.isEmpty()) { -// bytes_ = other.bytes_; -// bitField0_ = (bitField0_ & ~0x00000002); -// } else { -// ensureBytesIsMutable(); -// bytes_.addAll(other.bytes_); -// } -// onChanged(); -// } -// if (!other.chars_.isEmpty()) { -// if (chars_.isEmpty()) { -// chars_ = other.chars_; -// bitField0_ = (bitField0_ & ~0x00000004); -// } else { -// ensureCharsIsMutable(); -// chars_.addAll(other.chars_); -// } -// onChanged(); -// } -// if (entrysBuilder_ == null) { -// if (!other.entrys_.isEmpty()) { -// if (entrys_.isEmpty()) { -// entrys_ = other.entrys_; -// bitField0_ = (bitField0_ & ~0x00000008); -// } else { -// ensureEntrysIsMutable(); -// entrys_.addAll(other.entrys_); -// } -// onChanged(); -// } -// } else { -// if (!other.entrys_.isEmpty()) { -// if (entrysBuilder_.isEmpty()) { -// entrysBuilder_.dispose(); -// entrysBuilder_ = null; -// entrys_ = other.entrys_; -// bitField0_ = (bitField0_ & ~0x00000008); -// entrysBuilder_ = -// com.google.protobuf.GeneratedMessageV3.alwaysUseFieldBuilders ? -// getEntrysFieldBuilder() : null; -// } else { -// entrysBuilder_.addAllMessages(other.entrys_); -// } -// } -// } -// if (!other.ints_.isEmpty()) { -// if (ints_.isEmpty()) { -// ints_ = other.ints_; -// bitField0_ = (bitField0_ & ~0x00000010); -// } else { -// ensureIntsIsMutable(); -// ints_.addAll(other.ints_); -// } -// onChanged(); -// } -// if (!other.floats_.isEmpty()) { -// if (floats_.isEmpty()) { -// floats_ = other.floats_; -// bitField0_ = (bitField0_ & ~0x00000020); -// } else { -// ensureFloatsIsMutable(); -// floats_.addAll(other.floats_); -// } -// onChanged(); -// } -// if (!other.longs_.isEmpty()) { -// if (longs_.isEmpty()) { -// longs_ = other.longs_; -// bitField0_ = (bitField0_ & ~0x00000040); -// } else { -// ensureLongsIsMutable(); -// longs_.addAll(other.longs_); -// } -// onChanged(); -// } -// if (!other.doubles_.isEmpty()) { -// if (doubles_.isEmpty()) { -// doubles_ = other.doubles_; -// bitField0_ = (bitField0_ & ~0x00000080); -// } else { -// ensureDoublesIsMutable(); -// doubles_.addAll(other.doubles_); -// } -// onChanged(); -// } -// if (!other.strings_.isEmpty()) { -// if (strings_.isEmpty()) { -// strings_ = other.strings_; -// bitField0_ |= 0x00000100; -// } else { -// ensureStringsIsMutable(); -// strings_.addAll(other.strings_); -// } -// onChanged(); -// } -// if (other.getId() != 0) { -// setId(other.getId()); -// } -// if (!other.getName().isEmpty()) { -// name_ = other.name_; -// bitField0_ |= 0x00000400; -// onChanged(); -// } -// if (!other.getEmail().isEmpty()) { -// email_ = other.email_; -// bitField0_ |= 0x00000800; -// onChanged(); -// } -// if (other.kind_ != 0) { -// setKindValue(other.getKindValue()); -// } -// internalGetMutableMap().mergeFrom( -// other.internalGetMap()); -// bitField0_ |= 0x00002000; -// if (!other.getEnd().isEmpty()) { -// end_ = other.end_; -// bitField0_ |= 0x00004000; -// onChanged(); -// } -// this.mergeUnknownFields(other.getUnknownFields()); -// onChanged(); -// return this; -// } -// -// @java.lang.Override -// public final boolean isInitialized() { -// return true; -// } -// -// @java.lang.Override -// public Builder mergeFrom( -// com.google.protobuf.CodedInputStream input, -// com.google.protobuf.ExtensionRegistryLite extensionRegistry) -// throws java.io.IOException { -// if (extensionRegistry == null) { -// throw new java.lang.NullPointerException(); -// } -// try { -// boolean done = false; -// while (!done) { -// int tag = input.readTag(); -// switch (tag) { -// case 0: -// done = true; -// break; -// case 8: { -// boolean v = input.readBool(); -// ensureBoolsIsMutable(); -// bools_.addBoolean(v); -// break; -// } // case 8 -// case 10: { -// int length = input.readRawVarint32(); -// int limit = input.pushLimit(length); -// ensureBoolsIsMutable(); -// while (input.getBytesUntilLimit() > 0) { -// bools_.addBoolean(input.readBool()); -// } -// input.popLimit(limit); -// break; -// } // case 10 -// case 18: { -// com.google.protobuf.ByteString v = input.readBytes(); -// ensureBytesIsMutable(); -// bytes_.add(v); -// break; -// } // case 18 -// case 24: { -// int v = input.readSInt32(); -// ensureCharsIsMutable(); -// chars_.addInt(v); -// break; -// } // case 24 -// case 26: { -// int length = input.readRawVarint32(); -// int limit = input.pushLimit(length); -// ensureCharsIsMutable(); -// while (input.getBytesUntilLimit() > 0) { -// chars_.addInt(input.readSInt32()); -// } -// input.popLimit(limit); -// break; -// } // case 26 -// case 34: { -// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry m = -// input.readMessage( -// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry.parser(), -// extensionRegistry); -// if (entrysBuilder_ == null) { -// ensureEntrysIsMutable(); -// entrys_.add(m); -// } else { -// entrysBuilder_.addMessage(m); -// } -// break; -// } // case 34 -// case 40: { -// int v = input.readSInt32(); -// ensureIntsIsMutable(); -// ints_.addInt(v); -// break; -// } // case 40 -// case 42: { -// int length = input.readRawVarint32(); -// int limit = input.pushLimit(length); -// ensureIntsIsMutable(); -// while (input.getBytesUntilLimit() > 0) { -// ints_.addInt(input.readSInt32()); -// } -// input.popLimit(limit); -// break; -// } // case 42 -// case 53: { -// float v = input.readFloat(); -// ensureFloatsIsMutable(); -// floats_.addFloat(v); -// break; -// } // case 53 -// case 50: { -// int length = input.readRawVarint32(); -// int limit = input.pushLimit(length); -// ensureFloatsIsMutable(); -// while (input.getBytesUntilLimit() > 0) { -// floats_.addFloat(input.readFloat()); -// } -// input.popLimit(limit); -// break; -// } // case 50 -// case 56: { -// long v = input.readSInt64(); -// ensureLongsIsMutable(); -// longs_.addLong(v); -// break; -// } // case 56 -// case 58: { -// int length = input.readRawVarint32(); -// int limit = input.pushLimit(length); -// ensureLongsIsMutable(); -// while (input.getBytesUntilLimit() > 0) { -// longs_.addLong(input.readSInt64()); -// } -// input.popLimit(limit); -// break; -// } // case 58 -// case 65: { -// double v = input.readDouble(); -// ensureDoublesIsMutable(); -// doubles_.addDouble(v); -// break; -// } // case 65 -// case 66: { -// int length = input.readRawVarint32(); -// int limit = input.pushLimit(length); -// ensureDoublesIsMutable(); -// while (input.getBytesUntilLimit() > 0) { -// doubles_.addDouble(input.readDouble()); -// } -// input.popLimit(limit); -// break; -// } // case 66 -// case 74: { -// java.lang.String s = input.readStringRequireUtf8(); -// ensureStringsIsMutable(); -// strings_.add(s); -// break; -// } // case 74 -// case 80: { -// id_ = input.readSInt32(); -// bitField0_ |= 0x00000200; -// break; -// } // case 80 -// case 90: { -// name_ = input.readStringRequireUtf8(); -// bitField0_ |= 0x00000400; -// break; -// } // case 90 -// case 98: { -// email_ = input.readStringRequireUtf8(); -// bitField0_ |= 0x00000800; -// break; -// } // case 98 -// case 104: { -// kind_ = input.readEnum(); -// bitField0_ |= 0x00001000; -// break; -// } // case 104 -// case 114: { -// com.google.protobuf.MapEntry -// map__ = input.readMessage( -// MapDefaultEntryHolder.defaultEntry.getParserForType(), extensionRegistry); -// internalGetMutableMap().getMutableMap().put( -// map__.getKey(), map__.getValue()); -// bitField0_ |= 0x00002000; -// break; -// } // case 114 -// case 122: { -// end_ = input.readStringRequireUtf8(); -// bitField0_ |= 0x00004000; -// break; -// } // case 122 -// default: { -// if (!super.parseUnknownField(input, extensionRegistry, tag)) { -// done = true; // was an endgroup tag -// } -// break; -// } // default: -// } // switch (tag) -// } // while (!done) -// } catch (com.google.protobuf.InvalidProtocolBufferException e) { -// throw e.unwrapIOException(); -// } finally { -// onChanged(); -// } // finally -// return this; -// } -// private int bitField0_; -// -// private com.google.protobuf.Internal.BooleanList bools_ = emptyBooleanList(); -// private void ensureBoolsIsMutable() { -// if (!((bitField0_ & 0x00000001) != 0)) { -// bools_ = mutableCopy(bools_); -// bitField0_ |= 0x00000001; -// } -// } -// /** -// * repeated bool bools = 1; -// * @return A list containing the bools. -// */ -// public java.util.List -// getBoolsList() { -// return ((bitField0_ & 0x00000001) != 0) ? -// java.util.Collections.unmodifiableList(bools_) : bools_; -// } -// /** -// * repeated bool bools = 1; -// * @return The count of bools. -// */ -// public int getBoolsCount() { -// return bools_.size(); -// } -// /** -// * repeated bool bools = 1; -// * @param index The index of the element to return. -// * @return The bools at the given index. -// */ -// public boolean getBools(int index) { -// return bools_.getBoolean(index); -// } -// /** -// * repeated bool bools = 1; -// * @param index The index to set the value at. -// * @param value The bools to set. -// * @return This builder for chaining. -// */ -// public Builder setBools( -// int index, boolean value) { -// -// ensureBoolsIsMutable(); -// bools_.setBoolean(index, value); -// onChanged(); -// return this; -// } -// /** -// * repeated bool bools = 1; -// * @param value The bools to add. -// * @return This builder for chaining. -// */ -// public Builder addBools(boolean value) { -// -// ensureBoolsIsMutable(); -// bools_.addBoolean(value); -// onChanged(); -// return this; -// } -// /** -// * repeated bool bools = 1; -// * @param values The bools to add. -// * @return This builder for chaining. -// */ -// public Builder addAllBools( -// java.lang.Iterable values) { -// ensureBoolsIsMutable(); -// com.google.protobuf.AbstractMessageLite.Builder.addAll( -// values, bools_); -// onChanged(); -// return this; -// } -// /** -// * repeated bool bools = 1; -// * @return This builder for chaining. -// */ -// public Builder clearBools() { -// bools_ = emptyBooleanList(); -// bitField0_ = (bitField0_ & ~0x00000001); -// onChanged(); -// return this; -// } -// -// private java.util.List bytes_ = java.util.Collections.emptyList(); -// private void ensureBytesIsMutable() { -// if (!((bitField0_ & 0x00000002) != 0)) { -// bytes_ = new java.util.ArrayList(bytes_); -// bitField0_ |= 0x00000002; -// } -// } -// /** -// * repeated bytes bytes = 2; -// * @return A list containing the bytes. -// */ -// public java.util.List -// getBytesList() { -// return ((bitField0_ & 0x00000002) != 0) ? -// java.util.Collections.unmodifiableList(bytes_) : bytes_; -// } -// /** -// * repeated bytes bytes = 2; -// * @return The count of bytes. -// */ -// public int getBytesCount() { -// return bytes_.size(); -// } -// /** -// * repeated bytes bytes = 2; -// * @param index The index of the element to return. -// * @return The bytes at the given index. -// */ -// public com.google.protobuf.ByteString getBytes(int index) { -// return bytes_.get(index); -// } -// /** -// * repeated bytes bytes = 2; -// * @param index The index to set the value at. -// * @param value The bytes to set. -// * @return This builder for chaining. -// */ -// public Builder setBytes( -// int index, com.google.protobuf.ByteString value) { -// if (value == null) { throw new NullPointerException(); } -// ensureBytesIsMutable(); -// bytes_.set(index, value); -// onChanged(); -// return this; -// } -// /** -// * repeated bytes bytes = 2; -// * @param value The bytes to add. -// * @return This builder for chaining. -// */ -// public Builder addBytes(com.google.protobuf.ByteString value) { -// if (value == null) { throw new NullPointerException(); } -// ensureBytesIsMutable(); -// bytes_.add(value); -// onChanged(); -// return this; -// } -// /** -// * repeated bytes bytes = 2; -// * @param values The bytes to add. -// * @return This builder for chaining. -// */ -// public Builder addAllBytes( -// java.lang.Iterable values) { -// ensureBytesIsMutable(); -// com.google.protobuf.AbstractMessageLite.Builder.addAll( -// values, bytes_); -// onChanged(); -// return this; -// } -// /** -// * repeated bytes bytes = 2; -// * @return This builder for chaining. -// */ -// public Builder clearBytes() { -// bytes_ = java.util.Collections.emptyList(); -// bitField0_ = (bitField0_ & ~0x00000002); -// onChanged(); -// return this; -// } -// -// private com.google.protobuf.Internal.IntList chars_ = emptyIntList(); -// private void ensureCharsIsMutable() { -// if (!((bitField0_ & 0x00000004) != 0)) { -// chars_ = mutableCopy(chars_); -// bitField0_ |= 0x00000004; -// } -// } -// /** -// * repeated sint32 chars = 3; -// * @return A list containing the chars. -// */ -// public java.util.List -// getCharsList() { -// return ((bitField0_ & 0x00000004) != 0) ? -// java.util.Collections.unmodifiableList(chars_) : chars_; -// } -// /** -// * repeated sint32 chars = 3; -// * @return The count of chars. -// */ -// public int getCharsCount() { -// return chars_.size(); -// } -// /** -// * repeated sint32 chars = 3; -// * @param index The index of the element to return. -// * @return The chars at the given index. -// */ -// public int getChars(int index) { -// return chars_.getInt(index); -// } -// /** -// * repeated sint32 chars = 3; -// * @param index The index to set the value at. -// * @param value The chars to set. -// * @return This builder for chaining. -// */ -// public Builder setChars( -// int index, int value) { -// -// ensureCharsIsMutable(); -// chars_.setInt(index, value); -// onChanged(); -// return this; -// } -// /** -// * repeated sint32 chars = 3; -// * @param value The chars to add. -// * @return This builder for chaining. -// */ -// public Builder addChars(int value) { -// -// ensureCharsIsMutable(); -// chars_.addInt(value); -// onChanged(); -// return this; -// } -// /** -// * repeated sint32 chars = 3; -// * @param values The chars to add. -// * @return This builder for chaining. -// */ -// public Builder addAllChars( -// java.lang.Iterable values) { -// ensureCharsIsMutable(); -// com.google.protobuf.AbstractMessageLite.Builder.addAll( -// values, chars_); -// onChanged(); -// return this; -// } -// /** -// * repeated sint32 chars = 3; -// * @return This builder for chaining. -// */ -// public Builder clearChars() { -// chars_ = emptyIntList(); -// bitField0_ = (bitField0_ & ~0x00000004); -// onChanged(); -// return this; -// } -// -// private java.util.List entrys_ = -// java.util.Collections.emptyList(); -// private void ensureEntrysIsMutable() { -// if (!((bitField0_ & 0x00000008) != 0)) { -// entrys_ = new -// java.util.ArrayList(entrys_); -// bitField0_ |= 0x00000008; -// } -// } -// -// private com.google.protobuf.RepeatedFieldBuilderV3< -// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry, -// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry.Builder, -// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntryOrBuilder> entrysBuilder_; -// -// /** -// * repeated .PTestBean.PTestEntry entrys = 4; -// */ -// public java.util.List getEntrysList() { -// if (entrysBuilder_ == null) { -// return java.util.Collections.unmodifiableList(entrys_); -// } else { -// return entrysBuilder_.getMessageList(); -// } -// } -// /** -// * repeated .PTestBean.PTestEntry entrys = 4; -// */ -// public int getEntrysCount() { -// if (entrysBuilder_ == null) { -// return entrys_.size(); -// } else { -// return entrysBuilder_.getCount(); -// } -// } -// /** -// * repeated .PTestBean.PTestEntry entrys = 4; -// */ -// public org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry getEntrys(int index) { -// if (entrysBuilder_ == null) { -// return entrys_.get(index); -// } else { -// return entrysBuilder_.getMessage(index); -// } -// } -// /** -// * repeated .PTestBean.PTestEntry entrys = 4; -// */ -// public Builder setEntrys( -// int index, org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry value) { -// if (entrysBuilder_ == null) { -// if (value == null) { -// throw new NullPointerException(); -// } -// ensureEntrysIsMutable(); -// entrys_.set(index, value); -// onChanged(); -// } else { -// entrysBuilder_.setMessage(index, value); -// } -// return this; -// } -// /** -// * repeated .PTestBean.PTestEntry entrys = 4; -// */ -// public Builder setEntrys( -// int index, org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry.Builder builderForValue) { -// if (entrysBuilder_ == null) { -// ensureEntrysIsMutable(); -// entrys_.set(index, builderForValue.build()); -// onChanged(); -// } else { -// entrysBuilder_.setMessage(index, builderForValue.build()); -// } -// return this; -// } -// /** -// * repeated .PTestBean.PTestEntry entrys = 4; -// */ -// public Builder addEntrys(org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry value) { -// if (entrysBuilder_ == null) { -// if (value == null) { -// throw new NullPointerException(); -// } -// ensureEntrysIsMutable(); -// entrys_.add(value); -// onChanged(); -// } else { -// entrysBuilder_.addMessage(value); -// } -// return this; -// } -// /** -// * repeated .PTestBean.PTestEntry entrys = 4; -// */ -// public Builder addEntrys( -// int index, org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry value) { -// if (entrysBuilder_ == null) { -// if (value == null) { -// throw new NullPointerException(); -// } -// ensureEntrysIsMutable(); -// entrys_.add(index, value); -// onChanged(); -// } else { -// entrysBuilder_.addMessage(index, value); -// } -// return this; -// } -// /** -// * repeated .PTestBean.PTestEntry entrys = 4; -// */ -// public Builder addEntrys( -// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry.Builder builderForValue) { -// if (entrysBuilder_ == null) { -// ensureEntrysIsMutable(); -// entrys_.add(builderForValue.build()); -// onChanged(); -// } else { -// entrysBuilder_.addMessage(builderForValue.build()); -// } -// return this; -// } -// /** -// * repeated .PTestBean.PTestEntry entrys = 4; -// */ -// public Builder addEntrys( -// int index, org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry.Builder builderForValue) { -// if (entrysBuilder_ == null) { -// ensureEntrysIsMutable(); -// entrys_.add(index, builderForValue.build()); -// onChanged(); -// } else { -// entrysBuilder_.addMessage(index, builderForValue.build()); -// } -// return this; -// } -// /** -// * repeated .PTestBean.PTestEntry entrys = 4; -// */ -// public Builder addAllEntrys( -// java.lang.Iterable values) { -// if (entrysBuilder_ == null) { -// ensureEntrysIsMutable(); -// com.google.protobuf.AbstractMessageLite.Builder.addAll( -// values, entrys_); -// onChanged(); -// } else { -// entrysBuilder_.addAllMessages(values); -// } -// return this; -// } -// /** -// * repeated .PTestBean.PTestEntry entrys = 4; -// */ -// public Builder clearEntrys() { -// if (entrysBuilder_ == null) { -// entrys_ = java.util.Collections.emptyList(); -// bitField0_ = (bitField0_ & ~0x00000008); -// onChanged(); -// } else { -// entrysBuilder_.clear(); -// } -// return this; -// } -// /** -// * repeated .PTestBean.PTestEntry entrys = 4; -// */ -// public Builder removeEntrys(int index) { -// if (entrysBuilder_ == null) { -// ensureEntrysIsMutable(); -// entrys_.remove(index); -// onChanged(); -// } else { -// entrysBuilder_.remove(index); -// } -// return this; -// } -// /** -// * repeated .PTestBean.PTestEntry entrys = 4; -// */ -// public org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry.Builder getEntrysBuilder( -// int index) { -// return getEntrysFieldBuilder().getBuilder(index); -// } -// /** -// * repeated .PTestBean.PTestEntry entrys = 4; -// */ -// public org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntryOrBuilder getEntrysOrBuilder( -// int index) { -// if (entrysBuilder_ == null) { -// return entrys_.get(index); } else { -// return entrysBuilder_.getMessageOrBuilder(index); -// } -// } -// /** -// * repeated .PTestBean.PTestEntry entrys = 4; -// */ -// public java.util.List -// getEntrysOrBuilderList() { -// if (entrysBuilder_ != null) { -// return entrysBuilder_.getMessageOrBuilderList(); -// } else { -// return java.util.Collections.unmodifiableList(entrys_); -// } -// } -// /** -// * repeated .PTestBean.PTestEntry entrys = 4; -// */ -// public org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry.Builder addEntrysBuilder() { -// return getEntrysFieldBuilder().addBuilder( -// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry.getDefaultInstance()); -// } -// /** -// * repeated .PTestBean.PTestEntry entrys = 4; -// */ -// public org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry.Builder addEntrysBuilder( -// int index) { -// return getEntrysFieldBuilder().addBuilder( -// index, org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry.getDefaultInstance()); -// } -// /** -// * repeated .PTestBean.PTestEntry entrys = 4; -// */ -// public java.util.List -// getEntrysBuilderList() { -// return getEntrysFieldBuilder().getBuilderList(); -// } -// private com.google.protobuf.RepeatedFieldBuilderV3< -// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry, -// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry.Builder, -// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntryOrBuilder> -// getEntrysFieldBuilder() { -// if (entrysBuilder_ == null) { -// entrysBuilder_ = new com.google.protobuf.RepeatedFieldBuilderV3< -// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry, -// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry.Builder, -// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntryOrBuilder>( -// entrys_, -// ((bitField0_ & 0x00000008) != 0), -// getParentForChildren(), -// isClean()); -// entrys_ = null; -// } -// return entrysBuilder_; -// } -// -// private com.google.protobuf.Internal.IntList ints_ = emptyIntList(); -// private void ensureIntsIsMutable() { -// if (!((bitField0_ & 0x00000010) != 0)) { -// ints_ = mutableCopy(ints_); -// bitField0_ |= 0x00000010; -// } -// } -// /** -// * repeated sint32 ints = 5; -// * @return A list containing the ints. -// */ -// public java.util.List -// getIntsList() { -// return ((bitField0_ & 0x00000010) != 0) ? -// java.util.Collections.unmodifiableList(ints_) : ints_; -// } -// /** -// * repeated sint32 ints = 5; -// * @return The count of ints. -// */ -// public int getIntsCount() { -// return ints_.size(); -// } -// /** -// * repeated sint32 ints = 5; -// * @param index The index of the element to return. -// * @return The ints at the given index. -// */ -// public int getInts(int index) { -// return ints_.getInt(index); -// } -// /** -// * repeated sint32 ints = 5; -// * @param index The index to set the value at. -// * @param value The ints to set. -// * @return This builder for chaining. -// */ -// public Builder setInts( -// int index, int value) { -// -// ensureIntsIsMutable(); -// ints_.setInt(index, value); -// onChanged(); -// return this; -// } -// /** -// * repeated sint32 ints = 5; -// * @param value The ints to add. -// * @return This builder for chaining. -// */ -// public Builder addInts(int value) { -// -// ensureIntsIsMutable(); -// ints_.addInt(value); -// onChanged(); -// return this; -// } -// /** -// * repeated sint32 ints = 5; -// * @param values The ints to add. -// * @return This builder for chaining. -// */ -// public Builder addAllInts( -// java.lang.Iterable values) { -// ensureIntsIsMutable(); -// com.google.protobuf.AbstractMessageLite.Builder.addAll( -// values, ints_); -// onChanged(); -// return this; -// } -// /** -// * repeated sint32 ints = 5; -// * @return This builder for chaining. -// */ -// public Builder clearInts() { -// ints_ = emptyIntList(); -// bitField0_ = (bitField0_ & ~0x00000010); -// onChanged(); -// return this; -// } -// -// private com.google.protobuf.Internal.FloatList floats_ = emptyFloatList(); -// private void ensureFloatsIsMutable() { -// if (!((bitField0_ & 0x00000020) != 0)) { -// floats_ = mutableCopy(floats_); -// bitField0_ |= 0x00000020; -// } -// } -// /** -// * repeated float floats = 6; -// * @return A list containing the floats. -// */ -// public java.util.List -// getFloatsList() { -// return ((bitField0_ & 0x00000020) != 0) ? -// java.util.Collections.unmodifiableList(floats_) : floats_; -// } -// /** -// * repeated float floats = 6; -// * @return The count of floats. -// */ -// public int getFloatsCount() { -// return floats_.size(); -// } -// /** -// * repeated float floats = 6; -// * @param index The index of the element to return. -// * @return The floats at the given index. -// */ -// public float getFloats(int index) { -// return floats_.getFloat(index); -// } -// /** -// * repeated float floats = 6; -// * @param index The index to set the value at. -// * @param value The floats to set. -// * @return This builder for chaining. -// */ -// public Builder setFloats( -// int index, float value) { -// -// ensureFloatsIsMutable(); -// floats_.setFloat(index, value); -// onChanged(); -// return this; -// } -// /** -// * repeated float floats = 6; -// * @param value The floats to add. -// * @return This builder for chaining. -// */ -// public Builder addFloats(float value) { -// -// ensureFloatsIsMutable(); -// floats_.addFloat(value); -// onChanged(); -// return this; -// } -// /** -// * repeated float floats = 6; -// * @param values The floats to add. -// * @return This builder for chaining. -// */ -// public Builder addAllFloats( -// java.lang.Iterable values) { -// ensureFloatsIsMutable(); -// com.google.protobuf.AbstractMessageLite.Builder.addAll( -// values, floats_); -// onChanged(); -// return this; -// } -// /** -// * repeated float floats = 6; -// * @return This builder for chaining. -// */ -// public Builder clearFloats() { -// floats_ = emptyFloatList(); -// bitField0_ = (bitField0_ & ~0x00000020); -// onChanged(); -// return this; -// } -// -// private com.google.protobuf.Internal.LongList longs_ = emptyLongList(); -// private void ensureLongsIsMutable() { -// if (!((bitField0_ & 0x00000040) != 0)) { -// longs_ = mutableCopy(longs_); -// bitField0_ |= 0x00000040; -// } -// } -// /** -// * repeated sint64 longs = 7; -// * @return A list containing the longs. -// */ -// public java.util.List -// getLongsList() { -// return ((bitField0_ & 0x00000040) != 0) ? -// java.util.Collections.unmodifiableList(longs_) : longs_; -// } -// /** -// * repeated sint64 longs = 7; -// * @return The count of longs. -// */ -// public int getLongsCount() { -// return longs_.size(); -// } -// /** -// * repeated sint64 longs = 7; -// * @param index The index of the element to return. -// * @return The longs at the given index. -// */ -// public long getLongs(int index) { -// return longs_.getLong(index); -// } -// /** -// * repeated sint64 longs = 7; -// * @param index The index to set the value at. -// * @param value The longs to set. -// * @return This builder for chaining. -// */ -// public Builder setLongs( -// int index, long value) { -// -// ensureLongsIsMutable(); -// longs_.setLong(index, value); -// onChanged(); -// return this; -// } -// /** -// * repeated sint64 longs = 7; -// * @param value The longs to add. -// * @return This builder for chaining. -// */ -// public Builder addLongs(long value) { -// -// ensureLongsIsMutable(); -// longs_.addLong(value); -// onChanged(); -// return this; -// } -// /** -// * repeated sint64 longs = 7; -// * @param values The longs to add. -// * @return This builder for chaining. -// */ -// public Builder addAllLongs( -// java.lang.Iterable values) { -// ensureLongsIsMutable(); -// com.google.protobuf.AbstractMessageLite.Builder.addAll( -// values, longs_); -// onChanged(); -// return this; -// } -// /** -// * repeated sint64 longs = 7; -// * @return This builder for chaining. -// */ -// public Builder clearLongs() { -// longs_ = emptyLongList(); -// bitField0_ = (bitField0_ & ~0x00000040); -// onChanged(); -// return this; -// } -// -// private com.google.protobuf.Internal.DoubleList doubles_ = emptyDoubleList(); -// private void ensureDoublesIsMutable() { -// if (!((bitField0_ & 0x00000080) != 0)) { -// doubles_ = mutableCopy(doubles_); -// bitField0_ |= 0x00000080; -// } -// } -// /** -// * repeated double doubles = 8; -// * @return A list containing the doubles. -// */ -// public java.util.List -// getDoublesList() { -// return ((bitField0_ & 0x00000080) != 0) ? -// java.util.Collections.unmodifiableList(doubles_) : doubles_; -// } -// /** -// * repeated double doubles = 8; -// * @return The count of doubles. -// */ -// public int getDoublesCount() { -// return doubles_.size(); -// } -// /** -// * repeated double doubles = 8; -// * @param index The index of the element to return. -// * @return The doubles at the given index. -// */ -// public double getDoubles(int index) { -// return doubles_.getDouble(index); -// } -// /** -// * repeated double doubles = 8; -// * @param index The index to set the value at. -// * @param value The doubles to set. -// * @return This builder for chaining. -// */ -// public Builder setDoubles( -// int index, double value) { -// -// ensureDoublesIsMutable(); -// doubles_.setDouble(index, value); -// onChanged(); -// return this; -// } -// /** -// * repeated double doubles = 8; -// * @param value The doubles to add. -// * @return This builder for chaining. -// */ -// public Builder addDoubles(double value) { -// -// ensureDoublesIsMutable(); -// doubles_.addDouble(value); -// onChanged(); -// return this; -// } -// /** -// * repeated double doubles = 8; -// * @param values The doubles to add. -// * @return This builder for chaining. -// */ -// public Builder addAllDoubles( -// java.lang.Iterable values) { -// ensureDoublesIsMutable(); -// com.google.protobuf.AbstractMessageLite.Builder.addAll( -// values, doubles_); -// onChanged(); -// return this; -// } -// /** -// * repeated double doubles = 8; -// * @return This builder for chaining. -// */ -// public Builder clearDoubles() { -// doubles_ = emptyDoubleList(); -// bitField0_ = (bitField0_ & ~0x00000080); -// onChanged(); -// return this; -// } -// -// private com.google.protobuf.LazyStringArrayList strings_ = -// com.google.protobuf.LazyStringArrayList.emptyList(); -// private void ensureStringsIsMutable() { -// if (!strings_.isModifiable()) { -// strings_ = new com.google.protobuf.LazyStringArrayList(strings_); -// } -// bitField0_ |= 0x00000100; -// } -// /** -// * repeated string strings = 9; -// * @return A list containing the strings. -// */ -// public com.google.protobuf.ProtocolStringList -// getStringsList() { -// strings_.makeImmutable(); -// return strings_; -// } -// /** -// * repeated string strings = 9; -// * @return The count of strings. -// */ -// public int getStringsCount() { -// return strings_.size(); -// } -// /** -// * repeated string strings = 9; -// * @param index The index of the element to return. -// * @return The strings at the given index. -// */ -// public java.lang.String getStrings(int index) { -// return strings_.get(index); -// } -// /** -// * repeated string strings = 9; -// * @param index The index of the value to return. -// * @return The bytes of the strings at the given index. -// */ -// public com.google.protobuf.ByteString -// getStringsBytes(int index) { -// return strings_.getByteString(index); -// } -// /** -// * repeated string strings = 9; -// * @param index The index to set the value at. -// * @param value The strings to set. -// * @return This builder for chaining. -// */ -// public Builder setStrings( -// int index, java.lang.String value) { -// if (value == null) { throw new NullPointerException(); } -// ensureStringsIsMutable(); -// strings_.set(index, value); -// bitField0_ |= 0x00000100; -// onChanged(); -// return this; -// } -// /** -// * repeated string strings = 9; -// * @param value The strings to add. -// * @return This builder for chaining. -// */ -// public Builder addStrings( -// java.lang.String value) { -// if (value == null) { throw new NullPointerException(); } -// ensureStringsIsMutable(); -// strings_.add(value); -// bitField0_ |= 0x00000100; -// onChanged(); -// return this; -// } -// /** -// * repeated string strings = 9; -// * @param values The strings to add. -// * @return This builder for chaining. -// */ -// public Builder addAllStrings( -// java.lang.Iterable values) { -// ensureStringsIsMutable(); -// com.google.protobuf.AbstractMessageLite.Builder.addAll( -// values, strings_); -// bitField0_ |= 0x00000100; -// onChanged(); -// return this; -// } -// /** -// * repeated string strings = 9; -// * @return This builder for chaining. -// */ -// public Builder clearStrings() { -// strings_ = -// com.google.protobuf.LazyStringArrayList.emptyList(); -// bitField0_ = (bitField0_ & ~0x00000100);; -// onChanged(); -// return this; -// } -// /** -// * repeated string strings = 9; -// * @param value The bytes of the strings to add. -// * @return This builder for chaining. -// */ -// public Builder addStringsBytes( -// com.google.protobuf.ByteString value) { -// if (value == null) { throw new NullPointerException(); } -// checkByteStringIsUtf8(value); -// ensureStringsIsMutable(); -// strings_.add(value); -// bitField0_ |= 0x00000100; -// onChanged(); -// return this; -// } -// -// private int id_ ; -// /** -// * sint32 id = 10; -// * @return The id. -// */ -// @java.lang.Override -// public int getId() { -// return id_; -// } -// /** -// * sint32 id = 10; -// * @param value The id to set. -// * @return This builder for chaining. -// */ -// public Builder setId(int value) { -// -// id_ = value; -// bitField0_ |= 0x00000200; -// onChanged(); -// return this; -// } -// /** -// * sint32 id = 10; -// * @return This builder for chaining. -// */ -// public Builder clearId() { -// bitField0_ = (bitField0_ & ~0x00000200); -// id_ = 0; -// onChanged(); -// return this; -// } -// -// private java.lang.Object name_ = ""; -// /** -// * string name = 11; -// * @return The name. -// */ -// public java.lang.String getName() { -// java.lang.Object ref = name_; -// if (!(ref instanceof java.lang.String)) { -// com.google.protobuf.ByteString bs = -// (com.google.protobuf.ByteString) ref; -// java.lang.String s = bs.toStringUtf8(); -// name_ = s; -// return s; -// } else { -// return (java.lang.String) ref; -// } -// } -// /** -// * string name = 11; -// * @return The bytes for name. -// */ -// public com.google.protobuf.ByteString -// getNameBytes() { -// java.lang.Object ref = name_; -// if (ref instanceof String) { -// com.google.protobuf.ByteString b = -// com.google.protobuf.ByteString.copyFromUtf8( -// (java.lang.String) ref); -// name_ = b; -// return b; -// } else { -// return (com.google.protobuf.ByteString) ref; -// } -// } -// /** -// * string name = 11; -// * @param value The name to set. -// * @return This builder for chaining. -// */ -// public Builder setName( -// java.lang.String value) { -// if (value == null) { throw new NullPointerException(); } -// name_ = value; -// bitField0_ |= 0x00000400; -// onChanged(); -// return this; -// } -// /** -// * string name = 11; -// * @return This builder for chaining. -// */ -// public Builder clearName() { -// name_ = getDefaultInstance().getName(); -// bitField0_ = (bitField0_ & ~0x00000400); -// onChanged(); -// return this; -// } -// /** -// * string name = 11; -// * @param value The bytes for name to set. -// * @return This builder for chaining. -// */ -// public Builder setNameBytes( -// com.google.protobuf.ByteString value) { -// if (value == null) { throw new NullPointerException(); } -// checkByteStringIsUtf8(value); -// name_ = value; -// bitField0_ |= 0x00000400; -// onChanged(); -// return this; -// } -// -// private java.lang.Object email_ = ""; -// /** -// * string email = 12; -// * @return The email. -// */ -// public java.lang.String getEmail() { -// java.lang.Object ref = email_; -// if (!(ref instanceof java.lang.String)) { -// com.google.protobuf.ByteString bs = -// (com.google.protobuf.ByteString) ref; -// java.lang.String s = bs.toStringUtf8(); -// email_ = s; -// return s; -// } else { -// return (java.lang.String) ref; -// } -// } -// /** -// * string email = 12; -// * @return The bytes for email. -// */ -// public com.google.protobuf.ByteString -// getEmailBytes() { -// java.lang.Object ref = email_; -// if (ref instanceof String) { -// com.google.protobuf.ByteString b = -// com.google.protobuf.ByteString.copyFromUtf8( -// (java.lang.String) ref); -// email_ = b; -// return b; -// } else { -// return (com.google.protobuf.ByteString) ref; -// } -// } -// /** -// * string email = 12; -// * @param value The email to set. -// * @return This builder for chaining. -// */ -// public Builder setEmail( -// java.lang.String value) { -// if (value == null) { throw new NullPointerException(); } -// email_ = value; -// bitField0_ |= 0x00000800; -// onChanged(); -// return this; -// } -// /** -// * string email = 12; -// * @return This builder for chaining. -// */ -// public Builder clearEmail() { -// email_ = getDefaultInstance().getEmail(); -// bitField0_ = (bitField0_ & ~0x00000800); -// onChanged(); -// return this; -// } -// /** -// * string email = 12; -// * @param value The bytes for email to set. -// * @return This builder for chaining. -// */ -// public Builder setEmailBytes( -// com.google.protobuf.ByteString value) { -// if (value == null) { throw new NullPointerException(); } -// checkByteStringIsUtf8(value); -// email_ = value; -// bitField0_ |= 0x00000800; -// onChanged(); -// return this; -// } -// -// private int kind_ = 0; -// /** -// * .PTestBean.Kind kind = 13; -// * @return The enum numeric value on the wire for kind. -// */ -// @java.lang.Override public int getKindValue() { -// return kind_; -// } -// /** -// * .PTestBean.Kind kind = 13; -// * @param value The enum numeric value on the wire for kind to set. -// * @return This builder for chaining. -// */ -// public Builder setKindValue(int value) { -// kind_ = value; -// bitField0_ |= 0x00001000; -// onChanged(); -// return this; -// } -// /** -// * .PTestBean.Kind kind = 13; -// * @return The kind. -// */ -// @java.lang.Override -// public org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.Kind getKind() { -// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.Kind result = -// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.Kind.forNumber(kind_); -// return result == null ? org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.Kind.UNRECOGNIZED : result; -// } -// /** -// * .PTestBean.Kind kind = 13; -// * @param value The kind to set. -// * @return This builder for chaining. -// */ -// public Builder setKind(org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.Kind value) { -// if (value == null) { -// throw new NullPointerException(); -// } -// bitField0_ |= 0x00001000; -// kind_ = value.getNumber(); -// onChanged(); -// return this; -// } -// /** -// * .PTestBean.Kind kind = 13; -// * @return This builder for chaining. -// */ -// public Builder clearKind() { -// bitField0_ = (bitField0_ & ~0x00001000); -// kind_ = 0; -// onChanged(); -// return this; -// } -// -// private com.google.protobuf.MapField< -// java.lang.String, java.lang.Integer> map_; -// private com.google.protobuf.MapField -// internalGetMap() { -// if (map_ == null) { -// return com.google.protobuf.MapField.emptyMapField( -// MapDefaultEntryHolder.defaultEntry); -// } -// return map_; -// } -// private com.google.protobuf.MapField -// internalGetMutableMap() { -// if (map_ == null) { -// map_ = com.google.protobuf.MapField.newMapField( -// MapDefaultEntryHolder.defaultEntry); -// } -// if (!map_.isMutable()) { -// map_ = map_.copy(); -// } -// bitField0_ |= 0x00002000; -// onChanged(); -// return map_; -// } -// public int getMapCount() { -// return internalGetMap().getMap().size(); -// } -// /** -// * map<string, sint32> map = 14; -// */ -// @java.lang.Override -// public boolean containsMap( -// java.lang.String key) { -// if (key == null) { throw new NullPointerException("map key"); } -// return internalGetMap().getMap().containsKey(key); -// } -// /** -// * Use {@link #getMapMap()} instead. -// */ -// @java.lang.Override -// @java.lang.Deprecated -// public java.util.Map getMap() { -// return getMapMap(); -// } -// /** -// * map<string, sint32> map = 14; -// */ -// @java.lang.Override -// public java.util.Map getMapMap() { -// return internalGetMap().getMap(); -// } -// /** -// * map<string, sint32> map = 14; -// */ -// @java.lang.Override -// public int getMapOrDefault( -// java.lang.String key, -// int defaultValue) { -// if (key == null) { throw new NullPointerException("map key"); } -// java.util.Map map = -// internalGetMap().getMap(); -// return map.containsKey(key) ? map.get(key) : defaultValue; -// } -// /** -// * map<string, sint32> map = 14; -// */ -// @java.lang.Override -// public int getMapOrThrow( -// java.lang.String key) { -// if (key == null) { throw new NullPointerException("map key"); } -// java.util.Map map = -// internalGetMap().getMap(); -// if (!map.containsKey(key)) { -// throw new java.lang.IllegalArgumentException(); -// } -// return map.get(key); -// } -// public Builder clearMap() { -// bitField0_ = (bitField0_ & ~0x00002000); -// internalGetMutableMap().getMutableMap() -// .clear(); -// return this; -// } -// /** -// * map<string, sint32> map = 14; -// */ -// public Builder removeMap( -// java.lang.String key) { -// if (key == null) { throw new NullPointerException("map key"); } -// internalGetMutableMap().getMutableMap() -// .remove(key); -// return this; -// } -// /** -// * Use alternate mutation accessors instead. -// */ -// @java.lang.Deprecated -// public java.util.Map -// getMutableMap() { -// bitField0_ |= 0x00002000; -// return internalGetMutableMap().getMutableMap(); -// } -// /** -// * map<string, sint32> map = 14; -// */ -// public Builder putMap( -// java.lang.String key, -// int value) { -// if (key == null) { throw new NullPointerException("map key"); } -// -// internalGetMutableMap().getMutableMap() -// .put(key, value); -// bitField0_ |= 0x00002000; -// return this; -// } -// /** -// * map<string, sint32> map = 14; -// */ -// public Builder putAllMap( -// java.util.Map values) { -// internalGetMutableMap().getMutableMap() -// .putAll(values); -// bitField0_ |= 0x00002000; -// return this; -// } -// -// private java.lang.Object end_ = ""; -// /** -// * string end = 15; -// * @return The end. -// */ -// public java.lang.String getEnd() { -// java.lang.Object ref = end_; -// if (!(ref instanceof java.lang.String)) { -// com.google.protobuf.ByteString bs = -// (com.google.protobuf.ByteString) ref; -// java.lang.String s = bs.toStringUtf8(); -// end_ = s; -// return s; -// } else { -// return (java.lang.String) ref; -// } -// } -// /** -// * string end = 15; -// * @return The bytes for end. -// */ -// public com.google.protobuf.ByteString -// getEndBytes() { -// java.lang.Object ref = end_; -// if (ref instanceof String) { -// com.google.protobuf.ByteString b = -// com.google.protobuf.ByteString.copyFromUtf8( -// (java.lang.String) ref); -// end_ = b; -// return b; -// } else { -// return (com.google.protobuf.ByteString) ref; -// } -// } -// /** -// * string end = 15; -// * @param value The end to set. -// * @return This builder for chaining. -// */ -// public Builder setEnd( -// java.lang.String value) { -// if (value == null) { throw new NullPointerException(); } -// end_ = value; -// bitField0_ |= 0x00004000; -// onChanged(); -// return this; -// } -// /** -// * string end = 15; -// * @return This builder for chaining. -// */ -// public Builder clearEnd() { -// end_ = getDefaultInstance().getEnd(); -// bitField0_ = (bitField0_ & ~0x00004000); -// onChanged(); -// return this; -// } -// /** -// * string end = 15; -// * @param value The bytes for end to set. -// * @return This builder for chaining. -// */ -// public Builder setEndBytes( -// com.google.protobuf.ByteString value) { -// if (value == null) { throw new NullPointerException(); } -// checkByteStringIsUtf8(value); -// end_ = value; -// bitField0_ |= 0x00004000; -// onChanged(); -// return this; -// } -// @java.lang.Override -// public final Builder setUnknownFields( -// final com.google.protobuf.UnknownFieldSet unknownFields) { -// return super.setUnknownFields(unknownFields); -// } -// -// @java.lang.Override -// public final Builder mergeUnknownFields( -// final com.google.protobuf.UnknownFieldSet unknownFields) { -// return super.mergeUnknownFields(unknownFields); -// } -// -// -// // @@protoc_insertion_point(builder_scope:PTestBean) -// } -// -// // @@protoc_insertion_point(class_scope:PTestBean) -// private static final org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean DEFAULT_INSTANCE; -// static { -// DEFAULT_INSTANCE = new org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean(); -// } -// -// public static org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean getDefaultInstance() { -// return DEFAULT_INSTANCE; -// } -// -// private static final com.google.protobuf.Parser -// PARSER = new com.google.protobuf.AbstractParser() { -// @java.lang.Override -// public PTestBean parsePartialFrom( -// com.google.protobuf.CodedInputStream input, -// com.google.protobuf.ExtensionRegistryLite extensionRegistry) -// throws com.google.protobuf.InvalidProtocolBufferException { -// Builder builder = newBuilder(); -// try { -// builder.mergeFrom(input, extensionRegistry); -// } catch (com.google.protobuf.InvalidProtocolBufferException e) { -// throw e.setUnfinishedMessage(builder.buildPartial()); -// } catch (com.google.protobuf.UninitializedMessageException e) { -// throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); -// } catch (java.io.IOException e) { -// throw new com.google.protobuf.InvalidProtocolBufferException(e) -// .setUnfinishedMessage(builder.buildPartial()); -// } -// return builder.buildPartial(); -// } -// }; -// -// public static com.google.protobuf.Parser parser() { -// return PARSER; -// } -// -// @java.lang.Override -// public com.google.protobuf.Parser getParserForType() { -// return PARSER; -// } -// -// @java.lang.Override -// public org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean getDefaultInstanceForType() { -// return DEFAULT_INSTANCE; -// } -// -// } -// -// private static final com.google.protobuf.Descriptors.Descriptor -// internal_static_PTestBean_descriptor; -// private static final -// com.google.protobuf.GeneratedMessageV3.FieldAccessorTable -// internal_static_PTestBean_fieldAccessorTable; -// private static final com.google.protobuf.Descriptors.Descriptor -// internal_static_PTestBean_PTestEntry_descriptor; -// private static final -// com.google.protobuf.GeneratedMessageV3.FieldAccessorTable -// internal_static_PTestBean_PTestEntry_fieldAccessorTable; -// private static final com.google.protobuf.Descriptors.Descriptor -// internal_static_PTestBean_MapEntry_descriptor; -// private static final -// com.google.protobuf.GeneratedMessageV3.FieldAccessorTable -// internal_static_PTestBean_MapEntry_fieldAccessorTable; -// -// public static com.google.protobuf.Descriptors.FileDescriptor -// getDescriptor() { -// return descriptor; -// } -// private static com.google.protobuf.Descriptors.FileDescriptor -// descriptor; -// static { -// java.lang.String[] descriptorData = { -// "\n8src/test/java/org/redkalex/test/protob" + -// "uf/PTestBean.proto\"\301\003\n\tPTestBean\022\r\n\005bool" + -// "s\030\001 \003(\010\022\r\n\005bytes\030\002 \003(\014\022\r\n\005chars\030\003 \003(\021\022%\n" + -// "\006entrys\030\004 \003(\0132\025.PTestBean.PTestEntry\022\014\n\004" + -// "ints\030\005 \003(\021\022\016\n\006floats\030\006 \003(\002\022\r\n\005longs\030\007 \003(" + -// "\022\022\017\n\007doubles\030\010 \003(\001\022\017\n\007strings\030\t \003(\t\022\n\n\002i" + -// "d\030\n \001(\021\022\014\n\004name\030\013 \001(\t\022\r\n\005email\030\014 \001(\t\022\035\n\004" + -// "kind\030\r \001(\0162\017.PTestBean.Kind\022 \n\003map\030\016 \003(\013" + -// "2\023.PTestBean.MapEntry\022\013\n\003end\030\017 \001(\t\032I\n\nPT" + -// "estEntry\022\r\n\005bools\030\001 \003(\010\022\r\n\005bytes\030\002 \003(\014\022\r" + -// "\n\005chars\030\003 \003(\021\022\016\n\006shorts\030\004 \003(\021\032*\n\010MapEntr" + -// "y\022\013\n\003key\030\001 \001(\t\022\r\n\005value\030\002 \001(\021:\0028\001\"#\n\004Kin" + -// "d\022\007\n\003ONE\020\000\022\007\n\003TWO\020\001\022\t\n\005THREE\020\002B\034\n\032org.re" + -// "dkalex.test.protobufb\006proto3" -// }; -// descriptor = com.google.protobuf.Descriptors.FileDescriptor -// .internalBuildGeneratedFileFrom(descriptorData, -// new com.google.protobuf.Descriptors.FileDescriptor[] { -// }); -// internal_static_PTestBean_descriptor = -// getDescriptor().getMessageTypes().get(0); -// internal_static_PTestBean_fieldAccessorTable = new -// com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( -// internal_static_PTestBean_descriptor, -// new java.lang.String[] { "Bools", "Bytes", "Chars", "Entrys", "Ints", "Floats", "Longs", "Doubles", "Strings", -// "Id", "Name", "Email", "Kind", "Map", "End", }); -// internal_static_PTestBean_PTestEntry_descriptor = -// internal_static_PTestBean_descriptor.getNestedTypes().get(0); -// internal_static_PTestBean_PTestEntry_fieldAccessorTable = new -// com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( -// internal_static_PTestBean_PTestEntry_descriptor, -// new java.lang.String[] { "Bools", "Bytes", "Chars", "Shorts", }); -// internal_static_PTestBean_MapEntry_descriptor = -// internal_static_PTestBean_descriptor.getNestedTypes().get(1); -// internal_static_PTestBean_MapEntry_fieldAccessorTable = new -// com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( -// internal_static_PTestBean_MapEntry_descriptor, -// new java.lang.String[] { "Key", "Value", }); -// } -// -// // @@protoc_insertion_point(outer_class_scope) -// } +package org.redkale.test.convert.proto; + +//// Generated by the protocol buffer compiler. DO NOT EDIT! +//// source: src/test/java/org/redkalex/test/protobuf/PTestBean.proto +// +// package org.redkalex.test.protobuf; +// +// public final class PTestBeanOuterClass { +// private PTestBeanOuterClass() {} +// public static void registerAllExtensions( +// com.google.protobuf.ExtensionRegistryLite registry) { +// } +// +// public static void registerAllExtensions( +// com.google.protobuf.ExtensionRegistry registry) { +// registerAllExtensions( +// (com.google.protobuf.ExtensionRegistryLite) registry); +// } +// public interface PTestBeanOrBuilder extends +// // @@protoc_insertion_point(interface_extends:PTestBean) +// com.google.protobuf.MessageOrBuilder { +// +// /** +// * repeated bool bools = 1; +// * @return A list containing the bools. +// */ +// java.util.List getBoolsList(); +// /** +// * repeated bool bools = 1; +// * @return The count of bools. +// */ +// int getBoolsCount(); +// /** +// * repeated bool bools = 1; +// * @param index The index of the element to return. +// * @return The bools at the given index. +// */ +// boolean getBools(int index); +// +// /** +// * repeated bytes bytes = 2; +// * @return A list containing the bytes. +// */ +// java.util.List getBytesList(); +// /** +// * repeated bytes bytes = 2; +// * @return The count of bytes. +// */ +// int getBytesCount(); +// /** +// * repeated bytes bytes = 2; +// * @param index The index of the element to return. +// * @return The bytes at the given index. +// */ +// com.google.protobuf.ByteString getBytes(int index); +// +// /** +// * repeated sint32 chars = 3; +// * @return A list containing the chars. +// */ +// java.util.List getCharsList(); +// /** +// * repeated sint32 chars = 3; +// * @return The count of chars. +// */ +// int getCharsCount(); +// /** +// * repeated sint32 chars = 3; +// * @param index The index of the element to return. +// * @return The chars at the given index. +// */ +// int getChars(int index); +// +// /** +// * repeated .PTestBean.PTestEntry entrys = 4; +// */ +// java.util.List +// getEntrysList(); +// /** +// * repeated .PTestBean.PTestEntry entrys = 4; +// */ +// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry getEntrys(int index); +// /** +// * repeated .PTestBean.PTestEntry entrys = 4; +// */ +// int getEntrysCount(); +// /** +// * repeated .PTestBean.PTestEntry entrys = 4; +// */ +// java.util.List +// getEntrysOrBuilderList(); +// /** +// * repeated .PTestBean.PTestEntry entrys = 4; +// */ +// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntryOrBuilder getEntrysOrBuilder( +// int index); +// +// /** +// * repeated sint32 ints = 5; +// * @return A list containing the ints. +// */ +// java.util.List getIntsList(); +// /** +// * repeated sint32 ints = 5; +// * @return The count of ints. +// */ +// int getIntsCount(); +// /** +// * repeated sint32 ints = 5; +// * @param index The index of the element to return. +// * @return The ints at the given index. +// */ +// int getInts(int index); +// +// /** +// * repeated float floats = 6; +// * @return A list containing the floats. +// */ +// java.util.List getFloatsList(); +// /** +// * repeated float floats = 6; +// * @return The count of floats. +// */ +// int getFloatsCount(); +// /** +// * repeated float floats = 6; +// * @param index The index of the element to return. +// * @return The floats at the given index. +// */ +// float getFloats(int index); +// +// /** +// * repeated sint64 longs = 7; +// * @return A list containing the longs. +// */ +// java.util.List getLongsList(); +// /** +// * repeated sint64 longs = 7; +// * @return The count of longs. +// */ +// int getLongsCount(); +// /** +// * repeated sint64 longs = 7; +// * @param index The index of the element to return. +// * @return The longs at the given index. +// */ +// long getLongs(int index); +// +// /** +// * repeated double doubles = 8; +// * @return A list containing the doubles. +// */ +// java.util.List getDoublesList(); +// /** +// * repeated double doubles = 8; +// * @return The count of doubles. +// */ +// int getDoublesCount(); +// /** +// * repeated double doubles = 8; +// * @param index The index of the element to return. +// * @return The doubles at the given index. +// */ +// double getDoubles(int index); +// +// /** +// * repeated string strings = 9; +// * @return A list containing the strings. +// */ +// java.util.List +// getStringsList(); +// /** +// * repeated string strings = 9; +// * @return The count of strings. +// */ +// int getStringsCount(); +// /** +// * repeated string strings = 9; +// * @param index The index of the element to return. +// * @return The strings at the given index. +// */ +// java.lang.String getStrings(int index); +// /** +// * repeated string strings = 9; +// * @param index The index of the value to return. +// * @return The bytes of the strings at the given index. +// */ +// com.google.protobuf.ByteString +// getStringsBytes(int index); +// +// /** +// * sint32 id = 10; +// * @return The id. +// */ +// int getId(); +// +// /** +// * string name = 11; +// * @return The name. +// */ +// java.lang.String getName(); +// /** +// * string name = 11; +// * @return The bytes for name. +// */ +// com.google.protobuf.ByteString +// getNameBytes(); +// +// /** +// * string email = 12; +// * @return The email. +// */ +// java.lang.String getEmail(); +// /** +// * string email = 12; +// * @return The bytes for email. +// */ +// com.google.protobuf.ByteString +// getEmailBytes(); +// +// /** +// * .PTestBean.Kind kind = 13; +// * @return The enum numeric value on the wire for kind. +// */ +// int getKindValue(); +// /** +// * .PTestBean.Kind kind = 13; +// * @return The kind. +// */ +// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.Kind getKind(); +// +// /** +// * map<string, sint32> map = 14; +// */ +// int getMapCount(); +// /** +// * map<string, sint32> map = 14; +// */ +// boolean containsMap( +// java.lang.String key); +// /** +// * Use {@link #getMapMap()} instead. +// */ +// @java.lang.Deprecated +// java.util.Map +// getMap(); +// /** +// * map<string, sint32> map = 14; +// */ +// java.util.Map +// getMapMap(); +// /** +// * map<string, sint32> map = 14; +// */ +// int getMapOrDefault( +// java.lang.String key, +// int defaultValue); +// /** +// * map<string, sint32> map = 14; +// */ +// int getMapOrThrow( +// java.lang.String key); +// +// /** +// * string end = 15; +// * @return The end. +// */ +// java.lang.String getEnd(); +// /** +// * string end = 15; +// * @return The bytes for end. +// */ +// com.google.protobuf.ByteString +// getEndBytes(); +// } +// /** +// * Protobuf type {@code PTestBean} +// */ +// public static final class PTestBean extends +// com.google.protobuf.GeneratedMessageV3 implements +// // @@protoc_insertion_point(message_implements:PTestBean) +// PTestBeanOrBuilder { +// private static final long serialVersionUID = 0L; +// // Use PTestBean.newBuilder() to construct. +// private PTestBean(com.google.protobuf.GeneratedMessageV3.Builder builder) { +// super(builder); +// } +// private PTestBean() { +// bools_ = emptyBooleanList(); +// bytes_ = java.util.Collections.emptyList(); +// chars_ = emptyIntList(); +// entrys_ = java.util.Collections.emptyList(); +// ints_ = emptyIntList(); +// floats_ = emptyFloatList(); +// longs_ = emptyLongList(); +// doubles_ = emptyDoubleList(); +// strings_ = +// com.google.protobuf.LazyStringArrayList.emptyList(); +// name_ = ""; +// email_ = ""; +// kind_ = 0; +// end_ = ""; +// } +// +// @java.lang.Override +// @SuppressWarnings({"unused"}) +// protected java.lang.Object newInstance( +// UnusedPrivateParameter unused) { +// return new PTestBean(); +// } +// +// public static final com.google.protobuf.Descriptors.Descriptor +// getDescriptor() { +// return org.redkalex.test.protobuf.PTestBeanOuterClass.internal_static_PTestBean_descriptor; +// } +// +// @SuppressWarnings({"rawtypes"}) +// @java.lang.Override +// protected com.google.protobuf.MapField internalGetMapField( +// int number) { +// switch (number) { +// case 14: +// return internalGetMap(); +// default: +// throw new RuntimeException( +// "Invalid map field number: " + number); +// } +// } +// @java.lang.Override +// protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable +// internalGetFieldAccessorTable() { +// return org.redkalex.test.protobuf.PTestBeanOuterClass.internal_static_PTestBean_fieldAccessorTable +// .ensureFieldAccessorsInitialized( +// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.class, +// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.Builder.class); +// } +// +// /** +// * Protobuf enum {@code PTestBean.Kind} +// */ +// public enum Kind +// implements com.google.protobuf.ProtocolMessageEnum { +// /** +// * ONE = 0; +// */ +// ONE(0), +// /** +// * TWO = 1; +// */ +// TWO(1), +// /** +// * THREE = 2; +// */ +// THREE(2), +// UNRECOGNIZED(-1), +// ; +// +// /** +// * ONE = 0; +// */ +// public static final int ONE_VALUE = 0; +// /** +// * TWO = 1; +// */ +// public static final int TWO_VALUE = 1; +// /** +// * THREE = 2; +// */ +// public static final int THREE_VALUE = 2; +// +// +// public final int getNumber() { +// if (this == UNRECOGNIZED) { +// throw new java.lang.IllegalArgumentException( +// "Can't get the number of an unknown enum value."); +// } +// return value; +// } +// +// /** +// * @param value The numeric wire value of the corresponding enum entry. +// * @return The enum associated with the given numeric wire value. +// * @deprecated Use {@link #forNumber(int)} instead. +// */ +// @java.lang.Deprecated +// public static Kind valueOf(int value) { +// return forNumber(value); +// } +// +// /** +// * @param value The numeric wire value of the corresponding enum entry. +// * @return The enum associated with the given numeric wire value. +// */ +// public static Kind forNumber(int value) { +// switch (value) { +// case 0: return ONE; +// case 1: return TWO; +// case 2: return THREE; +// default: return null; +// } +// } +// +// public static com.google.protobuf.Internal.EnumLiteMap +// internalGetValueMap() { +// return internalValueMap; +// } +// private static final com.google.protobuf.Internal.EnumLiteMap< +// Kind> internalValueMap = +// new com.google.protobuf.Internal.EnumLiteMap() { +// public Kind findValueByNumber(int number) { +// return Kind.forNumber(number); +// } +// }; +// +// public final com.google.protobuf.Descriptors.EnumValueDescriptor +// getValueDescriptor() { +// if (this == UNRECOGNIZED) { +// throw new java.lang.IllegalStateException( +// "Can't get the descriptor of an unrecognized enum value."); +// } +// return getDescriptor().getValues().get(ordinal()); +// } +// public final com.google.protobuf.Descriptors.EnumDescriptor +// getDescriptorForType() { +// return getDescriptor(); +// } +// public static final com.google.protobuf.Descriptors.EnumDescriptor +// getDescriptor() { +// return org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.getDescriptor().getEnumTypes().get(0); +// } +// +// private static final Kind[] VALUES = values(); +// +// public static Kind valueOf( +// com.google.protobuf.Descriptors.EnumValueDescriptor desc) { +// if (desc.getType() != getDescriptor()) { +// throw new java.lang.IllegalArgumentException( +// "EnumValueDescriptor is not for this type."); +// } +// if (desc.getIndex() == -1) { +// return UNRECOGNIZED; +// } +// return VALUES[desc.getIndex()]; +// } +// +// private final int value; +// +// private Kind(int value) { +// this.value = value; +// } +// +// // @@protoc_insertion_point(enum_scope:PTestBean.Kind) +// } +// +// public interface PTestEntryOrBuilder extends +// // @@protoc_insertion_point(interface_extends:PTestBean.PTestEntry) +// com.google.protobuf.MessageOrBuilder { +// +// /** +// * repeated bool bools = 1; +// * @return A list containing the bools. +// */ +// java.util.List getBoolsList(); +// /** +// * repeated bool bools = 1; +// * @return The count of bools. +// */ +// int getBoolsCount(); +// /** +// * repeated bool bools = 1; +// * @param index The index of the element to return. +// * @return The bools at the given index. +// */ +// boolean getBools(int index); +// +// /** +// * repeated bytes bytes = 2; +// * @return A list containing the bytes. +// */ +// java.util.List getBytesList(); +// /** +// * repeated bytes bytes = 2; +// * @return The count of bytes. +// */ +// int getBytesCount(); +// /** +// * repeated bytes bytes = 2; +// * @param index The index of the element to return. +// * @return The bytes at the given index. +// */ +// com.google.protobuf.ByteString getBytes(int index); +// +// /** +// * repeated sint32 chars = 3; +// * @return A list containing the chars. +// */ +// java.util.List getCharsList(); +// /** +// * repeated sint32 chars = 3; +// * @return The count of chars. +// */ +// int getCharsCount(); +// /** +// * repeated sint32 chars = 3; +// * @param index The index of the element to return. +// * @return The chars at the given index. +// */ +// int getChars(int index); +// +// /** +// * repeated sint32 shorts = 4; +// * @return A list containing the shorts. +// */ +// java.util.List getShortsList(); +// /** +// * repeated sint32 shorts = 4; +// * @return The count of shorts. +// */ +// int getShortsCount(); +// /** +// * repeated sint32 shorts = 4; +// * @param index The index of the element to return. +// * @return The shorts at the given index. +// */ +// int getShorts(int index); +// } +// /** +// * Protobuf type {@code PTestBean.PTestEntry} +// */ +// public static final class PTestEntry extends +// com.google.protobuf.GeneratedMessageV3 implements +// // @@protoc_insertion_point(message_implements:PTestBean.PTestEntry) +// PTestEntryOrBuilder { +// private static final long serialVersionUID = 0L; +// // Use PTestEntry.newBuilder() to construct. +// private PTestEntry(com.google.protobuf.GeneratedMessageV3.Builder builder) { +// super(builder); +// } +// private PTestEntry() { +// bools_ = emptyBooleanList(); +// bytes_ = java.util.Collections.emptyList(); +// chars_ = emptyIntList(); +// shorts_ = emptyIntList(); +// } +// +// @java.lang.Override +// @SuppressWarnings({"unused"}) +// protected java.lang.Object newInstance( +// UnusedPrivateParameter unused) { +// return new PTestEntry(); +// } +// +// public static final com.google.protobuf.Descriptors.Descriptor +// getDescriptor() { +// return org.redkalex.test.protobuf.PTestBeanOuterClass.internal_static_PTestBean_PTestEntry_descriptor; +// } +// +// @java.lang.Override +// protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable +// internalGetFieldAccessorTable() { +// return org.redkalex.test.protobuf.PTestBeanOuterClass.internal_static_PTestBean_PTestEntry_fieldAccessorTable +// .ensureFieldAccessorsInitialized( +// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry.class, +// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry.Builder.class); +// } +// +// public static final int BOOLS_FIELD_NUMBER = 1; +// @SuppressWarnings("serial") +// private com.google.protobuf.Internal.BooleanList bools_; +// /** +// * repeated bool bools = 1; +// * @return A list containing the bools. +// */ +// @java.lang.Override +// public java.util.List +// getBoolsList() { +// return bools_; +// } +// /** +// * repeated bool bools = 1; +// * @return The count of bools. +// */ +// public int getBoolsCount() { +// return bools_.size(); +// } +// /** +// * repeated bool bools = 1; +// * @param index The index of the element to return. +// * @return The bools at the given index. +// */ +// public boolean getBools(int index) { +// return bools_.getBoolean(index); +// } +// private int boolsMemoizedSerializedSize = -1; +// +// public static final int BYTES_FIELD_NUMBER = 2; +// @SuppressWarnings("serial") +// private java.util.List bytes_; +// /** +// * repeated bytes bytes = 2; +// * @return A list containing the bytes. +// */ +// @java.lang.Override +// public java.util.List +// getBytesList() { +// return bytes_; +// } +// /** +// * repeated bytes bytes = 2; +// * @return The count of bytes. +// */ +// public int getBytesCount() { +// return bytes_.size(); +// } +// /** +// * repeated bytes bytes = 2; +// * @param index The index of the element to return. +// * @return The bytes at the given index. +// */ +// public com.google.protobuf.ByteString getBytes(int index) { +// return bytes_.get(index); +// } +// +// public static final int CHARS_FIELD_NUMBER = 3; +// @SuppressWarnings("serial") +// private com.google.protobuf.Internal.IntList chars_; +// /** +// * repeated sint32 chars = 3; +// * @return A list containing the chars. +// */ +// @java.lang.Override +// public java.util.List +// getCharsList() { +// return chars_; +// } +// /** +// * repeated sint32 chars = 3; +// * @return The count of chars. +// */ +// public int getCharsCount() { +// return chars_.size(); +// } +// /** +// * repeated sint32 chars = 3; +// * @param index The index of the element to return. +// * @return The chars at the given index. +// */ +// public int getChars(int index) { +// return chars_.getInt(index); +// } +// private int charsMemoizedSerializedSize = -1; +// +// public static final int SHORTS_FIELD_NUMBER = 4; +// @SuppressWarnings("serial") +// private com.google.protobuf.Internal.IntList shorts_; +// /** +// * repeated sint32 shorts = 4; +// * @return A list containing the shorts. +// */ +// @java.lang.Override +// public java.util.List +// getShortsList() { +// return shorts_; +// } +// /** +// * repeated sint32 shorts = 4; +// * @return The count of shorts. +// */ +// public int getShortsCount() { +// return shorts_.size(); +// } +// /** +// * repeated sint32 shorts = 4; +// * @param index The index of the element to return. +// * @return The shorts at the given index. +// */ +// public int getShorts(int index) { +// return shorts_.getInt(index); +// } +// private int shortsMemoizedSerializedSize = -1; +// +// private byte memoizedIsInitialized = -1; +// @java.lang.Override +// public final boolean isInitialized() { +// byte isInitialized = memoizedIsInitialized; +// if (isInitialized == 1) return true; +// if (isInitialized == 0) return false; +// +// memoizedIsInitialized = 1; +// return true; +// } +// +// @java.lang.Override +// public void writeTo(com.google.protobuf.CodedOutputStream output) +// throws java.io.IOException { +// getSerializedSize(); +// if (getBoolsList().size() > 0) { +// output.writeUInt32NoTag(10); +// output.writeUInt32NoTag(boolsMemoizedSerializedSize); +// } +// for (int i = 0; i < bools_.size(); i++) { +// output.writeBoolNoTag(bools_.getBoolean(i)); +// } +// for (int i = 0; i < bytes_.size(); i++) { +// output.writeBytes(2, bytes_.get(i)); +// } +// if (getCharsList().size() > 0) { +// output.writeUInt32NoTag(26); +// output.writeUInt32NoTag(charsMemoizedSerializedSize); +// } +// for (int i = 0; i < chars_.size(); i++) { +// output.writeSInt32NoTag(chars_.getInt(i)); +// } +// if (getShortsList().size() > 0) { +// output.writeUInt32NoTag(34); +// output.writeUInt32NoTag(shortsMemoizedSerializedSize); +// } +// for (int i = 0; i < shorts_.size(); i++) { +// output.writeSInt32NoTag(shorts_.getInt(i)); +// } +// getUnknownFields().writeTo(output); +// } +// +// @java.lang.Override +// public int getSerializedSize() { +// int size = memoizedSize; +// if (size != -1) return size; +// +// size = 0; +// { +// int dataSize = 0; +// dataSize = 1 * getBoolsList().size(); +// size += dataSize; +// if (!getBoolsList().isEmpty()) { +// size += 1; +// size += com.google.protobuf.CodedOutputStream +// .computeInt32SizeNoTag(dataSize); +// } +// boolsMemoizedSerializedSize = dataSize; +// } +// { +// int dataSize = 0; +// for (int i = 0; i < bytes_.size(); i++) { +// dataSize += com.google.protobuf.CodedOutputStream +// .computeBytesSizeNoTag(bytes_.get(i)); +// } +// size += dataSize; +// size += 1 * getBytesList().size(); +// } +// { +// int dataSize = 0; +// for (int i = 0; i < chars_.size(); i++) { +// dataSize += com.google.protobuf.CodedOutputStream +// .computeSInt32SizeNoTag(chars_.getInt(i)); +// } +// size += dataSize; +// if (!getCharsList().isEmpty()) { +// size += 1; +// size += com.google.protobuf.CodedOutputStream +// .computeInt32SizeNoTag(dataSize); +// } +// charsMemoizedSerializedSize = dataSize; +// } +// { +// int dataSize = 0; +// for (int i = 0; i < shorts_.size(); i++) { +// dataSize += com.google.protobuf.CodedOutputStream +// .computeSInt32SizeNoTag(shorts_.getInt(i)); +// } +// size += dataSize; +// if (!getShortsList().isEmpty()) { +// size += 1; +// size += com.google.protobuf.CodedOutputStream +// .computeInt32SizeNoTag(dataSize); +// } +// shortsMemoizedSerializedSize = dataSize; +// } +// size += getUnknownFields().getSerializedSize(); +// memoizedSize = size; +// return size; +// } +// +// @java.lang.Override +// public boolean equals(final java.lang.Object obj) { +// if (obj == this) { +// return true; +// } +// if (!(obj instanceof org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry)) { +// return super.equals(obj); +// } +// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry other = +// (org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry) obj; +// +// if (!getBoolsList() +// .equals(other.getBoolsList())) return false; +// if (!getBytesList() +// .equals(other.getBytesList())) return false; +// if (!getCharsList() +// .equals(other.getCharsList())) return false; +// if (!getShortsList() +// .equals(other.getShortsList())) return false; +// if (!getUnknownFields().equals(other.getUnknownFields())) return false; +// return true; +// } +// +// @java.lang.Override +// public int hashCode() { +// if (memoizedHashCode != 0) { +// return memoizedHashCode; +// } +// int hash = 41; +// hash = (19 * hash) + getDescriptor().hashCode(); +// if (getBoolsCount() > 0) { +// hash = (37 * hash) + BOOLS_FIELD_NUMBER; +// hash = (53 * hash) + getBoolsList().hashCode(); +// } +// if (getBytesCount() > 0) { +// hash = (37 * hash) + BYTES_FIELD_NUMBER; +// hash = (53 * hash) + getBytesList().hashCode(); +// } +// if (getCharsCount() > 0) { +// hash = (37 * hash) + CHARS_FIELD_NUMBER; +// hash = (53 * hash) + getCharsList().hashCode(); +// } +// if (getShortsCount() > 0) { +// hash = (37 * hash) + SHORTS_FIELD_NUMBER; +// hash = (53 * hash) + getShortsList().hashCode(); +// } +// hash = (29 * hash) + getUnknownFields().hashCode(); +// memoizedHashCode = hash; +// return hash; +// } +// +// public static org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry parseFrom( +// java.nio.ByteBuffer data) +// throws com.google.protobuf.InvalidProtocolBufferException { +// return PARSER.parseFrom(data); +// } +// public static org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry parseFrom( +// java.nio.ByteBuffer data, +// com.google.protobuf.ExtensionRegistryLite extensionRegistry) +// throws com.google.protobuf.InvalidProtocolBufferException { +// return PARSER.parseFrom(data, extensionRegistry); +// } +// public static org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry parseFrom( +// com.google.protobuf.ByteString data) +// throws com.google.protobuf.InvalidProtocolBufferException { +// return PARSER.parseFrom(data); +// } +// public static org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry parseFrom( +// com.google.protobuf.ByteString data, +// com.google.protobuf.ExtensionRegistryLite extensionRegistry) +// throws com.google.protobuf.InvalidProtocolBufferException { +// return PARSER.parseFrom(data, extensionRegistry); +// } +// public static org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry parseFrom(byte[] data) +// throws com.google.protobuf.InvalidProtocolBufferException { +// return PARSER.parseFrom(data); +// } +// public static org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry parseFrom( +// byte[] data, +// com.google.protobuf.ExtensionRegistryLite extensionRegistry) +// throws com.google.protobuf.InvalidProtocolBufferException { +// return PARSER.parseFrom(data, extensionRegistry); +// } +// public static org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry parseFrom(java.io.InputStream +// input) +// throws java.io.IOException { +// return com.google.protobuf.GeneratedMessageV3 +// .parseWithIOException(PARSER, input); +// } +// public static org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry parseFrom( +// java.io.InputStream input, +// com.google.protobuf.ExtensionRegistryLite extensionRegistry) +// throws java.io.IOException { +// return com.google.protobuf.GeneratedMessageV3 +// .parseWithIOException(PARSER, input, extensionRegistry); +// } +// +// public static org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry +// parseDelimitedFrom(java.io.InputStream input) +// throws java.io.IOException { +// return com.google.protobuf.GeneratedMessageV3 +// .parseDelimitedWithIOException(PARSER, input); +// } +// +// public static org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry parseDelimitedFrom( +// java.io.InputStream input, +// com.google.protobuf.ExtensionRegistryLite extensionRegistry) +// throws java.io.IOException { +// return com.google.protobuf.GeneratedMessageV3 +// .parseDelimitedWithIOException(PARSER, input, extensionRegistry); +// } +// public static org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry parseFrom( +// com.google.protobuf.CodedInputStream input) +// throws java.io.IOException { +// return com.google.protobuf.GeneratedMessageV3 +// .parseWithIOException(PARSER, input); +// } +// public static org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry parseFrom( +// com.google.protobuf.CodedInputStream input, +// com.google.protobuf.ExtensionRegistryLite extensionRegistry) +// throws java.io.IOException { +// return com.google.protobuf.GeneratedMessageV3 +// .parseWithIOException(PARSER, input, extensionRegistry); +// } +// +// @java.lang.Override +// public Builder newBuilderForType() { return newBuilder(); } +// public static Builder newBuilder() { +// return DEFAULT_INSTANCE.toBuilder(); +// } +// public static Builder newBuilder(org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry prototype) +// { +// return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); +// } +// @java.lang.Override +// public Builder toBuilder() { +// return this == DEFAULT_INSTANCE +// ? new Builder() : new Builder().mergeFrom(this); +// } +// +// @java.lang.Override +// protected Builder newBuilderForType( +// com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { +// Builder builder = new Builder(parent); +// return builder; +// } +// /** +// * Protobuf type {@code PTestBean.PTestEntry} +// */ +// public static final class Builder extends +// com.google.protobuf.GeneratedMessageV3.Builder implements +// // @@protoc_insertion_point(builder_implements:PTestBean.PTestEntry) +// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntryOrBuilder { +// public static final com.google.protobuf.Descriptors.Descriptor +// getDescriptor() { +// return org.redkalex.test.protobuf.PTestBeanOuterClass.internal_static_PTestBean_PTestEntry_descriptor; +// } +// +// @java.lang.Override +// protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable +// internalGetFieldAccessorTable() { +// return +// org.redkalex.test.protobuf.PTestBeanOuterClass.internal_static_PTestBean_PTestEntry_fieldAccessorTable +// .ensureFieldAccessorsInitialized( +// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry.class, +// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry.Builder.class); +// } +// +// // Construct using org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry.newBuilder() +// private Builder() { +// +// } +// +// private Builder( +// com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { +// super(parent); +// +// } +// @java.lang.Override +// public Builder clear() { +// super.clear(); +// bitField0_ = 0; +// bools_ = emptyBooleanList(); +// bytes_ = java.util.Collections.emptyList(); +// chars_ = emptyIntList(); +// shorts_ = emptyIntList(); +// return this; +// } +// +// @java.lang.Override +// public com.google.protobuf.Descriptors.Descriptor +// getDescriptorForType() { +// return org.redkalex.test.protobuf.PTestBeanOuterClass.internal_static_PTestBean_PTestEntry_descriptor; +// } +// +// @java.lang.Override +// public org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry getDefaultInstanceForType() { +// return org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry.getDefaultInstance(); +// } +// +// @java.lang.Override +// public org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry build() { +// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry result = buildPartial(); +// if (!result.isInitialized()) { +// throw newUninitializedMessageException(result); +// } +// return result; +// } +// +// @java.lang.Override +// public org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry buildPartial() { +// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry result = new +// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry(this); +// buildPartialRepeatedFields(result); +// if (bitField0_ != 0) { buildPartial0(result); } +// onBuilt(); +// return result; +// } +// +// private void buildPartialRepeatedFields(org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry +// result) { +// if (((bitField0_ & 0x00000001) != 0)) { +// bools_.makeImmutable(); +// bitField0_ = (bitField0_ & ~0x00000001); +// } +// result.bools_ = bools_; +// if (((bitField0_ & 0x00000002) != 0)) { +// bytes_ = java.util.Collections.unmodifiableList(bytes_); +// bitField0_ = (bitField0_ & ~0x00000002); +// } +// result.bytes_ = bytes_; +// if (((bitField0_ & 0x00000004) != 0)) { +// chars_.makeImmutable(); +// bitField0_ = (bitField0_ & ~0x00000004); +// } +// result.chars_ = chars_; +// if (((bitField0_ & 0x00000008) != 0)) { +// shorts_.makeImmutable(); +// bitField0_ = (bitField0_ & ~0x00000008); +// } +// result.shorts_ = shorts_; +// } +// +// private void buildPartial0(org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry result) { +// int from_bitField0_ = bitField0_; +// } +// +// @java.lang.Override +// public Builder clone() { +// return super.clone(); +// } +// @java.lang.Override +// public Builder setField( +// com.google.protobuf.Descriptors.FieldDescriptor field, +// java.lang.Object value) { +// return super.setField(field, value); +// } +// @java.lang.Override +// public Builder clearField( +// com.google.protobuf.Descriptors.FieldDescriptor field) { +// return super.clearField(field); +// } +// @java.lang.Override +// public Builder clearOneof( +// com.google.protobuf.Descriptors.OneofDescriptor oneof) { +// return super.clearOneof(oneof); +// } +// @java.lang.Override +// public Builder setRepeatedField( +// com.google.protobuf.Descriptors.FieldDescriptor field, +// int index, java.lang.Object value) { +// return super.setRepeatedField(field, index, value); +// } +// @java.lang.Override +// public Builder addRepeatedField( +// com.google.protobuf.Descriptors.FieldDescriptor field, +// java.lang.Object value) { +// return super.addRepeatedField(field, value); +// } +// @java.lang.Override +// public Builder mergeFrom(com.google.protobuf.Message other) { +// if (other instanceof org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry) { +// return mergeFrom((org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry)other); +// } else { +// super.mergeFrom(other); +// return this; +// } +// } +// +// public Builder mergeFrom(org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry other) { +// if (other == org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry.getDefaultInstance()) +// return this; +// if (!other.bools_.isEmpty()) { +// if (bools_.isEmpty()) { +// bools_ = other.bools_; +// bitField0_ = (bitField0_ & ~0x00000001); +// } else { +// ensureBoolsIsMutable(); +// bools_.addAll(other.bools_); +// } +// onChanged(); +// } +// if (!other.bytes_.isEmpty()) { +// if (bytes_.isEmpty()) { +// bytes_ = other.bytes_; +// bitField0_ = (bitField0_ & ~0x00000002); +// } else { +// ensureBytesIsMutable(); +// bytes_.addAll(other.bytes_); +// } +// onChanged(); +// } +// if (!other.chars_.isEmpty()) { +// if (chars_.isEmpty()) { +// chars_ = other.chars_; +// bitField0_ = (bitField0_ & ~0x00000004); +// } else { +// ensureCharsIsMutable(); +// chars_.addAll(other.chars_); +// } +// onChanged(); +// } +// if (!other.shorts_.isEmpty()) { +// if (shorts_.isEmpty()) { +// shorts_ = other.shorts_; +// bitField0_ = (bitField0_ & ~0x00000008); +// } else { +// ensureShortsIsMutable(); +// shorts_.addAll(other.shorts_); +// } +// onChanged(); +// } +// this.mergeUnknownFields(other.getUnknownFields()); +// onChanged(); +// return this; +// } +// +// @java.lang.Override +// public final boolean isInitialized() { +// return true; +// } +// +// @java.lang.Override +// public Builder mergeFrom( +// com.google.protobuf.CodedInputStream input, +// com.google.protobuf.ExtensionRegistryLite extensionRegistry) +// throws java.io.IOException { +// if (extensionRegistry == null) { +// throw new java.lang.NullPointerException(); +// } +// try { +// boolean done = false; +// while (!done) { +// int tag = input.readTag(); +// switch (tag) { +// case 0: +// done = true; +// break; +// case 8: { +// boolean v = input.readBool(); +// ensureBoolsIsMutable(); +// bools_.addBoolean(v); +// break; +// } // case 8 +// case 10: { +// int length = input.readRawVarint32(); +// int limit = input.pushLimit(length); +// ensureBoolsIsMutable(); +// while (input.getBytesUntilLimit() > 0) { +// bools_.addBoolean(input.readBool()); +// } +// input.popLimit(limit); +// break; +// } // case 10 +// case 18: { +// com.google.protobuf.ByteString v = input.readBytes(); +// ensureBytesIsMutable(); +// bytes_.add(v); +// break; +// } // case 18 +// case 24: { +// int v = input.readSInt32(); +// ensureCharsIsMutable(); +// chars_.addInt(v); +// break; +// } // case 24 +// case 26: { +// int length = input.readRawVarint32(); +// int limit = input.pushLimit(length); +// ensureCharsIsMutable(); +// while (input.getBytesUntilLimit() > 0) { +// chars_.addInt(input.readSInt32()); +// } +// input.popLimit(limit); +// break; +// } // case 26 +// case 32: { +// int v = input.readSInt32(); +// ensureShortsIsMutable(); +// shorts_.addInt(v); +// break; +// } // case 32 +// case 34: { +// int length = input.readRawVarint32(); +// int limit = input.pushLimit(length); +// ensureShortsIsMutable(); +// while (input.getBytesUntilLimit() > 0) { +// shorts_.addInt(input.readSInt32()); +// } +// input.popLimit(limit); +// break; +// } // case 34 +// default: { +// if (!super.parseUnknownField(input, extensionRegistry, tag)) { +// done = true; // was an endgroup tag +// } +// break; +// } // default: +// } // switch (tag) +// } // while (!done) +// } catch (com.google.protobuf.InvalidProtocolBufferException e) { +// throw e.unwrapIOException(); +// } finally { +// onChanged(); +// } // finally +// return this; +// } +// private int bitField0_; +// +// private com.google.protobuf.Internal.BooleanList bools_ = emptyBooleanList(); +// private void ensureBoolsIsMutable() { +// if (!((bitField0_ & 0x00000001) != 0)) { +// bools_ = mutableCopy(bools_); +// bitField0_ |= 0x00000001; +// } +// } +// /** +// * repeated bool bools = 1; +// * @return A list containing the bools. +// */ +// public java.util.List +// getBoolsList() { +// return ((bitField0_ & 0x00000001) != 0) ? +// java.util.Collections.unmodifiableList(bools_) : bools_; +// } +// /** +// * repeated bool bools = 1; +// * @return The count of bools. +// */ +// public int getBoolsCount() { +// return bools_.size(); +// } +// /** +// * repeated bool bools = 1; +// * @param index The index of the element to return. +// * @return The bools at the given index. +// */ +// public boolean getBools(int index) { +// return bools_.getBoolean(index); +// } +// /** +// * repeated bool bools = 1; +// * @param index The index to set the value at. +// * @param value The bools to set. +// * @return This builder for chaining. +// */ +// public Builder setBools( +// int index, boolean value) { +// +// ensureBoolsIsMutable(); +// bools_.setBoolean(index, value); +// onChanged(); +// return this; +// } +// /** +// * repeated bool bools = 1; +// * @param value The bools to add. +// * @return This builder for chaining. +// */ +// public Builder addBools(boolean value) { +// +// ensureBoolsIsMutable(); +// bools_.addBoolean(value); +// onChanged(); +// return this; +// } +// /** +// * repeated bool bools = 1; +// * @param values The bools to add. +// * @return This builder for chaining. +// */ +// public Builder addAllBools( +// java.lang.Iterable values) { +// ensureBoolsIsMutable(); +// com.google.protobuf.AbstractMessageLite.Builder.addAll( +// values, bools_); +// onChanged(); +// return this; +// } +// /** +// * repeated bool bools = 1; +// * @return This builder for chaining. +// */ +// public Builder clearBools() { +// bools_ = emptyBooleanList(); +// bitField0_ = (bitField0_ & ~0x00000001); +// onChanged(); +// return this; +// } +// +// private java.util.List bytes_ = java.util.Collections.emptyList(); +// private void ensureBytesIsMutable() { +// if (!((bitField0_ & 0x00000002) != 0)) { +// bytes_ = new java.util.ArrayList(bytes_); +// bitField0_ |= 0x00000002; +// } +// } +// /** +// * repeated bytes bytes = 2; +// * @return A list containing the bytes. +// */ +// public java.util.List +// getBytesList() { +// return ((bitField0_ & 0x00000002) != 0) ? +// java.util.Collections.unmodifiableList(bytes_) : bytes_; +// } +// /** +// * repeated bytes bytes = 2; +// * @return The count of bytes. +// */ +// public int getBytesCount() { +// return bytes_.size(); +// } +// /** +// * repeated bytes bytes = 2; +// * @param index The index of the element to return. +// * @return The bytes at the given index. +// */ +// public com.google.protobuf.ByteString getBytes(int index) { +// return bytes_.get(index); +// } +// /** +// * repeated bytes bytes = 2; +// * @param index The index to set the value at. +// * @param value The bytes to set. +// * @return This builder for chaining. +// */ +// public Builder setBytes( +// int index, com.google.protobuf.ByteString value) { +// if (value == null) { throw new NullPointerException(); } +// ensureBytesIsMutable(); +// bytes_.set(index, value); +// onChanged(); +// return this; +// } +// /** +// * repeated bytes bytes = 2; +// * @param value The bytes to add. +// * @return This builder for chaining. +// */ +// public Builder addBytes(com.google.protobuf.ByteString value) { +// if (value == null) { throw new NullPointerException(); } +// ensureBytesIsMutable(); +// bytes_.add(value); +// onChanged(); +// return this; +// } +// /** +// * repeated bytes bytes = 2; +// * @param values The bytes to add. +// * @return This builder for chaining. +// */ +// public Builder addAllBytes( +// java.lang.Iterable values) { +// ensureBytesIsMutable(); +// com.google.protobuf.AbstractMessageLite.Builder.addAll( +// values, bytes_); +// onChanged(); +// return this; +// } +// /** +// * repeated bytes bytes = 2; +// * @return This builder for chaining. +// */ +// public Builder clearBytes() { +// bytes_ = java.util.Collections.emptyList(); +// bitField0_ = (bitField0_ & ~0x00000002); +// onChanged(); +// return this; +// } +// +// private com.google.protobuf.Internal.IntList chars_ = emptyIntList(); +// private void ensureCharsIsMutable() { +// if (!((bitField0_ & 0x00000004) != 0)) { +// chars_ = mutableCopy(chars_); +// bitField0_ |= 0x00000004; +// } +// } +// /** +// * repeated sint32 chars = 3; +// * @return A list containing the chars. +// */ +// public java.util.List +// getCharsList() { +// return ((bitField0_ & 0x00000004) != 0) ? +// java.util.Collections.unmodifiableList(chars_) : chars_; +// } +// /** +// * repeated sint32 chars = 3; +// * @return The count of chars. +// */ +// public int getCharsCount() { +// return chars_.size(); +// } +// /** +// * repeated sint32 chars = 3; +// * @param index The index of the element to return. +// * @return The chars at the given index. +// */ +// public int getChars(int index) { +// return chars_.getInt(index); +// } +// /** +// * repeated sint32 chars = 3; +// * @param index The index to set the value at. +// * @param value The chars to set. +// * @return This builder for chaining. +// */ +// public Builder setChars( +// int index, int value) { +// +// ensureCharsIsMutable(); +// chars_.setInt(index, value); +// onChanged(); +// return this; +// } +// /** +// * repeated sint32 chars = 3; +// * @param value The chars to add. +// * @return This builder for chaining. +// */ +// public Builder addChars(int value) { +// +// ensureCharsIsMutable(); +// chars_.addInt(value); +// onChanged(); +// return this; +// } +// /** +// * repeated sint32 chars = 3; +// * @param values The chars to add. +// * @return This builder for chaining. +// */ +// public Builder addAllChars( +// java.lang.Iterable values) { +// ensureCharsIsMutable(); +// com.google.protobuf.AbstractMessageLite.Builder.addAll( +// values, chars_); +// onChanged(); +// return this; +// } +// /** +// * repeated sint32 chars = 3; +// * @return This builder for chaining. +// */ +// public Builder clearChars() { +// chars_ = emptyIntList(); +// bitField0_ = (bitField0_ & ~0x00000004); +// onChanged(); +// return this; +// } +// +// private com.google.protobuf.Internal.IntList shorts_ = emptyIntList(); +// private void ensureShortsIsMutable() { +// if (!((bitField0_ & 0x00000008) != 0)) { +// shorts_ = mutableCopy(shorts_); +// bitField0_ |= 0x00000008; +// } +// } +// /** +// * repeated sint32 shorts = 4; +// * @return A list containing the shorts. +// */ +// public java.util.List +// getShortsList() { +// return ((bitField0_ & 0x00000008) != 0) ? +// java.util.Collections.unmodifiableList(shorts_) : shorts_; +// } +// /** +// * repeated sint32 shorts = 4; +// * @return The count of shorts. +// */ +// public int getShortsCount() { +// return shorts_.size(); +// } +// /** +// * repeated sint32 shorts = 4; +// * @param index The index of the element to return. +// * @return The shorts at the given index. +// */ +// public int getShorts(int index) { +// return shorts_.getInt(index); +// } +// /** +// * repeated sint32 shorts = 4; +// * @param index The index to set the value at. +// * @param value The shorts to set. +// * @return This builder for chaining. +// */ +// public Builder setShorts( +// int index, int value) { +// +// ensureShortsIsMutable(); +// shorts_.setInt(index, value); +// onChanged(); +// return this; +// } +// /** +// * repeated sint32 shorts = 4; +// * @param value The shorts to add. +// * @return This builder for chaining. +// */ +// public Builder addShorts(int value) { +// +// ensureShortsIsMutable(); +// shorts_.addInt(value); +// onChanged(); +// return this; +// } +// /** +// * repeated sint32 shorts = 4; +// * @param values The shorts to add. +// * @return This builder for chaining. +// */ +// public Builder addAllShorts( +// java.lang.Iterable values) { +// ensureShortsIsMutable(); +// com.google.protobuf.AbstractMessageLite.Builder.addAll( +// values, shorts_); +// onChanged(); +// return this; +// } +// /** +// * repeated sint32 shorts = 4; +// * @return This builder for chaining. +// */ +// public Builder clearShorts() { +// shorts_ = emptyIntList(); +// bitField0_ = (bitField0_ & ~0x00000008); +// onChanged(); +// return this; +// } +// @java.lang.Override +// public final Builder setUnknownFields( +// final com.google.protobuf.UnknownFieldSet unknownFields) { +// return super.setUnknownFields(unknownFields); +// } +// +// @java.lang.Override +// public final Builder mergeUnknownFields( +// final com.google.protobuf.UnknownFieldSet unknownFields) { +// return super.mergeUnknownFields(unknownFields); +// } +// +// +// // @@protoc_insertion_point(builder_scope:PTestBean.PTestEntry) +// } +// +// // @@protoc_insertion_point(class_scope:PTestBean.PTestEntry) +// private static final org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry DEFAULT_INSTANCE; +// static { +// DEFAULT_INSTANCE = new org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry(); +// } +// +// public static org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry getDefaultInstance() { +// return DEFAULT_INSTANCE; +// } +// +// private static final com.google.protobuf.Parser +// PARSER = new com.google.protobuf.AbstractParser() { +// @java.lang.Override +// public PTestEntry parsePartialFrom( +// com.google.protobuf.CodedInputStream input, +// com.google.protobuf.ExtensionRegistryLite extensionRegistry) +// throws com.google.protobuf.InvalidProtocolBufferException { +// Builder builder = newBuilder(); +// try { +// builder.mergeFrom(input, extensionRegistry); +// } catch (com.google.protobuf.InvalidProtocolBufferException e) { +// throw e.setUnfinishedMessage(builder.buildPartial()); +// } catch (com.google.protobuf.UninitializedMessageException e) { +// throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); +// } catch (java.io.IOException e) { +// throw new com.google.protobuf.InvalidProtocolBufferException(e) +// .setUnfinishedMessage(builder.buildPartial()); +// } +// return builder.buildPartial(); +// } +// }; +// +// public static com.google.protobuf.Parser parser() { +// return PARSER; +// } +// +// @java.lang.Override +// public com.google.protobuf.Parser getParserForType() { +// return PARSER; +// } +// +// @java.lang.Override +// public org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry getDefaultInstanceForType() { +// return DEFAULT_INSTANCE; +// } +// +// } +// +// public static final int BOOLS_FIELD_NUMBER = 1; +// @SuppressWarnings("serial") +// private com.google.protobuf.Internal.BooleanList bools_; +// /** +// * repeated bool bools = 1; +// * @return A list containing the bools. +// */ +// @java.lang.Override +// public java.util.List +// getBoolsList() { +// return bools_; +// } +// /** +// * repeated bool bools = 1; +// * @return The count of bools. +// */ +// public int getBoolsCount() { +// return bools_.size(); +// } +// /** +// * repeated bool bools = 1; +// * @param index The index of the element to return. +// * @return The bools at the given index. +// */ +// public boolean getBools(int index) { +// return bools_.getBoolean(index); +// } +// private int boolsMemoizedSerializedSize = -1; +// +// public static final int BYTES_FIELD_NUMBER = 2; +// @SuppressWarnings("serial") +// private java.util.List bytes_; +// /** +// * repeated bytes bytes = 2; +// * @return A list containing the bytes. +// */ +// @java.lang.Override +// public java.util.List +// getBytesList() { +// return bytes_; +// } +// /** +// * repeated bytes bytes = 2; +// * @return The count of bytes. +// */ +// public int getBytesCount() { +// return bytes_.size(); +// } +// /** +// * repeated bytes bytes = 2; +// * @param index The index of the element to return. +// * @return The bytes at the given index. +// */ +// public com.google.protobuf.ByteString getBytes(int index) { +// return bytes_.get(index); +// } +// +// public static final int CHARS_FIELD_NUMBER = 3; +// @SuppressWarnings("serial") +// private com.google.protobuf.Internal.IntList chars_; +// /** +// * repeated sint32 chars = 3; +// * @return A list containing the chars. +// */ +// @java.lang.Override +// public java.util.List +// getCharsList() { +// return chars_; +// } +// /** +// * repeated sint32 chars = 3; +// * @return The count of chars. +// */ +// public int getCharsCount() { +// return chars_.size(); +// } +// /** +// * repeated sint32 chars = 3; +// * @param index The index of the element to return. +// * @return The chars at the given index. +// */ +// public int getChars(int index) { +// return chars_.getInt(index); +// } +// private int charsMemoizedSerializedSize = -1; +// +// public static final int ENTRYS_FIELD_NUMBER = 4; +// @SuppressWarnings("serial") +// private java.util.List entrys_; +// /** +// * repeated .PTestBean.PTestEntry entrys = 4; +// */ +// @java.lang.Override +// public java.util.List getEntrysList() { +// return entrys_; +// } +// /** +// * repeated .PTestBean.PTestEntry entrys = 4; +// */ +// @java.lang.Override +// public java.util.List +// getEntrysOrBuilderList() { +// return entrys_; +// } +// /** +// * repeated .PTestBean.PTestEntry entrys = 4; +// */ +// @java.lang.Override +// public int getEntrysCount() { +// return entrys_.size(); +// } +// /** +// * repeated .PTestBean.PTestEntry entrys = 4; +// */ +// @java.lang.Override +// public org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry getEntrys(int index) { +// return entrys_.get(index); +// } +// /** +// * repeated .PTestBean.PTestEntry entrys = 4; +// */ +// @java.lang.Override +// public org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntryOrBuilder getEntrysOrBuilder( +// int index) { +// return entrys_.get(index); +// } +// +// public static final int INTS_FIELD_NUMBER = 5; +// @SuppressWarnings("serial") +// private com.google.protobuf.Internal.IntList ints_; +// /** +// * repeated sint32 ints = 5; +// * @return A list containing the ints. +// */ +// @java.lang.Override +// public java.util.List +// getIntsList() { +// return ints_; +// } +// /** +// * repeated sint32 ints = 5; +// * @return The count of ints. +// */ +// public int getIntsCount() { +// return ints_.size(); +// } +// /** +// * repeated sint32 ints = 5; +// * @param index The index of the element to return. +// * @return The ints at the given index. +// */ +// public int getInts(int index) { +// return ints_.getInt(index); +// } +// private int intsMemoizedSerializedSize = -1; +// +// public static final int FLOATS_FIELD_NUMBER = 6; +// @SuppressWarnings("serial") +// private com.google.protobuf.Internal.FloatList floats_; +// /** +// * repeated float floats = 6; +// * @return A list containing the floats. +// */ +// @java.lang.Override +// public java.util.List +// getFloatsList() { +// return floats_; +// } +// /** +// * repeated float floats = 6; +// * @return The count of floats. +// */ +// public int getFloatsCount() { +// return floats_.size(); +// } +// /** +// * repeated float floats = 6; +// * @param index The index of the element to return. +// * @return The floats at the given index. +// */ +// public float getFloats(int index) { +// return floats_.getFloat(index); +// } +// private int floatsMemoizedSerializedSize = -1; +// +// public static final int LONGS_FIELD_NUMBER = 7; +// @SuppressWarnings("serial") +// private com.google.protobuf.Internal.LongList longs_; +// /** +// * repeated sint64 longs = 7; +// * @return A list containing the longs. +// */ +// @java.lang.Override +// public java.util.List +// getLongsList() { +// return longs_; +// } +// /** +// * repeated sint64 longs = 7; +// * @return The count of longs. +// */ +// public int getLongsCount() { +// return longs_.size(); +// } +// /** +// * repeated sint64 longs = 7; +// * @param index The index of the element to return. +// * @return The longs at the given index. +// */ +// public long getLongs(int index) { +// return longs_.getLong(index); +// } +// private int longsMemoizedSerializedSize = -1; +// +// public static final int DOUBLES_FIELD_NUMBER = 8; +// @SuppressWarnings("serial") +// private com.google.protobuf.Internal.DoubleList doubles_; +// /** +// * repeated double doubles = 8; +// * @return A list containing the doubles. +// */ +// @java.lang.Override +// public java.util.List +// getDoublesList() { +// return doubles_; +// } +// /** +// * repeated double doubles = 8; +// * @return The count of doubles. +// */ +// public int getDoublesCount() { +// return doubles_.size(); +// } +// /** +// * repeated double doubles = 8; +// * @param index The index of the element to return. +// * @return The doubles at the given index. +// */ +// public double getDoubles(int index) { +// return doubles_.getDouble(index); +// } +// private int doublesMemoizedSerializedSize = -1; +// +// public static final int STRINGS_FIELD_NUMBER = 9; +// @SuppressWarnings("serial") +// private com.google.protobuf.LazyStringArrayList strings_ = +// com.google.protobuf.LazyStringArrayList.emptyList(); +// /** +// * repeated string strings = 9; +// * @return A list containing the strings. +// */ +// public com.google.protobuf.ProtocolStringList +// getStringsList() { +// return strings_; +// } +// /** +// * repeated string strings = 9; +// * @return The count of strings. +// */ +// public int getStringsCount() { +// return strings_.size(); +// } +// /** +// * repeated string strings = 9; +// * @param index The index of the element to return. +// * @return The strings at the given index. +// */ +// public java.lang.String getStrings(int index) { +// return strings_.get(index); +// } +// /** +// * repeated string strings = 9; +// * @param index The index of the value to return. +// * @return The bytes of the strings at the given index. +// */ +// public com.google.protobuf.ByteString +// getStringsBytes(int index) { +// return strings_.getByteString(index); +// } +// +// public static final int ID_FIELD_NUMBER = 10; +// private int id_ = 0; +// /** +// * sint32 id = 10; +// * @return The id. +// */ +// @java.lang.Override +// public int getId() { +// return id_; +// } +// +// public static final int NAME_FIELD_NUMBER = 11; +// @SuppressWarnings("serial") +// private volatile java.lang.Object name_ = ""; +// /** +// * string name = 11; +// * @return The name. +// */ +// @java.lang.Override +// public java.lang.String getName() { +// java.lang.Object ref = name_; +// if (ref instanceof java.lang.String) { +// return (java.lang.String) ref; +// } else { +// com.google.protobuf.ByteString bs = +// (com.google.protobuf.ByteString) ref; +// java.lang.String s = bs.toStringUtf8(); +// name_ = s; +// return s; +// } +// } +// /** +// * string name = 11; +// * @return The bytes for name. +// */ +// @java.lang.Override +// public com.google.protobuf.ByteString +// getNameBytes() { +// java.lang.Object ref = name_; +// if (ref instanceof java.lang.String) { +// com.google.protobuf.ByteString b = +// com.google.protobuf.ByteString.copyFromUtf8( +// (java.lang.String) ref); +// name_ = b; +// return b; +// } else { +// return (com.google.protobuf.ByteString) ref; +// } +// } +// +// public static final int EMAIL_FIELD_NUMBER = 12; +// @SuppressWarnings("serial") +// private volatile java.lang.Object email_ = ""; +// /** +// * string email = 12; +// * @return The email. +// */ +// @java.lang.Override +// public java.lang.String getEmail() { +// java.lang.Object ref = email_; +// if (ref instanceof java.lang.String) { +// return (java.lang.String) ref; +// } else { +// com.google.protobuf.ByteString bs = +// (com.google.protobuf.ByteString) ref; +// java.lang.String s = bs.toStringUtf8(); +// email_ = s; +// return s; +// } +// } +// /** +// * string email = 12; +// * @return The bytes for email. +// */ +// @java.lang.Override +// public com.google.protobuf.ByteString +// getEmailBytes() { +// java.lang.Object ref = email_; +// if (ref instanceof java.lang.String) { +// com.google.protobuf.ByteString b = +// com.google.protobuf.ByteString.copyFromUtf8( +// (java.lang.String) ref); +// email_ = b; +// return b; +// } else { +// return (com.google.protobuf.ByteString) ref; +// } +// } +// +// public static final int KIND_FIELD_NUMBER = 13; +// private int kind_ = 0; +// /** +// * .PTestBean.Kind kind = 13; +// * @return The enum numeric value on the wire for kind. +// */ +// @java.lang.Override public int getKindValue() { +// return kind_; +// } +// /** +// * .PTestBean.Kind kind = 13; +// * @return The kind. +// */ +// @java.lang.Override public org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.Kind getKind() { +// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.Kind result = +// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.Kind.forNumber(kind_); +// return result == null ? org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.Kind.UNRECOGNIZED : result; +// } +// +// public static final int MAP_FIELD_NUMBER = 14; +// private static final class MapDefaultEntryHolder { +// static final com.google.protobuf.MapEntry< +// java.lang.String, java.lang.Integer> defaultEntry = +// com.google.protobuf.MapEntry +// .newDefaultInstance( +// org.redkalex.test.protobuf.PTestBeanOuterClass.internal_static_PTestBean_MapEntry_descriptor, +// com.google.protobuf.WireFormat.FieldType.STRING, +// "", +// com.google.protobuf.WireFormat.FieldType.SINT32, +// 0); +// } +// @SuppressWarnings("serial") +// private com.google.protobuf.MapField< +// java.lang.String, java.lang.Integer> map_; +// private com.google.protobuf.MapField +// internalGetMap() { +// if (map_ == null) { +// return com.google.protobuf.MapField.emptyMapField( +// MapDefaultEntryHolder.defaultEntry); +// } +// return map_; +// } +// public int getMapCount() { +// return internalGetMap().getMap().size(); +// } +// /** +// * map<string, sint32> map = 14; +// */ +// @java.lang.Override +// public boolean containsMap( +// java.lang.String key) { +// if (key == null) { throw new NullPointerException("map key"); } +// return internalGetMap().getMap().containsKey(key); +// } +// /** +// * Use {@link #getMapMap()} instead. +// */ +// @java.lang.Override +// @java.lang.Deprecated +// public java.util.Map getMap() { +// return getMapMap(); +// } +// /** +// * map<string, sint32> map = 14; +// */ +// @java.lang.Override +// public java.util.Map getMapMap() { +// return internalGetMap().getMap(); +// } +// /** +// * map<string, sint32> map = 14; +// */ +// @java.lang.Override +// public int getMapOrDefault( +// java.lang.String key, +// int defaultValue) { +// if (key == null) { throw new NullPointerException("map key"); } +// java.util.Map map = +// internalGetMap().getMap(); +// return map.containsKey(key) ? map.get(key) : defaultValue; +// } +// /** +// * map<string, sint32> map = 14; +// */ +// @java.lang.Override +// public int getMapOrThrow( +// java.lang.String key) { +// if (key == null) { throw new NullPointerException("map key"); } +// java.util.Map map = +// internalGetMap().getMap(); +// if (!map.containsKey(key)) { +// throw new java.lang.IllegalArgumentException(); +// } +// return map.get(key); +// } +// +// public static final int END_FIELD_NUMBER = 15; +// @SuppressWarnings("serial") +// private volatile java.lang.Object end_ = ""; +// /** +// * string end = 15; +// * @return The end. +// */ +// @java.lang.Override +// public java.lang.String getEnd() { +// java.lang.Object ref = end_; +// if (ref instanceof java.lang.String) { +// return (java.lang.String) ref; +// } else { +// com.google.protobuf.ByteString bs = +// (com.google.protobuf.ByteString) ref; +// java.lang.String s = bs.toStringUtf8(); +// end_ = s; +// return s; +// } +// } +// /** +// * string end = 15; +// * @return The bytes for end. +// */ +// @java.lang.Override +// public com.google.protobuf.ByteString +// getEndBytes() { +// java.lang.Object ref = end_; +// if (ref instanceof java.lang.String) { +// com.google.protobuf.ByteString b = +// com.google.protobuf.ByteString.copyFromUtf8( +// (java.lang.String) ref); +// end_ = b; +// return b; +// } else { +// return (com.google.protobuf.ByteString) ref; +// } +// } +// +// private byte memoizedIsInitialized = -1; +// @java.lang.Override +// public final boolean isInitialized() { +// byte isInitialized = memoizedIsInitialized; +// if (isInitialized == 1) return true; +// if (isInitialized == 0) return false; +// +// memoizedIsInitialized = 1; +// return true; +// } +// +// @java.lang.Override +// public void writeTo(com.google.protobuf.CodedOutputStream output) +// throws java.io.IOException { +// getSerializedSize(); +// if (getBoolsList().size() > 0) { +// output.writeUInt32NoTag(10); +// output.writeUInt32NoTag(boolsMemoizedSerializedSize); +// } +// for (int i = 0; i < bools_.size(); i++) { +// output.writeBoolNoTag(bools_.getBoolean(i)); +// } +// for (int i = 0; i < bytes_.size(); i++) { +// output.writeBytes(2, bytes_.get(i)); +// } +// if (getCharsList().size() > 0) { +// output.writeUInt32NoTag(26); +// output.writeUInt32NoTag(charsMemoizedSerializedSize); +// } +// for (int i = 0; i < chars_.size(); i++) { +// output.writeSInt32NoTag(chars_.getInt(i)); +// } +// for (int i = 0; i < entrys_.size(); i++) { +// output.writeMessage(4, entrys_.get(i)); +// } +// if (getIntsList().size() > 0) { +// output.writeUInt32NoTag(42); +// output.writeUInt32NoTag(intsMemoizedSerializedSize); +// } +// for (int i = 0; i < ints_.size(); i++) { +// output.writeSInt32NoTag(ints_.getInt(i)); +// } +// if (getFloatsList().size() > 0) { +// output.writeUInt32NoTag(50); +// output.writeUInt32NoTag(floatsMemoizedSerializedSize); +// } +// for (int i = 0; i < floats_.size(); i++) { +// output.writeFloatNoTag(floats_.getFloat(i)); +// } +// if (getLongsList().size() > 0) { +// output.writeUInt32NoTag(58); +// output.writeUInt32NoTag(longsMemoizedSerializedSize); +// } +// for (int i = 0; i < longs_.size(); i++) { +// output.writeSInt64NoTag(longs_.getLong(i)); +// } +// if (getDoublesList().size() > 0) { +// output.writeUInt32NoTag(66); +// output.writeUInt32NoTag(doublesMemoizedSerializedSize); +// } +// for (int i = 0; i < doubles_.size(); i++) { +// output.writeDoubleNoTag(doubles_.getDouble(i)); +// } +// for (int i = 0; i < strings_.size(); i++) { +// com.google.protobuf.GeneratedMessageV3.writeString(output, 9, strings_.getRaw(i)); +// } +// if (id_ != 0) { +// output.writeSInt32(10, id_); +// } +// if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(name_)) { +// com.google.protobuf.GeneratedMessageV3.writeString(output, 11, name_); +// } +// if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(email_)) { +// com.google.protobuf.GeneratedMessageV3.writeString(output, 12, email_); +// } +// if (kind_ != org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.Kind.ONE.getNumber()) { +// output.writeEnum(13, kind_); +// } +// com.google.protobuf.GeneratedMessageV3 +// .serializeStringMapTo( +// output, +// internalGetMap(), +// MapDefaultEntryHolder.defaultEntry, +// 14); +// if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(end_)) { +// com.google.protobuf.GeneratedMessageV3.writeString(output, 15, end_); +// } +// getUnknownFields().writeTo(output); +// } +// +// @java.lang.Override +// public int getSerializedSize() { +// int size = memoizedSize; +// if (size != -1) return size; +// +// size = 0; +// { +// int dataSize = 0; +// dataSize = 1 * getBoolsList().size(); +// size += dataSize; +// if (!getBoolsList().isEmpty()) { +// size += 1; +// size += com.google.protobuf.CodedOutputStream +// .computeInt32SizeNoTag(dataSize); +// } +// boolsMemoizedSerializedSize = dataSize; +// } +// { +// int dataSize = 0; +// for (int i = 0; i < bytes_.size(); i++) { +// dataSize += com.google.protobuf.CodedOutputStream +// .computeBytesSizeNoTag(bytes_.get(i)); +// } +// size += dataSize; +// size += 1 * getBytesList().size(); +// } +// { +// int dataSize = 0; +// for (int i = 0; i < chars_.size(); i++) { +// dataSize += com.google.protobuf.CodedOutputStream +// .computeSInt32SizeNoTag(chars_.getInt(i)); +// } +// size += dataSize; +// if (!getCharsList().isEmpty()) { +// size += 1; +// size += com.google.protobuf.CodedOutputStream +// .computeInt32SizeNoTag(dataSize); +// } +// charsMemoizedSerializedSize = dataSize; +// } +// for (int i = 0; i < entrys_.size(); i++) { +// size += com.google.protobuf.CodedOutputStream +// .computeMessageSize(4, entrys_.get(i)); +// } +// { +// int dataSize = 0; +// for (int i = 0; i < ints_.size(); i++) { +// dataSize += com.google.protobuf.CodedOutputStream +// .computeSInt32SizeNoTag(ints_.getInt(i)); +// } +// size += dataSize; +// if (!getIntsList().isEmpty()) { +// size += 1; +// size += com.google.protobuf.CodedOutputStream +// .computeInt32SizeNoTag(dataSize); +// } +// intsMemoizedSerializedSize = dataSize; +// } +// { +// int dataSize = 0; +// dataSize = 4 * getFloatsList().size(); +// size += dataSize; +// if (!getFloatsList().isEmpty()) { +// size += 1; +// size += com.google.protobuf.CodedOutputStream +// .computeInt32SizeNoTag(dataSize); +// } +// floatsMemoizedSerializedSize = dataSize; +// } +// { +// int dataSize = 0; +// for (int i = 0; i < longs_.size(); i++) { +// dataSize += com.google.protobuf.CodedOutputStream +// .computeSInt64SizeNoTag(longs_.getLong(i)); +// } +// size += dataSize; +// if (!getLongsList().isEmpty()) { +// size += 1; +// size += com.google.protobuf.CodedOutputStream +// .computeInt32SizeNoTag(dataSize); +// } +// longsMemoizedSerializedSize = dataSize; +// } +// { +// int dataSize = 0; +// dataSize = 8 * getDoublesList().size(); +// size += dataSize; +// if (!getDoublesList().isEmpty()) { +// size += 1; +// size += com.google.protobuf.CodedOutputStream +// .computeInt32SizeNoTag(dataSize); +// } +// doublesMemoizedSerializedSize = dataSize; +// } +// { +// int dataSize = 0; +// for (int i = 0; i < strings_.size(); i++) { +// dataSize += computeStringSizeNoTag(strings_.getRaw(i)); +// } +// size += dataSize; +// size += 1 * getStringsList().size(); +// } +// if (id_ != 0) { +// size += com.google.protobuf.CodedOutputStream +// .computeSInt32Size(10, id_); +// } +// if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(name_)) { +// size += com.google.protobuf.GeneratedMessageV3.computeStringSize(11, name_); +// } +// if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(email_)) { +// size += com.google.protobuf.GeneratedMessageV3.computeStringSize(12, email_); +// } +// if (kind_ != org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.Kind.ONE.getNumber()) { +// size += com.google.protobuf.CodedOutputStream +// .computeEnumSize(13, kind_); +// } +// for (java.util.Map.Entry entry +// : internalGetMap().getMap().entrySet()) { +// com.google.protobuf.MapEntry +// map__ = MapDefaultEntryHolder.defaultEntry.newBuilderForType() +// .setKey(entry.getKey()) +// .setValue(entry.getValue()) +// .build(); +// size += com.google.protobuf.CodedOutputStream +// .computeMessageSize(14, map__); +// } +// if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(end_)) { +// size += com.google.protobuf.GeneratedMessageV3.computeStringSize(15, end_); +// } +// size += getUnknownFields().getSerializedSize(); +// memoizedSize = size; +// return size; +// } +// +// @java.lang.Override +// public boolean equals(final java.lang.Object obj) { +// if (obj == this) { +// return true; +// } +// if (!(obj instanceof org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean)) { +// return super.equals(obj); +// } +// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean other = +// (org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean) obj; +// +// if (!getBoolsList() +// .equals(other.getBoolsList())) return false; +// if (!getBytesList() +// .equals(other.getBytesList())) return false; +// if (!getCharsList() +// .equals(other.getCharsList())) return false; +// if (!getEntrysList() +// .equals(other.getEntrysList())) return false; +// if (!getIntsList() +// .equals(other.getIntsList())) return false; +// if (!getFloatsList() +// .equals(other.getFloatsList())) return false; +// if (!getLongsList() +// .equals(other.getLongsList())) return false; +// if (!getDoublesList() +// .equals(other.getDoublesList())) return false; +// if (!getStringsList() +// .equals(other.getStringsList())) return false; +// if (getId() +// != other.getId()) return false; +// if (!getName() +// .equals(other.getName())) return false; +// if (!getEmail() +// .equals(other.getEmail())) return false; +// if (kind_ != other.kind_) return false; +// if (!internalGetMap().equals( +// other.internalGetMap())) return false; +// if (!getEnd() +// .equals(other.getEnd())) return false; +// if (!getUnknownFields().equals(other.getUnknownFields())) return false; +// return true; +// } +// +// @java.lang.Override +// public int hashCode() { +// if (memoizedHashCode != 0) { +// return memoizedHashCode; +// } +// int hash = 41; +// hash = (19 * hash) + getDescriptor().hashCode(); +// if (getBoolsCount() > 0) { +// hash = (37 * hash) + BOOLS_FIELD_NUMBER; +// hash = (53 * hash) + getBoolsList().hashCode(); +// } +// if (getBytesCount() > 0) { +// hash = (37 * hash) + BYTES_FIELD_NUMBER; +// hash = (53 * hash) + getBytesList().hashCode(); +// } +// if (getCharsCount() > 0) { +// hash = (37 * hash) + CHARS_FIELD_NUMBER; +// hash = (53 * hash) + getCharsList().hashCode(); +// } +// if (getEntrysCount() > 0) { +// hash = (37 * hash) + ENTRYS_FIELD_NUMBER; +// hash = (53 * hash) + getEntrysList().hashCode(); +// } +// if (getIntsCount() > 0) { +// hash = (37 * hash) + INTS_FIELD_NUMBER; +// hash = (53 * hash) + getIntsList().hashCode(); +// } +// if (getFloatsCount() > 0) { +// hash = (37 * hash) + FLOATS_FIELD_NUMBER; +// hash = (53 * hash) + getFloatsList().hashCode(); +// } +// if (getLongsCount() > 0) { +// hash = (37 * hash) + LONGS_FIELD_NUMBER; +// hash = (53 * hash) + getLongsList().hashCode(); +// } +// if (getDoublesCount() > 0) { +// hash = (37 * hash) + DOUBLES_FIELD_NUMBER; +// hash = (53 * hash) + getDoublesList().hashCode(); +// } +// if (getStringsCount() > 0) { +// hash = (37 * hash) + STRINGS_FIELD_NUMBER; +// hash = (53 * hash) + getStringsList().hashCode(); +// } +// hash = (37 * hash) + ID_FIELD_NUMBER; +// hash = (53 * hash) + getId(); +// hash = (37 * hash) + NAME_FIELD_NUMBER; +// hash = (53 * hash) + getName().hashCode(); +// hash = (37 * hash) + EMAIL_FIELD_NUMBER; +// hash = (53 * hash) + getEmail().hashCode(); +// hash = (37 * hash) + KIND_FIELD_NUMBER; +// hash = (53 * hash) + kind_; +// if (!internalGetMap().getMap().isEmpty()) { +// hash = (37 * hash) + MAP_FIELD_NUMBER; +// hash = (53 * hash) + internalGetMap().hashCode(); +// } +// hash = (37 * hash) + END_FIELD_NUMBER; +// hash = (53 * hash) + getEnd().hashCode(); +// hash = (29 * hash) + getUnknownFields().hashCode(); +// memoizedHashCode = hash; +// return hash; +// } +// +// public static org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean parseFrom( +// java.nio.ByteBuffer data) +// throws com.google.protobuf.InvalidProtocolBufferException { +// return PARSER.parseFrom(data); +// } +// public static org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean parseFrom( +// java.nio.ByteBuffer data, +// com.google.protobuf.ExtensionRegistryLite extensionRegistry) +// throws com.google.protobuf.InvalidProtocolBufferException { +// return PARSER.parseFrom(data, extensionRegistry); +// } +// public static org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean parseFrom( +// com.google.protobuf.ByteString data) +// throws com.google.protobuf.InvalidProtocolBufferException { +// return PARSER.parseFrom(data); +// } +// public static org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean parseFrom( +// com.google.protobuf.ByteString data, +// com.google.protobuf.ExtensionRegistryLite extensionRegistry) +// throws com.google.protobuf.InvalidProtocolBufferException { +// return PARSER.parseFrom(data, extensionRegistry); +// } +// public static org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean parseFrom(byte[] data) +// throws com.google.protobuf.InvalidProtocolBufferException { +// return PARSER.parseFrom(data); +// } +// public static org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean parseFrom( +// byte[] data, +// com.google.protobuf.ExtensionRegistryLite extensionRegistry) +// throws com.google.protobuf.InvalidProtocolBufferException { +// return PARSER.parseFrom(data, extensionRegistry); +// } +// public static org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean parseFrom(java.io.InputStream input) +// throws java.io.IOException { +// return com.google.protobuf.GeneratedMessageV3 +// .parseWithIOException(PARSER, input); +// } +// public static org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean parseFrom( +// java.io.InputStream input, +// com.google.protobuf.ExtensionRegistryLite extensionRegistry) +// throws java.io.IOException { +// return com.google.protobuf.GeneratedMessageV3 +// .parseWithIOException(PARSER, input, extensionRegistry); +// } +// +// public static org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean parseDelimitedFrom(java.io.InputStream +// input) +// throws java.io.IOException { +// return com.google.protobuf.GeneratedMessageV3 +// .parseDelimitedWithIOException(PARSER, input); +// } +// +// public static org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean parseDelimitedFrom( +// java.io.InputStream input, +// com.google.protobuf.ExtensionRegistryLite extensionRegistry) +// throws java.io.IOException { +// return com.google.protobuf.GeneratedMessageV3 +// .parseDelimitedWithIOException(PARSER, input, extensionRegistry); +// } +// public static org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean parseFrom( +// com.google.protobuf.CodedInputStream input) +// throws java.io.IOException { +// return com.google.protobuf.GeneratedMessageV3 +// .parseWithIOException(PARSER, input); +// } +// public static org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean parseFrom( +// com.google.protobuf.CodedInputStream input, +// com.google.protobuf.ExtensionRegistryLite extensionRegistry) +// throws java.io.IOException { +// return com.google.protobuf.GeneratedMessageV3 +// .parseWithIOException(PARSER, input, extensionRegistry); +// } +// +// @java.lang.Override +// public Builder newBuilderForType() { return newBuilder(); } +// public static Builder newBuilder() { +// return DEFAULT_INSTANCE.toBuilder(); +// } +// public static Builder newBuilder(org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean prototype) { +// return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); +// } +// @java.lang.Override +// public Builder toBuilder() { +// return this == DEFAULT_INSTANCE +// ? new Builder() : new Builder().mergeFrom(this); +// } +// +// @java.lang.Override +// protected Builder newBuilderForType( +// com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { +// Builder builder = new Builder(parent); +// return builder; +// } +// /** +// * Protobuf type {@code PTestBean} +// */ +// public static final class Builder extends +// com.google.protobuf.GeneratedMessageV3.Builder implements +// // @@protoc_insertion_point(builder_implements:PTestBean) +// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBeanOrBuilder { +// public static final com.google.protobuf.Descriptors.Descriptor +// getDescriptor() { +// return org.redkalex.test.protobuf.PTestBeanOuterClass.internal_static_PTestBean_descriptor; +// } +// +// @SuppressWarnings({"rawtypes"}) +// protected com.google.protobuf.MapField internalGetMapField( +// int number) { +// switch (number) { +// case 14: +// return internalGetMap(); +// default: +// throw new RuntimeException( +// "Invalid map field number: " + number); +// } +// } +// @SuppressWarnings({"rawtypes"}) +// protected com.google.protobuf.MapField internalGetMutableMapField( +// int number) { +// switch (number) { +// case 14: +// return internalGetMutableMap(); +// default: +// throw new RuntimeException( +// "Invalid map field number: " + number); +// } +// } +// @java.lang.Override +// protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable +// internalGetFieldAccessorTable() { +// return org.redkalex.test.protobuf.PTestBeanOuterClass.internal_static_PTestBean_fieldAccessorTable +// .ensureFieldAccessorsInitialized( +// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.class, +// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.Builder.class); +// } +// +// // Construct using org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.newBuilder() +// private Builder() { +// +// } +// +// private Builder( +// com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { +// super(parent); +// +// } +// @java.lang.Override +// public Builder clear() { +// super.clear(); +// bitField0_ = 0; +// bools_ = emptyBooleanList(); +// bytes_ = java.util.Collections.emptyList(); +// chars_ = emptyIntList(); +// if (entrysBuilder_ == null) { +// entrys_ = java.util.Collections.emptyList(); +// } else { +// entrys_ = null; +// entrysBuilder_.clear(); +// } +// bitField0_ = (bitField0_ & ~0x00000008); +// ints_ = emptyIntList(); +// floats_ = emptyFloatList(); +// longs_ = emptyLongList(); +// doubles_ = emptyDoubleList(); +// strings_ = +// com.google.protobuf.LazyStringArrayList.emptyList(); +// id_ = 0; +// name_ = ""; +// email_ = ""; +// kind_ = 0; +// internalGetMutableMap().clear(); +// end_ = ""; +// return this; +// } +// +// @java.lang.Override +// public com.google.protobuf.Descriptors.Descriptor +// getDescriptorForType() { +// return org.redkalex.test.protobuf.PTestBeanOuterClass.internal_static_PTestBean_descriptor; +// } +// +// @java.lang.Override +// public org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean getDefaultInstanceForType() { +// return org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.getDefaultInstance(); +// } +// +// @java.lang.Override +// public org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean build() { +// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean result = buildPartial(); +// if (!result.isInitialized()) { +// throw newUninitializedMessageException(result); +// } +// return result; +// } +// +// @java.lang.Override +// public org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean buildPartial() { +// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean result = new +// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean(this); +// buildPartialRepeatedFields(result); +// if (bitField0_ != 0) { buildPartial0(result); } +// onBuilt(); +// return result; +// } +// +// private void buildPartialRepeatedFields(org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean result) { +// if (((bitField0_ & 0x00000001) != 0)) { +// bools_.makeImmutable(); +// bitField0_ = (bitField0_ & ~0x00000001); +// } +// result.bools_ = bools_; +// if (((bitField0_ & 0x00000002) != 0)) { +// bytes_ = java.util.Collections.unmodifiableList(bytes_); +// bitField0_ = (bitField0_ & ~0x00000002); +// } +// result.bytes_ = bytes_; +// if (((bitField0_ & 0x00000004) != 0)) { +// chars_.makeImmutable(); +// bitField0_ = (bitField0_ & ~0x00000004); +// } +// result.chars_ = chars_; +// if (entrysBuilder_ == null) { +// if (((bitField0_ & 0x00000008) != 0)) { +// entrys_ = java.util.Collections.unmodifiableList(entrys_); +// bitField0_ = (bitField0_ & ~0x00000008); +// } +// result.entrys_ = entrys_; +// } else { +// result.entrys_ = entrysBuilder_.build(); +// } +// if (((bitField0_ & 0x00000010) != 0)) { +// ints_.makeImmutable(); +// bitField0_ = (bitField0_ & ~0x00000010); +// } +// result.ints_ = ints_; +// if (((bitField0_ & 0x00000020) != 0)) { +// floats_.makeImmutable(); +// bitField0_ = (bitField0_ & ~0x00000020); +// } +// result.floats_ = floats_; +// if (((bitField0_ & 0x00000040) != 0)) { +// longs_.makeImmutable(); +// bitField0_ = (bitField0_ & ~0x00000040); +// } +// result.longs_ = longs_; +// if (((bitField0_ & 0x00000080) != 0)) { +// doubles_.makeImmutable(); +// bitField0_ = (bitField0_ & ~0x00000080); +// } +// result.doubles_ = doubles_; +// } +// +// private void buildPartial0(org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean result) { +// int from_bitField0_ = bitField0_; +// if (((from_bitField0_ & 0x00000100) != 0)) { +// strings_.makeImmutable(); +// result.strings_ = strings_; +// } +// if (((from_bitField0_ & 0x00000200) != 0)) { +// result.id_ = id_; +// } +// if (((from_bitField0_ & 0x00000400) != 0)) { +// result.name_ = name_; +// } +// if (((from_bitField0_ & 0x00000800) != 0)) { +// result.email_ = email_; +// } +// if (((from_bitField0_ & 0x00001000) != 0)) { +// result.kind_ = kind_; +// } +// if (((from_bitField0_ & 0x00002000) != 0)) { +// result.map_ = internalGetMap(); +// result.map_.makeImmutable(); +// } +// if (((from_bitField0_ & 0x00004000) != 0)) { +// result.end_ = end_; +// } +// } +// +// @java.lang.Override +// public Builder clone() { +// return super.clone(); +// } +// @java.lang.Override +// public Builder setField( +// com.google.protobuf.Descriptors.FieldDescriptor field, +// java.lang.Object value) { +// return super.setField(field, value); +// } +// @java.lang.Override +// public Builder clearField( +// com.google.protobuf.Descriptors.FieldDescriptor field) { +// return super.clearField(field); +// } +// @java.lang.Override +// public Builder clearOneof( +// com.google.protobuf.Descriptors.OneofDescriptor oneof) { +// return super.clearOneof(oneof); +// } +// @java.lang.Override +// public Builder setRepeatedField( +// com.google.protobuf.Descriptors.FieldDescriptor field, +// int index, java.lang.Object value) { +// return super.setRepeatedField(field, index, value); +// } +// @java.lang.Override +// public Builder addRepeatedField( +// com.google.protobuf.Descriptors.FieldDescriptor field, +// java.lang.Object value) { +// return super.addRepeatedField(field, value); +// } +// @java.lang.Override +// public Builder mergeFrom(com.google.protobuf.Message other) { +// if (other instanceof org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean) { +// return mergeFrom((org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean)other); +// } else { +// super.mergeFrom(other); +// return this; +// } +// } +// +// public Builder mergeFrom(org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean other) { +// if (other == org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.getDefaultInstance()) return this; +// if (!other.bools_.isEmpty()) { +// if (bools_.isEmpty()) { +// bools_ = other.bools_; +// bitField0_ = (bitField0_ & ~0x00000001); +// } else { +// ensureBoolsIsMutable(); +// bools_.addAll(other.bools_); +// } +// onChanged(); +// } +// if (!other.bytes_.isEmpty()) { +// if (bytes_.isEmpty()) { +// bytes_ = other.bytes_; +// bitField0_ = (bitField0_ & ~0x00000002); +// } else { +// ensureBytesIsMutable(); +// bytes_.addAll(other.bytes_); +// } +// onChanged(); +// } +// if (!other.chars_.isEmpty()) { +// if (chars_.isEmpty()) { +// chars_ = other.chars_; +// bitField0_ = (bitField0_ & ~0x00000004); +// } else { +// ensureCharsIsMutable(); +// chars_.addAll(other.chars_); +// } +// onChanged(); +// } +// if (entrysBuilder_ == null) { +// if (!other.entrys_.isEmpty()) { +// if (entrys_.isEmpty()) { +// entrys_ = other.entrys_; +// bitField0_ = (bitField0_ & ~0x00000008); +// } else { +// ensureEntrysIsMutable(); +// entrys_.addAll(other.entrys_); +// } +// onChanged(); +// } +// } else { +// if (!other.entrys_.isEmpty()) { +// if (entrysBuilder_.isEmpty()) { +// entrysBuilder_.dispose(); +// entrysBuilder_ = null; +// entrys_ = other.entrys_; +// bitField0_ = (bitField0_ & ~0x00000008); +// entrysBuilder_ = +// com.google.protobuf.GeneratedMessageV3.alwaysUseFieldBuilders ? +// getEntrysFieldBuilder() : null; +// } else { +// entrysBuilder_.addAllMessages(other.entrys_); +// } +// } +// } +// if (!other.ints_.isEmpty()) { +// if (ints_.isEmpty()) { +// ints_ = other.ints_; +// bitField0_ = (bitField0_ & ~0x00000010); +// } else { +// ensureIntsIsMutable(); +// ints_.addAll(other.ints_); +// } +// onChanged(); +// } +// if (!other.floats_.isEmpty()) { +// if (floats_.isEmpty()) { +// floats_ = other.floats_; +// bitField0_ = (bitField0_ & ~0x00000020); +// } else { +// ensureFloatsIsMutable(); +// floats_.addAll(other.floats_); +// } +// onChanged(); +// } +// if (!other.longs_.isEmpty()) { +// if (longs_.isEmpty()) { +// longs_ = other.longs_; +// bitField0_ = (bitField0_ & ~0x00000040); +// } else { +// ensureLongsIsMutable(); +// longs_.addAll(other.longs_); +// } +// onChanged(); +// } +// if (!other.doubles_.isEmpty()) { +// if (doubles_.isEmpty()) { +// doubles_ = other.doubles_; +// bitField0_ = (bitField0_ & ~0x00000080); +// } else { +// ensureDoublesIsMutable(); +// doubles_.addAll(other.doubles_); +// } +// onChanged(); +// } +// if (!other.strings_.isEmpty()) { +// if (strings_.isEmpty()) { +// strings_ = other.strings_; +// bitField0_ |= 0x00000100; +// } else { +// ensureStringsIsMutable(); +// strings_.addAll(other.strings_); +// } +// onChanged(); +// } +// if (other.getId() != 0) { +// setId(other.getId()); +// } +// if (!other.getName().isEmpty()) { +// name_ = other.name_; +// bitField0_ |= 0x00000400; +// onChanged(); +// } +// if (!other.getEmail().isEmpty()) { +// email_ = other.email_; +// bitField0_ |= 0x00000800; +// onChanged(); +// } +// if (other.kind_ != 0) { +// setKindValue(other.getKindValue()); +// } +// internalGetMutableMap().mergeFrom( +// other.internalGetMap()); +// bitField0_ |= 0x00002000; +// if (!other.getEnd().isEmpty()) { +// end_ = other.end_; +// bitField0_ |= 0x00004000; +// onChanged(); +// } +// this.mergeUnknownFields(other.getUnknownFields()); +// onChanged(); +// return this; +// } +// +// @java.lang.Override +// public final boolean isInitialized() { +// return true; +// } +// +// @java.lang.Override +// public Builder mergeFrom( +// com.google.protobuf.CodedInputStream input, +// com.google.protobuf.ExtensionRegistryLite extensionRegistry) +// throws java.io.IOException { +// if (extensionRegistry == null) { +// throw new java.lang.NullPointerException(); +// } +// try { +// boolean done = false; +// while (!done) { +// int tag = input.readTag(); +// switch (tag) { +// case 0: +// done = true; +// break; +// case 8: { +// boolean v = input.readBool(); +// ensureBoolsIsMutable(); +// bools_.addBoolean(v); +// break; +// } // case 8 +// case 10: { +// int length = input.readRawVarint32(); +// int limit = input.pushLimit(length); +// ensureBoolsIsMutable(); +// while (input.getBytesUntilLimit() > 0) { +// bools_.addBoolean(input.readBool()); +// } +// input.popLimit(limit); +// break; +// } // case 10 +// case 18: { +// com.google.protobuf.ByteString v = input.readBytes(); +// ensureBytesIsMutable(); +// bytes_.add(v); +// break; +// } // case 18 +// case 24: { +// int v = input.readSInt32(); +// ensureCharsIsMutable(); +// chars_.addInt(v); +// break; +// } // case 24 +// case 26: { +// int length = input.readRawVarint32(); +// int limit = input.pushLimit(length); +// ensureCharsIsMutable(); +// while (input.getBytesUntilLimit() > 0) { +// chars_.addInt(input.readSInt32()); +// } +// input.popLimit(limit); +// break; +// } // case 26 +// case 34: { +// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry m = +// input.readMessage( +// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry.parser(), +// extensionRegistry); +// if (entrysBuilder_ == null) { +// ensureEntrysIsMutable(); +// entrys_.add(m); +// } else { +// entrysBuilder_.addMessage(m); +// } +// break; +// } // case 34 +// case 40: { +// int v = input.readSInt32(); +// ensureIntsIsMutable(); +// ints_.addInt(v); +// break; +// } // case 40 +// case 42: { +// int length = input.readRawVarint32(); +// int limit = input.pushLimit(length); +// ensureIntsIsMutable(); +// while (input.getBytesUntilLimit() > 0) { +// ints_.addInt(input.readSInt32()); +// } +// input.popLimit(limit); +// break; +// } // case 42 +// case 53: { +// float v = input.readFloat(); +// ensureFloatsIsMutable(); +// floats_.addFloat(v); +// break; +// } // case 53 +// case 50: { +// int length = input.readRawVarint32(); +// int limit = input.pushLimit(length); +// ensureFloatsIsMutable(); +// while (input.getBytesUntilLimit() > 0) { +// floats_.addFloat(input.readFloat()); +// } +// input.popLimit(limit); +// break; +// } // case 50 +// case 56: { +// long v = input.readSInt64(); +// ensureLongsIsMutable(); +// longs_.addLong(v); +// break; +// } // case 56 +// case 58: { +// int length = input.readRawVarint32(); +// int limit = input.pushLimit(length); +// ensureLongsIsMutable(); +// while (input.getBytesUntilLimit() > 0) { +// longs_.addLong(input.readSInt64()); +// } +// input.popLimit(limit); +// break; +// } // case 58 +// case 65: { +// double v = input.readDouble(); +// ensureDoublesIsMutable(); +// doubles_.addDouble(v); +// break; +// } // case 65 +// case 66: { +// int length = input.readRawVarint32(); +// int limit = input.pushLimit(length); +// ensureDoublesIsMutable(); +// while (input.getBytesUntilLimit() > 0) { +// doubles_.addDouble(input.readDouble()); +// } +// input.popLimit(limit); +// break; +// } // case 66 +// case 74: { +// java.lang.String s = input.readStringRequireUtf8(); +// ensureStringsIsMutable(); +// strings_.add(s); +// break; +// } // case 74 +// case 80: { +// id_ = input.readSInt32(); +// bitField0_ |= 0x00000200; +// break; +// } // case 80 +// case 90: { +// name_ = input.readStringRequireUtf8(); +// bitField0_ |= 0x00000400; +// break; +// } // case 90 +// case 98: { +// email_ = input.readStringRequireUtf8(); +// bitField0_ |= 0x00000800; +// break; +// } // case 98 +// case 104: { +// kind_ = input.readEnum(); +// bitField0_ |= 0x00001000; +// break; +// } // case 104 +// case 114: { +// com.google.protobuf.MapEntry +// map__ = input.readMessage( +// MapDefaultEntryHolder.defaultEntry.getParserForType(), extensionRegistry); +// internalGetMutableMap().getMutableMap().put( +// map__.getKey(), map__.getValue()); +// bitField0_ |= 0x00002000; +// break; +// } // case 114 +// case 122: { +// end_ = input.readStringRequireUtf8(); +// bitField0_ |= 0x00004000; +// break; +// } // case 122 +// default: { +// if (!super.parseUnknownField(input, extensionRegistry, tag)) { +// done = true; // was an endgroup tag +// } +// break; +// } // default: +// } // switch (tag) +// } // while (!done) +// } catch (com.google.protobuf.InvalidProtocolBufferException e) { +// throw e.unwrapIOException(); +// } finally { +// onChanged(); +// } // finally +// return this; +// } +// private int bitField0_; +// +// private com.google.protobuf.Internal.BooleanList bools_ = emptyBooleanList(); +// private void ensureBoolsIsMutable() { +// if (!((bitField0_ & 0x00000001) != 0)) { +// bools_ = mutableCopy(bools_); +// bitField0_ |= 0x00000001; +// } +// } +// /** +// * repeated bool bools = 1; +// * @return A list containing the bools. +// */ +// public java.util.List +// getBoolsList() { +// return ((bitField0_ & 0x00000001) != 0) ? +// java.util.Collections.unmodifiableList(bools_) : bools_; +// } +// /** +// * repeated bool bools = 1; +// * @return The count of bools. +// */ +// public int getBoolsCount() { +// return bools_.size(); +// } +// /** +// * repeated bool bools = 1; +// * @param index The index of the element to return. +// * @return The bools at the given index. +// */ +// public boolean getBools(int index) { +// return bools_.getBoolean(index); +// } +// /** +// * repeated bool bools = 1; +// * @param index The index to set the value at. +// * @param value The bools to set. +// * @return This builder for chaining. +// */ +// public Builder setBools( +// int index, boolean value) { +// +// ensureBoolsIsMutable(); +// bools_.setBoolean(index, value); +// onChanged(); +// return this; +// } +// /** +// * repeated bool bools = 1; +// * @param value The bools to add. +// * @return This builder for chaining. +// */ +// public Builder addBools(boolean value) { +// +// ensureBoolsIsMutable(); +// bools_.addBoolean(value); +// onChanged(); +// return this; +// } +// /** +// * repeated bool bools = 1; +// * @param values The bools to add. +// * @return This builder for chaining. +// */ +// public Builder addAllBools( +// java.lang.Iterable values) { +// ensureBoolsIsMutable(); +// com.google.protobuf.AbstractMessageLite.Builder.addAll( +// values, bools_); +// onChanged(); +// return this; +// } +// /** +// * repeated bool bools = 1; +// * @return This builder for chaining. +// */ +// public Builder clearBools() { +// bools_ = emptyBooleanList(); +// bitField0_ = (bitField0_ & ~0x00000001); +// onChanged(); +// return this; +// } +// +// private java.util.List bytes_ = java.util.Collections.emptyList(); +// private void ensureBytesIsMutable() { +// if (!((bitField0_ & 0x00000002) != 0)) { +// bytes_ = new java.util.ArrayList(bytes_); +// bitField0_ |= 0x00000002; +// } +// } +// /** +// * repeated bytes bytes = 2; +// * @return A list containing the bytes. +// */ +// public java.util.List +// getBytesList() { +// return ((bitField0_ & 0x00000002) != 0) ? +// java.util.Collections.unmodifiableList(bytes_) : bytes_; +// } +// /** +// * repeated bytes bytes = 2; +// * @return The count of bytes. +// */ +// public int getBytesCount() { +// return bytes_.size(); +// } +// /** +// * repeated bytes bytes = 2; +// * @param index The index of the element to return. +// * @return The bytes at the given index. +// */ +// public com.google.protobuf.ByteString getBytes(int index) { +// return bytes_.get(index); +// } +// /** +// * repeated bytes bytes = 2; +// * @param index The index to set the value at. +// * @param value The bytes to set. +// * @return This builder for chaining. +// */ +// public Builder setBytes( +// int index, com.google.protobuf.ByteString value) { +// if (value == null) { throw new NullPointerException(); } +// ensureBytesIsMutable(); +// bytes_.set(index, value); +// onChanged(); +// return this; +// } +// /** +// * repeated bytes bytes = 2; +// * @param value The bytes to add. +// * @return This builder for chaining. +// */ +// public Builder addBytes(com.google.protobuf.ByteString value) { +// if (value == null) { throw new NullPointerException(); } +// ensureBytesIsMutable(); +// bytes_.add(value); +// onChanged(); +// return this; +// } +// /** +// * repeated bytes bytes = 2; +// * @param values The bytes to add. +// * @return This builder for chaining. +// */ +// public Builder addAllBytes( +// java.lang.Iterable values) { +// ensureBytesIsMutable(); +// com.google.protobuf.AbstractMessageLite.Builder.addAll( +// values, bytes_); +// onChanged(); +// return this; +// } +// /** +// * repeated bytes bytes = 2; +// * @return This builder for chaining. +// */ +// public Builder clearBytes() { +// bytes_ = java.util.Collections.emptyList(); +// bitField0_ = (bitField0_ & ~0x00000002); +// onChanged(); +// return this; +// } +// +// private com.google.protobuf.Internal.IntList chars_ = emptyIntList(); +// private void ensureCharsIsMutable() { +// if (!((bitField0_ & 0x00000004) != 0)) { +// chars_ = mutableCopy(chars_); +// bitField0_ |= 0x00000004; +// } +// } +// /** +// * repeated sint32 chars = 3; +// * @return A list containing the chars. +// */ +// public java.util.List +// getCharsList() { +// return ((bitField0_ & 0x00000004) != 0) ? +// java.util.Collections.unmodifiableList(chars_) : chars_; +// } +// /** +// * repeated sint32 chars = 3; +// * @return The count of chars. +// */ +// public int getCharsCount() { +// return chars_.size(); +// } +// /** +// * repeated sint32 chars = 3; +// * @param index The index of the element to return. +// * @return The chars at the given index. +// */ +// public int getChars(int index) { +// return chars_.getInt(index); +// } +// /** +// * repeated sint32 chars = 3; +// * @param index The index to set the value at. +// * @param value The chars to set. +// * @return This builder for chaining. +// */ +// public Builder setChars( +// int index, int value) { +// +// ensureCharsIsMutable(); +// chars_.setInt(index, value); +// onChanged(); +// return this; +// } +// /** +// * repeated sint32 chars = 3; +// * @param value The chars to add. +// * @return This builder for chaining. +// */ +// public Builder addChars(int value) { +// +// ensureCharsIsMutable(); +// chars_.addInt(value); +// onChanged(); +// return this; +// } +// /** +// * repeated sint32 chars = 3; +// * @param values The chars to add. +// * @return This builder for chaining. +// */ +// public Builder addAllChars( +// java.lang.Iterable values) { +// ensureCharsIsMutable(); +// com.google.protobuf.AbstractMessageLite.Builder.addAll( +// values, chars_); +// onChanged(); +// return this; +// } +// /** +// * repeated sint32 chars = 3; +// * @return This builder for chaining. +// */ +// public Builder clearChars() { +// chars_ = emptyIntList(); +// bitField0_ = (bitField0_ & ~0x00000004); +// onChanged(); +// return this; +// } +// +// private java.util.List entrys_ = +// java.util.Collections.emptyList(); +// private void ensureEntrysIsMutable() { +// if (!((bitField0_ & 0x00000008) != 0)) { +// entrys_ = new +// java.util.ArrayList(entrys_); +// bitField0_ |= 0x00000008; +// } +// } +// +// private com.google.protobuf.RepeatedFieldBuilderV3< +// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry, +// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry.Builder, +// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntryOrBuilder> entrysBuilder_; +// +// /** +// * repeated .PTestBean.PTestEntry entrys = 4; +// */ +// public java.util.List getEntrysList() { +// if (entrysBuilder_ == null) { +// return java.util.Collections.unmodifiableList(entrys_); +// } else { +// return entrysBuilder_.getMessageList(); +// } +// } +// /** +// * repeated .PTestBean.PTestEntry entrys = 4; +// */ +// public int getEntrysCount() { +// if (entrysBuilder_ == null) { +// return entrys_.size(); +// } else { +// return entrysBuilder_.getCount(); +// } +// } +// /** +// * repeated .PTestBean.PTestEntry entrys = 4; +// */ +// public org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry getEntrys(int index) { +// if (entrysBuilder_ == null) { +// return entrys_.get(index); +// } else { +// return entrysBuilder_.getMessage(index); +// } +// } +// /** +// * repeated .PTestBean.PTestEntry entrys = 4; +// */ +// public Builder setEntrys( +// int index, org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry value) { +// if (entrysBuilder_ == null) { +// if (value == null) { +// throw new NullPointerException(); +// } +// ensureEntrysIsMutable(); +// entrys_.set(index, value); +// onChanged(); +// } else { +// entrysBuilder_.setMessage(index, value); +// } +// return this; +// } +// /** +// * repeated .PTestBean.PTestEntry entrys = 4; +// */ +// public Builder setEntrys( +// int index, org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry.Builder builderForValue) { +// if (entrysBuilder_ == null) { +// ensureEntrysIsMutable(); +// entrys_.set(index, builderForValue.build()); +// onChanged(); +// } else { +// entrysBuilder_.setMessage(index, builderForValue.build()); +// } +// return this; +// } +// /** +// * repeated .PTestBean.PTestEntry entrys = 4; +// */ +// public Builder addEntrys(org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry value) { +// if (entrysBuilder_ == null) { +// if (value == null) { +// throw new NullPointerException(); +// } +// ensureEntrysIsMutable(); +// entrys_.add(value); +// onChanged(); +// } else { +// entrysBuilder_.addMessage(value); +// } +// return this; +// } +// /** +// * repeated .PTestBean.PTestEntry entrys = 4; +// */ +// public Builder addEntrys( +// int index, org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry value) { +// if (entrysBuilder_ == null) { +// if (value == null) { +// throw new NullPointerException(); +// } +// ensureEntrysIsMutable(); +// entrys_.add(index, value); +// onChanged(); +// } else { +// entrysBuilder_.addMessage(index, value); +// } +// return this; +// } +// /** +// * repeated .PTestBean.PTestEntry entrys = 4; +// */ +// public Builder addEntrys( +// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry.Builder builderForValue) { +// if (entrysBuilder_ == null) { +// ensureEntrysIsMutable(); +// entrys_.add(builderForValue.build()); +// onChanged(); +// } else { +// entrysBuilder_.addMessage(builderForValue.build()); +// } +// return this; +// } +// /** +// * repeated .PTestBean.PTestEntry entrys = 4; +// */ +// public Builder addEntrys( +// int index, org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry.Builder builderForValue) { +// if (entrysBuilder_ == null) { +// ensureEntrysIsMutable(); +// entrys_.add(index, builderForValue.build()); +// onChanged(); +// } else { +// entrysBuilder_.addMessage(index, builderForValue.build()); +// } +// return this; +// } +// /** +// * repeated .PTestBean.PTestEntry entrys = 4; +// */ +// public Builder addAllEntrys( +// java.lang.Iterable values) { +// if (entrysBuilder_ == null) { +// ensureEntrysIsMutable(); +// com.google.protobuf.AbstractMessageLite.Builder.addAll( +// values, entrys_); +// onChanged(); +// } else { +// entrysBuilder_.addAllMessages(values); +// } +// return this; +// } +// /** +// * repeated .PTestBean.PTestEntry entrys = 4; +// */ +// public Builder clearEntrys() { +// if (entrysBuilder_ == null) { +// entrys_ = java.util.Collections.emptyList(); +// bitField0_ = (bitField0_ & ~0x00000008); +// onChanged(); +// } else { +// entrysBuilder_.clear(); +// } +// return this; +// } +// /** +// * repeated .PTestBean.PTestEntry entrys = 4; +// */ +// public Builder removeEntrys(int index) { +// if (entrysBuilder_ == null) { +// ensureEntrysIsMutable(); +// entrys_.remove(index); +// onChanged(); +// } else { +// entrysBuilder_.remove(index); +// } +// return this; +// } +// /** +// * repeated .PTestBean.PTestEntry entrys = 4; +// */ +// public org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry.Builder getEntrysBuilder( +// int index) { +// return getEntrysFieldBuilder().getBuilder(index); +// } +// /** +// * repeated .PTestBean.PTestEntry entrys = 4; +// */ +// public org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntryOrBuilder getEntrysOrBuilder( +// int index) { +// if (entrysBuilder_ == null) { +// return entrys_.get(index); } else { +// return entrysBuilder_.getMessageOrBuilder(index); +// } +// } +// /** +// * repeated .PTestBean.PTestEntry entrys = 4; +// */ +// public java.util.List +// getEntrysOrBuilderList() { +// if (entrysBuilder_ != null) { +// return entrysBuilder_.getMessageOrBuilderList(); +// } else { +// return java.util.Collections.unmodifiableList(entrys_); +// } +// } +// /** +// * repeated .PTestBean.PTestEntry entrys = 4; +// */ +// public org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry.Builder addEntrysBuilder() { +// return getEntrysFieldBuilder().addBuilder( +// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry.getDefaultInstance()); +// } +// /** +// * repeated .PTestBean.PTestEntry entrys = 4; +// */ +// public org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry.Builder addEntrysBuilder( +// int index) { +// return getEntrysFieldBuilder().addBuilder( +// index, org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry.getDefaultInstance()); +// } +// /** +// * repeated .PTestBean.PTestEntry entrys = 4; +// */ +// public java.util.List +// getEntrysBuilderList() { +// return getEntrysFieldBuilder().getBuilderList(); +// } +// private com.google.protobuf.RepeatedFieldBuilderV3< +// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry, +// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry.Builder, +// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntryOrBuilder> +// getEntrysFieldBuilder() { +// if (entrysBuilder_ == null) { +// entrysBuilder_ = new com.google.protobuf.RepeatedFieldBuilderV3< +// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry, +// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntry.Builder, +// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.PTestEntryOrBuilder>( +// entrys_, +// ((bitField0_ & 0x00000008) != 0), +// getParentForChildren(), +// isClean()); +// entrys_ = null; +// } +// return entrysBuilder_; +// } +// +// private com.google.protobuf.Internal.IntList ints_ = emptyIntList(); +// private void ensureIntsIsMutable() { +// if (!((bitField0_ & 0x00000010) != 0)) { +// ints_ = mutableCopy(ints_); +// bitField0_ |= 0x00000010; +// } +// } +// /** +// * repeated sint32 ints = 5; +// * @return A list containing the ints. +// */ +// public java.util.List +// getIntsList() { +// return ((bitField0_ & 0x00000010) != 0) ? +// java.util.Collections.unmodifiableList(ints_) : ints_; +// } +// /** +// * repeated sint32 ints = 5; +// * @return The count of ints. +// */ +// public int getIntsCount() { +// return ints_.size(); +// } +// /** +// * repeated sint32 ints = 5; +// * @param index The index of the element to return. +// * @return The ints at the given index. +// */ +// public int getInts(int index) { +// return ints_.getInt(index); +// } +// /** +// * repeated sint32 ints = 5; +// * @param index The index to set the value at. +// * @param value The ints to set. +// * @return This builder for chaining. +// */ +// public Builder setInts( +// int index, int value) { +// +// ensureIntsIsMutable(); +// ints_.setInt(index, value); +// onChanged(); +// return this; +// } +// /** +// * repeated sint32 ints = 5; +// * @param value The ints to add. +// * @return This builder for chaining. +// */ +// public Builder addInts(int value) { +// +// ensureIntsIsMutable(); +// ints_.addInt(value); +// onChanged(); +// return this; +// } +// /** +// * repeated sint32 ints = 5; +// * @param values The ints to add. +// * @return This builder for chaining. +// */ +// public Builder addAllInts( +// java.lang.Iterable values) { +// ensureIntsIsMutable(); +// com.google.protobuf.AbstractMessageLite.Builder.addAll( +// values, ints_); +// onChanged(); +// return this; +// } +// /** +// * repeated sint32 ints = 5; +// * @return This builder for chaining. +// */ +// public Builder clearInts() { +// ints_ = emptyIntList(); +// bitField0_ = (bitField0_ & ~0x00000010); +// onChanged(); +// return this; +// } +// +// private com.google.protobuf.Internal.FloatList floats_ = emptyFloatList(); +// private void ensureFloatsIsMutable() { +// if (!((bitField0_ & 0x00000020) != 0)) { +// floats_ = mutableCopy(floats_); +// bitField0_ |= 0x00000020; +// } +// } +// /** +// * repeated float floats = 6; +// * @return A list containing the floats. +// */ +// public java.util.List +// getFloatsList() { +// return ((bitField0_ & 0x00000020) != 0) ? +// java.util.Collections.unmodifiableList(floats_) : floats_; +// } +// /** +// * repeated float floats = 6; +// * @return The count of floats. +// */ +// public int getFloatsCount() { +// return floats_.size(); +// } +// /** +// * repeated float floats = 6; +// * @param index The index of the element to return. +// * @return The floats at the given index. +// */ +// public float getFloats(int index) { +// return floats_.getFloat(index); +// } +// /** +// * repeated float floats = 6; +// * @param index The index to set the value at. +// * @param value The floats to set. +// * @return This builder for chaining. +// */ +// public Builder setFloats( +// int index, float value) { +// +// ensureFloatsIsMutable(); +// floats_.setFloat(index, value); +// onChanged(); +// return this; +// } +// /** +// * repeated float floats = 6; +// * @param value The floats to add. +// * @return This builder for chaining. +// */ +// public Builder addFloats(float value) { +// +// ensureFloatsIsMutable(); +// floats_.addFloat(value); +// onChanged(); +// return this; +// } +// /** +// * repeated float floats = 6; +// * @param values The floats to add. +// * @return This builder for chaining. +// */ +// public Builder addAllFloats( +// java.lang.Iterable values) { +// ensureFloatsIsMutable(); +// com.google.protobuf.AbstractMessageLite.Builder.addAll( +// values, floats_); +// onChanged(); +// return this; +// } +// /** +// * repeated float floats = 6; +// * @return This builder for chaining. +// */ +// public Builder clearFloats() { +// floats_ = emptyFloatList(); +// bitField0_ = (bitField0_ & ~0x00000020); +// onChanged(); +// return this; +// } +// +// private com.google.protobuf.Internal.LongList longs_ = emptyLongList(); +// private void ensureLongsIsMutable() { +// if (!((bitField0_ & 0x00000040) != 0)) { +// longs_ = mutableCopy(longs_); +// bitField0_ |= 0x00000040; +// } +// } +// /** +// * repeated sint64 longs = 7; +// * @return A list containing the longs. +// */ +// public java.util.List +// getLongsList() { +// return ((bitField0_ & 0x00000040) != 0) ? +// java.util.Collections.unmodifiableList(longs_) : longs_; +// } +// /** +// * repeated sint64 longs = 7; +// * @return The count of longs. +// */ +// public int getLongsCount() { +// return longs_.size(); +// } +// /** +// * repeated sint64 longs = 7; +// * @param index The index of the element to return. +// * @return The longs at the given index. +// */ +// public long getLongs(int index) { +// return longs_.getLong(index); +// } +// /** +// * repeated sint64 longs = 7; +// * @param index The index to set the value at. +// * @param value The longs to set. +// * @return This builder for chaining. +// */ +// public Builder setLongs( +// int index, long value) { +// +// ensureLongsIsMutable(); +// longs_.setLong(index, value); +// onChanged(); +// return this; +// } +// /** +// * repeated sint64 longs = 7; +// * @param value The longs to add. +// * @return This builder for chaining. +// */ +// public Builder addLongs(long value) { +// +// ensureLongsIsMutable(); +// longs_.addLong(value); +// onChanged(); +// return this; +// } +// /** +// * repeated sint64 longs = 7; +// * @param values The longs to add. +// * @return This builder for chaining. +// */ +// public Builder addAllLongs( +// java.lang.Iterable values) { +// ensureLongsIsMutable(); +// com.google.protobuf.AbstractMessageLite.Builder.addAll( +// values, longs_); +// onChanged(); +// return this; +// } +// /** +// * repeated sint64 longs = 7; +// * @return This builder for chaining. +// */ +// public Builder clearLongs() { +// longs_ = emptyLongList(); +// bitField0_ = (bitField0_ & ~0x00000040); +// onChanged(); +// return this; +// } +// +// private com.google.protobuf.Internal.DoubleList doubles_ = emptyDoubleList(); +// private void ensureDoublesIsMutable() { +// if (!((bitField0_ & 0x00000080) != 0)) { +// doubles_ = mutableCopy(doubles_); +// bitField0_ |= 0x00000080; +// } +// } +// /** +// * repeated double doubles = 8; +// * @return A list containing the doubles. +// */ +// public java.util.List +// getDoublesList() { +// return ((bitField0_ & 0x00000080) != 0) ? +// java.util.Collections.unmodifiableList(doubles_) : doubles_; +// } +// /** +// * repeated double doubles = 8; +// * @return The count of doubles. +// */ +// public int getDoublesCount() { +// return doubles_.size(); +// } +// /** +// * repeated double doubles = 8; +// * @param index The index of the element to return. +// * @return The doubles at the given index. +// */ +// public double getDoubles(int index) { +// return doubles_.getDouble(index); +// } +// /** +// * repeated double doubles = 8; +// * @param index The index to set the value at. +// * @param value The doubles to set. +// * @return This builder for chaining. +// */ +// public Builder setDoubles( +// int index, double value) { +// +// ensureDoublesIsMutable(); +// doubles_.setDouble(index, value); +// onChanged(); +// return this; +// } +// /** +// * repeated double doubles = 8; +// * @param value The doubles to add. +// * @return This builder for chaining. +// */ +// public Builder addDoubles(double value) { +// +// ensureDoublesIsMutable(); +// doubles_.addDouble(value); +// onChanged(); +// return this; +// } +// /** +// * repeated double doubles = 8; +// * @param values The doubles to add. +// * @return This builder for chaining. +// */ +// public Builder addAllDoubles( +// java.lang.Iterable values) { +// ensureDoublesIsMutable(); +// com.google.protobuf.AbstractMessageLite.Builder.addAll( +// values, doubles_); +// onChanged(); +// return this; +// } +// /** +// * repeated double doubles = 8; +// * @return This builder for chaining. +// */ +// public Builder clearDoubles() { +// doubles_ = emptyDoubleList(); +// bitField0_ = (bitField0_ & ~0x00000080); +// onChanged(); +// return this; +// } +// +// private com.google.protobuf.LazyStringArrayList strings_ = +// com.google.protobuf.LazyStringArrayList.emptyList(); +// private void ensureStringsIsMutable() { +// if (!strings_.isModifiable()) { +// strings_ = new com.google.protobuf.LazyStringArrayList(strings_); +// } +// bitField0_ |= 0x00000100; +// } +// /** +// * repeated string strings = 9; +// * @return A list containing the strings. +// */ +// public com.google.protobuf.ProtocolStringList +// getStringsList() { +// strings_.makeImmutable(); +// return strings_; +// } +// /** +// * repeated string strings = 9; +// * @return The count of strings. +// */ +// public int getStringsCount() { +// return strings_.size(); +// } +// /** +// * repeated string strings = 9; +// * @param index The index of the element to return. +// * @return The strings at the given index. +// */ +// public java.lang.String getStrings(int index) { +// return strings_.get(index); +// } +// /** +// * repeated string strings = 9; +// * @param index The index of the value to return. +// * @return The bytes of the strings at the given index. +// */ +// public com.google.protobuf.ByteString +// getStringsBytes(int index) { +// return strings_.getByteString(index); +// } +// /** +// * repeated string strings = 9; +// * @param index The index to set the value at. +// * @param value The strings to set. +// * @return This builder for chaining. +// */ +// public Builder setStrings( +// int index, java.lang.String value) { +// if (value == null) { throw new NullPointerException(); } +// ensureStringsIsMutable(); +// strings_.set(index, value); +// bitField0_ |= 0x00000100; +// onChanged(); +// return this; +// } +// /** +// * repeated string strings = 9; +// * @param value The strings to add. +// * @return This builder for chaining. +// */ +// public Builder addStrings( +// java.lang.String value) { +// if (value == null) { throw new NullPointerException(); } +// ensureStringsIsMutable(); +// strings_.add(value); +// bitField0_ |= 0x00000100; +// onChanged(); +// return this; +// } +// /** +// * repeated string strings = 9; +// * @param values The strings to add. +// * @return This builder for chaining. +// */ +// public Builder addAllStrings( +// java.lang.Iterable values) { +// ensureStringsIsMutable(); +// com.google.protobuf.AbstractMessageLite.Builder.addAll( +// values, strings_); +// bitField0_ |= 0x00000100; +// onChanged(); +// return this; +// } +// /** +// * repeated string strings = 9; +// * @return This builder for chaining. +// */ +// public Builder clearStrings() { +// strings_ = +// com.google.protobuf.LazyStringArrayList.emptyList(); +// bitField0_ = (bitField0_ & ~0x00000100);; +// onChanged(); +// return this; +// } +// /** +// * repeated string strings = 9; +// * @param value The bytes of the strings to add. +// * @return This builder for chaining. +// */ +// public Builder addStringsBytes( +// com.google.protobuf.ByteString value) { +// if (value == null) { throw new NullPointerException(); } +// checkByteStringIsUtf8(value); +// ensureStringsIsMutable(); +// strings_.add(value); +// bitField0_ |= 0x00000100; +// onChanged(); +// return this; +// } +// +// private int id_ ; +// /** +// * sint32 id = 10; +// * @return The id. +// */ +// @java.lang.Override +// public int getId() { +// return id_; +// } +// /** +// * sint32 id = 10; +// * @param value The id to set. +// * @return This builder for chaining. +// */ +// public Builder setId(int value) { +// +// id_ = value; +// bitField0_ |= 0x00000200; +// onChanged(); +// return this; +// } +// /** +// * sint32 id = 10; +// * @return This builder for chaining. +// */ +// public Builder clearId() { +// bitField0_ = (bitField0_ & ~0x00000200); +// id_ = 0; +// onChanged(); +// return this; +// } +// +// private java.lang.Object name_ = ""; +// /** +// * string name = 11; +// * @return The name. +// */ +// public java.lang.String getName() { +// java.lang.Object ref = name_; +// if (!(ref instanceof java.lang.String)) { +// com.google.protobuf.ByteString bs = +// (com.google.protobuf.ByteString) ref; +// java.lang.String s = bs.toStringUtf8(); +// name_ = s; +// return s; +// } else { +// return (java.lang.String) ref; +// } +// } +// /** +// * string name = 11; +// * @return The bytes for name. +// */ +// public com.google.protobuf.ByteString +// getNameBytes() { +// java.lang.Object ref = name_; +// if (ref instanceof String) { +// com.google.protobuf.ByteString b = +// com.google.protobuf.ByteString.copyFromUtf8( +// (java.lang.String) ref); +// name_ = b; +// return b; +// } else { +// return (com.google.protobuf.ByteString) ref; +// } +// } +// /** +// * string name = 11; +// * @param value The name to set. +// * @return This builder for chaining. +// */ +// public Builder setName( +// java.lang.String value) { +// if (value == null) { throw new NullPointerException(); } +// name_ = value; +// bitField0_ |= 0x00000400; +// onChanged(); +// return this; +// } +// /** +// * string name = 11; +// * @return This builder for chaining. +// */ +// public Builder clearName() { +// name_ = getDefaultInstance().getName(); +// bitField0_ = (bitField0_ & ~0x00000400); +// onChanged(); +// return this; +// } +// /** +// * string name = 11; +// * @param value The bytes for name to set. +// * @return This builder for chaining. +// */ +// public Builder setNameBytes( +// com.google.protobuf.ByteString value) { +// if (value == null) { throw new NullPointerException(); } +// checkByteStringIsUtf8(value); +// name_ = value; +// bitField0_ |= 0x00000400; +// onChanged(); +// return this; +// } +// +// private java.lang.Object email_ = ""; +// /** +// * string email = 12; +// * @return The email. +// */ +// public java.lang.String getEmail() { +// java.lang.Object ref = email_; +// if (!(ref instanceof java.lang.String)) { +// com.google.protobuf.ByteString bs = +// (com.google.protobuf.ByteString) ref; +// java.lang.String s = bs.toStringUtf8(); +// email_ = s; +// return s; +// } else { +// return (java.lang.String) ref; +// } +// } +// /** +// * string email = 12; +// * @return The bytes for email. +// */ +// public com.google.protobuf.ByteString +// getEmailBytes() { +// java.lang.Object ref = email_; +// if (ref instanceof String) { +// com.google.protobuf.ByteString b = +// com.google.protobuf.ByteString.copyFromUtf8( +// (java.lang.String) ref); +// email_ = b; +// return b; +// } else { +// return (com.google.protobuf.ByteString) ref; +// } +// } +// /** +// * string email = 12; +// * @param value The email to set. +// * @return This builder for chaining. +// */ +// public Builder setEmail( +// java.lang.String value) { +// if (value == null) { throw new NullPointerException(); } +// email_ = value; +// bitField0_ |= 0x00000800; +// onChanged(); +// return this; +// } +// /** +// * string email = 12; +// * @return This builder for chaining. +// */ +// public Builder clearEmail() { +// email_ = getDefaultInstance().getEmail(); +// bitField0_ = (bitField0_ & ~0x00000800); +// onChanged(); +// return this; +// } +// /** +// * string email = 12; +// * @param value The bytes for email to set. +// * @return This builder for chaining. +// */ +// public Builder setEmailBytes( +// com.google.protobuf.ByteString value) { +// if (value == null) { throw new NullPointerException(); } +// checkByteStringIsUtf8(value); +// email_ = value; +// bitField0_ |= 0x00000800; +// onChanged(); +// return this; +// } +// +// private int kind_ = 0; +// /** +// * .PTestBean.Kind kind = 13; +// * @return The enum numeric value on the wire for kind. +// */ +// @java.lang.Override public int getKindValue() { +// return kind_; +// } +// /** +// * .PTestBean.Kind kind = 13; +// * @param value The enum numeric value on the wire for kind to set. +// * @return This builder for chaining. +// */ +// public Builder setKindValue(int value) { +// kind_ = value; +// bitField0_ |= 0x00001000; +// onChanged(); +// return this; +// } +// /** +// * .PTestBean.Kind kind = 13; +// * @return The kind. +// */ +// @java.lang.Override +// public org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.Kind getKind() { +// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.Kind result = +// org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.Kind.forNumber(kind_); +// return result == null ? org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.Kind.UNRECOGNIZED : result; +// } +// /** +// * .PTestBean.Kind kind = 13; +// * @param value The kind to set. +// * @return This builder for chaining. +// */ +// public Builder setKind(org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean.Kind value) { +// if (value == null) { +// throw new NullPointerException(); +// } +// bitField0_ |= 0x00001000; +// kind_ = value.getNumber(); +// onChanged(); +// return this; +// } +// /** +// * .PTestBean.Kind kind = 13; +// * @return This builder for chaining. +// */ +// public Builder clearKind() { +// bitField0_ = (bitField0_ & ~0x00001000); +// kind_ = 0; +// onChanged(); +// return this; +// } +// +// private com.google.protobuf.MapField< +// java.lang.String, java.lang.Integer> map_; +// private com.google.protobuf.MapField +// internalGetMap() { +// if (map_ == null) { +// return com.google.protobuf.MapField.emptyMapField( +// MapDefaultEntryHolder.defaultEntry); +// } +// return map_; +// } +// private com.google.protobuf.MapField +// internalGetMutableMap() { +// if (map_ == null) { +// map_ = com.google.protobuf.MapField.newMapField( +// MapDefaultEntryHolder.defaultEntry); +// } +// if (!map_.isMutable()) { +// map_ = map_.copy(); +// } +// bitField0_ |= 0x00002000; +// onChanged(); +// return map_; +// } +// public int getMapCount() { +// return internalGetMap().getMap().size(); +// } +// /** +// * map<string, sint32> map = 14; +// */ +// @java.lang.Override +// public boolean containsMap( +// java.lang.String key) { +// if (key == null) { throw new NullPointerException("map key"); } +// return internalGetMap().getMap().containsKey(key); +// } +// /** +// * Use {@link #getMapMap()} instead. +// */ +// @java.lang.Override +// @java.lang.Deprecated +// public java.util.Map getMap() { +// return getMapMap(); +// } +// /** +// * map<string, sint32> map = 14; +// */ +// @java.lang.Override +// public java.util.Map getMapMap() { +// return internalGetMap().getMap(); +// } +// /** +// * map<string, sint32> map = 14; +// */ +// @java.lang.Override +// public int getMapOrDefault( +// java.lang.String key, +// int defaultValue) { +// if (key == null) { throw new NullPointerException("map key"); } +// java.util.Map map = +// internalGetMap().getMap(); +// return map.containsKey(key) ? map.get(key) : defaultValue; +// } +// /** +// * map<string, sint32> map = 14; +// */ +// @java.lang.Override +// public int getMapOrThrow( +// java.lang.String key) { +// if (key == null) { throw new NullPointerException("map key"); } +// java.util.Map map = +// internalGetMap().getMap(); +// if (!map.containsKey(key)) { +// throw new java.lang.IllegalArgumentException(); +// } +// return map.get(key); +// } +// public Builder clearMap() { +// bitField0_ = (bitField0_ & ~0x00002000); +// internalGetMutableMap().getMutableMap() +// .clear(); +// return this; +// } +// /** +// * map<string, sint32> map = 14; +// */ +// public Builder removeMap( +// java.lang.String key) { +// if (key == null) { throw new NullPointerException("map key"); } +// internalGetMutableMap().getMutableMap() +// .remove(key); +// return this; +// } +// /** +// * Use alternate mutation accessors instead. +// */ +// @java.lang.Deprecated +// public java.util.Map +// getMutableMap() { +// bitField0_ |= 0x00002000; +// return internalGetMutableMap().getMutableMap(); +// } +// /** +// * map<string, sint32> map = 14; +// */ +// public Builder putMap( +// java.lang.String key, +// int value) { +// if (key == null) { throw new NullPointerException("map key"); } +// +// internalGetMutableMap().getMutableMap() +// .put(key, value); +// bitField0_ |= 0x00002000; +// return this; +// } +// /** +// * map<string, sint32> map = 14; +// */ +// public Builder putAllMap( +// java.util.Map values) { +// internalGetMutableMap().getMutableMap() +// .putAll(values); +// bitField0_ |= 0x00002000; +// return this; +// } +// +// private java.lang.Object end_ = ""; +// /** +// * string end = 15; +// * @return The end. +// */ +// public java.lang.String getEnd() { +// java.lang.Object ref = end_; +// if (!(ref instanceof java.lang.String)) { +// com.google.protobuf.ByteString bs = +// (com.google.protobuf.ByteString) ref; +// java.lang.String s = bs.toStringUtf8(); +// end_ = s; +// return s; +// } else { +// return (java.lang.String) ref; +// } +// } +// /** +// * string end = 15; +// * @return The bytes for end. +// */ +// public com.google.protobuf.ByteString +// getEndBytes() { +// java.lang.Object ref = end_; +// if (ref instanceof String) { +// com.google.protobuf.ByteString b = +// com.google.protobuf.ByteString.copyFromUtf8( +// (java.lang.String) ref); +// end_ = b; +// return b; +// } else { +// return (com.google.protobuf.ByteString) ref; +// } +// } +// /** +// * string end = 15; +// * @param value The end to set. +// * @return This builder for chaining. +// */ +// public Builder setEnd( +// java.lang.String value) { +// if (value == null) { throw new NullPointerException(); } +// end_ = value; +// bitField0_ |= 0x00004000; +// onChanged(); +// return this; +// } +// /** +// * string end = 15; +// * @return This builder for chaining. +// */ +// public Builder clearEnd() { +// end_ = getDefaultInstance().getEnd(); +// bitField0_ = (bitField0_ & ~0x00004000); +// onChanged(); +// return this; +// } +// /** +// * string end = 15; +// * @param value The bytes for end to set. +// * @return This builder for chaining. +// */ +// public Builder setEndBytes( +// com.google.protobuf.ByteString value) { +// if (value == null) { throw new NullPointerException(); } +// checkByteStringIsUtf8(value); +// end_ = value; +// bitField0_ |= 0x00004000; +// onChanged(); +// return this; +// } +// @java.lang.Override +// public final Builder setUnknownFields( +// final com.google.protobuf.UnknownFieldSet unknownFields) { +// return super.setUnknownFields(unknownFields); +// } +// +// @java.lang.Override +// public final Builder mergeUnknownFields( +// final com.google.protobuf.UnknownFieldSet unknownFields) { +// return super.mergeUnknownFields(unknownFields); +// } +// +// +// // @@protoc_insertion_point(builder_scope:PTestBean) +// } +// +// // @@protoc_insertion_point(class_scope:PTestBean) +// private static final org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean DEFAULT_INSTANCE; +// static { +// DEFAULT_INSTANCE = new org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean(); +// } +// +// public static org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean getDefaultInstance() { +// return DEFAULT_INSTANCE; +// } +// +// private static final com.google.protobuf.Parser +// PARSER = new com.google.protobuf.AbstractParser() { +// @java.lang.Override +// public PTestBean parsePartialFrom( +// com.google.protobuf.CodedInputStream input, +// com.google.protobuf.ExtensionRegistryLite extensionRegistry) +// throws com.google.protobuf.InvalidProtocolBufferException { +// Builder builder = newBuilder(); +// try { +// builder.mergeFrom(input, extensionRegistry); +// } catch (com.google.protobuf.InvalidProtocolBufferException e) { +// throw e.setUnfinishedMessage(builder.buildPartial()); +// } catch (com.google.protobuf.UninitializedMessageException e) { +// throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); +// } catch (java.io.IOException e) { +// throw new com.google.protobuf.InvalidProtocolBufferException(e) +// .setUnfinishedMessage(builder.buildPartial()); +// } +// return builder.buildPartial(); +// } +// }; +// +// public static com.google.protobuf.Parser parser() { +// return PARSER; +// } +// +// @java.lang.Override +// public com.google.protobuf.Parser getParserForType() { +// return PARSER; +// } +// +// @java.lang.Override +// public org.redkalex.test.protobuf.PTestBeanOuterClass.PTestBean getDefaultInstanceForType() { +// return DEFAULT_INSTANCE; +// } +// +// } +// +// private static final com.google.protobuf.Descriptors.Descriptor +// internal_static_PTestBean_descriptor; +// private static final +// com.google.protobuf.GeneratedMessageV3.FieldAccessorTable +// internal_static_PTestBean_fieldAccessorTable; +// private static final com.google.protobuf.Descriptors.Descriptor +// internal_static_PTestBean_PTestEntry_descriptor; +// private static final +// com.google.protobuf.GeneratedMessageV3.FieldAccessorTable +// internal_static_PTestBean_PTestEntry_fieldAccessorTable; +// private static final com.google.protobuf.Descriptors.Descriptor +// internal_static_PTestBean_MapEntry_descriptor; +// private static final +// com.google.protobuf.GeneratedMessageV3.FieldAccessorTable +// internal_static_PTestBean_MapEntry_fieldAccessorTable; +// +// public static com.google.protobuf.Descriptors.FileDescriptor +// getDescriptor() { +// return descriptor; +// } +// private static com.google.protobuf.Descriptors.FileDescriptor +// descriptor; +// static { +// java.lang.String[] descriptorData = { +// "\n8src/test/java/org/redkalex/test/protob" + +// "uf/PTestBean.proto\"\301\003\n\tPTestBean\022\r\n\005bool" + +// "s\030\001 \003(\010\022\r\n\005bytes\030\002 \003(\014\022\r\n\005chars\030\003 \003(\021\022%\n" + +// "\006entrys\030\004 \003(\0132\025.PTestBean.PTestEntry\022\014\n\004" + +// "ints\030\005 \003(\021\022\016\n\006floats\030\006 \003(\002\022\r\n\005longs\030\007 \003(" + +// "\022\022\017\n\007doubles\030\010 \003(\001\022\017\n\007strings\030\t \003(\t\022\n\n\002i" + +// "d\030\n \001(\021\022\014\n\004name\030\013 \001(\t\022\r\n\005email\030\014 \001(\t\022\035\n\004" + +// "kind\030\r \001(\0162\017.PTestBean.Kind\022 \n\003map\030\016 \003(\013" + +// "2\023.PTestBean.MapEntry\022\013\n\003end\030\017 \001(\t\032I\n\nPT" + +// "estEntry\022\r\n\005bools\030\001 \003(\010\022\r\n\005bytes\030\002 \003(\014\022\r" + +// "\n\005chars\030\003 \003(\021\022\016\n\006shorts\030\004 \003(\021\032*\n\010MapEntr" + +// "y\022\013\n\003key\030\001 \001(\t\022\r\n\005value\030\002 \001(\021:\0028\001\"#\n\004Kin" + +// "d\022\007\n\003ONE\020\000\022\007\n\003TWO\020\001\022\t\n\005THREE\020\002B\034\n\032org.re" + +// "dkalex.test.protobufb\006proto3" +// }; +// descriptor = com.google.protobuf.Descriptors.FileDescriptor +// .internalBuildGeneratedFileFrom(descriptorData, +// new com.google.protobuf.Descriptors.FileDescriptor[] { +// }); +// internal_static_PTestBean_descriptor = +// getDescriptor().getMessageTypes().get(0); +// internal_static_PTestBean_fieldAccessorTable = new +// com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( +// internal_static_PTestBean_descriptor, +// new java.lang.String[] { "Bools", "Bytes", "Chars", "Entrys", "Ints", "Floats", "Longs", "Doubles", "Strings", +// "Id", "Name", "Email", "Kind", "Map", "End", }); +// internal_static_PTestBean_PTestEntry_descriptor = +// internal_static_PTestBean_descriptor.getNestedTypes().get(0); +// internal_static_PTestBean_PTestEntry_fieldAccessorTable = new +// com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( +// internal_static_PTestBean_PTestEntry_descriptor, +// new java.lang.String[] { "Bools", "Bytes", "Chars", "Shorts", }); +// internal_static_PTestBean_MapEntry_descriptor = +// internal_static_PTestBean_descriptor.getNestedTypes().get(1); +// internal_static_PTestBean_MapEntry_fieldAccessorTable = new +// com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( +// internal_static_PTestBean_MapEntry_descriptor, +// new java.lang.String[] { "Key", "Value", }); +// } +// +// // @@protoc_insertion_point(outer_class_scope) +// } diff --git a/src/test/java/org/redkale/test/convert/proto/SimpleBean.java b/src/test/java/org/redkale/test/convert/proto/SimpleBean.java index 98387d8c9..c34cef43c 100644 --- a/src/test/java/org/redkale/test/convert/proto/SimpleBean.java +++ b/src/test/java/org/redkale/test/convert/proto/SimpleBean.java @@ -1,108 +1,108 @@ -package org.redkale.test.convert.proto; - -/// * -// * 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.redkalex.test.protobuf; -// -// import java.util.Arrays; -// import org.redkale.convert.ConvertColumn; -// import org.redkale.convert.json.JsonConvert; -// import org.redkale.util.Utility; -// import org.redkalex.convert.protobuf.ProtobufConvert; -// -/// ** -// * -// * @author zhangjx -// */ -// public class SimpleBean { -// -// public static class PSimpleEntry { -// -// @ConvertColumn(index = 1) -// public int id = 66; -// -// @ConvertColumn(index = 2) -// public String name = "哈哈"; -// -// @ConvertColumn(index = 3) -// public String email = "redkale@redkale.org"; -// } -// -// public static class PTwoEntry { -// -// @ConvertColumn(index = 1) -// public int status = 2; -// -// @ConvertColumn(index = 2) -// public long createtime = System.currentTimeMillis(); -// -// } -// -// @ConvertColumn(index = 1) -// public PSimpleEntry simple; -// -// @ConvertColumn(index = 2) -// public PTwoEntry two; -// -// @ConvertColumn(index = 3) -// public String strings = "abcd"; -// -// @Override -// public String toString() { -// return JsonConvert.root().convertTo(this); -// } -// -// public static void main(String[] args) throws Throwable { -// //System.out.println(ProtobufConvert.root().getProtoDescriptor(SimpleBean.class)); -// SimpleBean bean = new SimpleBean(); -// bean.simple = new PSimpleEntry(); -// bean.two = new PTwoEntry(); -// bean.strings = "abcde"; -// -// //------------------------------- -// byte[] jsonbs = JsonConvert.root().convertToBytes(bean); -// byte[] bs = ProtobufConvert.root().convertTo(bean); -// Utility.println("predkale ", bs); -// PSimpleBeanOuterClass.PSimpleBean.Builder builder = PSimpleBeanOuterClass.PSimpleBean.newBuilder(); -// -// PSimpleBeanOuterClass.PSimpleBean bean2 = createPSimpleBean(bean, builder); -// byte[] bs2 = bean2.toByteArray(); -// Utility.println("protobuf ", bs2); -// Thread.sleep(10); -// if (!Arrays.equals(bs, bs2)) throw new RuntimeException("两者序列化出来的byte[]不一致"); -// -// System.out.println(bean); -// System.out.println(ProtobufConvert.root().convertFrom(SimpleBean.class, bs).toString()); -// System.out.println(JsonConvert.root().convertFrom(SimpleBean.class, jsonbs).toString()); -// -// } -// -// private static PSimpleBeanOuterClass.PSimpleBean createPSimpleBean(SimpleBean bean, -// PSimpleBeanOuterClass.PSimpleBean.Builder builder) { -// if (builder == null) { -// builder = PSimpleBeanOuterClass.PSimpleBean.newBuilder(); -// } else { -// builder.clear(); -// } -// PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry.Builder sentry = -// PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry.newBuilder(); -// sentry.setId(bean.simple.id); -// sentry.setName(bean.simple.name); -// sentry.setEmail(bean.simple.email); -// builder.setSimple(sentry.build()); -// -// PSimpleBeanOuterClass.PSimpleBean.PTwoEntry.Builder tentry = -// PSimpleBeanOuterClass.PSimpleBean.PTwoEntry.newBuilder(); -// tentry.setStatus(bean.two.status); -// tentry.setCreatetime(bean.two.createtime); -// builder.setTwo(tentry.build()); -// -// builder.setStrings(bean.strings); -// -// PSimpleBeanOuterClass.PSimpleBean bean2 = builder.build(); -// return bean2; -// } -// } +package org.redkale.test.convert.proto; + +/// * +// * 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.redkalex.test.protobuf; +// +// import java.util.Arrays; +// import org.redkale.convert.ConvertColumn; +// import org.redkale.convert.json.JsonConvert; +// import org.redkale.util.Utility; +// import org.redkalex.convert.protobuf.ProtobufConvert; +// +/// ** +// * +// * @author zhangjx +// */ +// public class SimpleBean { +// +// public static class PSimpleEntry { +// +// @ConvertColumn(index = 1) +// public int id = 66; +// +// @ConvertColumn(index = 2) +// public String name = "哈哈"; +// +// @ConvertColumn(index = 3) +// public String email = "redkale@redkale.org"; +// } +// +// public static class PTwoEntry { +// +// @ConvertColumn(index = 1) +// public int status = 2; +// +// @ConvertColumn(index = 2) +// public long createtime = System.currentTimeMillis(); +// +// } +// +// @ConvertColumn(index = 1) +// public PSimpleEntry simple; +// +// @ConvertColumn(index = 2) +// public PTwoEntry two; +// +// @ConvertColumn(index = 3) +// public String strings = "abcd"; +// +// @Override +// public String toString() { +// return JsonConvert.root().convertTo(this); +// } +// +// public static void main(String[] args) throws Throwable { +// //System.out.println(ProtobufConvert.root().getProtoDescriptor(SimpleBean.class)); +// SimpleBean bean = new SimpleBean(); +// bean.simple = new PSimpleEntry(); +// bean.two = new PTwoEntry(); +// bean.strings = "abcde"; +// +// //------------------------------- +// byte[] jsonbs = JsonConvert.root().convertToBytes(bean); +// byte[] bs = ProtobufConvert.root().convertTo(bean); +// Utility.println("predkale ", bs); +// PSimpleBeanOuterClass.PSimpleBean.Builder builder = PSimpleBeanOuterClass.PSimpleBean.newBuilder(); +// +// PSimpleBeanOuterClass.PSimpleBean bean2 = createPSimpleBean(bean, builder); +// byte[] bs2 = bean2.toByteArray(); +// Utility.println("protobuf ", bs2); +// Thread.sleep(10); +// if (!Arrays.equals(bs, bs2)) throw new RuntimeException("两者序列化出来的byte[]不一致"); +// +// System.out.println(bean); +// System.out.println(ProtobufConvert.root().convertFrom(SimpleBean.class, bs).toString()); +// System.out.println(JsonConvert.root().convertFrom(SimpleBean.class, jsonbs).toString()); +// +// } +// +// private static PSimpleBeanOuterClass.PSimpleBean createPSimpleBean(SimpleBean bean, +// PSimpleBeanOuterClass.PSimpleBean.Builder builder) { +// if (builder == null) { +// builder = PSimpleBeanOuterClass.PSimpleBean.newBuilder(); +// } else { +// builder.clear(); +// } +// PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry.Builder sentry = +// PSimpleBeanOuterClass.PSimpleBean.PSimpleEntry.newBuilder(); +// sentry.setId(bean.simple.id); +// sentry.setName(bean.simple.name); +// sentry.setEmail(bean.simple.email); +// builder.setSimple(sentry.build()); +// +// PSimpleBeanOuterClass.PSimpleBean.PTwoEntry.Builder tentry = +// PSimpleBeanOuterClass.PSimpleBean.PTwoEntry.newBuilder(); +// tentry.setStatus(bean.two.status); +// tentry.setCreatetime(bean.two.createtime); +// builder.setTwo(tentry.build()); +// +// builder.setStrings(bean.strings); +// +// PSimpleBeanOuterClass.PSimpleBean bean2 = builder.build(); +// return bean2; +// } +// } diff --git a/src/test/java/org/redkale/test/convert/proto/TestBean.java b/src/test/java/org/redkale/test/convert/proto/TestBean.java index c8bfae3ad..0fee73d40 100644 --- a/src/test/java/org/redkale/test/convert/proto/TestBean.java +++ b/src/test/java/org/redkale/test/convert/proto/TestBean.java @@ -1,244 +1,244 @@ -package org.redkale.test.convert.proto; - -/// * -// * 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.redkalex.test.protobuf; -// -// import org.redkalex.convert.protobuf.ProtobufReader; -// import org.redkalex.convert.protobuf.ProtobufConvert; -// import com.google.protobuf.*; -// import java.util.*; -// import org.redkale.convert.ConvertColumn; -// import org.redkale.convert.json.JsonConvert; -// import org.redkale.service.RetResult; -// import org.redkale.util.*; -// -/// ** -// * -// * @author zhangjx -// */ -// public class TestBean { -// -// public static class PTestEntry { -// -// @ConvertColumn(index = 1) -// public boolean[] bools = new boolean[]{true, false, true}; -// -// @ConvertColumn(index = 2) -// public byte[] bytes = new byte[]{1, 2, 3, 4}; -// -// @ConvertColumn(index = 3) -// public char[] chars = new char[]{'A', 'B', 'C'}; -// -// @ConvertColumn(index = 4) -// public short[] shorts = new short[]{10, 20, 30}; -// -// @Override -// public String toString() { -// return JsonConvert.root().convertTo(this); -// } -// } -// -// public static enum Kind { -// ONE, -// TWO, -// THREE -// } -// -// @ConvertColumn(index = 1) -// public boolean[] bools; -// -// @ConvertColumn(index = 2) -// public byte[] bytes; -// -// @ConvertColumn(index = 3) -// public char[] chars; -// -// @ConvertColumn(index = 4) -// public PTestEntry[] entrys; -// -// @ConvertColumn(index = 5) -// public int[] ints; -// -// @ConvertColumn(index = 6) -// public float[] floats; -// -// @ConvertColumn(index = 7) -// public long[] longs; -// -// @ConvertColumn(index = 8) -// public double[] doubles; //8 -// -// @ConvertColumn(index = 9) -// public String[] strings; //9 -// -// @ConvertColumn(index = 10) -// public int id = 0x7788; //10 -// -// @ConvertColumn(index = 11) -// public String name; //11 -// -// @ConvertColumn(index = 12) -// public String email; //12 -// -// @ConvertColumn(index = 13) -// public Kind kind; //13 -// -// @ConvertColumn(index = 14) -// public Map map; //14 -// -// @ConvertColumn(index = 15) -// public String end; //15 -// -// @Override -// public String toString() { -// return JsonConvert.root().convertTo(this); -// } -// -// public static void main3(String[] args) throws Throwable { -// byte[] src = new byte[]{(byte) 0x82, (byte) 0x01, (byte) 0x84, (byte) 0x01, (byte) 0x86, (byte) 0x01}; -// src = new byte[]{(byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0x01}; -// CodedInputStream input = CodedInputStream.newInstance(src); -// System.out.println("结果1: " + input.readSInt32()); -// System.out.println("结果1: " + input.readSInt32()); -// System.out.println("结果1: " + input.readSInt32()); -// ProtobufReader reader = new ProtobufReader(src); -// System.out.println("结果2: " + reader.readInt()); -// System.out.println("结果2: " + reader.readInt()); -// System.out.println("结果2: " + reader.readInt()); -// } -// -// private static java.lang.reflect.Type retstring = new TypeToken>>() { -// }.getType(); -// -// public static void main2(String[] args) throws Throwable { -// System.out.println(ProtobufConvert.root().getProtoDescriptor(retstring)); -// } -// -// public static void main(String[] args) throws Throwable { -// System.setProperty("convert.protobuf.enumtostring", "false"); //禁用枚举按字符串类型出来 -// //System.out.println(ProtobufConvert.root().getProtoDescriptor(TestBean.class)); -// //System.out.println(Integer.toHexString(14<<3|2)); -// TestBean bean = new TestBean(); -// -// bean.bools = new boolean[]{true, false, true}; -// bean.bytes = new byte[]{1, 2, 3, 4}; -// bean.chars = new char[]{'A', 'B', 'C'}; -// bean.ints = new int[]{100, 200, 300}; -// bean.floats = new float[]{10.12f, 20.34f}; -// bean.longs = new long[]{111, 222, 333}; -// bean.doubles = new double[]{65.65, 78.78}; -// bean.name = "redkale"; -// bean.email = "redkale@qq.org"; -// bean.kind = Kind.TWO; -// bean.strings = new String[]{"str1", "str2", "str3"}; -// bean.entrys = new PTestEntry[]{new PTestEntry(), null, new PTestEntry()}; -// bean.map = Utility.ofMap("aa", 0x55, "bb", 0x66); -// bean.end = "over"; -// -// //------------------------------- -// byte[] jsonbs = JsonConvert.root().convertToBytes(bean); -// byte[] bs = ProtobufConvert.root().convertTo(bean); -// Utility.println("pconvert ", bs); -// PTestBeanOuterClass.PTestBean.Builder builder = PTestBeanOuterClass.PTestBean.newBuilder(); -// -// PTestBeanOuterClass.PTestBean bean2 = createPTestBean(bean, builder); -// byte[] bs2 = bean2.toByteArray(); -// Utility.println("protobuf ", bs2); -// Thread.sleep(10); -// if (!Arrays.equals(bs, bs2)) throw new RuntimeException("两者序列化出来的byte[]不一致"); -// -// System.out.println(bean); -// String frombean = ProtobufConvert.root().convertFrom(TestBean.class, bs).toString(); -// System.out.println(frombean); -// if (!bean.toString().equals(frombean)) throw new RuntimeException("ProtobufConvert反解析后的结果不正确"); -// System.out.println(JsonConvert.root().convertFrom(TestBean.class, jsonbs).toString()); -// -// int count = 100000; -// long s, e; -// s = System.currentTimeMillis(); -// for (int z = 0; z < count; z++) { -// ProtobufConvert.root().convertTo(bean); -// } -// e = System.currentTimeMillis() - s; -// System.out.println("redkale-protobuf耗时-------" + e); -// -// s = System.currentTimeMillis(); -// for (int z = 0; z < count; z++) { -// JsonConvert.root().convertToBytes(bean); -// } -// e = System.currentTimeMillis() - s; -// System.out.println("redkale-json文本耗时-------" + e); -// -// s = System.currentTimeMillis(); -// for (int z = 0; z < count; z++) { -// createPTestBean(bean, builder).toByteArray(); -// } -// e = System.currentTimeMillis() - s; -// System.out.println("原生编译protobuf耗时-------" + e); -// } -// -// private static PTestBeanOuterClass.PTestBean createPTestBean(TestBean bean, PTestBeanOuterClass.PTestBean.Builder -// builder) { -// if (builder == null) { -// builder = PTestBeanOuterClass.PTestBean.newBuilder(); -// } else { -// builder.clear(); -// } -// for (int i = 0; bean.bools != null && i < bean.bools.length; i++) { -// builder.addBools(bean.bools[i]); -// } -// if (bean.bytes != null) builder.addBytes(ByteString.copyFrom(bean.bytes)); -// for (int i = 0; bean.chars != null && i < bean.chars.length; i++) { -// builder.addChars(bean.chars[i]); -// } -// for (int i = 0; bean.entrys != null && i < bean.entrys.length; i++) { -// PTestBeanOuterClass.PTestBean.PTestEntry.Builder entry = -// PTestBeanOuterClass.PTestBean.PTestEntry.newBuilder(); -// if (bean.entrys[i] == null) { -// builder.addEntrys(entry.build()); -// continue; -// } -// for (int j = 0; bean.entrys[i].bools != null && j < bean.entrys[i].bools.length; j++) { -// entry.addBools(bean.entrys[i].bools[j]); -// } -// if (bean.entrys[i].bytes != null) entry.addBytes(ByteString.copyFrom(bean.entrys[i].bytes)); -// for (int j = 0; bean.entrys[i].chars != null && j < bean.entrys[i].chars.length; j++) { -// entry.addChars(bean.entrys[i].chars[j]); -// } -// for (int j = 0; bean.entrys[i].shorts != null && j < bean.entrys[i].shorts.length; j++) { -// entry.addShorts(bean.entrys[i].shorts[j]); -// } -// builder.addEntrys(entry.build()); -// } -// for (int i = 0; bean.ints != null && i < bean.ints.length; i++) { -// builder.addInts(bean.ints[i]); -// } -// for (int i = 0; bean.floats != null && i < bean.floats.length; i++) { -// builder.addFloats(bean.floats[i]); -// } -// for (int i = 0; bean.longs != null && i < bean.longs.length; i++) { -// builder.addLongs(bean.longs[i]); -// } -// for (int i = 0; bean.doubles != null && i < bean.doubles.length; i++) { -// builder.addDoubles(bean.doubles[i]); -// } -// for (int i = 0; bean.strings != null && i < bean.strings.length; i++) { -// builder.addStrings(bean.strings[i]); -// } -// builder.setId(bean.id); -// if (bean.name != null) builder.setName(bean.name); -// if (bean.email != null) builder.setEmail(bean.email); -// if (bean.kind != null) builder.setKind(PTestBeanOuterClass.PTestBean.Kind.TWO); -// if (bean.map != null) builder.putAllMap(bean.map); -// if (bean.end != null) builder.setEnd(bean.end); -// PTestBeanOuterClass.PTestBean bean2 = builder.build(); -// return bean2; -// } -// } -// -//// protoc --java_out=D:\Java-Projects\RedkalePluginsProject\test\ -// --proto_path=D:\Java-Projects\RedkalePluginsProject\test\org\redkalex\test\protobuf\ PTestBean.proto +package org.redkale.test.convert.proto; + +/// * +// * 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.redkalex.test.protobuf; +// +// import org.redkalex.convert.protobuf.ProtobufReader; +// import org.redkalex.convert.protobuf.ProtobufConvert; +// import com.google.protobuf.*; +// import java.util.*; +// import org.redkale.convert.ConvertColumn; +// import org.redkale.convert.json.JsonConvert; +// import org.redkale.service.RetResult; +// import org.redkale.util.*; +// +/// ** +// * +// * @author zhangjx +// */ +// public class TestBean { +// +// public static class PTestEntry { +// +// @ConvertColumn(index = 1) +// public boolean[] bools = new boolean[]{true, false, true}; +// +// @ConvertColumn(index = 2) +// public byte[] bytes = new byte[]{1, 2, 3, 4}; +// +// @ConvertColumn(index = 3) +// public char[] chars = new char[]{'A', 'B', 'C'}; +// +// @ConvertColumn(index = 4) +// public short[] shorts = new short[]{10, 20, 30}; +// +// @Override +// public String toString() { +// return JsonConvert.root().convertTo(this); +// } +// } +// +// public static enum Kind { +// ONE, +// TWO, +// THREE +// } +// +// @ConvertColumn(index = 1) +// public boolean[] bools; +// +// @ConvertColumn(index = 2) +// public byte[] bytes; +// +// @ConvertColumn(index = 3) +// public char[] chars; +// +// @ConvertColumn(index = 4) +// public PTestEntry[] entrys; +// +// @ConvertColumn(index = 5) +// public int[] ints; +// +// @ConvertColumn(index = 6) +// public float[] floats; +// +// @ConvertColumn(index = 7) +// public long[] longs; +// +// @ConvertColumn(index = 8) +// public double[] doubles; //8 +// +// @ConvertColumn(index = 9) +// public String[] strings; //9 +// +// @ConvertColumn(index = 10) +// public int id = 0x7788; //10 +// +// @ConvertColumn(index = 11) +// public String name; //11 +// +// @ConvertColumn(index = 12) +// public String email; //12 +// +// @ConvertColumn(index = 13) +// public Kind kind; //13 +// +// @ConvertColumn(index = 14) +// public Map map; //14 +// +// @ConvertColumn(index = 15) +// public String end; //15 +// +// @Override +// public String toString() { +// return JsonConvert.root().convertTo(this); +// } +// +// public static void main3(String[] args) throws Throwable { +// byte[] src = new byte[]{(byte) 0x82, (byte) 0x01, (byte) 0x84, (byte) 0x01, (byte) 0x86, (byte) 0x01}; +// src = new byte[]{(byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0x01}; +// CodedInputStream input = CodedInputStream.newInstance(src); +// System.out.println("结果1: " + input.readSInt32()); +// System.out.println("结果1: " + input.readSInt32()); +// System.out.println("结果1: " + input.readSInt32()); +// ProtobufReader reader = new ProtobufReader(src); +// System.out.println("结果2: " + reader.readInt()); +// System.out.println("结果2: " + reader.readInt()); +// System.out.println("结果2: " + reader.readInt()); +// } +// +// private static java.lang.reflect.Type retstring = new TypeToken>>() { +// }.getType(); +// +// public static void main2(String[] args) throws Throwable { +// System.out.println(ProtobufConvert.root().getProtoDescriptor(retstring)); +// } +// +// public static void main(String[] args) throws Throwable { +// System.setProperty("convert.protobuf.enumtostring", "false"); //禁用枚举按字符串类型出来 +// //System.out.println(ProtobufConvert.root().getProtoDescriptor(TestBean.class)); +// //System.out.println(Integer.toHexString(14<<3|2)); +// TestBean bean = new TestBean(); +// +// bean.bools = new boolean[]{true, false, true}; +// bean.bytes = new byte[]{1, 2, 3, 4}; +// bean.chars = new char[]{'A', 'B', 'C'}; +// bean.ints = new int[]{100, 200, 300}; +// bean.floats = new float[]{10.12f, 20.34f}; +// bean.longs = new long[]{111, 222, 333}; +// bean.doubles = new double[]{65.65, 78.78}; +// bean.name = "redkale"; +// bean.email = "redkale@qq.org"; +// bean.kind = Kind.TWO; +// bean.strings = new String[]{"str1", "str2", "str3"}; +// bean.entrys = new PTestEntry[]{new PTestEntry(), null, new PTestEntry()}; +// bean.map = Utility.ofMap("aa", 0x55, "bb", 0x66); +// bean.end = "over"; +// +// //------------------------------- +// byte[] jsonbs = JsonConvert.root().convertToBytes(bean); +// byte[] bs = ProtobufConvert.root().convertTo(bean); +// Utility.println("pconvert ", bs); +// PTestBeanOuterClass.PTestBean.Builder builder = PTestBeanOuterClass.PTestBean.newBuilder(); +// +// PTestBeanOuterClass.PTestBean bean2 = createPTestBean(bean, builder); +// byte[] bs2 = bean2.toByteArray(); +// Utility.println("protobuf ", bs2); +// Thread.sleep(10); +// if (!Arrays.equals(bs, bs2)) throw new RuntimeException("两者序列化出来的byte[]不一致"); +// +// System.out.println(bean); +// String frombean = ProtobufConvert.root().convertFrom(TestBean.class, bs).toString(); +// System.out.println(frombean); +// if (!bean.toString().equals(frombean)) throw new RuntimeException("ProtobufConvert反解析后的结果不正确"); +// System.out.println(JsonConvert.root().convertFrom(TestBean.class, jsonbs).toString()); +// +// int count = 100000; +// long s, e; +// s = System.currentTimeMillis(); +// for (int z = 0; z < count; z++) { +// ProtobufConvert.root().convertTo(bean); +// } +// e = System.currentTimeMillis() - s; +// System.out.println("redkale-protobuf耗时-------" + e); +// +// s = System.currentTimeMillis(); +// for (int z = 0; z < count; z++) { +// JsonConvert.root().convertToBytes(bean); +// } +// e = System.currentTimeMillis() - s; +// System.out.println("redkale-json文本耗时-------" + e); +// +// s = System.currentTimeMillis(); +// for (int z = 0; z < count; z++) { +// createPTestBean(bean, builder).toByteArray(); +// } +// e = System.currentTimeMillis() - s; +// System.out.println("原生编译protobuf耗时-------" + e); +// } +// +// private static PTestBeanOuterClass.PTestBean createPTestBean(TestBean bean, PTestBeanOuterClass.PTestBean.Builder +// builder) { +// if (builder == null) { +// builder = PTestBeanOuterClass.PTestBean.newBuilder(); +// } else { +// builder.clear(); +// } +// for (int i = 0; bean.bools != null && i < bean.bools.length; i++) { +// builder.addBools(bean.bools[i]); +// } +// if (bean.bytes != null) builder.addBytes(ByteString.copyFrom(bean.bytes)); +// for (int i = 0; bean.chars != null && i < bean.chars.length; i++) { +// builder.addChars(bean.chars[i]); +// } +// for (int i = 0; bean.entrys != null && i < bean.entrys.length; i++) { +// PTestBeanOuterClass.PTestBean.PTestEntry.Builder entry = +// PTestBeanOuterClass.PTestBean.PTestEntry.newBuilder(); +// if (bean.entrys[i] == null) { +// builder.addEntrys(entry.build()); +// continue; +// } +// for (int j = 0; bean.entrys[i].bools != null && j < bean.entrys[i].bools.length; j++) { +// entry.addBools(bean.entrys[i].bools[j]); +// } +// if (bean.entrys[i].bytes != null) entry.addBytes(ByteString.copyFrom(bean.entrys[i].bytes)); +// for (int j = 0; bean.entrys[i].chars != null && j < bean.entrys[i].chars.length; j++) { +// entry.addChars(bean.entrys[i].chars[j]); +// } +// for (int j = 0; bean.entrys[i].shorts != null && j < bean.entrys[i].shorts.length; j++) { +// entry.addShorts(bean.entrys[i].shorts[j]); +// } +// builder.addEntrys(entry.build()); +// } +// for (int i = 0; bean.ints != null && i < bean.ints.length; i++) { +// builder.addInts(bean.ints[i]); +// } +// for (int i = 0; bean.floats != null && i < bean.floats.length; i++) { +// builder.addFloats(bean.floats[i]); +// } +// for (int i = 0; bean.longs != null && i < bean.longs.length; i++) { +// builder.addLongs(bean.longs[i]); +// } +// for (int i = 0; bean.doubles != null && i < bean.doubles.length; i++) { +// builder.addDoubles(bean.doubles[i]); +// } +// for (int i = 0; bean.strings != null && i < bean.strings.length; i++) { +// builder.addStrings(bean.strings[i]); +// } +// builder.setId(bean.id); +// if (bean.name != null) builder.setName(bean.name); +// if (bean.email != null) builder.setEmail(bean.email); +// if (bean.kind != null) builder.setKind(PTestBeanOuterClass.PTestBean.Kind.TWO); +// if (bean.map != null) builder.putAllMap(bean.map); +// if (bean.end != null) builder.setEnd(bean.end); +// PTestBeanOuterClass.PTestBean bean2 = builder.build(); +// return bean2; +// } +// } +// +//// protoc --java_out=D:\Java-Projects\RedkalePluginsProject\test\ +// --proto_path=D:\Java-Projects\RedkalePluginsProject\test\org\redkalex\test\protobuf\ PTestBean.proto diff --git a/src/test/java/org/redkale/test/http/HttpRequestDesc.java b/src/test/java/org/redkale/test/http/HttpRequestDesc.java index 4d56a1bfa..1cae701d5 100644 --- a/src/test/java/org/redkale/test/http/HttpRequestDesc.java +++ b/src/test/java/org/redkale/test/http/HttpRequestDesc.java @@ -1,345 +1,345 @@ -/* - * 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.test.http; - -import java.io.*; -import java.lang.reflect.Type; -import java.net.*; -import java.nio.charset.*; -import java.util.*; -import org.redkale.convert.json.*; -import org.redkale.net.http.*; -import org.redkale.util.AnyValue; - -/** @author zhangjx */ -public interface HttpRequestDesc { - - // 获取客户端地址IP - public SocketAddress getRemoteAddress(); - - // 获取客户端地址IP, 与getRemoteAddres() 的区别在于: - // 本方法优先取header中指定为RemoteAddress名的值,没有则返回getRemoteAddres()的getHostAddress()。 - // 本方法适用于服务前端有如nginx的代理服务器进行中转,通过getRemoteAddres()是获取不到客户端的真实IP。 - public String getRemoteAddr(); - - // 获取请求内容指定的编码字符串 - public String getBody(Charset charset); - - // 获取请求内容的UTF-8编码字符串 - public String getBodyUTF8(); - - // 获取请求内容的byte[] - public byte[] getBody(); - - // 获取请求内容的JavaBean对象 - public T getBodyJson(java.lang.reflect.Type type); - - // 获取请求内容的JavaBean对象 - public T getBodyJson(JsonConvert convert, java.lang.reflect.Type type); - - // 获取文件上传对象 - public MultiContext getMultiContext(); - - // 获取文件上传信息列表 等价于 getMultiContext().parts(); - public Iterable multiParts() throws IOException; - - // 设置当前用户信息, 通常在HttpServlet.preExecute方法里设置currentUser - // 数据类型由@HttpUserType指定 - public HttpRequest setCurrentUser(T user); - - // 获取当前用户信息 数据类型由@HttpUserType指定 - public T currentUser(); - - // 获取模块ID,来自@HttpServlet.moduleid() - public int getModuleid(); - - // 获取操作ID,来自@HttpMapping.actionid() - public int getActionid(); - - // 获取sessionid - public String getSessionid(boolean autoCreate); - - // 更新sessionid - public String changeSessionid(); - - // 指定值更新sessionid - public String changeSessionid(String newsessionid); - - // 使sessionid失效 - public void invalidateSession(); - - // 获取所有Cookie对象 - public java.net.HttpCookie[] getCookies(); - - // 获取Cookie值 - public String getCookie(String name); - - // 获取Cookie值, 没有返回默认值 - public String getCookie(String name, String defaultValue); - - // 获取协议名 http、https、ws、wss等 - public String getProtocol(); - - // 获取请求方法 GET、POST等 - public String getMethod(); - - // 获取Content-Type的header值 - public String getContentType(); - - // 获取请求内容的长度, 为-1表示内容长度不确定 - public long getContentLength(); - - // 获取Connection的Header值 - public String getConnection(); - - // 获取Host的Header值 - public String getHost(); - - // 获取请求的URL - public String getRequestURI(); - - // 截取getRequestURI最后的一个/后面的部分 - public String getRequstURILastPath(); - - // 获取请求URL最后的一个/后面的部分的short值
- // 例如请求URL /pipes/record/query/2
- // 获取type参数: short type = request.getRequstURILastPath((short)0); //type = 2 - public short getRequstURILastPath(short defvalue); - - // 获取请求URL最后的一个/后面的部分的short值
- // 例如请求URL /pipes/record/query/2
- // 获取type参数: short type = request.getRequstURILastPath((short)0); //type = 2 - public short getRequstURILastPath(int radix, short defvalue); - - // 获取请求URL最后的一个/后面的部分的int值
- // 例如请求URL /pipes/record/query/2
- // 获取type参数: int type = request.getRequstURILastPath(0); //type = 2 - public int getRequstURILastPath(int defvalue); - - // 获取请求URL最后的一个/后面的部分的int值
- // 例如请求URL /pipes/record/query/2
- // 获取type参数: int type = request.getRequstURILastPath(0); //type = 2 - public int getRequstURILastPath(int radix, int defvalue); - - // 获取请求URL最后的一个/后面的部分的float值
- // 例如请求URL /pipes/record/query/2
- // 获取type参数: float type = request.getRequstURILastPath(0.f); //type = 2.f - public float getRequstURILastPath(float defvalue); - - // 获取请求URL最后的一个/后面的部分的long值
- // 例如请求URL /pipes/record/query/2
- // 获取type参数: long type = request.getRequstURILastPath(0L); //type = 2 - public long getRequstURILastPath(long defvalue); - - // 获取请求URL最后的一个/后面的部分的long值
- // 例如请求URL /pipes/record/query/2
- // 获取type参数: long type = request.getRequstURILastPath(0L); //type = 2 - public long getRequstURILastPath(int radix, long defvalue); - - // 获取请求URL最后的一个/后面的部分的double值
- // 例如请求URL /pipes/record/query/2
- // 获取type参数: double type = request.getRequstURILastPath(0.0); //type = 2.0 - public double getRequstURILastPath(double defvalue); - - // 从prefix之后截取getRequestURI再对"/"进行分隔 - public String[] getRequstURIPaths(String prefix); - - // 获取请求URL分段中含prefix段的值 - // 例如请求URL /pipes/record/query/name:hello - // 获取name参数: String name = request.getRequstURIPath("name:", "none"); - public String getRequstURIPath(String prefix, String defaultValue); - - // 获取请求URL分段中含prefix段的short值 - // 例如请求URL /pipes/record/query/type:10 - // 获取type参数: short type = request.getRequstURIPath("type:", (short)0); - public short getRequstURIPath(String prefix, short defaultValue); - - // 获取请求URL分段中含prefix段的short值 - // 例如请求URL /pipes/record/query/type:a - // 获取type参数: short type = request.getRequstURIPath(16, "type:", (short)0); type = 10 - public short getRequstURIPath(int radix, String prefix, short defvalue); - - // 获取请求URL分段中含prefix段的int值 - // 例如请求URL /pipes/record/query/offset:2/limit:50 - // 获取offset参数: int offset = request.getRequstURIPath("offset:", 1); - // 获取limit参数: int limit = request.getRequstURIPath("limit:", 20); - public int getRequstURIPath(String prefix, int defaultValue); - - // 获取请求URL分段中含prefix段的int值 - // 例如请求URL /pipes/record/query/offset:2/limit:10 - // 获取offset参数: int offset = request.getRequstURIPath("offset:", 1); - // 获取limit参数: int limit = request.getRequstURIPath(16, "limit:", 20); // limit = 16 - public int getRequstURIPath(int radix, String prefix, int defaultValue); - - // 获取请求URL分段中含prefix段的float值 - // 例如请求URL /pipes/record/query/point:40.0 - // 获取time参数: float point = request.getRequstURIPath("point:", 0.0f); - public float getRequstURIPath(String prefix, float defvalue); - - // 获取请求URL分段中含prefix段的long值 - // 例如请求URL /pipes/record/query/time:1453104341363/id:40 - // 获取time参数: long time = request.getRequstURIPath("time:", 0L); - public long getRequstURIPath(String prefix, long defaultValue); - - // 获取请求URL分段中含prefix段的long值 - // 例如请求URL /pipes/record/query/time:1453104341363/id:40 - // 获取time参数: long time = request.getRequstURIPath("time:", 0L); - public long getRequstURIPath(int radix, String prefix, long defvalue); - - // 获取请求URL分段中含prefix段的double值
- // 例如请求URL /pipes/record/query/point:40.0
- // 获取time参数: double point = request.getRequstURIPath("point:", 0.0); - public double getRequstURIPath(String prefix, double defvalue); - - // 获取所有的header名 - public AnyValue getHeaders(); - - // 将请求Header转换成Map - public Map getHeadersToMap(Map map); - - // 获取所有的header名 - public String[] getHeaderNames(); - - // 获取指定的header值 - public String getHeader(String name); - - // 获取指定的header值, 没有返回默认值 - public String getHeader(String name, String defaultValue); - - // 获取指定的header的json值 - public T getJsonHeader(Type type, String name); - - // 获取指定的header的json值 - public T getJsonHeader(JsonConvert convert, Type type, String name); - - // 获取指定的header的boolean值, 没有返回默认boolean值 - public boolean getBooleanHeader(String name, boolean defaultValue); - - // 获取指定的header的short值, 没有返回默认short值 - public short getShortHeader(String name, short defaultValue); - - // 获取指定的header的short值, 没有返回默认short值 - public short getShortHeader(int radix, String name, short defaultValue); - - // 获取指定的header的short值, 没有返回默认short值 - public short getShortHeader(String name, int defaultValue); - - // 获取指定的header的short值, 没有返回默认short值 - public short getShortHeader(int radix, String name, int defaultValue); - - // 获取指定的header的int值, 没有返回默认int值 - public int getIntHeader(String name, int defaultValue); - - // 获取指定的header的int值, 没有返回默认int值 - public int getIntHeader(int radix, String name, int defaultValue); - - // 获取指定的header的long值, 没有返回默认long值 - public long getLongHeader(String name, long defaultValue); - - // 获取指定的header的long值, 没有返回默认long值 - public long getLongHeader(int radix, String name, long defaultValue); - - // 获取指定的header的float值, 没有返回默认float值 - public float getFloatHeader(String name, float defaultValue); - - // 获取指定的header的double值, 没有返回默认double值 - public double getDoubleHeader(String name, double defaultValue); - - // 获取请求参数总对象 - public AnyValue getParameters(); - - // 将请求参数转换成Map - public Map getParametersToMap(Map map); - - // 将请求参数转换成String, 字符串格式为: bean1={}&id=13&name=xxx - // 不会返回null,没有参数返回空字符串 - public String getParametersToString(); - - // 将请求参数转换成String, 字符串格式为: prefix + bean1={}&id=13&name=xxx - // 拼接前缀, 如果无参数,返回的字符串不会含有拼接前缀 - // 不会返回null,没有参数返回空字符串 - public String getParametersToString(String prefix); - - // 获取所有参数名 - public String[] getParameterNames(); - - // 获取指定的参数值 - public String getParameter(String name); - - // 获取指定的参数值, 没有返回默认值 - public String getParameter(String name, String defaultValue); - - // 获取指定的参数json值 - public T getJsonParameter(Type type, String name); - - // 获取指定的参数json值 - public T getJsonParameter(JsonConvert convert, Type type, String name); - - // 获取指定的参数boolean值, 没有返回默认boolean值 - public boolean getBooleanParameter(String name, boolean defaultValue); - - // 获取指定的参数short值, 没有返回默认short值 - public short getShortParameter(String name, short defaultValue); - - // 获取指定的参数short值, 没有返回默认short值 - public short getShortParameter(int radix, String name, short defaultValue); - - // 获取指定的参数short值, 没有返回默认short值 - public short getShortParameter(int radix, String name, int defaultValue); - - // 获取指定的参数int值, 没有返回默认int值 - public int getIntParameter(String name, int defaultValue); - - // 获取指定的参数int值, 没有返回默认int值 - public int getIntParameter(int radix, String name, int defaultValue); - - // 获取指定的参数long值, 没有返回默认long值 - public long getLongParameter(String name, long defaultValue); - - // 获取指定的参数long值, 没有返回默认long值 - public long getLongParameter(int radix, String name, long defaultValue); - - // 获取指定的参数float值, 没有返回默认float值 - public float getFloatParameter(String name, float defaultValue); - - // 获取指定的参数double值, 没有返回默认double值 - public double getDoubleParameter(String name, double defaultValue); - - // 获取翻页对象 同 getFlipper("flipper", false, 0); - public org.redkale.source.Flipper getFlipper(); - - // 获取翻页对象 同 getFlipper("flipper", needcreate, 0); - public org.redkale.source.Flipper getFlipper(boolean needcreate); - - // 获取翻页对象 同 getFlipper("flipper", false, maxLimit); - public org.redkale.source.Flipper getFlipper(int maxLimit); - - // 获取翻页对象 同 getFlipper("flipper", needcreate, maxLimit) - public org.redkale.source.Flipper getFlipper(boolean needcreate, int maxLimit); - - // 获取翻页对象 http://redkale.org/pipes/records/list/offset:0/limit:20/sort:createtime%20ASC - // http://redkale.org/pipes/records/list?flipper={'offset':0,'limit':20, 'sort':'createtime ASC'} - // 以上两种接口都可以获取到翻页对象 - public org.redkale.source.Flipper getFlipper(String name, boolean needcreate, int maxLimit); - - // 获取HTTP上下文对象 - public HttpContext getContext(); - - // 获取所有属性值, servlet执行完后会被清空 - public Map getAttributes(); - - // 获取指定属性值, servlet执行完后会被清空 - public T getAttribute(String name); - - // 删除指定属性 - public void removeAttribute(String name); - - // 设置属性值, servlet执行完后会被清空 - public void setAttribute(String name, Object value); - - // 获取request创建时间 - public long getCreatetime(); -} +/* + * 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.test.http; + +import java.io.*; +import java.lang.reflect.Type; +import java.net.*; +import java.nio.charset.*; +import java.util.*; +import org.redkale.convert.json.*; +import org.redkale.net.http.*; +import org.redkale.util.AnyValue; + +/** @author zhangjx */ +public interface HttpRequestDesc { + + // 获取客户端地址IP + public SocketAddress getRemoteAddress(); + + // 获取客户端地址IP, 与getRemoteAddres() 的区别在于: + // 本方法优先取header中指定为RemoteAddress名的值,没有则返回getRemoteAddres()的getHostAddress()。 + // 本方法适用于服务前端有如nginx的代理服务器进行中转,通过getRemoteAddres()是获取不到客户端的真实IP。 + public String getRemoteAddr(); + + // 获取请求内容指定的编码字符串 + public String getBody(Charset charset); + + // 获取请求内容的UTF-8编码字符串 + public String getBodyUTF8(); + + // 获取请求内容的byte[] + public byte[] getBody(); + + // 获取请求内容的JavaBean对象 + public T getBodyJson(java.lang.reflect.Type type); + + // 获取请求内容的JavaBean对象 + public T getBodyJson(JsonConvert convert, java.lang.reflect.Type type); + + // 获取文件上传对象 + public MultiContext getMultiContext(); + + // 获取文件上传信息列表 等价于 getMultiContext().parts(); + public Iterable multiParts() throws IOException; + + // 设置当前用户信息, 通常在HttpServlet.preExecute方法里设置currentUser + // 数据类型由@HttpUserType指定 + public HttpRequest setCurrentUser(T user); + + // 获取当前用户信息 数据类型由@HttpUserType指定 + public T currentUser(); + + // 获取模块ID,来自@HttpServlet.moduleid() + public int getModuleid(); + + // 获取操作ID,来自@HttpMapping.actionid() + public int getActionid(); + + // 获取sessionid + public String getSessionid(boolean autoCreate); + + // 更新sessionid + public String changeSessionid(); + + // 指定值更新sessionid + public String changeSessionid(String newsessionid); + + // 使sessionid失效 + public void invalidateSession(); + + // 获取所有Cookie对象 + public java.net.HttpCookie[] getCookies(); + + // 获取Cookie值 + public String getCookie(String name); + + // 获取Cookie值, 没有返回默认值 + public String getCookie(String name, String defaultValue); + + // 获取协议名 http、https、ws、wss等 + public String getProtocol(); + + // 获取请求方法 GET、POST等 + public String getMethod(); + + // 获取Content-Type的header值 + public String getContentType(); + + // 获取请求内容的长度, 为-1表示内容长度不确定 + public long getContentLength(); + + // 获取Connection的Header值 + public String getConnection(); + + // 获取Host的Header值 + public String getHost(); + + // 获取请求的URL + public String getRequestURI(); + + // 截取getRequestURI最后的一个/后面的部分 + public String getRequstURILastPath(); + + // 获取请求URL最后的一个/后面的部分的short值
+ // 例如请求URL /pipes/record/query/2
+ // 获取type参数: short type = request.getRequstURILastPath((short)0); //type = 2 + public short getRequstURILastPath(short defvalue); + + // 获取请求URL最后的一个/后面的部分的short值
+ // 例如请求URL /pipes/record/query/2
+ // 获取type参数: short type = request.getRequstURILastPath((short)0); //type = 2 + public short getRequstURILastPath(int radix, short defvalue); + + // 获取请求URL最后的一个/后面的部分的int值
+ // 例如请求URL /pipes/record/query/2
+ // 获取type参数: int type = request.getRequstURILastPath(0); //type = 2 + public int getRequstURILastPath(int defvalue); + + // 获取请求URL最后的一个/后面的部分的int值
+ // 例如请求URL /pipes/record/query/2
+ // 获取type参数: int type = request.getRequstURILastPath(0); //type = 2 + public int getRequstURILastPath(int radix, int defvalue); + + // 获取请求URL最后的一个/后面的部分的float值
+ // 例如请求URL /pipes/record/query/2
+ // 获取type参数: float type = request.getRequstURILastPath(0.f); //type = 2.f + public float getRequstURILastPath(float defvalue); + + // 获取请求URL最后的一个/后面的部分的long值
+ // 例如请求URL /pipes/record/query/2
+ // 获取type参数: long type = request.getRequstURILastPath(0L); //type = 2 + public long getRequstURILastPath(long defvalue); + + // 获取请求URL最后的一个/后面的部分的long值
+ // 例如请求URL /pipes/record/query/2
+ // 获取type参数: long type = request.getRequstURILastPath(0L); //type = 2 + public long getRequstURILastPath(int radix, long defvalue); + + // 获取请求URL最后的一个/后面的部分的double值
+ // 例如请求URL /pipes/record/query/2
+ // 获取type参数: double type = request.getRequstURILastPath(0.0); //type = 2.0 + public double getRequstURILastPath(double defvalue); + + // 从prefix之后截取getRequestURI再对"/"进行分隔 + public String[] getRequstURIPaths(String prefix); + + // 获取请求URL分段中含prefix段的值 + // 例如请求URL /pipes/record/query/name:hello + // 获取name参数: String name = request.getRequstURIPath("name:", "none"); + public String getRequstURIPath(String prefix, String defaultValue); + + // 获取请求URL分段中含prefix段的short值 + // 例如请求URL /pipes/record/query/type:10 + // 获取type参数: short type = request.getRequstURIPath("type:", (short)0); + public short getRequstURIPath(String prefix, short defaultValue); + + // 获取请求URL分段中含prefix段的short值 + // 例如请求URL /pipes/record/query/type:a + // 获取type参数: short type = request.getRequstURIPath(16, "type:", (short)0); type = 10 + public short getRequstURIPath(int radix, String prefix, short defvalue); + + // 获取请求URL分段中含prefix段的int值 + // 例如请求URL /pipes/record/query/offset:2/limit:50 + // 获取offset参数: int offset = request.getRequstURIPath("offset:", 1); + // 获取limit参数: int limit = request.getRequstURIPath("limit:", 20); + public int getRequstURIPath(String prefix, int defaultValue); + + // 获取请求URL分段中含prefix段的int值 + // 例如请求URL /pipes/record/query/offset:2/limit:10 + // 获取offset参数: int offset = request.getRequstURIPath("offset:", 1); + // 获取limit参数: int limit = request.getRequstURIPath(16, "limit:", 20); // limit = 16 + public int getRequstURIPath(int radix, String prefix, int defaultValue); + + // 获取请求URL分段中含prefix段的float值 + // 例如请求URL /pipes/record/query/point:40.0 + // 获取time参数: float point = request.getRequstURIPath("point:", 0.0f); + public float getRequstURIPath(String prefix, float defvalue); + + // 获取请求URL分段中含prefix段的long值 + // 例如请求URL /pipes/record/query/time:1453104341363/id:40 + // 获取time参数: long time = request.getRequstURIPath("time:", 0L); + public long getRequstURIPath(String prefix, long defaultValue); + + // 获取请求URL分段中含prefix段的long值 + // 例如请求URL /pipes/record/query/time:1453104341363/id:40 + // 获取time参数: long time = request.getRequstURIPath("time:", 0L); + public long getRequstURIPath(int radix, String prefix, long defvalue); + + // 获取请求URL分段中含prefix段的double值
+ // 例如请求URL /pipes/record/query/point:40.0
+ // 获取time参数: double point = request.getRequstURIPath("point:", 0.0); + public double getRequstURIPath(String prefix, double defvalue); + + // 获取所有的header名 + public AnyValue getHeaders(); + + // 将请求Header转换成Map + public Map getHeadersToMap(Map map); + + // 获取所有的header名 + public String[] getHeaderNames(); + + // 获取指定的header值 + public String getHeader(String name); + + // 获取指定的header值, 没有返回默认值 + public String getHeader(String name, String defaultValue); + + // 获取指定的header的json值 + public T getJsonHeader(Type type, String name); + + // 获取指定的header的json值 + public T getJsonHeader(JsonConvert convert, Type type, String name); + + // 获取指定的header的boolean值, 没有返回默认boolean值 + public boolean getBooleanHeader(String name, boolean defaultValue); + + // 获取指定的header的short值, 没有返回默认short值 + public short getShortHeader(String name, short defaultValue); + + // 获取指定的header的short值, 没有返回默认short值 + public short getShortHeader(int radix, String name, short defaultValue); + + // 获取指定的header的short值, 没有返回默认short值 + public short getShortHeader(String name, int defaultValue); + + // 获取指定的header的short值, 没有返回默认short值 + public short getShortHeader(int radix, String name, int defaultValue); + + // 获取指定的header的int值, 没有返回默认int值 + public int getIntHeader(String name, int defaultValue); + + // 获取指定的header的int值, 没有返回默认int值 + public int getIntHeader(int radix, String name, int defaultValue); + + // 获取指定的header的long值, 没有返回默认long值 + public long getLongHeader(String name, long defaultValue); + + // 获取指定的header的long值, 没有返回默认long值 + public long getLongHeader(int radix, String name, long defaultValue); + + // 获取指定的header的float值, 没有返回默认float值 + public float getFloatHeader(String name, float defaultValue); + + // 获取指定的header的double值, 没有返回默认double值 + public double getDoubleHeader(String name, double defaultValue); + + // 获取请求参数总对象 + public AnyValue getParameters(); + + // 将请求参数转换成Map + public Map getParametersToMap(Map map); + + // 将请求参数转换成String, 字符串格式为: bean1={}&id=13&name=xxx + // 不会返回null,没有参数返回空字符串 + public String getParametersToString(); + + // 将请求参数转换成String, 字符串格式为: prefix + bean1={}&id=13&name=xxx + // 拼接前缀, 如果无参数,返回的字符串不会含有拼接前缀 + // 不会返回null,没有参数返回空字符串 + public String getParametersToString(String prefix); + + // 获取所有参数名 + public String[] getParameterNames(); + + // 获取指定的参数值 + public String getParameter(String name); + + // 获取指定的参数值, 没有返回默认值 + public String getParameter(String name, String defaultValue); + + // 获取指定的参数json值 + public T getJsonParameter(Type type, String name); + + // 获取指定的参数json值 + public T getJsonParameter(JsonConvert convert, Type type, String name); + + // 获取指定的参数boolean值, 没有返回默认boolean值 + public boolean getBooleanParameter(String name, boolean defaultValue); + + // 获取指定的参数short值, 没有返回默认short值 + public short getShortParameter(String name, short defaultValue); + + // 获取指定的参数short值, 没有返回默认short值 + public short getShortParameter(int radix, String name, short defaultValue); + + // 获取指定的参数short值, 没有返回默认short值 + public short getShortParameter(int radix, String name, int defaultValue); + + // 获取指定的参数int值, 没有返回默认int值 + public int getIntParameter(String name, int defaultValue); + + // 获取指定的参数int值, 没有返回默认int值 + public int getIntParameter(int radix, String name, int defaultValue); + + // 获取指定的参数long值, 没有返回默认long值 + public long getLongParameter(String name, long defaultValue); + + // 获取指定的参数long值, 没有返回默认long值 + public long getLongParameter(int radix, String name, long defaultValue); + + // 获取指定的参数float值, 没有返回默认float值 + public float getFloatParameter(String name, float defaultValue); + + // 获取指定的参数double值, 没有返回默认double值 + public double getDoubleParameter(String name, double defaultValue); + + // 获取翻页对象 同 getFlipper("flipper", false, 0); + public org.redkale.source.Flipper getFlipper(); + + // 获取翻页对象 同 getFlipper("flipper", needcreate, 0); + public org.redkale.source.Flipper getFlipper(boolean needcreate); + + // 获取翻页对象 同 getFlipper("flipper", false, maxLimit); + public org.redkale.source.Flipper getFlipper(int maxLimit); + + // 获取翻页对象 同 getFlipper("flipper", needcreate, maxLimit) + public org.redkale.source.Flipper getFlipper(boolean needcreate, int maxLimit); + + // 获取翻页对象 http://redkale.org/pipes/records/list/offset:0/limit:20/sort:createtime%20ASC + // http://redkale.org/pipes/records/list?flipper={'offset':0,'limit':20, 'sort':'createtime ASC'} + // 以上两种接口都可以获取到翻页对象 + public org.redkale.source.Flipper getFlipper(String name, boolean needcreate, int maxLimit); + + // 获取HTTP上下文对象 + public HttpContext getContext(); + + // 获取所有属性值, servlet执行完后会被清空 + public Map getAttributes(); + + // 获取指定属性值, servlet执行完后会被清空 + public T getAttribute(String name); + + // 删除指定属性 + public void removeAttribute(String name); + + // 设置属性值, servlet执行完后会被清空 + public void setAttribute(String name, Object value); + + // 获取request创建时间 + public long getCreatetime(); +} diff --git a/src/test/java/org/redkale/test/http/HttpResponseDesc.java b/src/test/java/org/redkale/test/http/HttpResponseDesc.java index e1088f9e1..8e59282f6 100644 --- a/src/test/java/org/redkale/test/http/HttpResponseDesc.java +++ b/src/test/java/org/redkale/test/http/HttpResponseDesc.java @@ -1,171 +1,171 @@ -/* - * 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.test.http; - -import java.io.*; -import java.lang.reflect.*; -import java.net.*; -import java.nio.*; -import java.nio.channels.CompletionHandler; -import java.util.*; -import java.util.concurrent.CompletableFuture; -import java.util.function.*; -import org.redkale.convert.Convert; -import org.redkale.convert.json.*; -import org.redkale.net.http.*; - -/** @author zhangjx */ -public interface HttpResponseDesc { - - // 增加Cookie值 - public HttpResponse addCookie(HttpCookie... cookies); - - // 增加Cookie值 - public HttpResponse addCookie(Collection cookies); - - // 创建CompletionHandler实例,将非字符串对象以JSON格式输出,字符串以文本输出 - public CompletionHandler createAsyncHandler(); - - // 传入的CompletionHandler子类必须是public,且保证其子类可被继承且completed、failed可被重载且包含空参数的构造函数 - public H createAsyncHandler(Class handlerClass); - - // 获取ByteBuffer生成器 - public Supplier getBufferSupplier(); - - // 设置状态码 - public void setStatus(int status); - - // 获取状态码 - public int getStatus(); - - // 获取 ContentType - public String getContentType(); - - // 设置 ContentType - public HttpResponse setContentType(String contentType); - - // 获取内容长度 - public long getContentLength(); - - // 设置内容长度 - public HttpResponse setContentLength(long contentLength); - - // 设置Header值 - public HttpResponse setHeader(String name, Object value); - - // 添加Header值 - public HttpResponse addHeader(String name, Object value); - - // 添加Header值 - public HttpResponse addHeader(Map map); - - // 跳过header的输出 - // 通常应用场景是,调用者的输出内容里已经包含了HTTP的响应头信息,因此需要调用此方法避免重复输出HTTP响应头信息。 - public HttpResponse skipHeader(); - - // 异步输出指定内容 - public void sendBody(ByteBuffer buffer, A attachment, CompletionHandler handler); - - // 异步输出指定内容 - public void sendBody(ByteBuffer[] buffers, A attachment, CompletionHandler handler); - - // 关闭HTTP连接,如果是keep-alive则不强制关闭 - public void finish(); - - // 强制关闭HTTP连接 - public void finish(boolean kill); - - // 将对象以JSON格式输出 - public void finishJson(Object obj); - - // 将对象数组用Map的形式以JSON格式输出 - // 例如: finishMap("a",2,"b",3) 输出结果为 {"a":2,"b":3} - public void finishMapJson(final Object... objs); - - // 将对象以JSON格式输出 - public void finishJson(JsonConvert convert, Object obj); - - // 将对象数组用Map的形式以JSON格式输出 - // 例如: finishMap("a",2,"b",3) 输出结果为 {"a":2,"b":3} - public void finishMapJson(final JsonConvert convert, final Object... objs); - - // 将对象以JSON格式输出 - public void finishJson(Type type, Object obj); - - // 将对象以JSON格式输出 - public void finishJson(final JsonConvert convert, final Type type, final Object obj); - - // 将对象以JSON格式输出 - public void finishJson(final Object... objs); - - // 将RetResult对象以JSON格式输出 - public void finishJson(final org.redkale.service.RetResult ret); - - // 将RetResult对象以JSON格式输出 - public void finishJson(final JsonConvert convert, final org.redkale.service.RetResult ret); - - // 将CompletableFuture的结果对象以JSON格式输出 - public void finishJson(final CompletableFuture future); - - // 将CompletableFuture的结果对象以JSON格式输出 - public void finishJson(final JsonConvert convert, final CompletableFuture future); - - // 将CompletableFuture的结果对象以JSON格式输出 - public void finishJson(final JsonConvert convert, final Type type, final CompletableFuture future); - - // 将HttpResult的结果对象以JSON格式输出 - public void finishJson(final HttpResult result); - - // 将HttpResult的结果对象以JSON格式输出 - public void finishJson(final JsonConvert convert, final HttpResult result); - - // 将指定字符串以响应结果输出 - public void finish(String obj); - - // 以指定响应码附带内容输出, message 可以为null - public void finish(int status, String message); - - // 将结果对象输出 - public void finish(final Object obj); - - // 将结果对象输出 - public void finish(final Convert convert, final Object obj); - - // 将结果对象输出 - public void finish(final Convert convert, final Type type, final Object obj); - - // 以304状态码输出 - public void finish304(); - - // 以404状态码输出 - public void finish404(); - - // 将指定byte[]按响应结果输出 - public void finish(final byte[] bs); - - // 将指定ByteBuffer按响应结果输出 - public void finish(ByteBuffer buffer); - - // 将指定ByteBuffer按响应结果输出 - // kill 输出后是否强制关闭连接 - public void finish(boolean kill, ByteBuffer buffer); - - // 将指定ByteBuffer数组按响应结果输出 - public void finish(ByteBuffer... buffers); - - // 将指定ByteBuffer数组按响应结果输出 - // kill 输出后是否强制关闭连接 - public void finish(boolean kill, ByteBuffer... buffers); - - // 将指定文件按响应结果输出 - public void finish(File file) throws IOException; - - // 将文件按指定文件名输出 - public void finish(final String filename, File file) throws IOException; - - // HttpResponse回收时回调的监听方法 - public void recycleListener(BiConsumer recycleListener); -} +/* + * 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.test.http; + +import java.io.*; +import java.lang.reflect.*; +import java.net.*; +import java.nio.*; +import java.nio.channels.CompletionHandler; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.function.*; +import org.redkale.convert.Convert; +import org.redkale.convert.json.*; +import org.redkale.net.http.*; + +/** @author zhangjx */ +public interface HttpResponseDesc { + + // 增加Cookie值 + public HttpResponse addCookie(HttpCookie... cookies); + + // 增加Cookie值 + public HttpResponse addCookie(Collection cookies); + + // 创建CompletionHandler实例,将非字符串对象以JSON格式输出,字符串以文本输出 + public CompletionHandler createAsyncHandler(); + + // 传入的CompletionHandler子类必须是public,且保证其子类可被继承且completed、failed可被重载且包含空参数的构造函数 + public H createAsyncHandler(Class handlerClass); + + // 获取ByteBuffer生成器 + public Supplier getBufferSupplier(); + + // 设置状态码 + public void setStatus(int status); + + // 获取状态码 + public int getStatus(); + + // 获取 ContentType + public String getContentType(); + + // 设置 ContentType + public HttpResponse setContentType(String contentType); + + // 获取内容长度 + public long getContentLength(); + + // 设置内容长度 + public HttpResponse setContentLength(long contentLength); + + // 设置Header值 + public HttpResponse setHeader(String name, Object value); + + // 添加Header值 + public HttpResponse addHeader(String name, Object value); + + // 添加Header值 + public HttpResponse addHeader(Map map); + + // 跳过header的输出 + // 通常应用场景是,调用者的输出内容里已经包含了HTTP的响应头信息,因此需要调用此方法避免重复输出HTTP响应头信息。 + public HttpResponse skipHeader(); + + // 异步输出指定内容 + public void sendBody(ByteBuffer buffer, A attachment, CompletionHandler handler); + + // 异步输出指定内容 + public void sendBody(ByteBuffer[] buffers, A attachment, CompletionHandler handler); + + // 关闭HTTP连接,如果是keep-alive则不强制关闭 + public void finish(); + + // 强制关闭HTTP连接 + public void finish(boolean kill); + + // 将对象以JSON格式输出 + public void finishJson(Object obj); + + // 将对象数组用Map的形式以JSON格式输出 + // 例如: finishMap("a",2,"b",3) 输出结果为 {"a":2,"b":3} + public void finishMapJson(final Object... objs); + + // 将对象以JSON格式输出 + public void finishJson(JsonConvert convert, Object obj); + + // 将对象数组用Map的形式以JSON格式输出 + // 例如: finishMap("a",2,"b",3) 输出结果为 {"a":2,"b":3} + public void finishMapJson(final JsonConvert convert, final Object... objs); + + // 将对象以JSON格式输出 + public void finishJson(Type type, Object obj); + + // 将对象以JSON格式输出 + public void finishJson(final JsonConvert convert, final Type type, final Object obj); + + // 将对象以JSON格式输出 + public void finishJson(final Object... objs); + + // 将RetResult对象以JSON格式输出 + public void finishJson(final org.redkale.service.RetResult ret); + + // 将RetResult对象以JSON格式输出 + public void finishJson(final JsonConvert convert, final org.redkale.service.RetResult ret); + + // 将CompletableFuture的结果对象以JSON格式输出 + public void finishJson(final CompletableFuture future); + + // 将CompletableFuture的结果对象以JSON格式输出 + public void finishJson(final JsonConvert convert, final CompletableFuture future); + + // 将CompletableFuture的结果对象以JSON格式输出 + public void finishJson(final JsonConvert convert, final Type type, final CompletableFuture future); + + // 将HttpResult的结果对象以JSON格式输出 + public void finishJson(final HttpResult result); + + // 将HttpResult的结果对象以JSON格式输出 + public void finishJson(final JsonConvert convert, final HttpResult result); + + // 将指定字符串以响应结果输出 + public void finish(String obj); + + // 以指定响应码附带内容输出, message 可以为null + public void finish(int status, String message); + + // 将结果对象输出 + public void finish(final Object obj); + + // 将结果对象输出 + public void finish(final Convert convert, final Object obj); + + // 将结果对象输出 + public void finish(final Convert convert, final Type type, final Object obj); + + // 以304状态码输出 + public void finish304(); + + // 以404状态码输出 + public void finish404(); + + // 将指定byte[]按响应结果输出 + public void finish(final byte[] bs); + + // 将指定ByteBuffer按响应结果输出 + public void finish(ByteBuffer buffer); + + // 将指定ByteBuffer按响应结果输出 + // kill 输出后是否强制关闭连接 + public void finish(boolean kill, ByteBuffer buffer); + + // 将指定ByteBuffer数组按响应结果输出 + public void finish(ByteBuffer... buffers); + + // 将指定ByteBuffer数组按响应结果输出 + // kill 输出后是否强制关闭连接 + public void finish(boolean kill, ByteBuffer... buffers); + + // 将指定文件按响应结果输出 + public void finish(File file) throws IOException; + + // 将文件按指定文件名输出 + public void finish(final String filename, File file) throws IOException; + + // HttpResponse回收时回调的监听方法 + public void recycleListener(BiConsumer recycleListener); +} diff --git a/src/test/java/org/redkale/test/http/HttpSimpleClientTest.java b/src/test/java/org/redkale/test/http/HttpSimpleClientTest.java index 4ba02cb66..b44b0299e 100644 --- a/src/test/java/org/redkale/test/http/HttpSimpleClientTest.java +++ b/src/test/java/org/redkale/test/http/HttpSimpleClientTest.java @@ -1,116 +1,116 @@ -/* - * - */ -package org.redkale.test.http; - -import java.net.InetSocketAddress; -import java.util.concurrent.CountDownLatch; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import org.redkale.boot.Application; -import org.redkale.inject.ResourceFactory; -import org.redkale.net.AsyncIOGroup; -import org.redkale.net.http.HttpServer; -import org.redkale.net.http.WebClient; -import org.redkale.net.http.WebRequest; -import org.redkale.util.AnyValueWriter; - -/** @author zhangjx */ -public class HttpSimpleClientTest { - - private static int port = 0; - - private static Application application; - - private static ResourceFactory factory; - - private static HttpServer server; - - private boolean main; - - public static void main(String[] args) throws Throwable { - HttpSimpleClientTest test = new HttpSimpleClientTest(); - test.main = true; - test.run(); - } - - @Test - public void run() throws Exception { - runServer(); - // Utility.sleep(50000); - final AsyncIOGroup asyncGroup = new AsyncIOGroup(8192, 16); - asyncGroup.start(); - WebClient client = WebClient.create(asyncGroup); - InetSocketAddress addr = new InetSocketAddress("127.0.0.1", port); - { - WebRequest req = WebRequest.createPostPath("/test").param("id", 100); - System.out.println(client.getAsync("http://127.0.0.1:" + port + req.getPath() + "?id=100") - .join()); - System.out.println(client.sendAsync(addr, req).join()); - } - final int count = 10; - { - final CountDownLatch cdl = new CountDownLatch(count); - for (int i = 100; i < 100 + count; i++) { - final int index = i; - WebRequest req = WebRequest.createPostPath("/test").param("id", index); - client.getAsync("http://127.0.0.1:" + port + req.getPath() + "?id=" + index) - .whenComplete((v, t) -> { - cdl.countDown(); - Assertions.assertEquals("ok-" + index, new String((byte[]) v.getResult())); - }); - } - cdl.await(); - System.out.println("结束并发1"); - } - { - final CountDownLatch cdl = new CountDownLatch(count); - for (int i = 100; i < 100 + count; i++) { - final int index = i; - WebRequest req = WebRequest.createPostPath("/test").param("id", index); - client.sendAsync(addr, req).whenComplete((v, t) -> { - cdl.countDown(); - System.out.println("输出: " + new String((byte[]) v.getResult())); - Assertions.assertEquals("ok-" + index, new String((byte[]) v.getResult())); - }); - } - cdl.await(); - System.out.println("结束并发2"); - } - server.shutdown(); - } - - private static void runServer() throws Exception { - application = Application.create(true); - factory = application.getResourceFactory(); - factory.register("", Application.class, application); - final CountDownLatch cdl = new CountDownLatch(1); - final AsyncIOGroup asyncGroup = new AsyncIOGroup(8192, 16); - asyncGroup.start(); - new Thread() { - { - setName("Thread-Server-01"); - } - - @Override - public void run() { - try { - AnyValueWriter conf = new AnyValueWriter(); - conf.addValue("host", "0.0.0.0"); - conf.addValue("port", "" + port); - conf.addValue("protocol", "HTTP"); - conf.addValue("maxbody", "" + (100 * 1024 * 1024)); - server = new HttpServer(factory); - server.init(conf); - server.addHttpServlet(new HttpSimpleServlet(), "/test"); - server.start(); - port = server.getSocketAddress().getPort(); - cdl.countDown(); - } catch (Exception e) { - e.printStackTrace(); - } - } - }.start(); - cdl.await(); - } -} +/* + * + */ +package org.redkale.test.http; + +import java.net.InetSocketAddress; +import java.util.concurrent.CountDownLatch; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.redkale.boot.Application; +import org.redkale.inject.ResourceFactory; +import org.redkale.net.AsyncIOGroup; +import org.redkale.net.http.HttpServer; +import org.redkale.net.http.WebClient; +import org.redkale.net.http.WebRequest; +import org.redkale.util.AnyValueWriter; + +/** @author zhangjx */ +public class HttpSimpleClientTest { + + private static int port = 0; + + private static Application application; + + private static ResourceFactory factory; + + private static HttpServer server; + + private boolean main; + + public static void main(String[] args) throws Throwable { + HttpSimpleClientTest test = new HttpSimpleClientTest(); + test.main = true; + test.run(); + } + + @Test + public void run() throws Exception { + runServer(); + // Utility.sleep(50000); + final AsyncIOGroup asyncGroup = new AsyncIOGroup(8192, 16); + asyncGroup.start(); + WebClient client = WebClient.create(asyncGroup); + InetSocketAddress addr = new InetSocketAddress("127.0.0.1", port); + { + WebRequest req = WebRequest.createPostPath("/test").param("id", 100); + System.out.println(client.getAsync("http://127.0.0.1:" + port + req.getPath() + "?id=100") + .join()); + System.out.println(client.sendAsync(addr, req).join()); + } + final int count = 10; + { + final CountDownLatch cdl = new CountDownLatch(count); + for (int i = 100; i < 100 + count; i++) { + final int index = i; + WebRequest req = WebRequest.createPostPath("/test").param("id", index); + client.getAsync("http://127.0.0.1:" + port + req.getPath() + "?id=" + index) + .whenComplete((v, t) -> { + cdl.countDown(); + Assertions.assertEquals("ok-" + index, new String((byte[]) v.getResult())); + }); + } + cdl.await(); + System.out.println("结束并发1"); + } + { + final CountDownLatch cdl = new CountDownLatch(count); + for (int i = 100; i < 100 + count; i++) { + final int index = i; + WebRequest req = WebRequest.createPostPath("/test").param("id", index); + client.sendAsync(addr, req).whenComplete((v, t) -> { + cdl.countDown(); + System.out.println("输出: " + new String((byte[]) v.getResult())); + Assertions.assertEquals("ok-" + index, new String((byte[]) v.getResult())); + }); + } + cdl.await(); + System.out.println("结束并发2"); + } + server.shutdown(); + } + + private static void runServer() throws Exception { + application = Application.create(true); + factory = application.getResourceFactory(); + factory.register("", Application.class, application); + final CountDownLatch cdl = new CountDownLatch(1); + final AsyncIOGroup asyncGroup = new AsyncIOGroup(8192, 16); + asyncGroup.start(); + new Thread() { + { + setName("Thread-Server-01"); + } + + @Override + public void run() { + try { + AnyValueWriter conf = new AnyValueWriter(); + conf.addValue("host", "0.0.0.0"); + conf.addValue("port", "" + port); + conf.addValue("protocol", "HTTP"); + conf.addValue("maxbody", "" + (100 * 1024 * 1024)); + server = new HttpServer(factory); + server.init(conf); + server.addHttpServlet(new HttpSimpleServlet(), "/test"); + server.start(); + port = server.getSocketAddress().getPort(); + cdl.countDown(); + } catch (Exception e) { + e.printStackTrace(); + } + } + }.start(); + cdl.await(); + } +} diff --git a/src/test/java/org/redkale/test/http/HttpSimpleServlet.java b/src/test/java/org/redkale/test/http/HttpSimpleServlet.java index ad2a7bd3e..58d05f671 100644 --- a/src/test/java/org/redkale/test/http/HttpSimpleServlet.java +++ b/src/test/java/org/redkale/test/http/HttpSimpleServlet.java @@ -1,20 +1,20 @@ -/* - * - */ -package org.redkale.test.http; - -import java.io.IOException; -import org.redkale.net.http.HttpMapping; -import org.redkale.net.http.HttpRequest; -import org.redkale.net.http.HttpResponse; -import org.redkale.net.http.HttpServlet; - -/** @author zhangjx */ -public class HttpSimpleServlet extends HttpServlet { - - @HttpMapping(url = "/test") - public void test(HttpRequest req, HttpResponse resp) throws IOException { - System.out.println("运行到test方法了, id=" + req.getParameter("id")); - resp.finish("ok-" + req.getParameter("id", "0")); - } -} +/* + * + */ +package org.redkale.test.http; + +import java.io.IOException; +import org.redkale.net.http.HttpMapping; +import org.redkale.net.http.HttpRequest; +import org.redkale.net.http.HttpResponse; +import org.redkale.net.http.HttpServlet; + +/** @author zhangjx */ +public class HttpSimpleServlet extends HttpServlet { + + @HttpMapping(url = "/test") + public void test(HttpRequest req, HttpResponse resp) throws IOException { + System.out.println("运行到test方法了, id=" + req.getParameter("id")); + resp.finish("ok-" + req.getParameter("id", "0")); + } +} diff --git a/src/test/java/org/redkale/test/http/RequestCoderTest.java b/src/test/java/org/redkale/test/http/RequestCoderTest.java index 582e83b45..8d21527b7 100644 --- a/src/test/java/org/redkale/test/http/RequestCoderTest.java +++ b/src/test/java/org/redkale/test/http/RequestCoderTest.java @@ -1,70 +1,70 @@ -/* - * - */ -package org.redkale.test.http; - -import java.lang.reflect.Field; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import org.redkale.mq.spi.WebRequestCoder; -import org.redkale.net.client.ClientRequest; -import org.redkale.net.http.WebRequest; - -/** @author zhangjx */ -public class RequestCoderTest { - - private boolean main; - - public static void main(String[] args) throws Throwable { - RequestCoderTest test = new RequestCoderTest(); - test.main = true; - test.run1(); - test.run2(); - test.run3(); - } - - @Test - public void run1() throws Exception { - WebRequest req1 = WebRequest.createPostPath("/aaa"); - System.out.println("simpleRequest1: " + req1); - byte[] bytes = WebRequestCoder.getInstance().encode(req1); - WebRequest req2 = WebRequestCoder.getInstance().decode(bytes); - Field timeFiedl = ClientRequest.class.getDeclaredField("createTime"); - timeFiedl.setAccessible(true); - timeFiedl.set(req2, req1.getCreateTime()); - System.out.println("simpleRequest2: " + req2); - Assertions.assertEquals(req1.toString(), req2.toString()); - } - - @Test - public void run2() throws Exception { - WebRequest req1 = WebRequest.createPostPath("/aaa"); - req1.addHeader("X-aaa", "aaa"); - req1.param("bean", "{}"); - System.out.println("simpleRequest1: " + req1); - byte[] bytes = WebRequestCoder.getInstance().encode(req1); - WebRequest req2 = WebRequestCoder.getInstance().decode(bytes); - Field timeFiedl = ClientRequest.class.getDeclaredField("createTime"); - timeFiedl.setAccessible(true); - timeFiedl.set(req2, req1.getCreateTime()); - System.out.println("simpleRequest2: " + req2); - Assertions.assertEquals(req1.toString(), req2.toString()); - } - - @Test - public void run3() throws Exception { - WebRequest req1 = WebRequest.createPostPath("/aaa"); - req1.addHeader("X-aaa", "aaa"); - req1.addHeader("X-bbb", "bbb1"); - req1.addHeader("X-bbb", "bbb2"); - req1.param("bean", "{}"); - System.out.println("simpleRequest1: " + req1); - byte[] bytes = WebRequestCoder.getInstance().encode(req1); - WebRequest req2 = WebRequestCoder.getInstance().decode(bytes); - Field timeFiedl = ClientRequest.class.getDeclaredField("createTime"); - timeFiedl.setAccessible(true); - timeFiedl.set(req2, req1.getCreateTime()); - System.out.println("simpleRequest2: " + req2); - Assertions.assertEquals(req1.toString(), req2.toString()); - } -} +/* + * + */ +package org.redkale.test.http; + +import java.lang.reflect.Field; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.redkale.mq.spi.WebRequestCoder; +import org.redkale.net.client.ClientRequest; +import org.redkale.net.http.WebRequest; + +/** @author zhangjx */ +public class RequestCoderTest { + + private boolean main; + + public static void main(String[] args) throws Throwable { + RequestCoderTest test = new RequestCoderTest(); + test.main = true; + test.run1(); + test.run2(); + test.run3(); + } + + @Test + public void run1() throws Exception { + WebRequest req1 = WebRequest.createPostPath("/aaa"); + System.out.println("simpleRequest1: " + req1); + byte[] bytes = WebRequestCoder.getInstance().encode(req1); + WebRequest req2 = WebRequestCoder.getInstance().decode(bytes); + Field timeFiedl = ClientRequest.class.getDeclaredField("createTime"); + timeFiedl.setAccessible(true); + timeFiedl.set(req2, req1.getCreateTime()); + System.out.println("simpleRequest2: " + req2); + Assertions.assertEquals(req1.toString(), req2.toString()); + } + + @Test + public void run2() throws Exception { + WebRequest req1 = WebRequest.createPostPath("/aaa"); + req1.addHeader("X-aaa", "aaa"); + req1.param("bean", "{}"); + System.out.println("simpleRequest1: " + req1); + byte[] bytes = WebRequestCoder.getInstance().encode(req1); + WebRequest req2 = WebRequestCoder.getInstance().decode(bytes); + Field timeFiedl = ClientRequest.class.getDeclaredField("createTime"); + timeFiedl.setAccessible(true); + timeFiedl.set(req2, req1.getCreateTime()); + System.out.println("simpleRequest2: " + req2); + Assertions.assertEquals(req1.toString(), req2.toString()); + } + + @Test + public void run3() throws Exception { + WebRequest req1 = WebRequest.createPostPath("/aaa"); + req1.addHeader("X-aaa", "aaa"); + req1.addHeader("X-bbb", "bbb1"); + req1.addHeader("X-bbb", "bbb2"); + req1.param("bean", "{}"); + System.out.println("simpleRequest1: " + req1); + byte[] bytes = WebRequestCoder.getInstance().encode(req1); + WebRequest req2 = WebRequestCoder.getInstance().decode(bytes); + Field timeFiedl = ClientRequest.class.getDeclaredField("createTime"); + timeFiedl.setAccessible(true); + timeFiedl.set(req2, req1.getCreateTime()); + System.out.println("simpleRequest2: " + req2); + Assertions.assertEquals(req1.toString(), req2.toString()); + } +} diff --git a/src/test/java/org/redkale/test/http/RestSleepService.java b/src/test/java/org/redkale/test/http/RestSleepService.java index 5fa03a6e3..34da01de2 100644 --- a/src/test/java/org/redkale/test/http/RestSleepService.java +++ b/src/test/java/org/redkale/test/http/RestSleepService.java @@ -1,34 +1,34 @@ -/* - * - */ -package org.redkale.test.http; - -import org.redkale.net.http.RestService; -import org.redkale.service.AbstractService; -import org.redkale.util.Utility; - -/** @author zhangjx */ -@RestService(name = "test", autoMapping = true) -public class RestSleepService extends AbstractService { - - public String sleep200() { - Utility.sleep(200); - System.out.println("当前执行线程: " + Thread.currentThread().getName()); - return "ok200"; - } - - public String sleep300() { - Utility.sleep(300); - return "ok300"; - } - - public String sleep400() { - Utility.sleep(400); - return "ok400"; - } - - public String sleep500() { - Utility.sleep(500); - return "ok500"; - } -} +/* + * + */ +package org.redkale.test.http; + +import org.redkale.net.http.RestService; +import org.redkale.service.AbstractService; +import org.redkale.util.Utility; + +/** @author zhangjx */ +@RestService(name = "test", autoMapping = true) +public class RestSleepService extends AbstractService { + + public String sleep200() { + Utility.sleep(200); + System.out.println("当前执行线程: " + Thread.currentThread().getName()); + return "ok200"; + } + + public String sleep300() { + Utility.sleep(300); + return "ok300"; + } + + public String sleep400() { + Utility.sleep(400); + return "ok400"; + } + + public String sleep500() { + Utility.sleep(500); + return "ok500"; + } +} diff --git a/src/test/java/org/redkale/test/http/RestSleepTest.java b/src/test/java/org/redkale/test/http/RestSleepTest.java index 04c60830f..5f074b0fe 100644 --- a/src/test/java/org/redkale/test/http/RestSleepTest.java +++ b/src/test/java/org/redkale/test/http/RestSleepTest.java @@ -1,72 +1,72 @@ -/* - * - */ -package org.redkale.test.http; - -import java.io.*; -import java.net.*; -import org.junit.jupiter.api.*; -import org.redkale.boot.Application; -import org.redkale.convert.bson.BsonConvert; -import org.redkale.convert.json.JsonConvert; -import org.redkale.inject.ResourceFactory; -import org.redkale.net.AsyncIOGroup; -import org.redkale.net.http.*; -import org.redkale.net.sncp.Sncp; -import org.redkale.util.*; - -/** @author zhangjx */ -public class RestSleepTest { - - private boolean main; - - public static void main(String[] args) throws Throwable { - RestSleepTest test = new RestSleepTest(); - test.main = true; - test.run(); - } - - @Test - public void run() throws Exception { - System.out.println("------------------- 并发调用 -----------------------------------"); - final Application application = Application.create(true); - final AsyncIOGroup asyncGroup = new AsyncIOGroup(8192, 16); - asyncGroup.start(); - final ResourceFactory resFactory = ResourceFactory.create(); - resFactory.register(JsonConvert.root()); - resFactory.register(BsonConvert.root()); - - // ------------------------ 初始化 CService ------------------------------------ - RestSleepService service = Sncp.createSimpleLocalService(RestSleepService.class, resFactory); - HttpServer server = new HttpServer(application, System.currentTimeMillis(), resFactory); - server.getResourceFactory().register(application); - System.out.println("servlet = " + server.addRestServlet(null, service, null, HttpServlet.class, "")); - server.init(AnyValueWriter.create("port", 0)); - server.start(); - - int port = server.getSocketAddress().getPort(); - System.out.println("服务器启动端口: " + port); - InetSocketAddress httpAddress = new InetSocketAddress("127.0.0.1", port); - Socket socket = new Socket(httpAddress.getAddress(), port); - OutputStream out = socket.getOutputStream(); - out.write(("GET /test/sleep200 HTTP/1.1\r\n" - + "Connection: Keep-Alive\r\n" - + "\r\n" - + "GET /test/sleep300 HTTP/1.1\r\n" - + "Connection: Keep-Alive\r\n" - + "\r\n" - + "GET /test/sleep500 HTTP/1.1\r\n" - + "Connection: Keep-Alive\r\n" - + "\r\n") - .getBytes()); - InputStream in = socket.getInputStream(); - byte[] bytes = new byte[8192]; - long s = System.currentTimeMillis(); - int pos = in.read(bytes); - long e = System.currentTimeMillis() - s; - System.out.println("返回结果: " + new String(bytes, 0, pos)); - System.out.println("耗时: " + e + " ms"); - server.shutdown(); - Assertions.assertTrue(e < 600); - } -} +/* + * + */ +package org.redkale.test.http; + +import java.io.*; +import java.net.*; +import org.junit.jupiter.api.*; +import org.redkale.boot.Application; +import org.redkale.convert.bson.BsonConvert; +import org.redkale.convert.json.JsonConvert; +import org.redkale.inject.ResourceFactory; +import org.redkale.net.AsyncIOGroup; +import org.redkale.net.http.*; +import org.redkale.net.sncp.Sncp; +import org.redkale.util.*; + +/** @author zhangjx */ +public class RestSleepTest { + + private boolean main; + + public static void main(String[] args) throws Throwable { + RestSleepTest test = new RestSleepTest(); + test.main = true; + test.run(); + } + + @Test + public void run() throws Exception { + System.out.println("------------------- 并发调用 -----------------------------------"); + final Application application = Application.create(true); + final AsyncIOGroup asyncGroup = new AsyncIOGroup(8192, 16); + asyncGroup.start(); + final ResourceFactory resFactory = ResourceFactory.create(); + resFactory.register(JsonConvert.root()); + resFactory.register(BsonConvert.root()); + + // ------------------------ 初始化 CService ------------------------------------ + RestSleepService service = Sncp.createSimpleLocalService(RestSleepService.class, resFactory); + HttpServer server = new HttpServer(application, System.currentTimeMillis(), resFactory); + server.getResourceFactory().register(application); + System.out.println("servlet = " + server.addRestServlet(null, service, null, HttpServlet.class, "")); + server.init(AnyValueWriter.create("port", 0)); + server.start(); + + int port = server.getSocketAddress().getPort(); + System.out.println("服务器启动端口: " + port); + InetSocketAddress httpAddress = new InetSocketAddress("127.0.0.1", port); + Socket socket = new Socket(httpAddress.getAddress(), port); + OutputStream out = socket.getOutputStream(); + out.write(("GET /test/sleep200 HTTP/1.1\r\n" + + "Connection: Keep-Alive\r\n" + + "\r\n" + + "GET /test/sleep300 HTTP/1.1\r\n" + + "Connection: Keep-Alive\r\n" + + "\r\n" + + "GET /test/sleep500 HTTP/1.1\r\n" + + "Connection: Keep-Alive\r\n" + + "\r\n") + .getBytes()); + InputStream in = socket.getInputStream(); + byte[] bytes = new byte[8192]; + long s = System.currentTimeMillis(); + int pos = in.read(bytes); + long e = System.currentTimeMillis() - s; + System.out.println("返回结果: " + new String(bytes, 0, pos)); + System.out.println("耗时: " + e + " ms"); + server.shutdown(); + Assertions.assertTrue(e < 600); + } +} diff --git a/src/test/java/org/redkale/test/http/SocketMain.java b/src/test/java/org/redkale/test/http/SocketMain.java index ad34ca097..ced7a624c 100644 --- a/src/test/java/org/redkale/test/http/SocketMain.java +++ b/src/test/java/org/redkale/test/http/SocketMain.java @@ -1,36 +1,36 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package org.redkale.test.http; - -import java.net.Socket; - -/** @author zhangjx */ -public class SocketMain { - - public static void main(String[] args) throws Throwable { - Socket socket = new Socket("127.0.0.1", 6060); - socket.getOutputStream() - .write( - "GET /json1 HTTP/1.1\r\nAccpet: aaa\r\nConnection: keep-alive\r\n\r\nGET /json2 HTTP/1.1\r\nAccpet: a" - .getBytes()); - socket.getOutputStream().flush(); - Thread.sleep(1000); - socket.getOutputStream().write("aa\r\nConnection: keep-alive\r\n\r".getBytes()); - socket.getOutputStream().flush(); - Thread.sleep(1000); - socket.getOutputStream() - .write("\nGET /json3 HTTP/1.1\r\nAccpet: aaa\r\nConnection: keep-alive\r\n\r".getBytes()); - socket.getOutputStream().flush(); - Thread.sleep(1000); - socket.getOutputStream().write("\n".getBytes()); - socket.getOutputStream().flush(); - byte[] bs = new byte[10240]; - int rs = socket.getInputStream().read(bs); - System.out.println(new String(bs, 0, rs)); - rs = socket.getInputStream().read(bs); - System.out.println(new String(bs, 0, rs)); - } -} +/* + * 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.test.http; + +import java.net.Socket; + +/** @author zhangjx */ +public class SocketMain { + + public static void main(String[] args) throws Throwable { + Socket socket = new Socket("127.0.0.1", 6060); + socket.getOutputStream() + .write( + "GET /json1 HTTP/1.1\r\nAccpet: aaa\r\nConnection: keep-alive\r\n\r\nGET /json2 HTTP/1.1\r\nAccpet: a" + .getBytes()); + socket.getOutputStream().flush(); + Thread.sleep(1000); + socket.getOutputStream().write("aa\r\nConnection: keep-alive\r\n\r".getBytes()); + socket.getOutputStream().flush(); + Thread.sleep(1000); + socket.getOutputStream() + .write("\nGET /json3 HTTP/1.1\r\nAccpet: aaa\r\nConnection: keep-alive\r\n\r".getBytes()); + socket.getOutputStream().flush(); + Thread.sleep(1000); + socket.getOutputStream().write("\n".getBytes()); + socket.getOutputStream().flush(); + byte[] bs = new byte[10240]; + int rs = socket.getInputStream().read(bs); + System.out.println(new String(bs, 0, rs)); + rs = socket.getInputStream().read(bs); + System.out.println(new String(bs, 0, rs)); + } +} diff --git a/src/test/java/org/redkale/test/http/UploadTestServlet.java b/src/test/java/org/redkale/test/http/UploadTestServlet.java index 98aa5ecef..ddcb1cd3a 100644 --- a/src/test/java/org/redkale/test/http/UploadTestServlet.java +++ b/src/test/java/org/redkale/test/http/UploadTestServlet.java @@ -1,43 +1,43 @@ -/* - * 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.test.http; - -import java.io.IOException; -import org.redkale.net.http.*; - -/** @author zhangjx */ -// @WebServlet({"/uploadtest/form", "/uploadtest/send"}) -public class UploadTestServlet extends HttpServlet { - - @Override - public void execute(HttpRequest request, HttpResponse response) throws IOException { - if (request.getRequestPath().contains("/uploadtest/send")) { - send(request, response); - } else { - form(request, response); - } - } - - public void form(HttpRequest req, HttpResponse resp) throws IOException { - resp.setContentType("text/html"); - resp.finish("" - + "

" - + ""); - } - - public void send(HttpRequest req, HttpResponse resp) throws IOException { - for (MultiPart entry : req.multiParts()) { - entry.skip(); - System.out.println(entry); - } - System.exit(0); - } -} +/* + * 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.test.http; + +import java.io.IOException; +import org.redkale.net.http.*; + +/** @author zhangjx */ +// @WebServlet({"/uploadtest/form", "/uploadtest/send"}) +public class UploadTestServlet extends HttpServlet { + + @Override + public void execute(HttpRequest request, HttpResponse response) throws IOException { + if (request.getRequestPath().contains("/uploadtest/send")) { + send(request, response); + } else { + form(request, response); + } + } + + public void form(HttpRequest req, HttpResponse resp) throws IOException { + resp.setContentType("text/html"); + resp.finish("" + + "
" + + "描述:         文件1:

" + + "描述:         文件2:

" + + "描述:         文件3:

" + + "描述:         

" + + "              
" + + ""); + } + + public void send(HttpRequest req, HttpResponse resp) throws IOException { + for (MultiPart entry : req.multiParts()) { + entry.skip(); + System.out.println(entry); + } + System.exit(0); + } +} diff --git a/src/test/java/org/redkale/test/http/WebSocketDesc.java b/src/test/java/org/redkale/test/http/WebSocketDesc.java index 0fd2f0859..4ced57269 100644 --- a/src/test/java/org/redkale/test/http/WebSocketDesc.java +++ b/src/test/java/org/redkale/test/http/WebSocketDesc.java @@ -1,198 +1,198 @@ -/* - * 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.test.http; - -import java.io.*; -import java.net.*; -import java.nio.ByteBuffer; -import java.util.*; -import java.util.concurrent.CompletableFuture; -import java.util.function.Supplier; -import java.util.stream.Stream; -import org.redkale.convert.Convert; -import org.redkale.net.http.*; - -/** @author zhangjx */ -public interface WebSocketDesc { - - // 给自身发送消息, 消息类型是String或byte[]或可JavaBean对象 返回结果0表示成功,非0表示错误码 - public CompletableFuture send(Object message); - - // 给自身发送消息, 消息类型是key-value键值对 返回结果0表示成功,非0表示错误码 - public CompletableFuture sendMap(Object... messages); - - // 给自身发送消息, 消息类型是String或byte[]或可JavaBean对象 返回结果0表示成功,非0表示错误码 - public CompletableFuture send(Object message, boolean last); - - // 给自身发送消息, 消息类型是key-value键值对 返回结果0表示成功,非0表示错误码 - public CompletableFuture sendMap(boolean last, Object... messages); - - // 给自身发送消息, 消息类型是JavaBean对象 返回结果0表示成功,非0表示错误码 - public CompletableFuture send(Convert convert, Object message); - - // 给自身发送消息, 消息类型是JavaBean对象 返回结果0表示成功,非0表示错误码 - public CompletableFuture send(Convert convert, Object message, boolean last); - - // 给指定userid的WebSocket节点发送 二进制消息/文本消息/JavaBean对象消息 返回结果0表示成功,非0表示错误码 - public CompletableFuture sendMessage(Object message, G... userids); - - // 给指定userid的WebSocket节点发送 二进制消息/文本消息/JavaBean对象消息 返回结果0表示成功,非0表示错误码 - public CompletableFuture sendMessage(Object message, Stream userids); - - // 给指定userid的WebSocket节点发送 二进制消息/文本消息/JavaBean对象消息 返回结果0表示成功,非0表示错误码 - public CompletableFuture sendMessage(Convert convert, Object message, G... userids); - - // 给指定userid的WebSocket节点发送 二进制消息/文本消息/JavaBean对象消息 返回结果0表示成功,非0表示错误码 - public CompletableFuture sendMessage(Convert convert, Object message, Stream userids); - - // 给指定userid的WebSocket节点发送 二进制消息/文本消息/JavaBean对象消息 返回结果0表示成功,非0表示错误码 - public CompletableFuture sendMessage(Object message, boolean last, G... userids); - - // 给指定userid的WebSocket节点发送 二进制消息/文本消息/JavaBean对象消息 返回结果0表示成功,非0表示错误码 - public CompletableFuture sendMessage(Object message, boolean last, Stream userids); - - // 给指定userid的WebSocket节点发送 二进制消息/文本消息/JavaBean对象消息 返回结果0表示成功,非0表示错误码 - public CompletableFuture sendMessage(Convert convert, Object message, boolean last, G... userids); - - // 给指定userid的WebSocket节点发送 二进制消息/文本消息/JavaBean对象消息 返回结果0表示成功,非0表示错误码 - public CompletableFuture sendMessage(Convert convert, Object message, boolean last, Stream userids); - - // 给所有人广播消息, 返回结果0表示成功,非0表示错误码 - public CompletableFuture broadcastMessage(final Object message); - - // 给所有人广播消息, 返回结果0表示成功,非0表示错误码 - public CompletableFuture broadcastMessage(final Convert convert, final Object message); - - // 给符合条件的人群广播消息, 返回结果0表示成功,非0表示错误码 - public CompletableFuture broadcastMessage(final WebSocketRange wsrange, final Object message); - - // 给符合条件的人群广播消息, 返回结果0表示成功,非0表示错误码 - public CompletableFuture broadcastMessage( - final WebSocketRange wsrange, final Convert convert, final Object message); - - // 给所有人广播消息, 返回结果0表示成功,非0表示错误码 - public CompletableFuture broadcastMessage(final Object message, boolean last); - - // 给所有人广播消息, 返回结果0表示成功,非0表示错误码 - public CompletableFuture broadcastMessage(final Convert convert, final Object message, boolean last); - - // 给符合条件的人群广播消息, 返回结果0表示成功,非0表示错误码 - public CompletableFuture broadcastMessage( - final WebSocketRange wsrange, final Object message, boolean last); - - // 给符合条件的人群广播消息, 返回结果0表示成功,非0表示错误码 - public CompletableFuture broadcastMessage( - WebSocketRange wsrange, Convert convert, final Object message, boolean last); - - // 给指定userid的WebSocket节点发送操作 - public CompletableFuture sendAction(final WebSocketAction action, Serializable... userids); - - // 广播操作, 给所有人发操作指令 - public CompletableFuture broadcastAction(final WebSocketAction action); - - // 获取用户在线的SNCP节点地址列表,不是分布式则返回元素数量为1,且元素值为null的列表 - public CompletableFuture> getRpcNodeAddresses(final Serializable userid); - - // 获取在线用户的详细连接信息 - public CompletableFuture>> getRpcNodeWebSocketAddresses( - final Serializable userid); - - // 发送PING消息 返回结果0表示成功,非0表示错误码 - public CompletableFuture sendPing(); - - // 发送PING消息,附带其他信息 返回结果0表示成功,非0表示错误码 - public CompletableFuture sendPing(byte[] data); - - // 发送PONG消息,附带其他信息 返回结果0表示成功,非0表示错误码 - public CompletableFuture sendPong(byte[] data); - - // 强制关闭用户的所有WebSocket - public CompletableFuture forceCloseWebSocket(Serializable userid); - - // 更改本WebSocket的userid - public CompletableFuture changeUserid(final G newuserid); - - // 获取指定userid的WebSocket数组, 没有返回null 此方法用于单用户多连接模式 - /* protected */ Stream getLocalWebSockets(G userid); - - // 获取指定userid的WebSocket数组, 没有返回null 此方法用于单用户单连接模式 - /* protected */ WebSocket findLocalWebSocket(G userid); - - // 获取当前进程节点所有在线的WebSocket - /* protected */ Collection getLocalWebSockets(); - - // 获取ByteBuffer资源池 - /* protected */ Supplier getByteBufferSupplier(); - - // 返回sessionid, null表示连接不合法或异常,默认实现是request.sessionid(true),通常需要重写该方法 - /* protected */ CompletableFuture onOpen(final HttpRequest request); - - // 创建userid, null表示异常, 必须实现该方法 - /* protected abstract */ CompletableFuture createUserid(); - - // WebSocket.broadcastMessage时的过滤条件 - /* protected */ boolean predicate(WebSocketRange wsrange); - - // WebSokcet连接成功后的回调方法 - public void onConnected(); - - // ping后的回调方法 - public void onPing(byte[] bytes); - - // pong后的回调方法 - public void onPong(byte[] bytes); - - // 接收到消息的回调方法 - public void onMessage(T message, boolean last); - - // 接收到文本消息的回调方法 - public void onMessage(String message, boolean last); - - // 接收到二进制消息的回调方法 - public void onMessage(byte[] bytes, boolean last); - - // 关闭的回调方法,调用此方法时WebSocket已经被关闭 - public void onClose(int code, String reason); - - // 获取当前WebSocket下的属性 - public T getAttribute(String name); - - // 移出当前WebSocket下的属性 - public T removeAttribute(String name); - - // 给当前WebSocket下的增加属性 - public void setAttribute(String name, Object value); - - // 获取当前WebSocket所属的userid - public G getUserid(); - - // 获取当前WebSocket的会话ID, 不会为null - public Serializable getSessionid(); - - // 获取客户端直接地址, 当WebSocket连接是由代理服务器转发的,则该值固定为代理服务器的IP地址 - public SocketAddress getRemoteAddress(); - - // 获取客户端真实地址 同 HttpRequest.getRemoteAddr() - public String getRemoteAddr(); - - // 获取WebSocket创建时间 - public long getCreatetime(); - - // 获取最后一次发送消息的时间 - public long getLastSendTime(); - - // 获取最后一次读取消息的时间 - public long getLastReadTime(); - - // 获取最后一次ping的时间 - public long getLastPingTime(); - - // 显式地关闭WebSocket - public void close(); - - // WebSocket是否已关闭 - public boolean isClosed(); -} +/* + * 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.test.http; + +import java.io.*; +import java.net.*; +import java.nio.ByteBuffer; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.function.Supplier; +import java.util.stream.Stream; +import org.redkale.convert.Convert; +import org.redkale.net.http.*; + +/** @author zhangjx */ +public interface WebSocketDesc { + + // 给自身发送消息, 消息类型是String或byte[]或可JavaBean对象 返回结果0表示成功,非0表示错误码 + public CompletableFuture send(Object message); + + // 给自身发送消息, 消息类型是key-value键值对 返回结果0表示成功,非0表示错误码 + public CompletableFuture sendMap(Object... messages); + + // 给自身发送消息, 消息类型是String或byte[]或可JavaBean对象 返回结果0表示成功,非0表示错误码 + public CompletableFuture send(Object message, boolean last); + + // 给自身发送消息, 消息类型是key-value键值对 返回结果0表示成功,非0表示错误码 + public CompletableFuture sendMap(boolean last, Object... messages); + + // 给自身发送消息, 消息类型是JavaBean对象 返回结果0表示成功,非0表示错误码 + public CompletableFuture send(Convert convert, Object message); + + // 给自身发送消息, 消息类型是JavaBean对象 返回结果0表示成功,非0表示错误码 + public CompletableFuture send(Convert convert, Object message, boolean last); + + // 给指定userid的WebSocket节点发送 二进制消息/文本消息/JavaBean对象消息 返回结果0表示成功,非0表示错误码 + public CompletableFuture sendMessage(Object message, G... userids); + + // 给指定userid的WebSocket节点发送 二进制消息/文本消息/JavaBean对象消息 返回结果0表示成功,非0表示错误码 + public CompletableFuture sendMessage(Object message, Stream userids); + + // 给指定userid的WebSocket节点发送 二进制消息/文本消息/JavaBean对象消息 返回结果0表示成功,非0表示错误码 + public CompletableFuture sendMessage(Convert convert, Object message, G... userids); + + // 给指定userid的WebSocket节点发送 二进制消息/文本消息/JavaBean对象消息 返回结果0表示成功,非0表示错误码 + public CompletableFuture sendMessage(Convert convert, Object message, Stream userids); + + // 给指定userid的WebSocket节点发送 二进制消息/文本消息/JavaBean对象消息 返回结果0表示成功,非0表示错误码 + public CompletableFuture sendMessage(Object message, boolean last, G... userids); + + // 给指定userid的WebSocket节点发送 二进制消息/文本消息/JavaBean对象消息 返回结果0表示成功,非0表示错误码 + public CompletableFuture sendMessage(Object message, boolean last, Stream userids); + + // 给指定userid的WebSocket节点发送 二进制消息/文本消息/JavaBean对象消息 返回结果0表示成功,非0表示错误码 + public CompletableFuture sendMessage(Convert convert, Object message, boolean last, G... userids); + + // 给指定userid的WebSocket节点发送 二进制消息/文本消息/JavaBean对象消息 返回结果0表示成功,非0表示错误码 + public CompletableFuture sendMessage(Convert convert, Object message, boolean last, Stream userids); + + // 给所有人广播消息, 返回结果0表示成功,非0表示错误码 + public CompletableFuture broadcastMessage(final Object message); + + // 给所有人广播消息, 返回结果0表示成功,非0表示错误码 + public CompletableFuture broadcastMessage(final Convert convert, final Object message); + + // 给符合条件的人群广播消息, 返回结果0表示成功,非0表示错误码 + public CompletableFuture broadcastMessage(final WebSocketRange wsrange, final Object message); + + // 给符合条件的人群广播消息, 返回结果0表示成功,非0表示错误码 + public CompletableFuture broadcastMessage( + final WebSocketRange wsrange, final Convert convert, final Object message); + + // 给所有人广播消息, 返回结果0表示成功,非0表示错误码 + public CompletableFuture broadcastMessage(final Object message, boolean last); + + // 给所有人广播消息, 返回结果0表示成功,非0表示错误码 + public CompletableFuture broadcastMessage(final Convert convert, final Object message, boolean last); + + // 给符合条件的人群广播消息, 返回结果0表示成功,非0表示错误码 + public CompletableFuture broadcastMessage( + final WebSocketRange wsrange, final Object message, boolean last); + + // 给符合条件的人群广播消息, 返回结果0表示成功,非0表示错误码 + public CompletableFuture broadcastMessage( + WebSocketRange wsrange, Convert convert, final Object message, boolean last); + + // 给指定userid的WebSocket节点发送操作 + public CompletableFuture sendAction(final WebSocketAction action, Serializable... userids); + + // 广播操作, 给所有人发操作指令 + public CompletableFuture broadcastAction(final WebSocketAction action); + + // 获取用户在线的SNCP节点地址列表,不是分布式则返回元素数量为1,且元素值为null的列表 + public CompletableFuture> getRpcNodeAddresses(final Serializable userid); + + // 获取在线用户的详细连接信息 + public CompletableFuture>> getRpcNodeWebSocketAddresses( + final Serializable userid); + + // 发送PING消息 返回结果0表示成功,非0表示错误码 + public CompletableFuture sendPing(); + + // 发送PING消息,附带其他信息 返回结果0表示成功,非0表示错误码 + public CompletableFuture sendPing(byte[] data); + + // 发送PONG消息,附带其他信息 返回结果0表示成功,非0表示错误码 + public CompletableFuture sendPong(byte[] data); + + // 强制关闭用户的所有WebSocket + public CompletableFuture forceCloseWebSocket(Serializable userid); + + // 更改本WebSocket的userid + public CompletableFuture changeUserid(final G newuserid); + + // 获取指定userid的WebSocket数组, 没有返回null 此方法用于单用户多连接模式 + /* protected */ Stream getLocalWebSockets(G userid); + + // 获取指定userid的WebSocket数组, 没有返回null 此方法用于单用户单连接模式 + /* protected */ WebSocket findLocalWebSocket(G userid); + + // 获取当前进程节点所有在线的WebSocket + /* protected */ Collection getLocalWebSockets(); + + // 获取ByteBuffer资源池 + /* protected */ Supplier getByteBufferSupplier(); + + // 返回sessionid, null表示连接不合法或异常,默认实现是request.sessionid(true),通常需要重写该方法 + /* protected */ CompletableFuture onOpen(final HttpRequest request); + + // 创建userid, null表示异常, 必须实现该方法 + /* protected abstract */ CompletableFuture createUserid(); + + // WebSocket.broadcastMessage时的过滤条件 + /* protected */ boolean predicate(WebSocketRange wsrange); + + // WebSokcet连接成功后的回调方法 + public void onConnected(); + + // ping后的回调方法 + public void onPing(byte[] bytes); + + // pong后的回调方法 + public void onPong(byte[] bytes); + + // 接收到消息的回调方法 + public void onMessage(T message, boolean last); + + // 接收到文本消息的回调方法 + public void onMessage(String message, boolean last); + + // 接收到二进制消息的回调方法 + public void onMessage(byte[] bytes, boolean last); + + // 关闭的回调方法,调用此方法时WebSocket已经被关闭 + public void onClose(int code, String reason); + + // 获取当前WebSocket下的属性 + public T getAttribute(String name); + + // 移出当前WebSocket下的属性 + public T removeAttribute(String name); + + // 给当前WebSocket下的增加属性 + public void setAttribute(String name, Object value); + + // 获取当前WebSocket所属的userid + public G getUserid(); + + // 获取当前WebSocket的会话ID, 不会为null + public Serializable getSessionid(); + + // 获取客户端直接地址, 当WebSocket连接是由代理服务器转发的,则该值固定为代理服务器的IP地址 + public SocketAddress getRemoteAddress(); + + // 获取客户端真实地址 同 HttpRequest.getRemoteAddr() + public String getRemoteAddr(); + + // 获取WebSocket创建时间 + public long getCreatetime(); + + // 获取最后一次发送消息的时间 + public long getLastSendTime(); + + // 获取最后一次读取消息的时间 + public long getLastReadTime(); + + // 获取最后一次ping的时间 + public long getLastPingTime(); + + // 显式地关闭WebSocket + public void close(); + + // WebSocket是否已关闭 + public boolean isClosed(); +} diff --git a/src/test/java/org/redkale/test/inject/ResourceAnnotationTest.java b/src/test/java/org/redkale/test/inject/ResourceAnnotationTest.java index a1588af99..62229cb36 100644 --- a/src/test/java/org/redkale/test/inject/ResourceAnnotationTest.java +++ b/src/test/java/org/redkale/test/inject/ResourceAnnotationTest.java @@ -1,81 +1,81 @@ -/* - * 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.test.inject; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.io.File; -import java.lang.annotation.*; -import java.lang.reflect.Field; -import org.junit.jupiter.api.*; -import org.redkale.convert.json.JsonConvert; -import org.redkale.inject.ResourceAnnotationLoader; -import org.redkale.inject.ResourceFactory; - -/** @author zhangjx */ -public class ResourceAnnotationTest { - - private boolean main; - - public static void main(String[] args) throws Throwable { - ResourceAnnotationTest test = new ResourceAnnotationTest(); - test.main = true; - test.run(); - } - - @Test - public void run() throws Exception { - ResourceFactory factory = ResourceFactory.create(); - factory.register(new CustomConfProvider()); - InjectBean bean = new InjectBean(); - factory.inject(bean); - if (!main) Assertions.assertEquals(new File("conf/test.xml").toString(), bean.conf.toString()); - } - - public static class CustomConfProvider implements ResourceAnnotationLoader { - - @Override - public void load( - ResourceFactory factory, - String srcResourceName, - Object srcObj, - CustomConf annotation, - Field field, - Object attachment) { - try { - field.set(srcObj, new File(annotation.path())); - } catch (Exception e) { - e.printStackTrace(); - } - System.out.println("对象是 src =" + srcObj + ", path=" + annotation.path()); - } - - @Override - public Class annotationType() { - return CustomConf.class; - } - } - - public static class InjectBean { - - @CustomConf(path = "conf/test.xml") - public File conf; - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } - } - - @Documented - @Target({FIELD}) - @Retention(RUNTIME) - public static @interface CustomConf { - - String path(); - } -} +/* + * 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.test.inject; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.io.File; +import java.lang.annotation.*; +import java.lang.reflect.Field; +import org.junit.jupiter.api.*; +import org.redkale.convert.json.JsonConvert; +import org.redkale.inject.ResourceAnnotationLoader; +import org.redkale.inject.ResourceFactory; + +/** @author zhangjx */ +public class ResourceAnnotationTest { + + private boolean main; + + public static void main(String[] args) throws Throwable { + ResourceAnnotationTest test = new ResourceAnnotationTest(); + test.main = true; + test.run(); + } + + @Test + public void run() throws Exception { + ResourceFactory factory = ResourceFactory.create(); + factory.register(new CustomConfProvider()); + InjectBean bean = new InjectBean(); + factory.inject(bean); + if (!main) Assertions.assertEquals(new File("conf/test.xml").toString(), bean.conf.toString()); + } + + public static class CustomConfProvider implements ResourceAnnotationLoader { + + @Override + public void load( + ResourceFactory factory, + String srcResourceName, + Object srcObj, + CustomConf annotation, + Field field, + Object attachment) { + try { + field.set(srcObj, new File(annotation.path())); + } catch (Exception e) { + e.printStackTrace(); + } + System.out.println("对象是 src =" + srcObj + ", path=" + annotation.path()); + } + + @Override + public Class annotationType() { + return CustomConf.class; + } + } + + public static class InjectBean { + + @CustomConf(path = "conf/test.xml") + public File conf; + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + } + + @Documented + @Target({FIELD}) + @Retention(RUNTIME) + public static @interface CustomConf { + + String path(); + } +} diff --git a/src/test/java/org/redkale/test/inject/ResourceInjectedTest.java b/src/test/java/org/redkale/test/inject/ResourceInjectedTest.java index 1b0d1c6bd..b523ad79d 100644 --- a/src/test/java/org/redkale/test/inject/ResourceInjectedTest.java +++ b/src/test/java/org/redkale/test/inject/ResourceInjectedTest.java @@ -1,65 +1,65 @@ -/* - * - */ -package org.redkale.test.inject; - -import java.util.concurrent.atomic.AtomicInteger; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import org.redkale.annotation.Resource; -import org.redkale.annotation.ResourceInjected; -import org.redkale.inject.ResourceFactory; -import org.redkale.service.Service; - -/** @author zhangjx */ -public class ResourceInjectedTest { - - public static void main(String[] args) throws Throwable { - ResourceInjectedTest test = new ResourceInjectedTest(); - test.run(); - } - - @Test - public void run() throws Exception { - ResourceFactory factory = ResourceFactory.create(); - factory.register("res.id", "2345"); - factory.register("res.name", "my old name"); - ResourceService res = new ResourceService(); - factory.inject(res); - factory.register("", res); - RoomService serice = new RoomService(); - factory.inject(serice); - Assertions.assertEquals(1, ResourceService.counter.get()); - } - - public static class RoomService implements Service { - - @Resource - private ResourceService resService; - - public void test() { - resService.doing(); - } - } - - public static class ResourceService implements Service { - - private static final AtomicInteger counter = new AtomicInteger(); - - @Resource(name = "res.id") - private int id; - - @Resource(name = "res.name") - private String name; - - @ResourceInjected - private void onInjected(Object src, String fieldName) { - counter.incrementAndGet(); - System.out.println("资源被注入到对象(" + src + ")的字段(" + fieldName + ")上"); - } - - public void doing() { - System.out.println("id = " + id + ", name = " + name); - } - } -} +/* + * + */ +package org.redkale.test.inject; + +import java.util.concurrent.atomic.AtomicInteger; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.redkale.annotation.Resource; +import org.redkale.annotation.ResourceInjected; +import org.redkale.inject.ResourceFactory; +import org.redkale.service.Service; + +/** @author zhangjx */ +public class ResourceInjectedTest { + + public static void main(String[] args) throws Throwable { + ResourceInjectedTest test = new ResourceInjectedTest(); + test.run(); + } + + @Test + public void run() throws Exception { + ResourceFactory factory = ResourceFactory.create(); + factory.register("res.id", "2345"); + factory.register("res.name", "my old name"); + ResourceService res = new ResourceService(); + factory.inject(res); + factory.register("", res); + RoomService serice = new RoomService(); + factory.inject(serice); + Assertions.assertEquals(1, ResourceService.counter.get()); + } + + public static class RoomService implements Service { + + @Resource + private ResourceService resService; + + public void test() { + resService.doing(); + } + } + + public static class ResourceService implements Service { + + private static final AtomicInteger counter = new AtomicInteger(); + + @Resource(name = "res.id") + private int id; + + @Resource(name = "res.name") + private String name; + + @ResourceInjected + private void onInjected(Object src, String fieldName) { + counter.incrementAndGet(); + System.out.println("资源被注入到对象(" + src + ")的字段(" + fieldName + ")上"); + } + + public void doing() { + System.out.println("id = " + id + ", name = " + name); + } + } +} diff --git a/src/test/java/org/redkale/test/inject/ResourceTest.java b/src/test/java/org/redkale/test/inject/ResourceTest.java index 0ac7d58cb..ae75e6147 100644 --- a/src/test/java/org/redkale/test/inject/ResourceTest.java +++ b/src/test/java/org/redkale/test/inject/ResourceTest.java @@ -1,181 +1,181 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template bigint, choose Tools | Templates - * and open the template in the editor. - */ -package org.redkale.test.inject; - -import java.math.BigInteger; -import java.util.Properties; -import org.junit.jupiter.api.Test; -import org.redkale.annotation.*; -import org.redkale.inject.ResourceEvent; -import org.redkale.inject.ResourceFactory; - -/** @author zhangjx */ -public class ResourceTest { - - private boolean main; - - public static void main(String[] args) throws Throwable { - ResourceTest test = new ResourceTest(); - test.main = true; - test.run(); - } - - @Test - public void run() throws Exception { - ResourceFactory factory = ResourceFactory.create(); - factory.register("id", "2345"); // 注入String类型的property.id - AService aservice = new AService(); - BService bservice = new BService("eeeee"); - - factory.register(aservice); // 放进Resource池内,默认的资源名name为"" - factory.register(bservice); // 放进Resource池内,默认的资源名name为"" - - factory.inject(aservice); // 给aservice注入id、bservice,bigint没有资源,所以为null - factory.inject(bservice); // 给bservice注入id、aservice - System.out.println(aservice); // 输出结果为:{id:"2345", intid: 2345, bigint:null, bservice:{name:eeeee}} - System.out.println(bservice); // 输出结果为:{name:"eeeee", id: 2345, aserivce:{id:"2345", intid: 2345, bigint:null, - // bservice:{name:eeeee}}} - - factory.register("seqid", 200); // 放进Resource池内, 同时ResourceFactory会自动更新aservice的seqid值 - System.out.println(factory.find("seqid", int.class)); // 输出结果为:200 - factory.register( - "bigint", new BigInteger("666666666666666")); // 放进Resource池内, 同时ResourceFactory会自动更新aservice对象的bigint值 - System.out.println(aservice); // 输出结果为:{id:"2345", intid: 2345, bigint:666666666666666, bservice:{name:eeeee}} - // 可以看出seqid与bigint值都已自动更新 - - factory.register("id", "6789"); // 更新Resource池内的id资源值, 同时ResourceFactory会自动更新aservice、bservice的id值 - System.out.println(aservice); // 输出结果为:{id:"6789", intid: 6789, bigint:666666666666666, bservice:{name:eeeee}} - System.out.println( - bservice); // 输出结果为:{name:"eeeee", id: 6789, aserivce:{id:"6789", intid: 6789, bigint:666666666666666, - // bservice:{name:eeeee}}} - - Properties props = new Properties(); - props.put("id", "5555"); - props.put("desc", "my desc"); - factory.register(props); - - bservice = new BService("ffff"); - factory.register(bservice); // 更新Resource池内name=""的BService资源, 同时ResourceFactory会自动更新aservice的bservice对象 - factory.inject(bservice); - System.out.println(aservice); // 输出结果为:{id:"6789", intid: 6789, bigint:666666666666666, bservice:{name:ffff}} - } -} - -class BService { - - @Resource(name = "${id}") - private String id; - - @Resource(name = "${desc}", required = false) - private String desc; - - @Resource - private AService aservice; - - private String name = ""; - - @ResourceChanged - private void changeResource(ResourceEvent[] events) { - for (ResourceEvent event : events) { - System.out.println(getClass().getSimpleName() + " @Resource = " + event.name() + " 资源变更: newVal = " - + event.newValue() + ", oldVal = " + event.oldValue()); - } - } - - @ConstructorParameters({"name"}) - public BService(String name) { - this.name = name; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public AService getAservice() { - return aservice; - } - - public void setAservice(AService aservice) { - this.aservice = aservice; - } - - @Override - public String toString() { - return "{name:\"" + name + "\", id: " + id + ", aserivce:" + aservice + "}"; - } -} - -class AService { - - @Resource(name = "${id}") - private String id; - - @Resource(name = "id") // property.开头的资源名允许String自动转换成primitive数值类型 - private int intid; - - @Resource(name = "bigint", required = false) - private BigInteger bigint; - - @Resource(name = "seqid", required = false) - private int seqid; - - @Resource - private BService bservice; - - @Override - public String toString() { - return "{id:\"" + id + "\", intid: " + intid + ", bigint:" + bigint + ", bservice:" - + (bservice == null ? null : ("{name:" + bservice.getName() + "}")) + "}"; - } - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public int getIntid() { - return intid; - } - - public void setIntid(int intid) { - this.intid = intid; - } - - public int getSeqid() { - return seqid; - } - - public void setSeqid(int seqid) { - this.seqid = seqid; - } - - public BigInteger getBigint() { - return bigint; - } - - public void setBigint(BigInteger bigint) { - this.bigint = bigint; - } - - public void setBservice(BService bservice) { - this.bservice = bservice; - } -} +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template bigint, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.test.inject; + +import java.math.BigInteger; +import java.util.Properties; +import org.junit.jupiter.api.Test; +import org.redkale.annotation.*; +import org.redkale.inject.ResourceEvent; +import org.redkale.inject.ResourceFactory; + +/** @author zhangjx */ +public class ResourceTest { + + private boolean main; + + public static void main(String[] args) throws Throwable { + ResourceTest test = new ResourceTest(); + test.main = true; + test.run(); + } + + @Test + public void run() throws Exception { + ResourceFactory factory = ResourceFactory.create(); + factory.register("id", "2345"); // 注入String类型的property.id + AService aservice = new AService(); + BService bservice = new BService("eeeee"); + + factory.register(aservice); // 放进Resource池内,默认的资源名name为"" + factory.register(bservice); // 放进Resource池内,默认的资源名name为"" + + factory.inject(aservice); // 给aservice注入id、bservice,bigint没有资源,所以为null + factory.inject(bservice); // 给bservice注入id、aservice + System.out.println(aservice); // 输出结果为:{id:"2345", intid: 2345, bigint:null, bservice:{name:eeeee}} + System.out.println(bservice); // 输出结果为:{name:"eeeee", id: 2345, aserivce:{id:"2345", intid: 2345, bigint:null, + // bservice:{name:eeeee}}} + + factory.register("seqid", 200); // 放进Resource池内, 同时ResourceFactory会自动更新aservice的seqid值 + System.out.println(factory.find("seqid", int.class)); // 输出结果为:200 + factory.register( + "bigint", new BigInteger("666666666666666")); // 放进Resource池内, 同时ResourceFactory会自动更新aservice对象的bigint值 + System.out.println(aservice); // 输出结果为:{id:"2345", intid: 2345, bigint:666666666666666, bservice:{name:eeeee}} + // 可以看出seqid与bigint值都已自动更新 + + factory.register("id", "6789"); // 更新Resource池内的id资源值, 同时ResourceFactory会自动更新aservice、bservice的id值 + System.out.println(aservice); // 输出结果为:{id:"6789", intid: 6789, bigint:666666666666666, bservice:{name:eeeee}} + System.out.println( + bservice); // 输出结果为:{name:"eeeee", id: 6789, aserivce:{id:"6789", intid: 6789, bigint:666666666666666, + // bservice:{name:eeeee}}} + + Properties props = new Properties(); + props.put("id", "5555"); + props.put("desc", "my desc"); + factory.register(props); + + bservice = new BService("ffff"); + factory.register(bservice); // 更新Resource池内name=""的BService资源, 同时ResourceFactory会自动更新aservice的bservice对象 + factory.inject(bservice); + System.out.println(aservice); // 输出结果为:{id:"6789", intid: 6789, bigint:666666666666666, bservice:{name:ffff}} + } +} + +class BService { + + @Resource(name = "${id}") + private String id; + + @Resource(name = "${desc}", required = false) + private String desc; + + @Resource + private AService aservice; + + private String name = ""; + + @ResourceChanged + private void changeResource(ResourceEvent[] events) { + for (ResourceEvent event : events) { + System.out.println(getClass().getSimpleName() + " @Resource = " + event.name() + " 资源变更: newVal = " + + event.newValue() + ", oldVal = " + event.oldValue()); + } + } + + @ConstructorParameters({"name"}) + public BService(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public AService getAservice() { + return aservice; + } + + public void setAservice(AService aservice) { + this.aservice = aservice; + } + + @Override + public String toString() { + return "{name:\"" + name + "\", id: " + id + ", aserivce:" + aservice + "}"; + } +} + +class AService { + + @Resource(name = "${id}") + private String id; + + @Resource(name = "id") // property.开头的资源名允许String自动转换成primitive数值类型 + private int intid; + + @Resource(name = "bigint", required = false) + private BigInteger bigint; + + @Resource(name = "seqid", required = false) + private int seqid; + + @Resource + private BService bservice; + + @Override + public String toString() { + return "{id:\"" + id + "\", intid: " + intid + ", bigint:" + bigint + ", bservice:" + + (bservice == null ? null : ("{name:" + bservice.getName() + "}")) + "}"; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public int getIntid() { + return intid; + } + + public void setIntid(int intid) { + this.intid = intid; + } + + public int getSeqid() { + return seqid; + } + + public void setSeqid(int seqid) { + this.seqid = seqid; + } + + public BigInteger getBigint() { + return bigint; + } + + public void setBigint(BigInteger bigint) { + this.bigint = bigint; + } + + public void setBservice(BService bservice) { + this.bservice = bservice; + } +} diff --git a/src/test/java/org/redkale/test/rest/CreateTimeSimpleCoder.java b/src/test/java/org/redkale/test/rest/CreateTimeSimpleCoder.java index d02b1269e..285d66f63 100644 --- a/src/test/java/org/redkale/test/rest/CreateTimeSimpleCoder.java +++ b/src/test/java/org/redkale/test/rest/CreateTimeSimpleCoder.java @@ -1,39 +1,39 @@ -/* - * 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.test.rest; - -import java.text.SimpleDateFormat; -import org.redkale.convert.*; - -/** - * @author zhangjx - * @param R - * @param W - */ -public class CreateTimeSimpleCoder extends SimpledCoder { - - private static final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - - @Override - public void convertTo(W out, Long value) { - if (value == null) { - out.writeNull(); - } else { - out.writeString(format.format(new java.util.Date(value))); - } - } - - @Override - public Long convertFrom(R in) { - String val = in.readString(); - if (val == null) return 0L; - try { - return format.parse(val).getTime(); - } catch (Exception e) { - return 0L; - } - } -} +/* + * 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.test.rest; + +import java.text.SimpleDateFormat; +import org.redkale.convert.*; + +/** + * @author zhangjx + * @param R + * @param W + */ +public class CreateTimeSimpleCoder extends SimpledCoder { + + private static final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + + @Override + public void convertTo(W out, Long value) { + if (value == null) { + out.writeNull(); + } else { + out.writeString(format.format(new java.util.Date(value))); + } + } + + @Override + public Long convertFrom(R in) { + String val = in.readString(); + if (val == null) return 0L; + try { + return format.parse(val).getTime(); + } catch (Exception e) { + return 0L; + } + } +} diff --git a/src/test/java/org/redkale/test/rest/HelloAsyncHandler.java b/src/test/java/org/redkale/test/rest/HelloAsyncHandler.java index 421fcc2e9..8d0283ea7 100644 --- a/src/test/java/org/redkale/test/rest/HelloAsyncHandler.java +++ b/src/test/java/org/redkale/test/rest/HelloAsyncHandler.java @@ -1,23 +1,23 @@ -/* - * 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.test.rest; - -import java.nio.channels.CompletionHandler; - -/** @author zhangjx */ -public class HelloAsyncHandler implements CompletionHandler { - - @Override - public void completed(Object result, Object attachment) { - System.out.println("-----HelloAsyncHandler--------result : " + result + ", attachment: " + attachment); - } - - @Override - public void failed(Throwable exc, Object attachment) { - throw new UnsupportedOperationException( - "Not supported yet."); // To change body of generated methods, choose Tools | Templates. - } -} +/* + * 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.test.rest; + +import java.nio.channels.CompletionHandler; + +/** @author zhangjx */ +public class HelloAsyncHandler implements CompletionHandler { + + @Override + public void completed(Object result, Object attachment) { + System.out.println("-----HelloAsyncHandler--------result : " + result + ", attachment: " + attachment); + } + + @Override + public void failed(Throwable exc, Object attachment) { + throw new UnsupportedOperationException( + "Not supported yet."); // To change body of generated methods, choose Tools | Templates. + } +} diff --git a/src/test/java/org/redkale/test/rest/HelloBean.java b/src/test/java/org/redkale/test/rest/HelloBean.java index be137c76f..68c6f4f30 100644 --- a/src/test/java/org/redkale/test/rest/HelloBean.java +++ b/src/test/java/org/redkale/test/rest/HelloBean.java @@ -1,68 +1,68 @@ -package org.redkale.test.rest; - -import org.redkale.convert.json.JsonFactory; -import org.redkale.net.http.*; -import org.redkale.source.FilterBean; - -public class HelloBean implements FilterBean { - - private int helloid; - - @RestHeader(name = "User-Agent") - private String useragent; // 从Http Header中获取浏览器信息 - - @RestCookie(name = "hello-cookie") - private String rescookie; // 从Cookie中获取名为hello-cookie的值 - - @RestAddress - private String clientaddr; // 客户端请求IP - - @RestSessionid - private String sessionid; // 用户Sessionid, 未登录时为null - - /** 以下省略getter setter方法 */ - public int getHelloid() { - return helloid; - } - - public void setHelloid(int helloid) { - this.helloid = helloid; - } - - public String getUseragent() { - return useragent; - } - - public void setUseragent(String useragent) { - this.useragent = useragent; - } - - public String getRescookie() { - return rescookie; - } - - public void setRescookie(String rescookie) { - this.rescookie = rescookie; - } - - public String getClientaddr() { - return clientaddr; - } - - public void setClientaddr(String clientaddr) { - this.clientaddr = clientaddr; - } - - public String getSessionid() { - return sessionid; - } - - public void setSessionid(String sessionid) { - this.sessionid = sessionid; - } - - @Override - public String toString() { - return JsonFactory.root().getConvert().convertTo(this); - } -} +package org.redkale.test.rest; + +import org.redkale.convert.json.JsonFactory; +import org.redkale.net.http.*; +import org.redkale.source.FilterBean; + +public class HelloBean implements FilterBean { + + private int helloid; + + @RestHeader(name = "User-Agent") + private String useragent; // 从Http Header中获取浏览器信息 + + @RestCookie(name = "hello-cookie") + private String rescookie; // 从Cookie中获取名为hello-cookie的值 + + @RestAddress + private String clientaddr; // 客户端请求IP + + @RestSessionid + private String sessionid; // 用户Sessionid, 未登录时为null + + /** 以下省略getter setter方法 */ + public int getHelloid() { + return helloid; + } + + public void setHelloid(int helloid) { + this.helloid = helloid; + } + + public String getUseragent() { + return useragent; + } + + public void setUseragent(String useragent) { + this.useragent = useragent; + } + + public String getRescookie() { + return rescookie; + } + + public void setRescookie(String rescookie) { + this.rescookie = rescookie; + } + + public String getClientaddr() { + return clientaddr; + } + + public void setClientaddr(String clientaddr) { + this.clientaddr = clientaddr; + } + + public String getSessionid() { + return sessionid; + } + + public void setSessionid(String sessionid) { + this.sessionid = sessionid; + } + + @Override + public String toString() { + return JsonFactory.root().getConvert().convertTo(this); + } +} diff --git a/src/test/java/org/redkale/test/rest/HelloEntity.java b/src/test/java/org/redkale/test/rest/HelloEntity.java index 906c109b6..2f5fabf07 100644 --- a/src/test/java/org/redkale/test/rest/HelloEntity.java +++ b/src/test/java/org/redkale/test/rest/HelloEntity.java @@ -1,151 +1,151 @@ -package org.redkale.test.rest; - -import java.util.Map; -import org.redkale.convert.json.JsonFactory; -import org.redkale.net.http.*; -import org.redkale.persistence.Id; -import org.redkale.persistence.VirtualEntity; - -@VirtualEntity -public class HelloEntity { - - @Id - private int helloid; - - private String helloname; - - private int creator; - - private long updatetime; - - private long createtime; - - @RestHeader(name = "hello-res") - private String resname; - - @RestBody - private String bodystr; - - @RestBody - private byte[] bodys; - - @RestUploadFile - private byte[] uploads; - - @RestBody - private Map bodymap; - - @RestAddress - private String clientaddr; - - @RestPath - private String uri; - - public HelloEntity() {} - - public HelloEntity(int id) { - this.helloid = id; - } - - /** 以下省略getter setter方法 */ - public int getHelloid() { - return helloid; - } - - public void setHelloid(int helloid) { - this.helloid = helloid; - } - - public String getHelloname() { - return helloname; - } - - public void setHelloname(String helloname) { - this.helloname = helloname; - } - - public long getUpdatetime() { - return updatetime; - } - - public void setUpdatetime(long updatetime) { - this.updatetime = updatetime; - } - - public long getCreatetime() { - return createtime; - } - - public void setCreatetime(long createtime) { - this.createtime = createtime; - } - - public int getCreator() { - return creator; - } - - public void setCreator(int creator) { - this.creator = creator; - } - - public String getClientaddr() { - return clientaddr; - } - - public void setClientaddr(String clientaddr) { - this.clientaddr = clientaddr; - } - - public String getResname() { - return resname; - } - - public void setResname(String resname) { - this.resname = resname; - } - - public String getBodystr() { - return bodystr; - } - - public void setBodystr(String bodystr) { - this.bodystr = bodystr; - } - - public byte[] getBodys() { - return bodys; - } - - public void setBodys(byte[] bodys) { - this.bodys = bodys; - } - - public Map getBodymap() { - return bodymap; - } - - public void setBodymap(Map bodymap) { - this.bodymap = bodymap; - } - - public byte[] getUploads() { - return uploads; - } - - public void setUploads(byte[] uploads) { - this.uploads = uploads; - } - - public String getUri() { - return uri; - } - - public void setUri(String uri) { - this.uri = uri; - } - - @Override - public String toString() { - return JsonFactory.root().getConvert().convertTo(this); - } -} +package org.redkale.test.rest; + +import java.util.Map; +import org.redkale.convert.json.JsonFactory; +import org.redkale.net.http.*; +import org.redkale.persistence.Id; +import org.redkale.persistence.VirtualEntity; + +@VirtualEntity +public class HelloEntity { + + @Id + private int helloid; + + private String helloname; + + private int creator; + + private long updatetime; + + private long createtime; + + @RestHeader(name = "hello-res") + private String resname; + + @RestBody + private String bodystr; + + @RestBody + private byte[] bodys; + + @RestUploadFile + private byte[] uploads; + + @RestBody + private Map bodymap; + + @RestAddress + private String clientaddr; + + @RestPath + private String uri; + + public HelloEntity() {} + + public HelloEntity(int id) { + this.helloid = id; + } + + /** 以下省略getter setter方法 */ + public int getHelloid() { + return helloid; + } + + public void setHelloid(int helloid) { + this.helloid = helloid; + } + + public String getHelloname() { + return helloname; + } + + public void setHelloname(String helloname) { + this.helloname = helloname; + } + + public long getUpdatetime() { + return updatetime; + } + + public void setUpdatetime(long updatetime) { + this.updatetime = updatetime; + } + + public long getCreatetime() { + return createtime; + } + + public void setCreatetime(long createtime) { + this.createtime = createtime; + } + + public int getCreator() { + return creator; + } + + public void setCreator(int creator) { + this.creator = creator; + } + + public String getClientaddr() { + return clientaddr; + } + + public void setClientaddr(String clientaddr) { + this.clientaddr = clientaddr; + } + + public String getResname() { + return resname; + } + + public void setResname(String resname) { + this.resname = resname; + } + + public String getBodystr() { + return bodystr; + } + + public void setBodystr(String bodystr) { + this.bodystr = bodystr; + } + + public byte[] getBodys() { + return bodys; + } + + public void setBodys(byte[] bodys) { + this.bodys = bodys; + } + + public Map getBodymap() { + return bodymap; + } + + public void setBodymap(Map bodymap) { + this.bodymap = bodymap; + } + + public byte[] getUploads() { + return uploads; + } + + public void setUploads(byte[] uploads) { + this.uploads = uploads; + } + + public String getUri() { + return uri; + } + + public void setUri(String uri) { + this.uri = uri; + } + + @Override + public String toString() { + return JsonFactory.root().getConvert().convertTo(this); + } +} diff --git a/src/test/java/org/redkale/test/rest/HelloService.java b/src/test/java/org/redkale/test/rest/HelloService.java index a1d3cd61f..46b1b4dc0 100644 --- a/src/test/java/org/redkale/test/rest/HelloService.java +++ b/src/test/java/org/redkale/test/rest/HelloService.java @@ -1,130 +1,130 @@ -package org.redkale.test.rest; - -import java.nio.channels.CompletionHandler; -import java.util.*; -import java.util.concurrent.CompletableFuture; -import org.redkale.annotation.Resource; -import org.redkale.net.http.*; -import org.redkale.service.*; -import org.redkale.source.DataSource; -import org.redkale.source.Flipper; -import org.redkale.util.*; - -/** 类说明: Flipper : Source组件中的翻页对象 UserInfo :当前用户类 HelloEntity: Hello模块的实体类 HelloBean: Hello模块实现FilterBean的过滤Bean类 */ -@RestService(autoMapping = true) -public class HelloService implements Service { - - private int nodeid; - - @Resource - private DataSource source; - - public HelloService() {} - - public HelloService(int nodeid) { - this.nodeid = nodeid; - } - - // 增加记录 - public RetResult createHello(UserInfo info, HelloEntity entity, @RestBody Map body) { - System.out.println("增加记录----------------" + nodeid + ": body =" + body + ", entity =" + entity); - entity.setCreator(info == null ? 0 : info.getUserid()); // 设置当前用户ID - entity.setCreatetime(System.currentTimeMillis()); - if (source != null) source.insert(entity); - return new RetResult<>(entity); - } - - // - public HttpResult showHello(int id) { - return new HttpResult("a"); - } - - // 删除记录 - public void deleteHello(int id) { // 通过 /pipes/hello/delete/1234 删除对象 - source.delete(HelloEntity.class, id); - } - - // 修改记录 - public void updateHello( - @RestAddress String clientAddr, HelloEntity entity) { // 通过 /pipes/hello/update?bean={...} 修改对象 - System.out.println("修改记录-" + nodeid + ": clientAddr = " + clientAddr + ", entity =" + entity); - if (entity != null) entity.setUpdatetime(System.currentTimeMillis()); - if (source != null) source.update(entity); - } - - // 修改记录 - public void update2Hello( - @RestAddress String clientAddr, @RestUploadFile byte[] fs) { // 通过 /pipes/hello/update2?bean={...} 修改对象 - System.out.println("修改记录2-" + nodeid + ": clientAddr = " + clientAddr + ", fs =" + fs); - } - - // 修改记录 - @RestMapping(name = "partupdate") - public void updateHello( - HelloEntity entity, - @RestParam(name = "cols") String[] columns) { // 通过 /pipes/hello/partupdate?bean={...}&cols=... 修改对象 - entity.setUpdatetime(System.currentTimeMillis()); - source.updateColumn(entity, columns); - } - - // 查询Sheet列表 - public Sheet queryHello( - HelloBean bean, Flipper flipper) { // 通过 /pipes/hello/query/offset:0/limit:20?bean={...} 查询Sheet列表 - return source.querySheet(HelloEntity.class, flipper, bean); - } - - // 查询List列表 - @RestMapping(name = "list") - @RestConvert( - type = HelloEntity.class, - ignoreColumns = {"createtime"}) - public List queryHello(HelloBean bean) { // 通过 /pipes/hello/list?bean={...} 查询List列表 - return source.queryList(HelloEntity.class, bean); - } - - // 查询List列表 - @RestMapping(name = "listmap") - public List queryHello( - HelloBean bean, - @RestParam(name = "map") Map map) { // 通过 /pipes/hello/list?bean={...} 查询List列表 - System.out.println("map参数: " + map); - if (source != null) return source.queryList(HelloEntity.class, bean); - return new ArrayList<>(); - } - - // 查询单个 - @RestMapping(name = "find") - public HelloEntity findHello( - @RestParam(name = "#") int id) { // 通过 /pipes/hello/find/1234、/pipes/hello/jsfind/1234 查询对象 - return source.find(HelloEntity.class, id); - } - - // 异步查询单个 - @RestMapping(name = "asyncfind") - public CompletableFuture asyncFindHello( - @RestParam(name = "#") int id) { // 通过 /pipes/hello/find/1234、/pipes/hello/jsfind/1234 查询对象 - if (source != null) source.findAsync(HelloEntity.class, id); - System.out.println("------------进入asyncfind1-------"); - return CompletableFuture.completedFuture(new HelloEntity()); - } - - // 异步查询单个 - @RestMapping(name = "asyncfind2") - public void asyncFindHello( - CompletionHandler hander, - @RestParam(name = "#") int id) { // 通过 /pipes/hello/find/1234、/pipes/hello/jsfind/1234 查询对象 - if (source != null) source.findAsync(HelloEntity.class, id); - System.out.println("-----------进入asyncfind2--------" + hander); - hander.completed(new HelloEntity(id), id); - } - - // 异步查询单个 - @RestMapping(name = "asyncfind3") - public void asyncFindHello( - HelloAsyncHandler hander, - @RestParam(name = "#") int id) { // 通过 /pipes/hello/find/1234、/pipes/hello/jsfind/1234 查询对象 - if (source != null) source.findAsync(HelloEntity.class, id); - System.out.println("-----------进入asyncfind3--------" + hander); - hander.completed(new HelloEntity(id), id); - } -} +package org.redkale.test.rest; + +import java.nio.channels.CompletionHandler; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import org.redkale.annotation.Resource; +import org.redkale.net.http.*; +import org.redkale.service.*; +import org.redkale.source.DataSource; +import org.redkale.source.Flipper; +import org.redkale.util.*; + +/** 类说明: Flipper : Source组件中的翻页对象 UserInfo :当前用户类 HelloEntity: Hello模块的实体类 HelloBean: Hello模块实现FilterBean的过滤Bean类 */ +@RestService(autoMapping = true) +public class HelloService implements Service { + + private int nodeid; + + @Resource + private DataSource source; + + public HelloService() {} + + public HelloService(int nodeid) { + this.nodeid = nodeid; + } + + // 增加记录 + public RetResult createHello(UserInfo info, HelloEntity entity, @RestBody Map body) { + System.out.println("增加记录----------------" + nodeid + ": body =" + body + ", entity =" + entity); + entity.setCreator(info == null ? 0 : info.getUserid()); // 设置当前用户ID + entity.setCreatetime(System.currentTimeMillis()); + if (source != null) source.insert(entity); + return new RetResult<>(entity); + } + + // + public HttpResult showHello(int id) { + return new HttpResult("a"); + } + + // 删除记录 + public void deleteHello(int id) { // 通过 /pipes/hello/delete/1234 删除对象 + source.delete(HelloEntity.class, id); + } + + // 修改记录 + public void updateHello( + @RestAddress String clientAddr, HelloEntity entity) { // 通过 /pipes/hello/update?bean={...} 修改对象 + System.out.println("修改记录-" + nodeid + ": clientAddr = " + clientAddr + ", entity =" + entity); + if (entity != null) entity.setUpdatetime(System.currentTimeMillis()); + if (source != null) source.update(entity); + } + + // 修改记录 + public void update2Hello( + @RestAddress String clientAddr, @RestUploadFile byte[] fs) { // 通过 /pipes/hello/update2?bean={...} 修改对象 + System.out.println("修改记录2-" + nodeid + ": clientAddr = " + clientAddr + ", fs =" + fs); + } + + // 修改记录 + @RestMapping(name = "partupdate") + public void updateHello( + HelloEntity entity, + @RestParam(name = "cols") String[] columns) { // 通过 /pipes/hello/partupdate?bean={...}&cols=... 修改对象 + entity.setUpdatetime(System.currentTimeMillis()); + source.updateColumn(entity, columns); + } + + // 查询Sheet列表 + public Sheet queryHello( + HelloBean bean, Flipper flipper) { // 通过 /pipes/hello/query/offset:0/limit:20?bean={...} 查询Sheet列表 + return source.querySheet(HelloEntity.class, flipper, bean); + } + + // 查询List列表 + @RestMapping(name = "list") + @RestConvert( + type = HelloEntity.class, + ignoreColumns = {"createtime"}) + public List queryHello(HelloBean bean) { // 通过 /pipes/hello/list?bean={...} 查询List列表 + return source.queryList(HelloEntity.class, bean); + } + + // 查询List列表 + @RestMapping(name = "listmap") + public List queryHello( + HelloBean bean, + @RestParam(name = "map") Map map) { // 通过 /pipes/hello/list?bean={...} 查询List列表 + System.out.println("map参数: " + map); + if (source != null) return source.queryList(HelloEntity.class, bean); + return new ArrayList<>(); + } + + // 查询单个 + @RestMapping(name = "find") + public HelloEntity findHello( + @RestParam(name = "#") int id) { // 通过 /pipes/hello/find/1234、/pipes/hello/jsfind/1234 查询对象 + return source.find(HelloEntity.class, id); + } + + // 异步查询单个 + @RestMapping(name = "asyncfind") + public CompletableFuture asyncFindHello( + @RestParam(name = "#") int id) { // 通过 /pipes/hello/find/1234、/pipes/hello/jsfind/1234 查询对象 + if (source != null) source.findAsync(HelloEntity.class, id); + System.out.println("------------进入asyncfind1-------"); + return CompletableFuture.completedFuture(new HelloEntity()); + } + + // 异步查询单个 + @RestMapping(name = "asyncfind2") + public void asyncFindHello( + CompletionHandler hander, + @RestParam(name = "#") int id) { // 通过 /pipes/hello/find/1234、/pipes/hello/jsfind/1234 查询对象 + if (source != null) source.findAsync(HelloEntity.class, id); + System.out.println("-----------进入asyncfind2--------" + hander); + hander.completed(new HelloEntity(id), id); + } + + // 异步查询单个 + @RestMapping(name = "asyncfind3") + public void asyncFindHello( + HelloAsyncHandler hander, + @RestParam(name = "#") int id) { // 通过 /pipes/hello/find/1234、/pipes/hello/jsfind/1234 查询对象 + if (source != null) source.findAsync(HelloEntity.class, id); + System.out.println("-----------进入asyncfind3--------" + hander); + hander.completed(new HelloEntity(id), id); + } +} diff --git a/src/test/java/org/redkale/test/rest/HelloService2.java b/src/test/java/org/redkale/test/rest/HelloService2.java index 6cff004ac..95ed841fe 100644 --- a/src/test/java/org/redkale/test/rest/HelloService2.java +++ b/src/test/java/org/redkale/test/rest/HelloService2.java @@ -1,59 +1,59 @@ -/* - * 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.test.rest; - -import org.redkale.annotation.Resource; -import org.redkale.net.http.*; -import org.redkale.service.*; -import org.redkale.source.*; -import org.redkale.util.Sheet; - -/** 类说明: Flipper : Source组件中的翻页对象 UserInfo :当前用户类 HelloEntity: Hello模块的实体类 HelloBean: Hello模块实现FilterBean的过滤Bean类 */ -@RestService(name = "hello", moduleid = 0, autoMapping = true, repair = true, ignore = false, comment = "Hello服务模块") -public class HelloService2 implements Service { - - @Resource - private DataSource source; - - // 增加记录 - @RestMapping(name = "create", auth = false, comment = "创建Hello对象") - public RetResult createHello( - UserInfo info, @RestParam(name = "bean", comment = "Hello对象") HelloEntity entity) { - entity.setCreator(info == null ? 0 : info.getUserid()); // 设置当前用户ID - entity.setCreatetime(System.currentTimeMillis()); - source.insert(entity); - return new RetResult<>(entity); - } - - // 删除记录 - @RestMapping(name = "delete", auth = false, comment = "根据id删除Hello对象") - public void deleteHello(@RestParam(name = "#", comment = "Hello对象id") int id) { // 通过 /hello/delete/1234 删除对象 - source.delete(HelloEntity.class, id); - } - - // 修改记录 - @RestMapping(name = "update", auth = false, comment = "修改Hello对象") - public void updateHello( - @RestParam(name = "bean", comment = "Hello对象") HelloEntity entity) { // 通过 /hello/update?bean={...} 修改对象 - entity.setUpdatetime(System.currentTimeMillis()); - source.update(entity); - } - - // 查询列表 - @RestConvertCoder(type = HelloEntity.class, field = "createtime", coder = CreateTimeSimpleCoder.class) - @RestMapping(name = "query", auth = false, comment = "查询Hello对象列表") - public Sheet queryHello( - @RestParam(name = "bean", comment = "过滤条件") HelloBean bean, - Flipper flipper) { // 通过 /hello/query/offset:0/limit:20?bean={...} 查询列表 - return source.querySheet(HelloEntity.class, flipper, bean); - } - - // 查询单个 - @RestMapping(name = "find", auth = false, comment = "根据id查找单个Hello对象") - public HelloEntity findHello(@RestParam(name = "#", comment = "Hello对象id") int id) { // 通过 /hello/find/1234 查询对象 - return source.find(HelloEntity.class, id); - } -} +/* + * 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.test.rest; + +import org.redkale.annotation.Resource; +import org.redkale.net.http.*; +import org.redkale.service.*; +import org.redkale.source.*; +import org.redkale.util.Sheet; + +/** 类说明: Flipper : Source组件中的翻页对象 UserInfo :当前用户类 HelloEntity: Hello模块的实体类 HelloBean: Hello模块实现FilterBean的过滤Bean类 */ +@RestService(name = "hello", moduleid = 0, autoMapping = true, repair = true, ignore = false, comment = "Hello服务模块") +public class HelloService2 implements Service { + + @Resource + private DataSource source; + + // 增加记录 + @RestMapping(name = "create", auth = false, comment = "创建Hello对象") + public RetResult createHello( + UserInfo info, @RestParam(name = "bean", comment = "Hello对象") HelloEntity entity) { + entity.setCreator(info == null ? 0 : info.getUserid()); // 设置当前用户ID + entity.setCreatetime(System.currentTimeMillis()); + source.insert(entity); + return new RetResult<>(entity); + } + + // 删除记录 + @RestMapping(name = "delete", auth = false, comment = "根据id删除Hello对象") + public void deleteHello(@RestParam(name = "#", comment = "Hello对象id") int id) { // 通过 /hello/delete/1234 删除对象 + source.delete(HelloEntity.class, id); + } + + // 修改记录 + @RestMapping(name = "update", auth = false, comment = "修改Hello对象") + public void updateHello( + @RestParam(name = "bean", comment = "Hello对象") HelloEntity entity) { // 通过 /hello/update?bean={...} 修改对象 + entity.setUpdatetime(System.currentTimeMillis()); + source.update(entity); + } + + // 查询列表 + @RestConvertCoder(type = HelloEntity.class, field = "createtime", coder = CreateTimeSimpleCoder.class) + @RestMapping(name = "query", auth = false, comment = "查询Hello对象列表") + public Sheet queryHello( + @RestParam(name = "bean", comment = "过滤条件") HelloBean bean, + Flipper flipper) { // 通过 /hello/query/offset:0/limit:20?bean={...} 查询列表 + return source.querySheet(HelloEntity.class, flipper, bean); + } + + // 查询单个 + @RestMapping(name = "find", auth = false, comment = "根据id查找单个Hello对象") + public HelloEntity findHello(@RestParam(name = "#", comment = "Hello对象id") int id) { // 通过 /hello/find/1234 查询对象 + return source.find(HelloEntity.class, id); + } +} diff --git a/src/test/java/org/redkale/test/rest/LoginBean.java b/src/test/java/org/redkale/test/rest/LoginBean.java index 937c42e89..3a2bfea64 100644 --- a/src/test/java/org/redkale/test/rest/LoginBean.java +++ b/src/test/java/org/redkale/test/rest/LoginBean.java @@ -1,43 +1,43 @@ -/* - * 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.test.rest; - -import org.redkale.convert.json.JsonFactory; - -/** - * LoginBean - * - * @author zhangjx - */ -public class LoginBean { - - //账号 - private String account = ""; - - //密码 - private String password = ""; - - public String getAccount() { - return account; - } - - public void setAccount(String account) { - this.account = account; - } - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } - - @Override - public String toString() { - return JsonFactory.root().getConvert().convertTo(this); - } -} +/* + * 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.test.rest; + +import org.redkale.convert.json.JsonFactory; + +/** + * LoginBean + * + * @author zhangjx + */ +public class LoginBean { + + // 账号 + private String account = ""; + + // 密码 + private String password = ""; + + public String getAccount() { + return account; + } + + public void setAccount(String account) { + this.account = account; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + @Override + public String toString() { + return JsonFactory.root().getConvert().convertTo(this); + } +} diff --git a/src/test/java/org/redkale/test/rest/RetCodes.java b/src/test/java/org/redkale/test/rest/RetCodes.java index 496f2dd1a..83310eac4 100644 --- a/src/test/java/org/redkale/test/rest/RetCodes.java +++ b/src/test/java/org/redkale/test/rest/RetCodes.java @@ -1,157 +1,157 @@ -/* - * 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.test.rest; - -import java.lang.reflect.*; -import java.util.*; -import org.redkale.service.*; - -/** @author zhangjx */ -public abstract class RetCodes { - - protected static final Map rets = new HashMap<>(); - - protected RetCodes() {} - // ----------------------------------------------------------------------------------------------------------- - - protected static void load(Class clazz) { - for (Field field : clazz.getFields()) { - if (!Modifier.isStatic(field.getModifiers())) continue; - if (field.getType() != int.class) continue; - RetLabel info = field.getAnnotation(RetLabel.class); - if (info == null) continue; - int value; - try { - value = field.getInt(null); - } catch (Exception ex) { - ex.printStackTrace(); - continue; - } - rets.put(value, info.value()); - } - } - - public static RetResult retResult(int retcode) { - if (retcode == 0) return RetResult.success(); - return new RetResult(retcode, retInfo(retcode)); - } - - public static String retInfo(int retcode) { - if (retcode == 0) return "成功"; - return rets.getOrDefault(retcode, "未知错误"); - } - - // 2000_0001 - 2999_9999 预留给 Redkale的扩展包redkalex使用 - // 3000_0001 - 7999_9999 为平台系统使用 - // 8000_0001 - 9999_9999 为OSS系统使用 - // ------------------------------------- 通用模块 ----------------------------------------- - @RetLabel("参数无效") - public static final int RET_PARAMS_ILLEGAL = 30010001; - - @RetLabel("无上传文件") - public static final int RET_UPLOAD_NOFILE = 30010002; - - @RetLabel("上传文件过大") - public static final int RET_UPLOAD_FILETOOBIG = 30010003; - - @RetLabel("上传文件不是图片") - public static final int RET_UPLOAD_NOTIMAGE = 30010004; - - // ------------------------------------- 用户模块 ----------------------------------------- - @RetLabel("未登录") - public static final int RET_USER_UNLOGIN = 30020001; - - @RetLabel("用户登录失败") - public static final int RET_USER_LOGIN_FAIL = 30020002; - - @RetLabel("用户或密码错误") - public static final int RET_USER_ACCOUNT_PWD_ILLEGAL = 30020003; - - @RetLabel("密码设置无效") - public static final int RET_USER_PASSWORD_ILLEGAL = 30020004; - - @RetLabel("用户被禁用") - public static final int RET_USER_FREEZED = 30020005; - - @RetLabel("用户权限不够") - public static final int RET_USER_AUTH_ILLEGAL = 30020006; - - @RetLabel("用户不存在") - public static final int RET_USER_NOTEXISTS = 30020007; - - @RetLabel("用户状态异常") - public static final int RET_USER_STATUS_ILLEGAL = 30020008; - - @RetLabel("用户注册参数无效") - public static final int RET_USER_SIGNUP_ILLEGAL = 30020009; - - @RetLabel("用户性别参数无效") - public static final int RET_USER_GENDER_ILLEGAL = 30020010; - - @RetLabel("用户名无效") - public static final int RET_USER_USERNAME_ILLEGAL = 30020011; - - @RetLabel("用户账号无效") - public static final int RET_USER_ACCOUNT_ILLEGAL = 30020012; - - @RetLabel("用户账号已存在") - public static final int RET_USER_ACCOUNT_EXISTS = 30020013; - - @RetLabel("手机号码无效") - public static final int RET_USER_MOBILE_ILLEGAL = 30020014; - - @RetLabel("手机号码已存在") - public static final int RET_USER_MOBILE_EXISTS = 30020015; - - @RetLabel("手机验证码发送过于频繁") - public static final int RET_USER_MOBILE_SMSFREQUENT = 30020016; - - @RetLabel("邮箱地址无效") - public static final int RET_USER_EMAIL_ILLEGAL = 30020017; - - @RetLabel("邮箱地址已存在") - public static final int RET_USER_EMAIL_EXISTS = 30020018; - - @RetLabel("微信绑定号无效") - public static final int RET_USER_WXID_ILLEGAL = 30020019; - - @RetLabel("微信绑定号已存在") - public static final int RET_USER_WXID_EXISTS = 30020020; - - @RetLabel("绑定微信号失败") - public static final int RET_USER_WXID_BIND_FAIL = 30020021; - - @RetLabel("QQ绑定号无效") - public static final int RET_USER_QQID_ILLEGAL = 30020022; - - @RetLabel("QQ绑定号已存在") - public static final int RET_USER_QQID_EXISTS = 30020023; - - @RetLabel("绑定QQ号失败") - public static final int RET_USER_QQID_BIND_FAIL = 30020024; - - @RetLabel("获取绑定QQ信息失败") - public static final int RET_USER_QQID_INFO_FAIL = 30020025; - - @RetLabel("验证码无效") - public static final int RET_USER_RANDCODE_ILLEGAL = 30020026; // 邮件或者短信验证码 - - @RetLabel("验证码已过期") - public static final int RET_USER_RANDCODE_EXPIRED = 30020027; // 邮件或者短信验证码 - - @RetLabel("验证码错误或失效") - public static final int RET_USER_CAPTCHA_ILLEGAL = 30020028; // 图片验证码 - - @RetLabel("用户类型无效") - public static final int RET_USER_TYPE_ILLEGAL = 30020029; - - @RetLabel("用户设备ID无效") - public static final int RET_USER_APPTOKEN_ILLEGAL = 30020030; - - static { - load(RetCodes.class); - } -} +/* + * 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.test.rest; + +import java.lang.reflect.*; +import java.util.*; +import org.redkale.service.*; + +/** @author zhangjx */ +public abstract class RetCodes { + + protected static final Map rets = new HashMap<>(); + + protected RetCodes() {} + // ----------------------------------------------------------------------------------------------------------- + + protected static void load(Class clazz) { + for (Field field : clazz.getFields()) { + if (!Modifier.isStatic(field.getModifiers())) continue; + if (field.getType() != int.class) continue; + RetLabel info = field.getAnnotation(RetLabel.class); + if (info == null) continue; + int value; + try { + value = field.getInt(null); + } catch (Exception ex) { + ex.printStackTrace(); + continue; + } + rets.put(value, info.value()); + } + } + + public static RetResult retResult(int retcode) { + if (retcode == 0) return RetResult.success(); + return new RetResult(retcode, retInfo(retcode)); + } + + public static String retInfo(int retcode) { + if (retcode == 0) return "成功"; + return rets.getOrDefault(retcode, "未知错误"); + } + + // 2000_0001 - 2999_9999 预留给 Redkale的扩展包redkalex使用 + // 3000_0001 - 7999_9999 为平台系统使用 + // 8000_0001 - 9999_9999 为OSS系统使用 + // ------------------------------------- 通用模块 ----------------------------------------- + @RetLabel("参数无效") + public static final int RET_PARAMS_ILLEGAL = 30010001; + + @RetLabel("无上传文件") + public static final int RET_UPLOAD_NOFILE = 30010002; + + @RetLabel("上传文件过大") + public static final int RET_UPLOAD_FILETOOBIG = 30010003; + + @RetLabel("上传文件不是图片") + public static final int RET_UPLOAD_NOTIMAGE = 30010004; + + // ------------------------------------- 用户模块 ----------------------------------------- + @RetLabel("未登录") + public static final int RET_USER_UNLOGIN = 30020001; + + @RetLabel("用户登录失败") + public static final int RET_USER_LOGIN_FAIL = 30020002; + + @RetLabel("用户或密码错误") + public static final int RET_USER_ACCOUNT_PWD_ILLEGAL = 30020003; + + @RetLabel("密码设置无效") + public static final int RET_USER_PASSWORD_ILLEGAL = 30020004; + + @RetLabel("用户被禁用") + public static final int RET_USER_FREEZED = 30020005; + + @RetLabel("用户权限不够") + public static final int RET_USER_AUTH_ILLEGAL = 30020006; + + @RetLabel("用户不存在") + public static final int RET_USER_NOTEXISTS = 30020007; + + @RetLabel("用户状态异常") + public static final int RET_USER_STATUS_ILLEGAL = 30020008; + + @RetLabel("用户注册参数无效") + public static final int RET_USER_SIGNUP_ILLEGAL = 30020009; + + @RetLabel("用户性别参数无效") + public static final int RET_USER_GENDER_ILLEGAL = 30020010; + + @RetLabel("用户名无效") + public static final int RET_USER_USERNAME_ILLEGAL = 30020011; + + @RetLabel("用户账号无效") + public static final int RET_USER_ACCOUNT_ILLEGAL = 30020012; + + @RetLabel("用户账号已存在") + public static final int RET_USER_ACCOUNT_EXISTS = 30020013; + + @RetLabel("手机号码无效") + public static final int RET_USER_MOBILE_ILLEGAL = 30020014; + + @RetLabel("手机号码已存在") + public static final int RET_USER_MOBILE_EXISTS = 30020015; + + @RetLabel("手机验证码发送过于频繁") + public static final int RET_USER_MOBILE_SMSFREQUENT = 30020016; + + @RetLabel("邮箱地址无效") + public static final int RET_USER_EMAIL_ILLEGAL = 30020017; + + @RetLabel("邮箱地址已存在") + public static final int RET_USER_EMAIL_EXISTS = 30020018; + + @RetLabel("微信绑定号无效") + public static final int RET_USER_WXID_ILLEGAL = 30020019; + + @RetLabel("微信绑定号已存在") + public static final int RET_USER_WXID_EXISTS = 30020020; + + @RetLabel("绑定微信号失败") + public static final int RET_USER_WXID_BIND_FAIL = 30020021; + + @RetLabel("QQ绑定号无效") + public static final int RET_USER_QQID_ILLEGAL = 30020022; + + @RetLabel("QQ绑定号已存在") + public static final int RET_USER_QQID_EXISTS = 30020023; + + @RetLabel("绑定QQ号失败") + public static final int RET_USER_QQID_BIND_FAIL = 30020024; + + @RetLabel("获取绑定QQ信息失败") + public static final int RET_USER_QQID_INFO_FAIL = 30020025; + + @RetLabel("验证码无效") + public static final int RET_USER_RANDCODE_ILLEGAL = 30020026; // 邮件或者短信验证码 + + @RetLabel("验证码已过期") + public static final int RET_USER_RANDCODE_EXPIRED = 30020027; // 邮件或者短信验证码 + + @RetLabel("验证码错误或失效") + public static final int RET_USER_CAPTCHA_ILLEGAL = 30020028; // 图片验证码 + + @RetLabel("用户类型无效") + public static final int RET_USER_TYPE_ILLEGAL = 30020029; + + @RetLabel("用户设备ID无效") + public static final int RET_USER_APPTOKEN_ILLEGAL = 30020030; + + static { + load(RetCodes.class); + } +} diff --git a/src/test/java/org/redkale/test/rest/SimpleRestServlet.java b/src/test/java/org/redkale/test/rest/SimpleRestServlet.java index a0a1ad44c..ce0a9d192 100644 --- a/src/test/java/org/redkale/test/rest/SimpleRestServlet.java +++ b/src/test/java/org/redkale/test/rest/SimpleRestServlet.java @@ -1,37 +1,37 @@ -package org.redkale.test.rest; - -import java.io.IOException; -import org.redkale.annotation.Resource; -import org.redkale.net.http.*; -import org.redkale.service.RetResult; - -public class SimpleRestServlet extends HttpServlet { - - protected static final RetResult RET_UNLOGIN = RetCodes.retResult(RetCodes.RET_USER_UNLOGIN); - - protected static final RetResult RET_AUTHILLEGAL = RetCodes.retResult(RetCodes.RET_USER_AUTH_ILLEGAL); - - @Resource - private UserService userService = new UserService(); - - @Override - public void preExecute(HttpRequest request, HttpResponse response) throws IOException { - final String sessionid = request.getSessionid(true); - if (sessionid != null) { - UserInfo user = userService.current(sessionid); - if (user != null) request.setCurrentUserid(user.getUserid()); - } - response.nextEvent(); - } - - // 普通鉴权 - @Override - public void authenticate(HttpRequest request, HttpResponse response) throws IOException { - int userid = request.currentUserid(int.class); - if (userid < 1) { - response.finishJson(RET_UNLOGIN); - return; - } - response.nextEvent(); - } -} +package org.redkale.test.rest; + +import java.io.IOException; +import org.redkale.annotation.Resource; +import org.redkale.net.http.*; +import org.redkale.service.RetResult; + +public class SimpleRestServlet extends HttpServlet { + + protected static final RetResult RET_UNLOGIN = RetCodes.retResult(RetCodes.RET_USER_UNLOGIN); + + protected static final RetResult RET_AUTHILLEGAL = RetCodes.retResult(RetCodes.RET_USER_AUTH_ILLEGAL); + + @Resource + private UserService userService = new UserService(); + + @Override + public void preExecute(HttpRequest request, HttpResponse response) throws IOException { + final String sessionid = request.getSessionid(true); + if (sessionid != null) { + UserInfo user = userService.current(sessionid); + if (user != null) request.setCurrentUserid(user.getUserid()); + } + response.nextEvent(); + } + + // 普通鉴权 + @Override + public void authenticate(HttpRequest request, HttpResponse response) throws IOException { + int userid = request.currentUserid(int.class); + if (userid < 1) { + response.finishJson(RET_UNLOGIN); + return; + } + response.nextEvent(); + } +} diff --git a/src/test/java/org/redkale/test/rest/UserInfo.java b/src/test/java/org/redkale/test/rest/UserInfo.java index e725663d3..751b20a5b 100644 --- a/src/test/java/org/redkale/test/rest/UserInfo.java +++ b/src/test/java/org/redkale/test/rest/UserInfo.java @@ -1,44 +1,44 @@ -package org.redkale.test.rest; - -import org.redkale.convert.json.JsonFactory; -import org.redkale.persistence.Id; - -/** - * 当前用户对象 - * - * @author zhangjx - */ -public class UserInfo { - - @Id - private int userid; - - private String username = ""; - - public int getUserid() { - return userid; - } - - public boolean checkAuth(int moduleid, int actionid) { - if (moduleid == 0 || actionid == 0) return true; - // 权限判断 - return true; - } - - public void setUserid(int userid) { - this.userid = userid; - } - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - @Override - public String toString() { - return JsonFactory.root().getConvert().convertTo(this); - } -} +package org.redkale.test.rest; + +import org.redkale.convert.json.JsonFactory; +import org.redkale.persistence.Id; + +/** + * 当前用户对象 + * + * @author zhangjx + */ +public class UserInfo { + + @Id + private int userid; + + private String username = ""; + + public int getUserid() { + return userid; + } + + public boolean checkAuth(int moduleid, int actionid) { + if (moduleid == 0 || actionid == 0) return true; + // 权限判断 + return true; + } + + public void setUserid(int userid) { + this.userid = userid; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + @Override + public String toString() { + return JsonFactory.root().getConvert().convertTo(this); + } +} diff --git a/src/test/java/org/redkale/test/rest/UserService.java b/src/test/java/org/redkale/test/rest/UserService.java index b679b071f..196db4d0a 100644 --- a/src/test/java/org/redkale/test/rest/UserService.java +++ b/src/test/java/org/redkale/test/rest/UserService.java @@ -1,30 +1,30 @@ -/* - * 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.test.rest; - -import org.redkale.service.*; - -/** - * 简单的定义UserService接口 - * - * @author zhangjx - */ -public class UserService implements Service { - - /** - * 根据登录态获取当前用户信息 - * - * @param sessionid - * @return - */ - public UserInfo current(String sessionid) { - return new UserInfo(); - } - - public RetResult login(LoginBean bean) { - return new RetResult<>(new UserInfo()); - } -} +/* + * 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.test.rest; + +import org.redkale.service.*; + +/** + * 简单的定义UserService接口 + * + * @author zhangjx + */ +public class UserService implements Service { + + /** + * 根据登录态获取当前用户信息 + * + * @param sessionid + * @return + */ + public UserInfo current(String sessionid) { + return new UserInfo(); + } + + public RetResult login(LoginBean bean) { + return new RetResult<>(new UserInfo()); + } +} diff --git a/src/test/java/org/redkale/test/rest/_DynHelloRestServlet1.java b/src/test/java/org/redkale/test/rest/_DynHelloRestServlet1.java index 0d29506d1..63d66da22 100644 --- a/src/test/java/org/redkale/test/rest/_DynHelloRestServlet1.java +++ b/src/test/java/org/redkale/test/rest/_DynHelloRestServlet1.java @@ -1,177 +1,177 @@ -package org.redkale.test.rest; - -import java.io.IOException; -import java.io.Serializable; -import java.util.*; -import org.redkale.annotation.Resource; -import org.redkale.net.http.*; -import org.redkale.service.RetResult; -import org.redkale.source.Flipper; -import org.redkale.util.*; - -@WebServlet( - value = {"/hello/*"}, - repair = true) -public class _DynHelloRestServlet1 extends SimpleRestServlet { - - @Resource - private HelloService _redkale_service; - - @Resource - private Map _redkale_servicemap; - - public static void main(String[] args) throws Throwable { - final int port = 8888; - HelloService service = new HelloService(); - HttpServer server = new HttpServer(); - - System.out.println(server.addRestServlet(null, service, null, SimpleRestServlet.class, "/pipes")); - System.out.println(server.addRestServlet(null, new HelloService(3), null, SimpleRestServlet.class, "/pipes")); - - AnyValueWriter conf = AnyValueWriter.create("port", "" + port); - server.init(conf); - server.start(); - Utility.sleep(100); - - HelloEntity entity = new HelloEntity(); - entity.setHelloname("my name"); - Map headers = new HashMap<>(); - headers.put("hello-res", "my res"); - // headers.put(Rest.REST_HEADER_RESNAME, "my-res"); - String url = "http://127.0.0.1:" + port + "/pipes/hello/update?entity={}&bean2={}"; - System.out.println(Utility.postHttpContent(url, headers, null)); - url = "http://127.0.0.1:" + port + "/pipes/hello/update2?entity={}&bean2={}"; - System.out.println(Utility.postHttpContent(url, headers, null)); - - url = "http://127.0.0.1:" + port + "/pipes/hello/asyncfind/1234"; - System.out.println("异步查找: " + Utility.postHttpContent(url, headers, null)); - - url = "http://127.0.0.1:" + port + "/pipes/hello/listmap?map={'a':5}"; - System.out.println("listmap: " + Utility.postHttpContent(url, headers, null)); - - url = "http://127.0.0.1:" + port + "/pipes/hello/create?entity={}"; - System.out.println("增加记录: " + Utility.postHttpContent(url, headers, "{'a':2,'b':3}")); - - url = "http://127.0.0.1:" + port + "/pipes/hello/asyncfind/111111"; - System.out.println("listmap: " + Utility.postHttpContent(url, headers, null)); - url = "http://127.0.0.1:" + port + "/pipes/hello/asyncfind2/22222"; - System.out.println("listmap: " + Utility.postHttpContent(url, headers, null)); - url = "http://127.0.0.1:" + port + "/pipes/hello/asyncfind3/333333"; - System.out.println("listmap: " + Utility.postHttpContent(url, headers, null)); - } - - @HttpMapping(url = "/hello/create", auth = false) - public void create(HttpRequest req, HttpResponse resp) throws IOException { - HelloService service = _redkale_servicemap == null - ? _redkale_service - : _redkale_servicemap.get(req.getHeader(Rest.REST_HEADER_RESNAME, "")); - HelloEntity bean = req.getJsonParameter(HelloEntity.class, "bean"); - bean.setClientaddr(req.getRemoteAddr()); - bean.setResname(req.getHeader("hello-res")); - UserInfo user = new UserInfo(); - RetResult result = service.createHello(user, bean, req.getBodyJson(Map.class)); - resp.finishJson(result); - } - - @HttpMapping(url = "/hello/delete/", auth = false) - public void delete(HttpRequest req, HttpResponse resp) throws IOException { - HelloService service = _redkale_servicemap == null - ? _redkale_service - : _redkale_servicemap.get(req.getHeader(Rest.REST_HEADER_RESNAME, "")); - int id = Integer.parseInt(req.getPathLastParam()); - service.deleteHello(id); - resp.finishJson(RetResult.success()); - } - - @HttpMapping(url = "/hello/update", auth = false) - public void update(HttpRequest req, HttpResponse resp) throws IOException { - HelloService service = _redkale_servicemap == null - ? _redkale_service - : _redkale_servicemap.get(req.getHeader(Rest.REST_HEADER_RESNAME, "")); - String clientaddr = req.getRemoteAddr(); - HelloEntity bean = req.getJsonParameter(HelloEntity.class, "bean"); - bean.setClientaddr(req.getRemoteAddr()); - bean.setResname(req.getHeader("hello-res")); - service.updateHello(clientaddr, bean); - resp.finishJson(RetResult.success()); - } - - @HttpMapping(url = "/hello/partupdate", auth = false) - public void partupdate(HttpRequest req, HttpResponse resp) throws IOException { - HelloService service = _redkale_servicemap == null - ? _redkale_service - : _redkale_servicemap.get(req.getHeader(Rest.REST_HEADER_RESNAME, "")); - HelloEntity bean = req.getJsonParameter(HelloEntity.class, "bean"); - bean.setClientaddr(req.getRemoteAddr()); - bean.setResname(req.getHeader("hello-res")); - String[] cols = req.getJsonParameter(String[].class, "cols"); - service.updateHello(bean, cols); - resp.finishJson(RetResult.success()); - } - - @HttpMapping(url = "/hello/query", auth = false) - public void query(HttpRequest req, HttpResponse resp) throws IOException { - HelloService service = _redkale_servicemap == null - ? _redkale_service - : _redkale_servicemap.get(req.getHeader(Rest.REST_HEADER_RESNAME, "")); - HelloBean bean = req.getJsonParameter(HelloBean.class, "bean"); - bean.setClientaddr(req.getRemoteAddr()); - bean.setUseragent(req.getHeader("User-Agent")); - bean.setRescookie(req.getCookie("hello-cookie")); - bean.setSessionid(req.getSessionid(false)); - Flipper flipper = req.getFlipper(); - Sheet result = service.queryHello(bean, flipper); - resp.finishJson(result); - } - - @HttpMapping(url = "/hello/list", auth = false) - public void list(HttpRequest req, HttpResponse resp) throws IOException { - HelloService service = _redkale_servicemap == null - ? _redkale_service - : _redkale_servicemap.get(req.getHeader(Rest.REST_HEADER_RESNAME, "")); - HelloBean bean = req.getJsonParameter(HelloBean.class, "bean"); - bean.setClientaddr(req.getRemoteAddr()); - bean.setUseragent(req.getHeader("User-Agent")); - bean.setRescookie(req.getCookie("hello-cookie")); - bean.setSessionid(req.getSessionid(false)); - List result = service.queryHello(bean); - resp.finishJson(result); - } - - @HttpMapping(url = "/hello/find/", auth = false) - public void find(HttpRequest req, HttpResponse resp) throws IOException { - HelloService service = _redkale_servicemap == null - ? _redkale_service - : _redkale_servicemap.get(req.getHeader(Rest.REST_HEADER_RESNAME, "")); - int id = Integer.parseInt(req.getPathLastParam()); - HelloEntity bean = service.findHello(id); - resp.finishJson(bean); - } - - @HttpMapping(url = "/hello/asyncfind/", auth = false) - public void asyncfind(HttpRequest req, HttpResponse resp) throws IOException { - HelloService service = _redkale_servicemap == null - ? _redkale_service - : _redkale_servicemap.get(req.getHeader(Rest.REST_HEADER_RESNAME, "")); - int id = Integer.parseInt(req.getPathLastParam()); - resp.finishJson(service.asyncFindHello(id)); - } - - @HttpMapping(url = "/hello/asyncfind2/", auth = false) - public void asyncfind2(HttpRequest req, HttpResponse resp) throws IOException { - HelloService service = _redkale_servicemap == null - ? _redkale_service - : _redkale_servicemap.get(req.getHeader(Rest.REST_HEADER_RESNAME, "")); - int id = Integer.parseInt(req.getPathLastParam()); - service.asyncFindHello(resp.createAsyncHandler(), id); - } - - @HttpMapping(url = "/hello/asyncfind3/", auth = false) - public void asyncfind3(HttpRequest req, HttpResponse resp) throws IOException { - HelloService service = _redkale_servicemap == null - ? _redkale_service - : _redkale_servicemap.get(req.getHeader(Rest.REST_HEADER_RESNAME, "")); - int id = Integer.parseInt(req.getPathLastParam()); - service.asyncFindHello(resp.createAsyncHandler(HelloAsyncHandler.class), id); - } -} +package org.redkale.test.rest; + +import java.io.IOException; +import java.io.Serializable; +import java.util.*; +import org.redkale.annotation.Resource; +import org.redkale.net.http.*; +import org.redkale.service.RetResult; +import org.redkale.source.Flipper; +import org.redkale.util.*; + +@WebServlet( + value = {"/hello/*"}, + repair = true) +public class _DynHelloRestServlet1 extends SimpleRestServlet { + + @Resource + private HelloService _redkale_service; + + @Resource + private Map _redkale_servicemap; + + public static void main(String[] args) throws Throwable { + final int port = 8888; + HelloService service = new HelloService(); + HttpServer server = new HttpServer(); + + System.out.println(server.addRestServlet(null, service, null, SimpleRestServlet.class, "/pipes")); + System.out.println(server.addRestServlet(null, new HelloService(3), null, SimpleRestServlet.class, "/pipes")); + + AnyValueWriter conf = AnyValueWriter.create("port", "" + port); + server.init(conf); + server.start(); + Utility.sleep(100); + + HelloEntity entity = new HelloEntity(); + entity.setHelloname("my name"); + Map headers = new HashMap<>(); + headers.put("hello-res", "my res"); + // headers.put(Rest.REST_HEADER_RESNAME, "my-res"); + String url = "http://127.0.0.1:" + port + "/pipes/hello/update?entity={}&bean2={}"; + System.out.println(Utility.postHttpContent(url, headers, null)); + url = "http://127.0.0.1:" + port + "/pipes/hello/update2?entity={}&bean2={}"; + System.out.println(Utility.postHttpContent(url, headers, null)); + + url = "http://127.0.0.1:" + port + "/pipes/hello/asyncfind/1234"; + System.out.println("异步查找: " + Utility.postHttpContent(url, headers, null)); + + url = "http://127.0.0.1:" + port + "/pipes/hello/listmap?map={'a':5}"; + System.out.println("listmap: " + Utility.postHttpContent(url, headers, null)); + + url = "http://127.0.0.1:" + port + "/pipes/hello/create?entity={}"; + System.out.println("增加记录: " + Utility.postHttpContent(url, headers, "{'a':2,'b':3}")); + + url = "http://127.0.0.1:" + port + "/pipes/hello/asyncfind/111111"; + System.out.println("listmap: " + Utility.postHttpContent(url, headers, null)); + url = "http://127.0.0.1:" + port + "/pipes/hello/asyncfind2/22222"; + System.out.println("listmap: " + Utility.postHttpContent(url, headers, null)); + url = "http://127.0.0.1:" + port + "/pipes/hello/asyncfind3/333333"; + System.out.println("listmap: " + Utility.postHttpContent(url, headers, null)); + } + + @HttpMapping(url = "/hello/create", auth = false) + public void create(HttpRequest req, HttpResponse resp) throws IOException { + HelloService service = _redkale_servicemap == null + ? _redkale_service + : _redkale_servicemap.get(req.getHeader(Rest.REST_HEADER_RESNAME, "")); + HelloEntity bean = req.getJsonParameter(HelloEntity.class, "bean"); + bean.setClientaddr(req.getRemoteAddr()); + bean.setResname(req.getHeader("hello-res")); + UserInfo user = new UserInfo(); + RetResult result = service.createHello(user, bean, req.getBodyJson(Map.class)); + resp.finishJson(result); + } + + @HttpMapping(url = "/hello/delete/", auth = false) + public void delete(HttpRequest req, HttpResponse resp) throws IOException { + HelloService service = _redkale_servicemap == null + ? _redkale_service + : _redkale_servicemap.get(req.getHeader(Rest.REST_HEADER_RESNAME, "")); + int id = Integer.parseInt(req.getPathLastParam()); + service.deleteHello(id); + resp.finishJson(RetResult.success()); + } + + @HttpMapping(url = "/hello/update", auth = false) + public void update(HttpRequest req, HttpResponse resp) throws IOException { + HelloService service = _redkale_servicemap == null + ? _redkale_service + : _redkale_servicemap.get(req.getHeader(Rest.REST_HEADER_RESNAME, "")); + String clientaddr = req.getRemoteAddr(); + HelloEntity bean = req.getJsonParameter(HelloEntity.class, "bean"); + bean.setClientaddr(req.getRemoteAddr()); + bean.setResname(req.getHeader("hello-res")); + service.updateHello(clientaddr, bean); + resp.finishJson(RetResult.success()); + } + + @HttpMapping(url = "/hello/partupdate", auth = false) + public void partupdate(HttpRequest req, HttpResponse resp) throws IOException { + HelloService service = _redkale_servicemap == null + ? _redkale_service + : _redkale_servicemap.get(req.getHeader(Rest.REST_HEADER_RESNAME, "")); + HelloEntity bean = req.getJsonParameter(HelloEntity.class, "bean"); + bean.setClientaddr(req.getRemoteAddr()); + bean.setResname(req.getHeader("hello-res")); + String[] cols = req.getJsonParameter(String[].class, "cols"); + service.updateHello(bean, cols); + resp.finishJson(RetResult.success()); + } + + @HttpMapping(url = "/hello/query", auth = false) + public void query(HttpRequest req, HttpResponse resp) throws IOException { + HelloService service = _redkale_servicemap == null + ? _redkale_service + : _redkale_servicemap.get(req.getHeader(Rest.REST_HEADER_RESNAME, "")); + HelloBean bean = req.getJsonParameter(HelloBean.class, "bean"); + bean.setClientaddr(req.getRemoteAddr()); + bean.setUseragent(req.getHeader("User-Agent")); + bean.setRescookie(req.getCookie("hello-cookie")); + bean.setSessionid(req.getSessionid(false)); + Flipper flipper = req.getFlipper(); + Sheet result = service.queryHello(bean, flipper); + resp.finishJson(result); + } + + @HttpMapping(url = "/hello/list", auth = false) + public void list(HttpRequest req, HttpResponse resp) throws IOException { + HelloService service = _redkale_servicemap == null + ? _redkale_service + : _redkale_servicemap.get(req.getHeader(Rest.REST_HEADER_RESNAME, "")); + HelloBean bean = req.getJsonParameter(HelloBean.class, "bean"); + bean.setClientaddr(req.getRemoteAddr()); + bean.setUseragent(req.getHeader("User-Agent")); + bean.setRescookie(req.getCookie("hello-cookie")); + bean.setSessionid(req.getSessionid(false)); + List result = service.queryHello(bean); + resp.finishJson(result); + } + + @HttpMapping(url = "/hello/find/", auth = false) + public void find(HttpRequest req, HttpResponse resp) throws IOException { + HelloService service = _redkale_servicemap == null + ? _redkale_service + : _redkale_servicemap.get(req.getHeader(Rest.REST_HEADER_RESNAME, "")); + int id = Integer.parseInt(req.getPathLastParam()); + HelloEntity bean = service.findHello(id); + resp.finishJson(bean); + } + + @HttpMapping(url = "/hello/asyncfind/", auth = false) + public void asyncfind(HttpRequest req, HttpResponse resp) throws IOException { + HelloService service = _redkale_servicemap == null + ? _redkale_service + : _redkale_servicemap.get(req.getHeader(Rest.REST_HEADER_RESNAME, "")); + int id = Integer.parseInt(req.getPathLastParam()); + resp.finishJson(service.asyncFindHello(id)); + } + + @HttpMapping(url = "/hello/asyncfind2/", auth = false) + public void asyncfind2(HttpRequest req, HttpResponse resp) throws IOException { + HelloService service = _redkale_servicemap == null + ? _redkale_service + : _redkale_servicemap.get(req.getHeader(Rest.REST_HEADER_RESNAME, "")); + int id = Integer.parseInt(req.getPathLastParam()); + service.asyncFindHello(resp.createAsyncHandler(), id); + } + + @HttpMapping(url = "/hello/asyncfind3/", auth = false) + public void asyncfind3(HttpRequest req, HttpResponse resp) throws IOException { + HelloService service = _redkale_servicemap == null + ? _redkale_service + : _redkale_servicemap.get(req.getHeader(Rest.REST_HEADER_RESNAME, "")); + int id = Integer.parseInt(req.getPathLastParam()); + service.asyncFindHello(resp.createAsyncHandler(HelloAsyncHandler.class), id); + } +} diff --git a/src/test/java/org/redkale/test/rest/_DynHelloRestServlet2.java b/src/test/java/org/redkale/test/rest/_DynHelloRestServlet2.java index 310330a46..be24c891c 100644 --- a/src/test/java/org/redkale/test/rest/_DynHelloRestServlet2.java +++ b/src/test/java/org/redkale/test/rest/_DynHelloRestServlet2.java @@ -1,96 +1,96 @@ -/* - * 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.test.rest; - -import java.io.IOException; -import java.util.Map; -import org.redkale.annotation.Resource; -import org.redkale.net.http.*; -import org.redkale.service.RetResult; -import org.redkale.source.Flipper; -import org.redkale.util.*; - -/** @author zhangjx */ -@WebServlet( - value = {"/hello/*"}, - repair = true) -public class _DynHelloRestServlet2 extends SimpleRestServlet { - - @Resource - private HelloService2 _redkale_service; - - @Resource - private Map _redkale_servicemap; - - @HttpMapping(url = "/hello/create", auth = false, comment = "创建Hello对象") - @HttpParam(name = "bean", type = HelloEntity.class, comment = "Hello对象") - public void create(HttpRequest req, HttpResponse resp) throws IOException { - HelloService2 service = _redkale_servicemap == null - ? _redkale_service - : _redkale_servicemap.get(req.getHeader(Rest.REST_HEADER_RESNAME, "")); - HelloEntity bean = req.getJsonParameter(HelloEntity.class, "bean"); - bean.setClientaddr(req.getRemoteAddr()); - bean.setResname(req.getHeader("hello-res")); - bean.setBodys(req.getBody()); - bean.setBodystr(req.getBodyUTF8()); - UserInfo user = new UserInfo(); - RetResult result = service.createHello(user, bean); - resp.finishJson(result); - } - - @HttpMapping(url = "/hello/delete/", auth = false, comment = "根据id删除Hello对象") - @HttpParam(name = "#", type = int.class, comment = "Hello对象id") - public void delete(HttpRequest req, HttpResponse resp) throws IOException { - HelloService2 service = _redkale_servicemap == null - ? _redkale_service - : _redkale_servicemap.get(req.getHeader(Rest.REST_HEADER_RESNAME, "")); - int id = Integer.parseInt(req.getPathLastParam()); - service.deleteHello(id); - resp.finishJson(RetResult.success()); - } - - @HttpMapping(url = "/hello/update", auth = false, comment = "修改Hello对象") - @HttpParam(name = "bean", type = HelloEntity.class, comment = "Hello对象") - public void update(HttpRequest req, HttpResponse resp) throws IOException { - HelloService2 service = _redkale_servicemap == null - ? _redkale_service - : _redkale_servicemap.get(req.getHeader(Rest.REST_HEADER_RESNAME, "")); - HelloEntity bean = req.getJsonParameter(HelloEntity.class, "bean"); - bean.setClientaddr(req.getRemoteAddr()); - bean.setResname(req.getHeader("hello-res")); - bean.setBodys(req.getBody()); - bean.setBodystr(req.getBodyUTF8()); - service.updateHello(bean); - resp.finishJson(RetResult.success()); - } - - @HttpMapping(url = "/hello/query", auth = false, comment = "查询Hello对象列表") - @HttpParam(name = "bean", type = HelloBean.class, comment = "过滤条件") - public void query(HttpRequest req, HttpResponse resp) throws IOException { - HelloService2 service = _redkale_servicemap == null - ? _redkale_service - : _redkale_servicemap.get(req.getHeader(Rest.REST_HEADER_RESNAME, "")); - HelloBean bean = req.getJsonParameter(HelloBean.class, "bean"); - bean.setClientaddr(req.getRemoteAddr()); - bean.setUseragent(req.getHeader("User-Agent")); - bean.setRescookie(req.getCookie("hello-cookie")); - bean.setSessionid(req.getSessionid(false)); - Flipper flipper = req.getFlipper(); - Sheet result = service.queryHello(bean, flipper); - resp.finishJson(result); - } - - @HttpMapping(url = "/hello/find/", auth = false, comment = "根据id删除Hello对象") - @HttpParam(name = "#", type = int.class, comment = "Hello对象id") - public void find(HttpRequest req, HttpResponse resp) throws IOException { - HelloService2 service = _redkale_servicemap == null - ? _redkale_service - : _redkale_servicemap.get(req.getHeader(Rest.REST_HEADER_RESNAME, "")); - int id = Integer.parseInt(req.getPathLastParam()); - HelloEntity bean = service.findHello(id); - resp.finishJson(bean); - } -} +/* + * 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.test.rest; + +import java.io.IOException; +import java.util.Map; +import org.redkale.annotation.Resource; +import org.redkale.net.http.*; +import org.redkale.service.RetResult; +import org.redkale.source.Flipper; +import org.redkale.util.*; + +/** @author zhangjx */ +@WebServlet( + value = {"/hello/*"}, + repair = true) +public class _DynHelloRestServlet2 extends SimpleRestServlet { + + @Resource + private HelloService2 _redkale_service; + + @Resource + private Map _redkale_servicemap; + + @HttpMapping(url = "/hello/create", auth = false, comment = "创建Hello对象") + @HttpParam(name = "bean", type = HelloEntity.class, comment = "Hello对象") + public void create(HttpRequest req, HttpResponse resp) throws IOException { + HelloService2 service = _redkale_servicemap == null + ? _redkale_service + : _redkale_servicemap.get(req.getHeader(Rest.REST_HEADER_RESNAME, "")); + HelloEntity bean = req.getJsonParameter(HelloEntity.class, "bean"); + bean.setClientaddr(req.getRemoteAddr()); + bean.setResname(req.getHeader("hello-res")); + bean.setBodys(req.getBody()); + bean.setBodystr(req.getBodyUTF8()); + UserInfo user = new UserInfo(); + RetResult result = service.createHello(user, bean); + resp.finishJson(result); + } + + @HttpMapping(url = "/hello/delete/", auth = false, comment = "根据id删除Hello对象") + @HttpParam(name = "#", type = int.class, comment = "Hello对象id") + public void delete(HttpRequest req, HttpResponse resp) throws IOException { + HelloService2 service = _redkale_servicemap == null + ? _redkale_service + : _redkale_servicemap.get(req.getHeader(Rest.REST_HEADER_RESNAME, "")); + int id = Integer.parseInt(req.getPathLastParam()); + service.deleteHello(id); + resp.finishJson(RetResult.success()); + } + + @HttpMapping(url = "/hello/update", auth = false, comment = "修改Hello对象") + @HttpParam(name = "bean", type = HelloEntity.class, comment = "Hello对象") + public void update(HttpRequest req, HttpResponse resp) throws IOException { + HelloService2 service = _redkale_servicemap == null + ? _redkale_service + : _redkale_servicemap.get(req.getHeader(Rest.REST_HEADER_RESNAME, "")); + HelloEntity bean = req.getJsonParameter(HelloEntity.class, "bean"); + bean.setClientaddr(req.getRemoteAddr()); + bean.setResname(req.getHeader("hello-res")); + bean.setBodys(req.getBody()); + bean.setBodystr(req.getBodyUTF8()); + service.updateHello(bean); + resp.finishJson(RetResult.success()); + } + + @HttpMapping(url = "/hello/query", auth = false, comment = "查询Hello对象列表") + @HttpParam(name = "bean", type = HelloBean.class, comment = "过滤条件") + public void query(HttpRequest req, HttpResponse resp) throws IOException { + HelloService2 service = _redkale_servicemap == null + ? _redkale_service + : _redkale_servicemap.get(req.getHeader(Rest.REST_HEADER_RESNAME, "")); + HelloBean bean = req.getJsonParameter(HelloBean.class, "bean"); + bean.setClientaddr(req.getRemoteAddr()); + bean.setUseragent(req.getHeader("User-Agent")); + bean.setRescookie(req.getCookie("hello-cookie")); + bean.setSessionid(req.getSessionid(false)); + Flipper flipper = req.getFlipper(); + Sheet result = service.queryHello(bean, flipper); + resp.finishJson(result); + } + + @HttpMapping(url = "/hello/find/", auth = false, comment = "根据id删除Hello对象") + @HttpParam(name = "#", type = int.class, comment = "Hello对象id") + public void find(HttpRequest req, HttpResponse resp) throws IOException { + HelloService2 service = _redkale_servicemap == null + ? _redkale_service + : _redkale_servicemap.get(req.getHeader(Rest.REST_HEADER_RESNAME, "")); + int id = Integer.parseInt(req.getPathLastParam()); + HelloEntity bean = service.findHello(id); + resp.finishJson(bean); + } +} diff --git a/src/test/java/org/redkale/test/schedule/ScheduleService.java b/src/test/java/org/redkale/test/schedule/ScheduleService.java index d2108528a..c62f75540 100644 --- a/src/test/java/org/redkale/test/schedule/ScheduleService.java +++ b/src/test/java/org/redkale/test/schedule/ScheduleService.java @@ -1,28 +1,28 @@ -/* - * - */ -package org.redkale.test.schedule; - -import org.redkale.schedule.Scheduled; -import org.redkale.service.Service; -import org.redkale.util.Times; - -/** @author zhangjx */ -public class ScheduleService implements Service { - - @Scheduled(cron = "0/1 * * * * ?") - public void task1() { - System.out.println(Times.nowMillis() + "每秒-----------执行task1"); - } - - @Scheduled(cron = "0/1 * * * * ?") - public String task2() { - System.out.println(Times.nowMillis() + "每秒*****执行task2"); - return ""; - } - - @Scheduled(cron = "0/1 * * * * ?") - private void task3() { - System.out.println(Times.nowMillis() + "每秒执行task3"); - } -} +/* + * + */ +package org.redkale.test.schedule; + +import org.redkale.schedule.Scheduled; +import org.redkale.service.Service; +import org.redkale.util.Times; + +/** @author zhangjx */ +public class ScheduleService implements Service { + + @Scheduled(cron = "0/1 * * * * ?") + public void task1() { + System.out.println(Times.nowMillis() + "每秒-----------执行task1"); + } + + @Scheduled(cron = "0/1 * * * * ?") + public String task2() { + System.out.println(Times.nowMillis() + "每秒*****执行task2"); + return ""; + } + + @Scheduled(cron = "0/1 * * * * ?") + private void task3() { + System.out.println(Times.nowMillis() + "每秒执行task3"); + } +} diff --git a/src/test/java/org/redkale/test/schedule/SchedulingTest.java b/src/test/java/org/redkale/test/schedule/SchedulingTest.java index 82121d808..9d945ac25 100644 --- a/src/test/java/org/redkale/test/schedule/SchedulingTest.java +++ b/src/test/java/org/redkale/test/schedule/SchedulingTest.java @@ -1,28 +1,28 @@ -/* - * - */ -package org.redkale.test.schedule; - -import org.junit.jupiter.api.Test; -import org.redkale.schedule.spi.ScheduleManagerService; -import org.redkale.util.Utility; - -/** @author zhangjx */ -public class SchedulingTest { - - public static void main(String[] args) throws Throwable { - SchedulingTest test = new SchedulingTest(); - test.run(); - } - - @Test - public void run() throws Exception { - ScheduleManagerService manager = ScheduleManagerService.create(null); - manager.init(null); - ScheduleService service = new ScheduleService(); - manager.schedule(service); - Utility.sleep(3000); - manager.unschedule(service); - manager.destroy(null); - } -} +/* + * + */ +package org.redkale.test.schedule; + +import org.junit.jupiter.api.Test; +import org.redkale.schedule.spi.ScheduleManagerService; +import org.redkale.util.Utility; + +/** @author zhangjx */ +public class SchedulingTest { + + public static void main(String[] args) throws Throwable { + SchedulingTest test = new SchedulingTest(); + test.run(); + } + + @Test + public void run() throws Exception { + ScheduleManagerService manager = ScheduleManagerService.create(null); + manager.init(null); + ScheduleService service = new ScheduleService(); + manager.schedule(service); + Utility.sleep(3000); + manager.unschedule(service); + manager.destroy(null); + } +} diff --git a/src/test/java/org/redkale/test/service/ABMainService.java b/src/test/java/org/redkale/test/service/ABMainService.java index e1985290e..1f051183d 100644 --- a/src/test/java/org/redkale/test/service/ABMainService.java +++ b/src/test/java/org/redkale/test/service/ABMainService.java @@ -1,249 +1,249 @@ -/* - * 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.test.service; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.nio.ByteBuffer; -import java.nio.channels.*; -import java.nio.charset.StandardCharsets; -import java.util.concurrent.*; -import java.util.concurrent.atomic.*; -import java.util.logging.Level; -import org.redkale.annotation.Resource; -import org.redkale.boot.*; -import org.redkale.convert.bson.BsonConvert; -import org.redkale.convert.json.JsonConvert; -import org.redkale.inject.ResourceFactory; -import org.redkale.net.AsyncIOGroup; -import org.redkale.net.client.ClientAddress; -import org.redkale.net.http.*; -import org.redkale.net.sncp.*; -import org.redkale.service.Service; -import org.redkale.util.*; - -/** @author zhangjx */ -@RestService(name = "abmain") -public class ABMainService implements Service { - - private static final int abport = 8866; - - @Resource - private BCService bcService; - - public static void remote(String[] args) throws Throwable { - System.out.println("------------------- 远程模式调用 -----------------------------------"); - final Application application = Application.create(true); - final AsyncIOGroup asyncGroup = new AsyncIOGroup(8192, 16); - asyncGroup.start(); - InetSocketAddress sncpAddress = new InetSocketAddress("127.0.0.1", abport); - final SncpClient client = - new SncpClient("", asyncGroup, "0", sncpAddress, new ClientAddress(sncpAddress), "TCP", 16, 100); - final ResourceFactory resFactory = ResourceFactory.create(); - resFactory.register(JsonConvert.root()); - resFactory.register(BsonConvert.root()); - final SncpRpcGroups rpcGroups = application.getSncpRpcGroups(); - rpcGroups.computeIfAbsent("g77", "TCP").putAddress(new InetSocketAddress("127.0.0.1", 5577)); - rpcGroups.computeIfAbsent("g88", "TCP").putAddress(new InetSocketAddress("127.0.0.1", 5588)); - rpcGroups.computeIfAbsent("g99", "TCP").putAddress(new InetSocketAddress("127.0.0.1", 5599)); - - // ------------------------ 初始化 CService ------------------------------------ - CService cservice = Sncp.createSimpleLocalService(CService.class, resFactory); - SncpServer cserver = new SncpServer(); - cserver.getResourceFactory().register(application); - // cserver.getLogger().setLevel(Level.WARNING); - cserver.addSncpServlet(cservice); - cserver.init(AnyValueWriter.create("port", 5577)); - cserver.start(); - - // ------------------------ 初始化 BCService ------------------------------------ - BCService bcservice = Sncp.createSimpleLocalService(BCService.class, resFactory); - CService remoteCService = Sncp.createSimpleRemoteService(CService.class, resFactory, rpcGroups, client, "g77"); - if (remoteCService != null) { - resFactory.inject(remoteCService); - resFactory.register("", remoteCService); - } - SncpServer bcserver = new SncpServer(); - bcserver.getResourceFactory().register(application); - // bcserver.getLogger().setLevel(Level.WARNING); - bcserver.addSncpServlet(bcservice); - bcserver.init(AnyValueWriter.create("port", 5588)); - bcserver.start(); - - // ------------------------ 初始化 ABMainService ------------------------------------ - ABMainService service = Sncp.createSimpleLocalService(ABMainService.class, resFactory); - BCService remoteBCService = - Sncp.createSimpleRemoteService(BCService.class, resFactory, rpcGroups, client, "g88"); - if (remoteBCService != null) { - resFactory.inject(remoteBCService); - resFactory.register("", remoteBCService); - } - - resFactory.inject(cservice); - resFactory.inject(bcservice); - resFactory.inject(service); - - HttpServer server = new HttpServer(); - server.getResourceFactory().register(application); - // server.getLogger().setLevel(Level.WARNING); - - server.init(AnyValueWriter.create("port", abport)); - server.addRestServlet(null, service, null, HttpServlet.class, "/pipes"); - server.start(); - Utility.sleep(100); - System.out.println("开始请求"); - - // 不声明一个新的HttpClient会导致Utility.postHttpContent操作 - // 同一url在Utility里的httpClient会缓存导致调用是吧,应该是httpClient的bug - java.net.http.HttpClient httpClient = java.net.http.HttpClient.newHttpClient(); - System.out.println("httpclient类: " + httpClient.getClass().getName()); - // 同步方法 - String url = "http://127.0.0.1:" + abport + "/pipes/abmain/sab/张先生"; - System.out.println(Utility.postHttpContentAsync(httpClient, url, StandardCharsets.UTF_8, null) - .join()); - - // 异步方法 - url = "http://127.0.0.1:" + abport + "/pipes/abmain/abc/张先生"; - System.out.println(Utility.postHttpContentAsync(httpClient, url, StandardCharsets.UTF_8, null) - .join()); - - // 异步方法 - url = "http://127.0.0.1:" + abport + "/pipes/abmain/abc2/张先生"; - System.out.println(Utility.postHttpContentAsync(httpClient, url, StandardCharsets.UTF_8, null) - .join()); - - server.shutdown(); - bcserver.shutdown(); - cserver.shutdown(); - } - - public static void main(String[] args) throws Throwable { - LoggingBaseHandler.initDebugLogConfig(); - System.out.println("------------------- 本地模式调用 -----------------------------------"); - final Application application = Application.create(true); - ResourceFactory factory = ResourceFactory.create(); - - ABMainService service = new ABMainService(); - - BCService bcservice = new BCService(); - factory.register("", bcservice); - factory.register("", new CService()); - factory.inject(bcservice); - factory.inject(service); - System.out.println("bcservice.name = " + bcservice.serviceName()); - System.out.println("bcservice.type = " + bcservice.serviceType()); - - HttpServer server = new HttpServer(); - server.getResourceFactory().register(application); - server.getLogger().setLevel(Level.WARNING); - - server.addRestServlet(null, service, null, HttpServlet.class, "/pipes"); - - server.init(AnyValueWriter.create("port", "" + abport)); - server.start(); - Thread.sleep(100); - - System.out.println("开始请求"); - // 同步方法 - String url = "http://127.0.0.1:" + abport + "/pipes/abmain/sab/张先生"; - System.out.println(Utility.postHttpContent(url)); - - // 异步方法 - url = "http://127.0.0.1:" + abport + "/pipes/abmain/abc/张先生"; - System.out.println(Utility.postHttpContent(url)); - - // 异步方法 - url = "http://127.0.0.1:" + abport + "/pipes/abmain/abc2/张先生"; - System.out.println(Utility.postHttpContent(url)); - - server.shutdown(); - // 远程模式 - remote(args); - } - - public static AsynchronousChannelGroup newChannelGroup() throws IOException { - final AtomicInteger counter = new AtomicInteger(); - ExecutorService transportExec = Executors.newFixedThreadPool(16, (Runnable r) -> { - Thread t = new Thread(r); - t.setDaemon(true); - t.setName("Transport-Thread-" + counter.incrementAndGet()); - return t; - }); - return AsynchronousChannelGroup.withCachedThreadPool(transportExec, 1); - } - - public static ObjectPool newBufferPool() { - return ObjectPool.createSafePool( - new LongAdder(), - new LongAdder(), - 16, - (Object... params) -> ByteBuffer.allocateDirect(8192), - null, - (e) -> { - if (e == null || e.isReadOnly() || e.capacity() != 8192) { - return false; - } - e.clear(); - return true; - }); - } - - @RestMapping(name = "sab") - public String abCurrentTime(@RestParam(name = "#") final String name) { - System.out.println("准备执行ABMainService.sab方法"); - String rs = "同步abCurrentTime: " + bcService.bcCurrentTime1(name); - System.out.println("执行了 ABMainService.abCurrentTime++++同步方法"); - return rs; - } - - @RestMapping(name = "abc") - public void abCurrentTime(final CompletionHandler handler, @RestParam(name = "#") final String name) { - bcService.bcCurrentTime2( - Utility.createAsyncHandler( - (v, a) -> { - System.out.println("执行了 ABMainService.abCurrentTime----异步方法"); - String rs = "异步abCurrentTime: " + v; - if (handler != null) { - handler.completed(rs, a); - } - }, - (t, a) -> { - if (handler != null) { - handler.failed(t, a); - } - }), - name); - } - - @RestMapping(name = "abc2") - public void abCurrentTime(final MyAsyncHandler handler, @RestParam(name = "#") final String name) { - bcService.bcCurrentTime3( - new MyAsyncHandler() { - @Override - public int id() { - return 1; - } - - @Override - public void completed(String v, Void a) { - System.out.println("执行了 ABMainService.abCurrentTime----异步方法2"); - String rs = "异步abCurrentTime: " + v; - if (handler != null) { - handler.completed(rs, a); - } - } - - @Override - public void failed(Throwable exc, Void attachment) {} - - @Override - public int id2() { - return 2; - } - }, - name); - } -} +/* + * 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.test.service; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.nio.ByteBuffer; +import java.nio.channels.*; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.*; +import java.util.concurrent.atomic.*; +import java.util.logging.Level; +import org.redkale.annotation.Resource; +import org.redkale.boot.*; +import org.redkale.convert.bson.BsonConvert; +import org.redkale.convert.json.JsonConvert; +import org.redkale.inject.ResourceFactory; +import org.redkale.net.AsyncIOGroup; +import org.redkale.net.client.ClientAddress; +import org.redkale.net.http.*; +import org.redkale.net.sncp.*; +import org.redkale.service.Service; +import org.redkale.util.*; + +/** @author zhangjx */ +@RestService(name = "abmain") +public class ABMainService implements Service { + + private static final int abport = 8866; + + @Resource + private BCService bcService; + + public static void remote(String[] args) throws Throwable { + System.out.println("------------------- 远程模式调用 -----------------------------------"); + final Application application = Application.create(true); + final AsyncIOGroup asyncGroup = new AsyncIOGroup(8192, 16); + asyncGroup.start(); + InetSocketAddress sncpAddress = new InetSocketAddress("127.0.0.1", abport); + final SncpClient client = + new SncpClient("", asyncGroup, "0", sncpAddress, new ClientAddress(sncpAddress), "TCP", 16, 100); + final ResourceFactory resFactory = ResourceFactory.create(); + resFactory.register(JsonConvert.root()); + resFactory.register(BsonConvert.root()); + final SncpRpcGroups rpcGroups = application.getSncpRpcGroups(); + rpcGroups.computeIfAbsent("g77", "TCP").putAddress(new InetSocketAddress("127.0.0.1", 5577)); + rpcGroups.computeIfAbsent("g88", "TCP").putAddress(new InetSocketAddress("127.0.0.1", 5588)); + rpcGroups.computeIfAbsent("g99", "TCP").putAddress(new InetSocketAddress("127.0.0.1", 5599)); + + // ------------------------ 初始化 CService ------------------------------------ + CService cservice = Sncp.createSimpleLocalService(CService.class, resFactory); + SncpServer cserver = new SncpServer(); + cserver.getResourceFactory().register(application); + // cserver.getLogger().setLevel(Level.WARNING); + cserver.addSncpServlet(cservice); + cserver.init(AnyValueWriter.create("port", 5577)); + cserver.start(); + + // ------------------------ 初始化 BCService ------------------------------------ + BCService bcservice = Sncp.createSimpleLocalService(BCService.class, resFactory); + CService remoteCService = Sncp.createSimpleRemoteService(CService.class, resFactory, rpcGroups, client, "g77"); + if (remoteCService != null) { + resFactory.inject(remoteCService); + resFactory.register("", remoteCService); + } + SncpServer bcserver = new SncpServer(); + bcserver.getResourceFactory().register(application); + // bcserver.getLogger().setLevel(Level.WARNING); + bcserver.addSncpServlet(bcservice); + bcserver.init(AnyValueWriter.create("port", 5588)); + bcserver.start(); + + // ------------------------ 初始化 ABMainService ------------------------------------ + ABMainService service = Sncp.createSimpleLocalService(ABMainService.class, resFactory); + BCService remoteBCService = + Sncp.createSimpleRemoteService(BCService.class, resFactory, rpcGroups, client, "g88"); + if (remoteBCService != null) { + resFactory.inject(remoteBCService); + resFactory.register("", remoteBCService); + } + + resFactory.inject(cservice); + resFactory.inject(bcservice); + resFactory.inject(service); + + HttpServer server = new HttpServer(); + server.getResourceFactory().register(application); + // server.getLogger().setLevel(Level.WARNING); + + server.init(AnyValueWriter.create("port", abport)); + server.addRestServlet(null, service, null, HttpServlet.class, "/pipes"); + server.start(); + Utility.sleep(100); + System.out.println("开始请求"); + + // 不声明一个新的HttpClient会导致Utility.postHttpContent操作 + // 同一url在Utility里的httpClient会缓存导致调用是吧,应该是httpClient的bug + java.net.http.HttpClient httpClient = java.net.http.HttpClient.newHttpClient(); + System.out.println("httpclient类: " + httpClient.getClass().getName()); + // 同步方法 + String url = "http://127.0.0.1:" + abport + "/pipes/abmain/sab/张先生"; + System.out.println(Utility.postHttpContentAsync(httpClient, url, StandardCharsets.UTF_8, null) + .join()); + + // 异步方法 + url = "http://127.0.0.1:" + abport + "/pipes/abmain/abc/张先生"; + System.out.println(Utility.postHttpContentAsync(httpClient, url, StandardCharsets.UTF_8, null) + .join()); + + // 异步方法 + url = "http://127.0.0.1:" + abport + "/pipes/abmain/abc2/张先生"; + System.out.println(Utility.postHttpContentAsync(httpClient, url, StandardCharsets.UTF_8, null) + .join()); + + server.shutdown(); + bcserver.shutdown(); + cserver.shutdown(); + } + + public static void main(String[] args) throws Throwable { + LoggingBaseHandler.initDebugLogConfig(); + System.out.println("------------------- 本地模式调用 -----------------------------------"); + final Application application = Application.create(true); + ResourceFactory factory = ResourceFactory.create(); + + ABMainService service = new ABMainService(); + + BCService bcservice = new BCService(); + factory.register("", bcservice); + factory.register("", new CService()); + factory.inject(bcservice); + factory.inject(service); + System.out.println("bcservice.name = " + bcservice.serviceName()); + System.out.println("bcservice.type = " + bcservice.serviceType()); + + HttpServer server = new HttpServer(); + server.getResourceFactory().register(application); + server.getLogger().setLevel(Level.WARNING); + + server.addRestServlet(null, service, null, HttpServlet.class, "/pipes"); + + server.init(AnyValueWriter.create("port", "" + abport)); + server.start(); + Thread.sleep(100); + + System.out.println("开始请求"); + // 同步方法 + String url = "http://127.0.0.1:" + abport + "/pipes/abmain/sab/张先生"; + System.out.println(Utility.postHttpContent(url)); + + // 异步方法 + url = "http://127.0.0.1:" + abport + "/pipes/abmain/abc/张先生"; + System.out.println(Utility.postHttpContent(url)); + + // 异步方法 + url = "http://127.0.0.1:" + abport + "/pipes/abmain/abc2/张先生"; + System.out.println(Utility.postHttpContent(url)); + + server.shutdown(); + // 远程模式 + remote(args); + } + + public static AsynchronousChannelGroup newChannelGroup() throws IOException { + final AtomicInteger counter = new AtomicInteger(); + ExecutorService transportExec = Executors.newFixedThreadPool(16, (Runnable r) -> { + Thread t = new Thread(r); + t.setDaemon(true); + t.setName("Transport-Thread-" + counter.incrementAndGet()); + return t; + }); + return AsynchronousChannelGroup.withCachedThreadPool(transportExec, 1); + } + + public static ObjectPool newBufferPool() { + return ObjectPool.createSafePool( + new LongAdder(), + new LongAdder(), + 16, + (Object... params) -> ByteBuffer.allocateDirect(8192), + null, + (e) -> { + if (e == null || e.isReadOnly() || e.capacity() != 8192) { + return false; + } + e.clear(); + return true; + }); + } + + @RestMapping(name = "sab") + public String abCurrentTime(@RestParam(name = "#") final String name) { + System.out.println("准备执行ABMainService.sab方法"); + String rs = "同步abCurrentTime: " + bcService.bcCurrentTime1(name); + System.out.println("执行了 ABMainService.abCurrentTime++++同步方法"); + return rs; + } + + @RestMapping(name = "abc") + public void abCurrentTime(final CompletionHandler handler, @RestParam(name = "#") final String name) { + bcService.bcCurrentTime2( + Utility.createAsyncHandler( + (v, a) -> { + System.out.println("执行了 ABMainService.abCurrentTime----异步方法"); + String rs = "异步abCurrentTime: " + v; + if (handler != null) { + handler.completed(rs, a); + } + }, + (t, a) -> { + if (handler != null) { + handler.failed(t, a); + } + }), + name); + } + + @RestMapping(name = "abc2") + public void abCurrentTime(final MyAsyncHandler handler, @RestParam(name = "#") final String name) { + bcService.bcCurrentTime3( + new MyAsyncHandler() { + @Override + public int id() { + return 1; + } + + @Override + public void completed(String v, Void a) { + System.out.println("执行了 ABMainService.abCurrentTime----异步方法2"); + String rs = "异步abCurrentTime: " + v; + if (handler != null) { + handler.completed(rs, a); + } + } + + @Override + public void failed(Throwable exc, Void attachment) {} + + @Override + public int id2() { + return 2; + } + }, + name); + } +} diff --git a/src/test/java/org/redkale/test/service/BCService.java b/src/test/java/org/redkale/test/service/BCService.java index 02196a1c6..ad4c56063 100644 --- a/src/test/java/org/redkale/test/service/BCService.java +++ b/src/test/java/org/redkale/test/service/BCService.java @@ -1,85 +1,85 @@ -/* - * 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.test.service; - -import java.nio.channels.CompletionHandler; -import org.redkale.annotation.Resource; -import org.redkale.service.*; -import org.redkale.util.Utility; - -/** @author zhangjx */ -public class BCService implements Service { - - @Resource - private CService cService; - - @Resource(name = "@name") - private String serviceName; - - @Resource(name = "@type") - private Class serviceType; - - public String serviceName() { - return serviceName; - } - - public Class serviceType() { - return serviceType; - } - - public String bcCurrentTime1(final String name) { - System.out.println("准备执行BCService.bcCurrentTime1方法"); - String rs = "同步bcCurrentTime1: " + cService.ccCurrentTime1(name).getResult(); - System.out.println("执行了 BCService.bcCurrentTime1++++同步方法1"); - return rs; - } - - public void bcCurrentTime2(final CompletionHandler handler, final String name) { - cService.ccCurrentTime2( - Utility.createAsyncHandler( - (v, a) -> { - System.out.println("执行了 BCService.bcCurrentTime2----异步方法2"); - String rs = "异步bcCurrentTime2: " + (v == null ? null : v.getResult()); - if (handler != null) { - handler.completed(rs, null); - } - }, - (t, a) -> { - if (handler != null) { - handler.failed(t, a); - } - }), - name); - } - - public void bcCurrentTime3(final MyAsyncHandler handler, final String name) { - cService.mcCurrentTime3( - new MyAsyncHandler, Void>() { - @Override - public int id() { - return 1; - } - - @Override - public void completed(RetResult v, Void a) { - System.out.println("执行了 BCService.bcCurrentTime3----异步方法3"); - String rs = "异步bcCurrentTime3: " + (v == null ? null : v.getResult()); - if (handler != null) { - handler.completed(rs, null); - } - } - - @Override - public void failed(Throwable exc, Void attachment) {} - - @Override - public int id2() { - return 2; - } - }, - name); - } -} +/* + * 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.test.service; + +import java.nio.channels.CompletionHandler; +import org.redkale.annotation.Resource; +import org.redkale.service.*; +import org.redkale.util.Utility; + +/** @author zhangjx */ +public class BCService implements Service { + + @Resource + private CService cService; + + @Resource(name = "@name") + private String serviceName; + + @Resource(name = "@type") + private Class serviceType; + + public String serviceName() { + return serviceName; + } + + public Class serviceType() { + return serviceType; + } + + public String bcCurrentTime1(final String name) { + System.out.println("准备执行BCService.bcCurrentTime1方法"); + String rs = "同步bcCurrentTime1: " + cService.ccCurrentTime1(name).getResult(); + System.out.println("执行了 BCService.bcCurrentTime1++++同步方法1"); + return rs; + } + + public void bcCurrentTime2(final CompletionHandler handler, final String name) { + cService.ccCurrentTime2( + Utility.createAsyncHandler( + (v, a) -> { + System.out.println("执行了 BCService.bcCurrentTime2----异步方法2"); + String rs = "异步bcCurrentTime2: " + (v == null ? null : v.getResult()); + if (handler != null) { + handler.completed(rs, null); + } + }, + (t, a) -> { + if (handler != null) { + handler.failed(t, a); + } + }), + name); + } + + public void bcCurrentTime3(final MyAsyncHandler handler, final String name) { + cService.mcCurrentTime3( + new MyAsyncHandler, Void>() { + @Override + public int id() { + return 1; + } + + @Override + public void completed(RetResult v, Void a) { + System.out.println("执行了 BCService.bcCurrentTime3----异步方法3"); + String rs = "异步bcCurrentTime3: " + (v == null ? null : v.getResult()); + if (handler != null) { + handler.completed(rs, null); + } + } + + @Override + public void failed(Throwable exc, Void attachment) {} + + @Override + public int id2() { + return 2; + } + }, + name); + } +} diff --git a/src/test/java/org/redkale/test/service/CService.java b/src/test/java/org/redkale/test/service/CService.java index bd951470e..e41c93514 100644 --- a/src/test/java/org/redkale/test/service/CService.java +++ b/src/test/java/org/redkale/test/service/CService.java @@ -1,47 +1,47 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package org.redkale.test.service; - -import java.nio.channels.CompletionHandler; -import org.redkale.annotation.Resource; -import org.redkale.service.*; -import org.redkale.util.Times; - -/** @author zhangjx */ -public class CService implements Service { - - @Resource(name = "@name") - private String serviceName; - - @Resource(name = "@type") - private Class serviceType; - - public String serviceName() { - return serviceName; - } - - public Class serviceType() { - return serviceType; - } - - public RetResult ccCurrentTime1(final String name) { - String rs = "同步ccCurrentTime1: " + name + ": " + Times.formatTime(System.currentTimeMillis()); - System.out.println("执行了 CService.ccCurrentTime1++++同步方法1"); - return new RetResult(rs); - } - - public void ccCurrentTime2(final CompletionHandler, Void> handler, final String name) { - String rs = "异步ccCurrentTime2: " + name + ": " + Times.formatTime(System.currentTimeMillis()); - System.out.println("执行了 CService.ccCurrentTime2----异步方法2"); - if (handler != null) handler.completed(new RetResult(rs), null); - } - - public void mcCurrentTime3(final MyAsyncHandler, Void> handler, final String name) { - String rs = "异步mcCurrentTime3: " + name + ": " + Times.formatTime(System.currentTimeMillis()); - System.out.println("执行了 CService.mcCurrentTime3----异步方法3"); - if (handler != null) handler.completed(new RetResult(rs), null); - } -} +/* + * 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.test.service; + +import java.nio.channels.CompletionHandler; +import org.redkale.annotation.Resource; +import org.redkale.service.*; +import org.redkale.util.Times; + +/** @author zhangjx */ +public class CService implements Service { + + @Resource(name = "@name") + private String serviceName; + + @Resource(name = "@type") + private Class serviceType; + + public String serviceName() { + return serviceName; + } + + public Class serviceType() { + return serviceType; + } + + public RetResult ccCurrentTime1(final String name) { + String rs = "同步ccCurrentTime1: " + name + ": " + Times.formatTime(System.currentTimeMillis()); + System.out.println("执行了 CService.ccCurrentTime1++++同步方法1"); + return new RetResult(rs); + } + + public void ccCurrentTime2(final CompletionHandler, Void> handler, final String name) { + String rs = "异步ccCurrentTime2: " + name + ": " + Times.formatTime(System.currentTimeMillis()); + System.out.println("执行了 CService.ccCurrentTime2----异步方法2"); + if (handler != null) handler.completed(new RetResult(rs), null); + } + + public void mcCurrentTime3(final MyAsyncHandler, Void> handler, final String name) { + String rs = "异步mcCurrentTime3: " + name + ": " + Times.formatTime(System.currentTimeMillis()); + System.out.println("执行了 CService.mcCurrentTime3----异步方法3"); + if (handler != null) handler.completed(new RetResult(rs), null); + } +} diff --git a/src/test/java/org/redkale/test/service/MyAsyncHandler.java b/src/test/java/org/redkale/test/service/MyAsyncHandler.java index 9e8a4709d..311f558d7 100644 --- a/src/test/java/org/redkale/test/service/MyAsyncHandler.java +++ b/src/test/java/org/redkale/test/service/MyAsyncHandler.java @@ -1,16 +1,16 @@ -/* - * 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.test.service; - -/** - * @author zhangjx - * @param V - * @param
A - */ -public abstract class MyAsyncHandler extends MyAsyncInnerHandler { - - public abstract int id(); -} +/* + * 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.test.service; + +/** + * @author zhangjx + * @param V + * @param A + */ +public abstract class MyAsyncHandler extends MyAsyncInnerHandler { + + public abstract int id(); +} diff --git a/src/test/java/org/redkale/test/service/MyAsyncInnerHandler.java b/src/test/java/org/redkale/test/service/MyAsyncInnerHandler.java index 6ef335d18..8cc5ed167 100644 --- a/src/test/java/org/redkale/test/service/MyAsyncInnerHandler.java +++ b/src/test/java/org/redkale/test/service/MyAsyncInnerHandler.java @@ -1,14 +1,14 @@ -/* - * 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.test.service; - -import java.nio.channels.CompletionHandler; - -/** @author zhangjx */ -public abstract class MyAsyncInnerHandler implements CompletionHandler { - - protected abstract int id2(); -} +/* + * 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.test.service; + +import java.nio.channels.CompletionHandler; + +/** @author zhangjx */ +public abstract class MyAsyncInnerHandler implements CompletionHandler { + + protected abstract int id2(); +} diff --git a/src/test/java/org/redkale/test/service/Person.java b/src/test/java/org/redkale/test/service/Person.java index 978442c65..74c523042 100644 --- a/src/test/java/org/redkale/test/service/Person.java +++ b/src/test/java/org/redkale/test/service/Person.java @@ -1,31 +1,31 @@ -package org.redkale.test.service; - -import java.io.Serializable; - -public class Person implements Serializable { - - private byte[] b = new byte[1024 * 2]; - - private String name; - - @Override - public String toString() { - return "{name=" + name + ", b =" + (b == null ? "null" : "[length=" + b.length + "]") + "}"; - } - - public byte[] getB() { - return b; - } - - public void setB(byte[] b) { - this.b = b; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } -} +package org.redkale.test.service; + +import java.io.Serializable; + +public class Person implements Serializable { + + private byte[] b = new byte[1024 * 2]; + + private String name; + + @Override + public String toString() { + return "{name=" + name + ", b =" + (b == null ? "null" : "[length=" + b.length + "]") + "}"; + } + + public byte[] getB() { + return b; + } + + public void setB(byte[] b) { + this.b = b; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/src/test/java/org/redkale/test/service/TestBean.java b/src/test/java/org/redkale/test/service/TestBean.java index 7f077aa26..1804b46b5 100644 --- a/src/test/java/org/redkale/test/service/TestBean.java +++ b/src/test/java/org/redkale/test/service/TestBean.java @@ -1,9 +1,9 @@ -/* - * 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.test.service; - -/** @author zhangjx */ -public class TestBean {} +/* + * 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.test.service; + +/** @author zhangjx */ +public class TestBean {} diff --git a/src/test/java/org/redkale/test/service/TestService.java b/src/test/java/org/redkale/test/service/TestService.java index 9b932cf45..3f5dbc710 100644 --- a/src/test/java/org/redkale/test/service/TestService.java +++ b/src/test/java/org/redkale/test/service/TestService.java @@ -1,29 +1,29 @@ -/* - * 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.test.service; - -import java.nio.channels.*; -import org.redkale.boot.*; -import org.redkale.net.sncp.*; -import org.redkale.service.*; -import org.redkale.util.*; - -/** @author zhangjx */ -public class TestService implements Service { - - // public boolean change(TestBean bean, String name, int id) { - // return false; - // } - public void change(CompletionHandler handler, TestBean bean, String name, int id) {} - - public static void main(String[] args) throws Throwable { - final Application application = Application.create(true); - SncpServer cserver = new SncpServer(); - cserver.getResourceFactory().register(application); - cserver.addSncpServlet(new TestService()); - cserver.init(AnyValueWriter.create("port", 5577)); - } -} +/* + * 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.test.service; + +import java.nio.channels.*; +import org.redkale.boot.*; +import org.redkale.net.sncp.*; +import org.redkale.service.*; +import org.redkale.util.*; + +/** @author zhangjx */ +public class TestService implements Service { + + // public boolean change(TestBean bean, String name, int id) { + // return false; + // } + public void change(CompletionHandler handler, TestBean bean, String name, int id) {} + + public static void main(String[] args) throws Throwable { + final Application application = Application.create(true); + SncpServer cserver = new SncpServer(); + cserver.getResourceFactory().register(application); + cserver.addSncpServlet(new TestService()); + cserver.init(AnyValueWriter.create("port", 5577)); + } +} diff --git a/src/test/java/org/redkale/test/sncp/SncpClientCodecTest.java b/src/test/java/org/redkale/test/sncp/SncpClientCodecTest.java index 1c47f0012..61248de2b 100644 --- a/src/test/java/org/redkale/test/sncp/SncpClientCodecTest.java +++ b/src/test/java/org/redkale/test/sncp/SncpClientCodecTest.java @@ -1,94 +1,94 @@ -/* - * - */ -package org.redkale.test.sncp; - -import java.lang.reflect.Field; -import java.net.InetSocketAddress; -import java.nio.ByteBuffer; -import java.util.*; -import org.junit.jupiter.api.*; -import org.redkale.net.AsyncIOGroup; -import org.redkale.net.client.*; -import org.redkale.net.sncp.*; -import org.redkale.util.*; - -/** @author zhangjx */ -public class SncpClientCodecTest { - - private boolean main; - - public static void main(String[] args) throws Throwable { - SncpClientCodecTest test = new SncpClientCodecTest(); - test.main = true; - test.run(); - } - - @Test - public void run() throws Exception { - InetSocketAddress sncpAddress = new InetSocketAddress("127.0.0.1", 3389); - InetSocketAddress remoteAddress = new InetSocketAddress("127.0.0.1", 3344); - final AsyncIOGroup asyncGroup = new AsyncIOGroup(8192, 16); - SncpClient client = new SncpClient( - "test", asyncGroup, "0", sncpAddress, new ClientAddress(remoteAddress), "TCP", Utility.cpus(), 16); - SncpClientConnection conn = client.createClientConnection(asyncGroup.newTCPClientConnection()); - SncpClientCodec codec = new SncpClientCodec(conn); - List respResults = new ArrayList(); - try { - Field respResultsField = ClientCodec.class.getDeclaredField("respResults"); - respResultsField.setAccessible(true); - respResults = (List) respResultsField.get(codec); - } catch (Exception e) { - e.printStackTrace(); - } - ByteBuffer realBuf; - // ---------------------------------------------- - respResults.clear(); - { - SncpHeader header = SncpHeader.create(sncpAddress, Uint128.ZERO, "", Uint128.ZERO, ""); - SncpClientRequest request = new SncpClientRequest(); - ByteArray writeArray1 = new ByteArray(); - request.prepare(header, 1, "aa", new byte[20]); - request.writeTo(conn, writeArray1); - System.out.println("request.1 = " + request); - System.out.println("headerSize = " + SncpHeader.calcHeaderSize(request) + ", arraySzie = " - + writeArray1.getBytes().length); - ByteArray writeArray2 = new ByteArray(); - request.prepare(header, 2, "bb", new byte[25]); - request.writeTo(conn, writeArray2); - System.out.println("request.2 = " + request); - System.out.println("headerSize = " + SncpHeader.calcHeaderSize(request) + ", arraySzie = " - + writeArray2.getBytes().length); - writeArray1.put(writeArray2); - realBuf = ByteBuffer.wrap(writeArray1.getBytes()); - } - System.out.println("sncp.realBuf = " + realBuf.remaining()); - codec.decodeMessages(realBuf, new ByteArray()); - System.out.println("respResults.size = " + respResults.size()); - Assertions.assertEquals(2, respResults.size()); - // ---------------------------------------------- - respResults.clear(); - { - SncpHeader header = SncpHeader.create(sncpAddress, Uint128.ZERO, "", Uint128.ZERO, ""); - SncpClientRequest request = new SncpClientRequest(); - ByteArray writeArray1 = new ByteArray(); - request.prepare(header, 1, "", new byte[20]); - request.writeTo(conn, writeArray1); - System.out.println("request.1 = " + request); - System.out.println("headerSize = " + SncpHeader.calcHeaderSize(request) + ", arraySzie = " - + writeArray1.getBytes().length); - ByteArray writeArray2 = new ByteArray(); - request.prepare(header, 2, "", new byte[25]); - request.writeTo(conn, writeArray2); - System.out.println("request.2 = " + request); - System.out.println("headerSize = " + SncpHeader.calcHeaderSize(request) + ", arraySzie = " - + writeArray2.getBytes().length); - writeArray1.put(writeArray2); - realBuf = ByteBuffer.wrap(writeArray1.getBytes()); - } - System.out.println("sncp.realBuf = " + realBuf.remaining()); - codec.decodeMessages(realBuf, new ByteArray()); - System.out.println("respResults.size = " + respResults.size()); - Assertions.assertEquals(2, respResults.size()); - } -} +/* + * + */ +package org.redkale.test.sncp; + +import java.lang.reflect.Field; +import java.net.InetSocketAddress; +import java.nio.ByteBuffer; +import java.util.*; +import org.junit.jupiter.api.*; +import org.redkale.net.AsyncIOGroup; +import org.redkale.net.client.*; +import org.redkale.net.sncp.*; +import org.redkale.util.*; + +/** @author zhangjx */ +public class SncpClientCodecTest { + + private boolean main; + + public static void main(String[] args) throws Throwable { + SncpClientCodecTest test = new SncpClientCodecTest(); + test.main = true; + test.run(); + } + + @Test + public void run() throws Exception { + InetSocketAddress sncpAddress = new InetSocketAddress("127.0.0.1", 3389); + InetSocketAddress remoteAddress = new InetSocketAddress("127.0.0.1", 3344); + final AsyncIOGroup asyncGroup = new AsyncIOGroup(8192, 16); + SncpClient client = new SncpClient( + "test", asyncGroup, "0", sncpAddress, new ClientAddress(remoteAddress), "TCP", Utility.cpus(), 16); + SncpClientConnection conn = client.createClientConnection(asyncGroup.newTCPClientConnection()); + SncpClientCodec codec = new SncpClientCodec(conn); + List respResults = new ArrayList(); + try { + Field respResultsField = ClientCodec.class.getDeclaredField("respResults"); + respResultsField.setAccessible(true); + respResults = (List) respResultsField.get(codec); + } catch (Exception e) { + e.printStackTrace(); + } + ByteBuffer realBuf; + // ---------------------------------------------- + respResults.clear(); + { + SncpHeader header = SncpHeader.create(sncpAddress, Uint128.ZERO, "", Uint128.ZERO, ""); + SncpClientRequest request = new SncpClientRequest(); + ByteArray writeArray1 = new ByteArray(); + request.prepare(header, 1, "aa", new byte[20]); + request.writeTo(conn, writeArray1); + System.out.println("request.1 = " + request); + System.out.println("headerSize = " + SncpHeader.calcHeaderSize(request) + ", arraySzie = " + + writeArray1.getBytes().length); + ByteArray writeArray2 = new ByteArray(); + request.prepare(header, 2, "bb", new byte[25]); + request.writeTo(conn, writeArray2); + System.out.println("request.2 = " + request); + System.out.println("headerSize = " + SncpHeader.calcHeaderSize(request) + ", arraySzie = " + + writeArray2.getBytes().length); + writeArray1.put(writeArray2); + realBuf = ByteBuffer.wrap(writeArray1.getBytes()); + } + System.out.println("sncp.realBuf = " + realBuf.remaining()); + codec.decodeMessages(realBuf, new ByteArray()); + System.out.println("respResults.size = " + respResults.size()); + Assertions.assertEquals(2, respResults.size()); + // ---------------------------------------------- + respResults.clear(); + { + SncpHeader header = SncpHeader.create(sncpAddress, Uint128.ZERO, "", Uint128.ZERO, ""); + SncpClientRequest request = new SncpClientRequest(); + ByteArray writeArray1 = new ByteArray(); + request.prepare(header, 1, "", new byte[20]); + request.writeTo(conn, writeArray1); + System.out.println("request.1 = " + request); + System.out.println("headerSize = " + SncpHeader.calcHeaderSize(request) + ", arraySzie = " + + writeArray1.getBytes().length); + ByteArray writeArray2 = new ByteArray(); + request.prepare(header, 2, "", new byte[25]); + request.writeTo(conn, writeArray2); + System.out.println("request.2 = " + request); + System.out.println("headerSize = " + SncpHeader.calcHeaderSize(request) + ", arraySzie = " + + writeArray2.getBytes().length); + writeArray1.put(writeArray2); + realBuf = ByteBuffer.wrap(writeArray1.getBytes()); + } + System.out.println("sncp.realBuf = " + realBuf.remaining()); + codec.decodeMessages(realBuf, new ByteArray()); + System.out.println("respResults.size = " + respResults.size()); + Assertions.assertEquals(2, respResults.size()); + } +} diff --git a/src/test/java/org/redkale/test/sncp/SncpHandlerTest.java b/src/test/java/org/redkale/test/sncp/SncpHandlerTest.java index 03fea76ff..a21730b90 100644 --- a/src/test/java/org/redkale/test/sncp/SncpHandlerTest.java +++ b/src/test/java/org/redkale/test/sncp/SncpHandlerTest.java @@ -1,86 +1,86 @@ -/* - * - */ -package org.redkale.test.sncp; - -import java.io.File; -import java.nio.channels.CompletionHandler; -import java.util.Map; -import org.junit.jupiter.api.Test; -import org.redkale.net.sncp.SncpAsyncHandler; - -/** @author zhangjx */ -public class SncpHandlerTest { - - private boolean main; - - public static void main(String[] args) throws Throwable { - SncpHandlerTest test = new SncpHandlerTest(); - test.main = true; - test.run(); - } - - @Test - public void run() throws Exception { - SncpAsyncHandler.createHandler(CompletionHandler.class, new CompletionHandler() { - @Override - public void completed(Object result, Object attachment) { - if (main) { - System.out.println("handler result: " + result + ", attachment: " + attachment); - } - } - - @Override - public void failed(Throwable exc, Object attachment) {} - }) - .completed(1, 2); - - SncpAsyncHandler.createHandler(ITestHandler1.class, new CompletionHandler() { - @Override - public void completed(Object result, Object attachment) { - System.out.println("handler1 result: " + result + ", attachment: " + attachment); - } - - @Override - public void failed(Throwable exc, Object attachment) {} - }) - .completed("name", "/user/"); - - SncpAsyncHandler.createHandler(ITestHandler2.class, new CompletionHandler() { - @Override - public void completed(Object result, Object attachment) { - System.out.println("handler2 result: " + result + ", attachment: " + attachment); - } - - @Override - public void failed(Throwable exc, Object attachment) {} - }) - .completed("aaa", "bbb"); - - SncpAsyncHandler.createHandler(ITestHandler3.class, new CompletionHandler() { - @Override - public void completed(Object result, Object attachment) { - System.out.println("handler3 result: " + result + ", attachment: " + attachment); - } - - @Override - public void failed(Throwable exc, Object attachment) {} - }) - .completed("key1", "val1"); - } - - public abstract static class ITestHandler1 implements CompletionHandler { - - @Override - public abstract void completed(String result, File attachment); - } - - public static interface IClose { - - public void close(T val); - } - - public static interface ITestHandler2 extends CompletionHandler, IClose {} - - public static interface ITestHandler3 extends CompletionHandler, Map {} -} +/* + * + */ +package org.redkale.test.sncp; + +import java.io.File; +import java.nio.channels.CompletionHandler; +import java.util.Map; +import org.junit.jupiter.api.Test; +import org.redkale.net.sncp.SncpAsyncHandler; + +/** @author zhangjx */ +public class SncpHandlerTest { + + private boolean main; + + public static void main(String[] args) throws Throwable { + SncpHandlerTest test = new SncpHandlerTest(); + test.main = true; + test.run(); + } + + @Test + public void run() throws Exception { + SncpAsyncHandler.createHandler(CompletionHandler.class, new CompletionHandler() { + @Override + public void completed(Object result, Object attachment) { + if (main) { + System.out.println("handler result: " + result + ", attachment: " + attachment); + } + } + + @Override + public void failed(Throwable exc, Object attachment) {} + }) + .completed(1, 2); + + SncpAsyncHandler.createHandler(ITestHandler1.class, new CompletionHandler() { + @Override + public void completed(Object result, Object attachment) { + System.out.println("handler1 result: " + result + ", attachment: " + attachment); + } + + @Override + public void failed(Throwable exc, Object attachment) {} + }) + .completed("name", "/user/"); + + SncpAsyncHandler.createHandler(ITestHandler2.class, new CompletionHandler() { + @Override + public void completed(Object result, Object attachment) { + System.out.println("handler2 result: " + result + ", attachment: " + attachment); + } + + @Override + public void failed(Throwable exc, Object attachment) {} + }) + .completed("aaa", "bbb"); + + SncpAsyncHandler.createHandler(ITestHandler3.class, new CompletionHandler() { + @Override + public void completed(Object result, Object attachment) { + System.out.println("handler3 result: " + result + ", attachment: " + attachment); + } + + @Override + public void failed(Throwable exc, Object attachment) {} + }) + .completed("key1", "val1"); + } + + public abstract static class ITestHandler1 implements CompletionHandler { + + @Override + public abstract void completed(String result, File attachment); + } + + public static interface IClose { + + public void close(T val); + } + + public static interface ITestHandler2 extends CompletionHandler, IClose {} + + public static interface ITestHandler3 extends CompletionHandler, Map {} +} diff --git a/src/test/java/org/redkale/test/sncp/SncpRequestParseTest.java b/src/test/java/org/redkale/test/sncp/SncpRequestParseTest.java index e53b82c32..2b9310136 100644 --- a/src/test/java/org/redkale/test/sncp/SncpRequestParseTest.java +++ b/src/test/java/org/redkale/test/sncp/SncpRequestParseTest.java @@ -1,83 +1,83 @@ -/* - * - */ -package org.redkale.test.sncp; - -import java.net.InetSocketAddress; -import java.nio.ByteBuffer; -import java.util.Arrays; -import java.util.logging.Logger; -import org.junit.jupiter.api.*; -import org.redkale.net.*; -import org.redkale.net.client.ClientAddress; -import org.redkale.net.sncp.*; -import org.redkale.util.*; - -/** @author zhangjx */ -public class SncpRequestParseTest { - - private boolean main; - - public static void main(String[] args) throws Throwable { - SncpRequestParseTest test = new SncpRequestParseTest(); - test.main = true; - test.run(); - } - - @Test - public void run() throws Exception { - InetSocketAddress sncpAddress = new InetSocketAddress("127.0.0.1", 3389); - InetSocketAddress remoteAddress = new InetSocketAddress("127.0.0.1", 3344); - final AsyncIOGroup asyncGroup = new AsyncIOGroup(8192, 16); - SncpClient client = new SncpClient( - "test", asyncGroup, "0", sncpAddress, new ClientAddress(remoteAddress), "TCP", Utility.cpus(), 16); - SncpClientConnection conn = client.createClientConnection(asyncGroup.newTCPClientConnection()); - - SncpContext.SncpContextConfig config = new SncpContext.SncpContextConfig(); - config.logger = Logger.getLogger(SncpRequestParseTest.class.getSimpleName()); - config.serverAddress = sncpAddress; - config.maxBody = 1024 * 1024 * 1024; - SncpContext context = new SncpContext(config); - - SncpHeader header = SncpHeader.create(sncpAddress, Uint128.ZERO, "", Uint128.ZERO, ""); - SncpClientRequest clientRequest = new SncpClientRequest(); - ByteArray writeArray = new ByteArray(); - clientRequest.prepare(header, 1, "aa", new byte[20]); - clientRequest.writeTo(conn, writeArray); - byte[] bs = writeArray.getBytes(); - int headerSize = SncpHeader.calcHeaderSize(clientRequest); - System.out.println("整个sncp请求长度: " + bs.length + "." + Arrays.toString(bs)); - System.out.println(" " + Arrays.toString(Arrays.copyOfRange(bs, 2, bs.length))); - - SncpRequestTest request = new SncpRequestTest(context); - Assertions.assertEquals(1, request.readHeader(ByteBuffer.wrap(Arrays.copyOfRange(bs, 0, 1)), null)); - Assertions.assertEquals( - headerSize - 2, request.readHeader(ByteBuffer.wrap(Arrays.copyOfRange(bs, 1, 2)), null)); - Assertions.assertEquals(0, request.readHeader(ByteBuffer.wrap(Arrays.copyOfRange(bs, 2, bs.length)), null)); - Assertions.assertEquals("aa", request.getHeader().getTraceid()); - - System.out.println("测试第二段"); - request = new SncpRequestTest(context); - Assertions.assertEquals(1, request.readHeader(ByteBuffer.wrap(Arrays.copyOfRange(bs, 0, 1)), null)); - Assertions.assertEquals( - headerSize - 2, request.readHeader(ByteBuffer.wrap(Arrays.copyOfRange(bs, 1, 2)), null)); - Assertions.assertEquals( - headerSize - headerSize / 2, - request.readHeader(ByteBuffer.wrap(Arrays.copyOfRange(bs, 2, headerSize / 2)), null)); - Assertions.assertEquals( - 0, request.readHeader(ByteBuffer.wrap(Arrays.copyOfRange(bs, headerSize / 2, bs.length)), null)); - Assertions.assertEquals("aa", request.getHeader().getTraceid()); - } - - public static class SncpRequestTest extends SncpRequest { - - protected SncpRequestTest(SncpContext context) { - super(context); - } - - @Override - protected int readHeader(ByteBuffer buffer, Request last) { - return super.readHeader(buffer, last); - } - } -} +/* + * + */ +package org.redkale.test.sncp; + +import java.net.InetSocketAddress; +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.logging.Logger; +import org.junit.jupiter.api.*; +import org.redkale.net.*; +import org.redkale.net.client.ClientAddress; +import org.redkale.net.sncp.*; +import org.redkale.util.*; + +/** @author zhangjx */ +public class SncpRequestParseTest { + + private boolean main; + + public static void main(String[] args) throws Throwable { + SncpRequestParseTest test = new SncpRequestParseTest(); + test.main = true; + test.run(); + } + + @Test + public void run() throws Exception { + InetSocketAddress sncpAddress = new InetSocketAddress("127.0.0.1", 3389); + InetSocketAddress remoteAddress = new InetSocketAddress("127.0.0.1", 3344); + final AsyncIOGroup asyncGroup = new AsyncIOGroup(8192, 16); + SncpClient client = new SncpClient( + "test", asyncGroup, "0", sncpAddress, new ClientAddress(remoteAddress), "TCP", Utility.cpus(), 16); + SncpClientConnection conn = client.createClientConnection(asyncGroup.newTCPClientConnection()); + + SncpContext.SncpContextConfig config = new SncpContext.SncpContextConfig(); + config.logger = Logger.getLogger(SncpRequestParseTest.class.getSimpleName()); + config.serverAddress = sncpAddress; + config.maxBody = 1024 * 1024 * 1024; + SncpContext context = new SncpContext(config); + + SncpHeader header = SncpHeader.create(sncpAddress, Uint128.ZERO, "", Uint128.ZERO, ""); + SncpClientRequest clientRequest = new SncpClientRequest(); + ByteArray writeArray = new ByteArray(); + clientRequest.prepare(header, 1, "aa", new byte[20]); + clientRequest.writeTo(conn, writeArray); + byte[] bs = writeArray.getBytes(); + int headerSize = SncpHeader.calcHeaderSize(clientRequest); + System.out.println("整个sncp请求长度: " + bs.length + "." + Arrays.toString(bs)); + System.out.println(" " + Arrays.toString(Arrays.copyOfRange(bs, 2, bs.length))); + + SncpRequestTest request = new SncpRequestTest(context); + Assertions.assertEquals(1, request.readHeader(ByteBuffer.wrap(Arrays.copyOfRange(bs, 0, 1)), null)); + Assertions.assertEquals( + headerSize - 2, request.readHeader(ByteBuffer.wrap(Arrays.copyOfRange(bs, 1, 2)), null)); + Assertions.assertEquals(0, request.readHeader(ByteBuffer.wrap(Arrays.copyOfRange(bs, 2, bs.length)), null)); + Assertions.assertEquals("aa", request.getHeader().getTraceid()); + + System.out.println("测试第二段"); + request = new SncpRequestTest(context); + Assertions.assertEquals(1, request.readHeader(ByteBuffer.wrap(Arrays.copyOfRange(bs, 0, 1)), null)); + Assertions.assertEquals( + headerSize - 2, request.readHeader(ByteBuffer.wrap(Arrays.copyOfRange(bs, 1, 2)), null)); + Assertions.assertEquals( + headerSize - headerSize / 2, + request.readHeader(ByteBuffer.wrap(Arrays.copyOfRange(bs, 2, headerSize / 2)), null)); + Assertions.assertEquals( + 0, request.readHeader(ByteBuffer.wrap(Arrays.copyOfRange(bs, headerSize / 2, bs.length)), null)); + Assertions.assertEquals("aa", request.getHeader().getTraceid()); + } + + public static class SncpRequestTest extends SncpRequest { + + protected SncpRequestTest(SncpContext context) { + super(context); + } + + @Override + protected int readHeader(ByteBuffer buffer, Request last) { + return super.readHeader(buffer, last); + } + } +} diff --git a/src/test/java/org/redkale/test/sncp/SncpSleepService.java b/src/test/java/org/redkale/test/sncp/SncpSleepService.java index 6aa364dc9..2834470a4 100644 --- a/src/test/java/org/redkale/test/sncp/SncpSleepService.java +++ b/src/test/java/org/redkale/test/sncp/SncpSleepService.java @@ -1,49 +1,49 @@ -/* - * - */ -package org.redkale.test.sncp; - -import java.util.concurrent.CompletableFuture; -import org.redkale.service.AbstractService; -import org.redkale.util.Times; -import org.redkale.util.Utility; - -/** @author zhangjx */ -public class SncpSleepService extends AbstractService { - - public CompletableFuture sleep200() { - System.out.println(Times.nowMillis() + " " + Thread.currentThread().getName() + " 接收sleep200"); - return CompletableFuture.supplyAsync( - () -> { - Utility.sleep(200); - System.out.println( - Times.nowMillis() + " " + Thread.currentThread().getName() + " 执行完sleep200"); - return "ok200"; - }, - getExecutor()); - } - - public CompletableFuture sleep300() { - System.out.println(Times.nowMillis() + " " + Thread.currentThread().getName() + " 接收sleep300"); - return CompletableFuture.supplyAsync( - () -> { - Utility.sleep(300); - System.out.println( - Times.nowMillis() + " " + Thread.currentThread().getName() + " 执行完sleep300"); - return "ok300"; - }, - getExecutor()); - } - - public CompletableFuture sleep500() { - System.out.println(Times.nowMillis() + " " + Thread.currentThread().getName() + " 接收sleep500"); - return CompletableFuture.supplyAsync( - () -> { - Utility.sleep(500); - System.out.println( - Times.nowMillis() + " " + Thread.currentThread().getName() + " 执行完sleep500"); - return "ok500"; - }, - getExecutor()); - } -} +/* + * + */ +package org.redkale.test.sncp; + +import java.util.concurrent.CompletableFuture; +import org.redkale.service.AbstractService; +import org.redkale.util.Times; +import org.redkale.util.Utility; + +/** @author zhangjx */ +public class SncpSleepService extends AbstractService { + + public CompletableFuture sleep200() { + System.out.println(Times.nowMillis() + " " + Thread.currentThread().getName() + " 接收sleep200"); + return CompletableFuture.supplyAsync( + () -> { + Utility.sleep(200); + System.out.println( + Times.nowMillis() + " " + Thread.currentThread().getName() + " 执行完sleep200"); + return "ok200"; + }, + getExecutor()); + } + + public CompletableFuture sleep300() { + System.out.println(Times.nowMillis() + " " + Thread.currentThread().getName() + " 接收sleep300"); + return CompletableFuture.supplyAsync( + () -> { + Utility.sleep(300); + System.out.println( + Times.nowMillis() + " " + Thread.currentThread().getName() + " 执行完sleep300"); + return "ok300"; + }, + getExecutor()); + } + + public CompletableFuture sleep500() { + System.out.println(Times.nowMillis() + " " + Thread.currentThread().getName() + " 接收sleep500"); + return CompletableFuture.supplyAsync( + () -> { + Utility.sleep(500); + System.out.println( + Times.nowMillis() + " " + Thread.currentThread().getName() + " 执行完sleep500"); + return "ok500"; + }, + getExecutor()); + } +} diff --git a/src/test/java/org/redkale/test/sncp/SncpSleepTest.java b/src/test/java/org/redkale/test/sncp/SncpSleepTest.java index fc0d87230..8f919c6b7 100644 --- a/src/test/java/org/redkale/test/sncp/SncpSleepTest.java +++ b/src/test/java/org/redkale/test/sncp/SncpSleepTest.java @@ -1,69 +1,69 @@ -package org.redkale.test.sncp; - -import java.net.InetSocketAddress; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutorService; -import org.junit.jupiter.api.*; -import org.redkale.boot.Application; -import org.redkale.convert.bson.BsonConvert; -import org.redkale.convert.json.JsonConvert; -import org.redkale.inject.ResourceFactory; -import org.redkale.net.AsyncIOGroup; -import org.redkale.net.WorkThread; -import org.redkale.net.client.ClientAddress; -import org.redkale.net.sncp.*; -import org.redkale.util.*; - -/** @author zhangjx */ -public class SncpSleepTest { - - private boolean main; - - public static void main(String[] args) throws Throwable { - SncpSleepTest test = new SncpSleepTest(); - test.main = true; - test.run(); - } - - @Test - public void run() throws Exception { - System.out.println("------------------- 并发调用 -----------------------------------"); - final Application application = Application.create(true); - final ExecutorService workExecutor = WorkThread.createWorkExecutor(10, "Thread-Work-%s"); - final AsyncIOGroup asyncGroup = new AsyncIOGroup("Redkale-TestClient-IOThread-%s", workExecutor, 8192, 16); - asyncGroup.start(); - final ResourceFactory resFactory = ResourceFactory.create(); - resFactory.register(Application.RESNAME_APP_EXECUTOR, ExecutorService.class, workExecutor); - resFactory.register(JsonConvert.root()); - resFactory.register(BsonConvert.root()); - - // ------------------------ 初始化 CService ------------------------------------ - SncpSleepService service = Sncp.createSimpleLocalService(SncpSleepService.class, resFactory); - resFactory.inject(service); - SncpServer server = new SncpServer(application, System.currentTimeMillis(), null, resFactory); - server.getResourceFactory().register(application); - server.addSncpServlet(service); - server.init(AnyValueWriter.create("port", 0)); - server.start(); - - int port = server.getSocketAddress().getPort(); - System.out.println("SNCP服务器启动端口: " + port); - InetSocketAddress sncpAddress = new InetSocketAddress("127.0.0.1", port); - final SncpClient client = - new SncpClient("", asyncGroup, "0", sncpAddress, new ClientAddress(sncpAddress), "TCP", 16, 100); - final SncpRpcGroups rpcGroups = application.getSncpRpcGroups(); - rpcGroups.computeIfAbsent("cs", "TCP").putAddress(sncpAddress); - SncpSleepService remoteCService = - Sncp.createSimpleRemoteService(SncpSleepService.class, resFactory, rpcGroups, client, "cs"); - long s = System.currentTimeMillis(); - CompletableFuture[] futures = - new CompletableFuture[] {remoteCService.sleep200(), remoteCService.sleep300(), remoteCService.sleep500() - }; - CompletableFuture.allOf(futures).join(); - long e = System.currentTimeMillis() - s; - System.out.println("耗时: " + e + " ms"); - server.shutdown(); - workExecutor.shutdown(); - Assertions.assertTrue(e < 600); - } -} +package org.redkale.test.sncp; + +import java.net.InetSocketAddress; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; +import org.junit.jupiter.api.*; +import org.redkale.boot.Application; +import org.redkale.convert.bson.BsonConvert; +import org.redkale.convert.json.JsonConvert; +import org.redkale.inject.ResourceFactory; +import org.redkale.net.AsyncIOGroup; +import org.redkale.net.WorkThread; +import org.redkale.net.client.ClientAddress; +import org.redkale.net.sncp.*; +import org.redkale.util.*; + +/** @author zhangjx */ +public class SncpSleepTest { + + private boolean main; + + public static void main(String[] args) throws Throwable { + SncpSleepTest test = new SncpSleepTest(); + test.main = true; + test.run(); + } + + @Test + public void run() throws Exception { + System.out.println("------------------- 并发调用 -----------------------------------"); + final Application application = Application.create(true); + final ExecutorService workExecutor = WorkThread.createWorkExecutor(10, "Thread-Work-%s"); + final AsyncIOGroup asyncGroup = new AsyncIOGroup("Redkale-TestClient-IOThread-%s", workExecutor, 8192, 16); + asyncGroup.start(); + final ResourceFactory resFactory = ResourceFactory.create(); + resFactory.register(Application.RESNAME_APP_EXECUTOR, ExecutorService.class, workExecutor); + resFactory.register(JsonConvert.root()); + resFactory.register(BsonConvert.root()); + + // ------------------------ 初始化 CService ------------------------------------ + SncpSleepService service = Sncp.createSimpleLocalService(SncpSleepService.class, resFactory); + resFactory.inject(service); + SncpServer server = new SncpServer(application, System.currentTimeMillis(), null, resFactory); + server.getResourceFactory().register(application); + server.addSncpServlet(service); + server.init(AnyValueWriter.create("port", 0)); + server.start(); + + int port = server.getSocketAddress().getPort(); + System.out.println("SNCP服务器启动端口: " + port); + InetSocketAddress sncpAddress = new InetSocketAddress("127.0.0.1", port); + final SncpClient client = + new SncpClient("", asyncGroup, "0", sncpAddress, new ClientAddress(sncpAddress), "TCP", 16, 100); + final SncpRpcGroups rpcGroups = application.getSncpRpcGroups(); + rpcGroups.computeIfAbsent("cs", "TCP").putAddress(sncpAddress); + SncpSleepService remoteCService = + Sncp.createSimpleRemoteService(SncpSleepService.class, resFactory, rpcGroups, client, "cs"); + long s = System.currentTimeMillis(); + CompletableFuture[] futures = + new CompletableFuture[] {remoteCService.sleep200(), remoteCService.sleep300(), remoteCService.sleep500() + }; + CompletableFuture.allOf(futures).join(); + long e = System.currentTimeMillis() - s; + System.out.println("耗时: " + e + " ms"); + server.shutdown(); + workExecutor.shutdown(); + Assertions.assertTrue(e < 600); + } +} diff --git a/src/test/java/org/redkale/test/sncp/SncpTest.java b/src/test/java/org/redkale/test/sncp/SncpTest.java index 001d1c746..18ff04087 100644 --- a/src/test/java/org/redkale/test/sncp/SncpTest.java +++ b/src/test/java/org/redkale/test/sncp/SncpTest.java @@ -1,258 +1,258 @@ -/* - * 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.test.sncp; - -import java.net.InetSocketAddress; -import java.util.concurrent.*; -import java.util.concurrent.atomic.AtomicInteger; -import org.junit.jupiter.api.Test; -import org.redkale.boot.*; -import org.redkale.convert.bson.*; -import org.redkale.inject.ResourceFactory; -import org.redkale.net.*; -import org.redkale.net.client.ClientAddress; -import org.redkale.net.sncp.*; -import org.redkale.service.Service; -import org.redkale.util.*; - -/** @author zhangjx */ -public class SncpTest { - - private static final String myhost = "127.0.0.1"; - - private static int port = 0; - - private static int port2 = 1; - - private static final String protocol = "SNCP.TCP"; // TCP UDP - - private static final int clientCapacity = protocol.endsWith(".UDP") ? AsyncGroup.UDP_BUFFER_CAPACITY : 8192; - - private static ResourceFactory factory; - - private static Application application; - - private static SncpRpcGroups rpcGroups; - - private boolean main; - - public static void main(String[] args) throws Throwable { - SncpTest test = new SncpTest(); - test.main = true; - test.run(); - } - - @Test - public void run() throws Exception { - LoggingBaseHandler.initDebugLogConfig(); - application = Application.create(true); - rpcGroups = application.getSncpRpcGroups(); - factory = application.getResourceFactory(); - factory.register("", BsonConvert.class, BsonFactory.root().getConvert()); - factory.register("", Application.class, application); - - if (System.getProperty("client") == null) { - runServer(); - if (port2 > 0) { - runServer2(); - } - } - if (System.getProperty("server") == null) { - runClient(); - } - if (System.getProperty("server") != null) { - System.in.read(); - } - } - - private void runClient() throws Exception { - InetSocketAddress addr = new InetSocketAddress(myhost, port); - rpcGroups - .computeIfAbsent("client", protocol.endsWith(".UDP") ? "UDP" : "TCP") - .putAddress(addr); - if (port2 > 0) { - rpcGroups - .computeIfAbsent("client", protocol.endsWith(".UDP") ? "UDP" : "TCP") - .putAddress(new InetSocketAddress(myhost, port2)); - } - final AsyncIOGroup asyncGroup = new AsyncIOGroup(clientCapacity, 16); - asyncGroup.start(); - - InetSocketAddress sncpAddress = addr; - final SncpClient client = new SncpClient( - "", - asyncGroup, - "0", - sncpAddress, - new ClientAddress(sncpAddress), - protocol.endsWith(".UDP") ? "UDP" : "TCP", - 16, - 100); - - final SncpTestIService service = Sncp.createSimpleRemoteService( - SncpTestIService.class, - factory, - rpcGroups, - client, - "client"); // Sncp.createSimpleRemoteService(SncpTestIService.class, null, transFactory, addr, - // "client"); - factory.inject(service); - - // SncpTestBean bean = new SncpTestBean(); - // StringBuilder sb = new StringBuilder(); - // for (int i = 0; i < 2000; i++) { - // sb.append("_").append(i).append("_0123456789"); - // } - // bean.setContent(sb.toString()); - // bean.setContent("hello sncp"); - SncpTestBean callbean = new SncpTestBean(); - callbean.setId(1); - callbean.setContent("数据X"); - service.queryLongResult("f", 3, 33L); - - callbean = service.insert(callbean); - System.out.println("bean: " + callbean); - System.out.println("\r\n\r\n\r\n\r\n---------------------------------------------------"); - Utility.sleep(200); - final int count = main ? 40 : 11; - final CountDownLatch cld = new CountDownLatch(count); - final AtomicInteger ai = new AtomicInteger(); - long s = System.currentTimeMillis(); - for (int i = 10; i < count + 10; i++) { - final int k = i + 1; - new Thread() { - @Override - public void run() { - try { - // Thread.sleep(k); - SncpTestBean bean = new SncpTestBean(); - bean.setId(k); - bean.setContent("数据: " + k); - StringBuilder sb = new StringBuilder(); - sb.append(k).append("--------"); - for (int j = 0; j < 1000; j++) { - sb.append("_").append(j % 10).append("_").append(k).append("7890_0123456789"); - } - bean.setContent(sb.toString()); - - service.queryResult(bean); - // service.updateBean(bean); - } catch (Exception e) { - e.printStackTrace(); - } finally { - long a = ai.incrementAndGet(); - System.out.println( - "运行了 " + (a == 100 ? "--------------------------------------------------" : "") + a); - cld.countDown(); - } - } - }.start(); - } - cld.await(); - System.out.println("---并发" + count + "次耗时: " + (System.currentTimeMillis() - s) / 1000.0 + "s"); - if (count == 1) { - if (main) { - System.exit(0); - } - return; - } - Utility.sleep(200); - final CountDownLatch cld2 = new CountDownLatch(1); - long s2 = System.currentTimeMillis(); - final CompletableFuture future = service.queryResultAsync(callbean); - future.whenComplete((v, e) -> { - System.out.println( - "异步执行结果: " + v + ", 异常为: " + e + ", 耗时: " + (System.currentTimeMillis() - s2) / 1000.0 + "s"); - cld2.countDown(); - }); - cld2.await(); - System.out.println("---全部运行完毕---"); - } - - private static void runServer() throws Exception { - InetSocketAddress addr = new InetSocketAddress(myhost, port); - final CountDownLatch cdl = new CountDownLatch(1); - final AsyncIOGroup asyncGroup = new AsyncIOGroup(8192, 16); - asyncGroup.start(); - new Thread() { - { - setName("Thread-Server-01"); - } - - @Override - public void run() { - try { - AnyValueWriter conf = new AnyValueWriter(); - conf.addValue("host", "0.0.0.0"); - conf.addValue("port", "" + port); - conf.addValue("protocol", protocol); - conf.addValue("maxbody", "" + (100 * 1024 * 1024)); - SncpServer server = new SncpServer(null, System.currentTimeMillis(), conf, factory); - if (port2 > 0) { - rpcGroups - .computeIfAbsent("server", protocol.endsWith(".UDP") ? "UDP" : "TCP") - .putAddress(new InetSocketAddress(myhost, port2)); - } - - SncpTestIService service = Sncp.createSimpleLocalService( - SncpTestServiceImpl.class, - factory); // Sncp.createSimpleLocalService(SncpTestServiceImpl.class, null, factory, - // transFactory, addr, "server"); - factory.inject(service); - server.addSncpServlet(service); - System.out.println(service); - server.init(conf); - server.start(); - port = server.getSocketAddress().getPort(); - cdl.countDown(); - } catch (Exception e) { - e.printStackTrace(); - } - } - }.start(); - cdl.await(); - } - - private static void runServer2() throws Exception { - InetSocketAddress addr = new InetSocketAddress(myhost, port2); - final CountDownLatch cdl = new CountDownLatch(1); - final AsyncIOGroup asyncGroup = new AsyncIOGroup(8196, 16); - asyncGroup.start(); - new Thread() { - { - setName("Thread-Server-02"); - } - - @Override - public void run() { - try { - AnyValueWriter conf = new AnyValueWriter(); - conf.addValue("host", "0.0.0.0"); - conf.addValue("port", "" + (port2 < 10 ? 0 : port2)); - conf.addValue("protocol", protocol); - conf.addValue("maxbody", "" + (100 * 1024 * 1024)); - SncpServer server = new SncpServer(null, System.currentTimeMillis(), conf, factory); - rpcGroups - .computeIfAbsent("server", protocol.endsWith(".UDP") ? "UDP" : "TCP") - .putAddress(new InetSocketAddress(myhost, port)); - - Service service = Sncp.createSimpleLocalService( - SncpTestServiceImpl.class, - factory); // Sncp.createSimpleLocalService(SncpTestServiceImpl.class, null, factory, - // transFactory, addr, "server"); - server.addSncpServlet(service); - server.init(conf); - server.start(); - port2 = server.getSocketAddress().getPort(); - cdl.countDown(); - } catch (Exception e) { - e.printStackTrace(); - } - } - }.start(); - cdl.await(); - } -} +/* + * 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.test.sncp; + +import java.net.InetSocketAddress; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicInteger; +import org.junit.jupiter.api.Test; +import org.redkale.boot.*; +import org.redkale.convert.bson.*; +import org.redkale.inject.ResourceFactory; +import org.redkale.net.*; +import org.redkale.net.client.ClientAddress; +import org.redkale.net.sncp.*; +import org.redkale.service.Service; +import org.redkale.util.*; + +/** @author zhangjx */ +public class SncpTest { + + private static final String myhost = "127.0.0.1"; + + private static int port = 0; + + private static int port2 = 1; + + private static final String protocol = "SNCP.TCP"; // TCP UDP + + private static final int clientCapacity = protocol.endsWith(".UDP") ? AsyncGroup.UDP_BUFFER_CAPACITY : 8192; + + private static ResourceFactory factory; + + private static Application application; + + private static SncpRpcGroups rpcGroups; + + private boolean main; + + public static void main(String[] args) throws Throwable { + SncpTest test = new SncpTest(); + test.main = true; + test.run(); + } + + @Test + public void run() throws Exception { + LoggingBaseHandler.initDebugLogConfig(); + application = Application.create(true); + rpcGroups = application.getSncpRpcGroups(); + factory = application.getResourceFactory(); + factory.register("", BsonConvert.class, BsonFactory.root().getConvert()); + factory.register("", Application.class, application); + + if (System.getProperty("client") == null) { + runServer(); + if (port2 > 0) { + runServer2(); + } + } + if (System.getProperty("server") == null) { + runClient(); + } + if (System.getProperty("server") != null) { + System.in.read(); + } + } + + private void runClient() throws Exception { + InetSocketAddress addr = new InetSocketAddress(myhost, port); + rpcGroups + .computeIfAbsent("client", protocol.endsWith(".UDP") ? "UDP" : "TCP") + .putAddress(addr); + if (port2 > 0) { + rpcGroups + .computeIfAbsent("client", protocol.endsWith(".UDP") ? "UDP" : "TCP") + .putAddress(new InetSocketAddress(myhost, port2)); + } + final AsyncIOGroup asyncGroup = new AsyncIOGroup(clientCapacity, 16); + asyncGroup.start(); + + InetSocketAddress sncpAddress = addr; + final SncpClient client = new SncpClient( + "", + asyncGroup, + "0", + sncpAddress, + new ClientAddress(sncpAddress), + protocol.endsWith(".UDP") ? "UDP" : "TCP", + 16, + 100); + + final SncpTestIService service = Sncp.createSimpleRemoteService( + SncpTestIService.class, + factory, + rpcGroups, + client, + "client"); // Sncp.createSimpleRemoteService(SncpTestIService.class, null, transFactory, addr, + // "client"); + factory.inject(service); + + // SncpTestBean bean = new SncpTestBean(); + // StringBuilder sb = new StringBuilder(); + // for (int i = 0; i < 2000; i++) { + // sb.append("_").append(i).append("_0123456789"); + // } + // bean.setContent(sb.toString()); + // bean.setContent("hello sncp"); + SncpTestBean callbean = new SncpTestBean(); + callbean.setId(1); + callbean.setContent("数据X"); + service.queryLongResult("f", 3, 33L); + + callbean = service.insert(callbean); + System.out.println("bean: " + callbean); + System.out.println("\r\n\r\n\r\n\r\n---------------------------------------------------"); + Utility.sleep(200); + final int count = main ? 40 : 11; + final CountDownLatch cld = new CountDownLatch(count); + final AtomicInteger ai = new AtomicInteger(); + long s = System.currentTimeMillis(); + for (int i = 10; i < count + 10; i++) { + final int k = i + 1; + new Thread() { + @Override + public void run() { + try { + // Thread.sleep(k); + SncpTestBean bean = new SncpTestBean(); + bean.setId(k); + bean.setContent("数据: " + k); + StringBuilder sb = new StringBuilder(); + sb.append(k).append("--------"); + for (int j = 0; j < 1000; j++) { + sb.append("_").append(j % 10).append("_").append(k).append("7890_0123456789"); + } + bean.setContent(sb.toString()); + + service.queryResult(bean); + // service.updateBean(bean); + } catch (Exception e) { + e.printStackTrace(); + } finally { + long a = ai.incrementAndGet(); + System.out.println( + "运行了 " + (a == 100 ? "--------------------------------------------------" : "") + a); + cld.countDown(); + } + } + }.start(); + } + cld.await(); + System.out.println("---并发" + count + "次耗时: " + (System.currentTimeMillis() - s) / 1000.0 + "s"); + if (count == 1) { + if (main) { + System.exit(0); + } + return; + } + Utility.sleep(200); + final CountDownLatch cld2 = new CountDownLatch(1); + long s2 = System.currentTimeMillis(); + final CompletableFuture future = service.queryResultAsync(callbean); + future.whenComplete((v, e) -> { + System.out.println( + "异步执行结果: " + v + ", 异常为: " + e + ", 耗时: " + (System.currentTimeMillis() - s2) / 1000.0 + "s"); + cld2.countDown(); + }); + cld2.await(); + System.out.println("---全部运行完毕---"); + } + + private static void runServer() throws Exception { + InetSocketAddress addr = new InetSocketAddress(myhost, port); + final CountDownLatch cdl = new CountDownLatch(1); + final AsyncIOGroup asyncGroup = new AsyncIOGroup(8192, 16); + asyncGroup.start(); + new Thread() { + { + setName("Thread-Server-01"); + } + + @Override + public void run() { + try { + AnyValueWriter conf = new AnyValueWriter(); + conf.addValue("host", "0.0.0.0"); + conf.addValue("port", "" + port); + conf.addValue("protocol", protocol); + conf.addValue("maxbody", "" + (100 * 1024 * 1024)); + SncpServer server = new SncpServer(null, System.currentTimeMillis(), conf, factory); + if (port2 > 0) { + rpcGroups + .computeIfAbsent("server", protocol.endsWith(".UDP") ? "UDP" : "TCP") + .putAddress(new InetSocketAddress(myhost, port2)); + } + + SncpTestIService service = Sncp.createSimpleLocalService( + SncpTestServiceImpl.class, + factory); // Sncp.createSimpleLocalService(SncpTestServiceImpl.class, null, factory, + // transFactory, addr, "server"); + factory.inject(service); + server.addSncpServlet(service); + System.out.println(service); + server.init(conf); + server.start(); + port = server.getSocketAddress().getPort(); + cdl.countDown(); + } catch (Exception e) { + e.printStackTrace(); + } + } + }.start(); + cdl.await(); + } + + private static void runServer2() throws Exception { + InetSocketAddress addr = new InetSocketAddress(myhost, port2); + final CountDownLatch cdl = new CountDownLatch(1); + final AsyncIOGroup asyncGroup = new AsyncIOGroup(8196, 16); + asyncGroup.start(); + new Thread() { + { + setName("Thread-Server-02"); + } + + @Override + public void run() { + try { + AnyValueWriter conf = new AnyValueWriter(); + conf.addValue("host", "0.0.0.0"); + conf.addValue("port", "" + (port2 < 10 ? 0 : port2)); + conf.addValue("protocol", protocol); + conf.addValue("maxbody", "" + (100 * 1024 * 1024)); + SncpServer server = new SncpServer(null, System.currentTimeMillis(), conf, factory); + rpcGroups + .computeIfAbsent("server", protocol.endsWith(".UDP") ? "UDP" : "TCP") + .putAddress(new InetSocketAddress(myhost, port)); + + Service service = Sncp.createSimpleLocalService( + SncpTestServiceImpl.class, + factory); // Sncp.createSimpleLocalService(SncpTestServiceImpl.class, null, factory, + // transFactory, addr, "server"); + server.addSncpServlet(service); + server.init(conf); + server.start(); + port2 = server.getSocketAddress().getPort(); + cdl.countDown(); + } catch (Exception e) { + e.printStackTrace(); + } + } + }.start(); + cdl.await(); + } +} diff --git a/src/test/java/org/redkale/test/sncp/SncpTestBean.java b/src/test/java/org/redkale/test/sncp/SncpTestBean.java index 6d71fdac4..e2e1a4547 100644 --- a/src/test/java/org/redkale/test/sncp/SncpTestBean.java +++ b/src/test/java/org/redkale/test/sncp/SncpTestBean.java @@ -1,54 +1,54 @@ -/* - * 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.test.sncp; - -import org.redkale.convert.bson.BsonFactory; -import org.redkale.convert.json.JsonConvert; -import org.redkale.persistence.Id; -import org.redkale.source.FilterBean; -import org.redkale.util.Utility; - -/** @author zhangjx */ -public class SncpTestBean implements FilterBean { - - @Id - private long id; - - private String content; - - public static void main(String[] args) throws Exception { - String json = "{\"content\":\"数据: 01\",\"id\":1}"; - SncpTestBean bean = JsonConvert.root().convertFrom(SncpTestBean.class, json); - System.out.println(bean); - byte[] bs = BsonFactory.root().getConvert().convertTo(bean); - Utility.println("---------", bs); - System.out.println(BsonFactory.root() - .getConvert() - .convertFrom(SncpTestBean.class, bs) - .toString()); - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } - - public long getId() { - return id; - } - - public void setId(long id) { - this.id = id; - } - - public String getContent() { - return content; - } - - public void setContent(String content) { - this.content = content; - } -} +/* + * 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.test.sncp; + +import org.redkale.convert.bson.BsonFactory; +import org.redkale.convert.json.JsonConvert; +import org.redkale.persistence.Id; +import org.redkale.source.FilterBean; +import org.redkale.util.Utility; + +/** @author zhangjx */ +public class SncpTestBean implements FilterBean { + + @Id + private long id; + + private String content; + + public static void main(String[] args) throws Exception { + String json = "{\"content\":\"数据: 01\",\"id\":1}"; + SncpTestBean bean = JsonConvert.root().convertFrom(SncpTestBean.class, json); + System.out.println(bean); + byte[] bs = BsonFactory.root().getConvert().convertTo(bean); + Utility.println("---------", bs); + System.out.println(BsonFactory.root() + .getConvert() + .convertFrom(SncpTestBean.class, bs) + .toString()); + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } +} diff --git a/src/test/java/org/redkale/test/sncp/SncpTestIService.java b/src/test/java/org/redkale/test/sncp/SncpTestIService.java index 6d9e0c8fa..80a165954 100644 --- a/src/test/java/org/redkale/test/sncp/SncpTestIService.java +++ b/src/test/java/org/redkale/test/sncp/SncpTestIService.java @@ -1,25 +1,25 @@ -/* - * 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.test.sncp; - -import java.util.concurrent.CompletableFuture; -import org.redkale.service.Service; - -/** @author zhangjx */ -public interface SncpTestIService extends Service { - - public String queryResult(SncpTestBean bean); - - public double queryDoubleResult(String a, int b, double value); - - public long queryLongResult(String a, int b, long value); - - public CompletableFuture queryResultAsync(SncpTestBean bean); - - public SncpTestBean insert(SncpTestBean bean); - - public String updateBean(SncpTestBean bean); -} +/* + * 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.test.sncp; + +import java.util.concurrent.CompletableFuture; +import org.redkale.service.Service; + +/** @author zhangjx */ +public interface SncpTestIService extends Service { + + public String queryResult(SncpTestBean bean); + + public double queryDoubleResult(String a, int b, double value); + + public long queryLongResult(String a, int b, long value); + + public CompletableFuture queryResultAsync(SncpTestBean bean); + + public SncpTestBean insert(SncpTestBean bean); + + public String updateBean(SncpTestBean bean); +} diff --git a/src/test/java/org/redkale/test/sncp/SncpTestServiceImpl.java b/src/test/java/org/redkale/test/sncp/SncpTestServiceImpl.java index 93652bb84..180873d6b 100644 --- a/src/test/java/org/redkale/test/sncp/SncpTestServiceImpl.java +++ b/src/test/java/org/redkale/test/sncp/SncpTestServiceImpl.java @@ -1,126 +1,126 @@ -/* - * 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.test.sncp; - -import java.lang.reflect.Method; -import java.net.InetSocketAddress; -import java.nio.channels.CompletionHandler; -import java.util.concurrent.CompletableFuture; -import org.redkale.annotation.ResourceType; -import org.redkale.boot.Application; -import org.redkale.inject.ResourceFactory; -import org.redkale.net.AsyncIOGroup; -import org.redkale.net.client.ClientAddress; -import org.redkale.net.sncp.*; -import org.redkale.service.*; -import org.redkale.util.Utility; - -/** @author zhangjx */ -@ResourceType(SncpTestIService.class) -public class SncpTestServiceImpl implements SncpTestIService { - - @Override - public CompletableFuture queryResultAsync(SncpTestBean bean) { - final CompletableFuture future = new CompletableFuture<>(); - new Thread() { - @Override - public void run() { - try { - Utility.sleep(200); - System.out.println( - Thread.currentThread().getName() + " sleep 200ms后运行了异步方法-----------queryResultAsync方法"); - future.complete("异步 result: " + bean); - } catch (Exception e) { - e.printStackTrace(); - } - } - }.start(); - return future; - } - - @Override - public long queryLongResult(String a, int b, long value) { - return value + 1; - } - - @Override - public double queryDoubleResult(String a, int b, double value) { - return value + 1; - } - - @Override - public SncpTestBean insert(SncpTestBean bean) { - bean.setId(System.currentTimeMillis()); - return bean; - } - - public SncpTestBean expand(SncpTestBean bean) { - bean.setId(System.currentTimeMillis()); - return bean; - } - - @Override - public String queryResult(SncpTestBean bean) { - System.out.println(Thread.currentThread().getName() + " 运行了queryResult方法 content-length: " - + bean.getContent().length()); - return "result-content: " + bean.getContent(); - } - - public void queryResult(CompletionHandler handler, @RpcAttachment SncpTestBean bean) { - System.out.println(Thread.currentThread().getName() + " handler 运行了queryResult方法"); - if (handler != null) { - handler.completed("result: " + bean.getId(), bean); - } - } - - @Override - public String updateBean(SncpTestBean bean) { - bean.setId(System.currentTimeMillis()); - System.out.println(Thread.currentThread().getName() + " 运行了updateBean方法"); - return "result: " + bean; - } - - public static void main(String[] args) throws Exception { - - final Application application = Application.create(true); - final AsyncIOGroup asyncGroup = new AsyncIOGroup(8192, 16); - asyncGroup.start(); - final ResourceFactory factory = ResourceFactory.create(); - final SncpRpcGroups rpcGroups = application.getSncpRpcGroups(); - InetSocketAddress sncpAddress = new InetSocketAddress("127.0.0.1", 7070); - rpcGroups.computeIfAbsent("g70", "TCP").putAddress(sncpAddress); - final SncpClient client = - new SncpClient("", asyncGroup, "0", sncpAddress, new ClientAddress(sncpAddress), "TCP", 16, 100); - - Service service = Sncp.createSimpleLocalService(SncpTestServiceImpl.class, factory); - for (Method method : service.getClass().getDeclaredMethods()) { - System.out.println(method); - } - System.out.println("-----------------------------------"); - for (Method method : Sncp.loadRemoteMethodActions(service.getClass()).values()) { - System.out.println(method); - } - System.out.println("-----------------------------------"); - service = Sncp.createSimpleRemoteService(SncpTestServiceImpl.class, factory, rpcGroups, client, "g70"); - for (Method method : service.getClass().getDeclaredMethods()) { - System.out.println(method); - } - System.out.println("-----------------------------------"); - for (Method method : Sncp.loadRemoteMethodActions(service.getClass()).values()) { - System.out.println(method); - } - System.out.println("-----------------------------------"); - service = Sncp.createSimpleRemoteService(SncpTestIService.class, factory, rpcGroups, client, "g70"); - for (Method method : service.getClass().getDeclaredMethods()) { - System.out.println(method); - } - System.out.println("-----------------------------------"); - for (Method method : Sncp.loadRemoteMethodActions(service.getClass()).values()) { - System.out.println(method); - } - System.out.println("-----------------------------------"); - } -} +/* + * 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.test.sncp; + +import java.lang.reflect.Method; +import java.net.InetSocketAddress; +import java.nio.channels.CompletionHandler; +import java.util.concurrent.CompletableFuture; +import org.redkale.annotation.ResourceType; +import org.redkale.boot.Application; +import org.redkale.inject.ResourceFactory; +import org.redkale.net.AsyncIOGroup; +import org.redkale.net.client.ClientAddress; +import org.redkale.net.sncp.*; +import org.redkale.service.*; +import org.redkale.util.Utility; + +/** @author zhangjx */ +@ResourceType(SncpTestIService.class) +public class SncpTestServiceImpl implements SncpTestIService { + + @Override + public CompletableFuture queryResultAsync(SncpTestBean bean) { + final CompletableFuture future = new CompletableFuture<>(); + new Thread() { + @Override + public void run() { + try { + Utility.sleep(200); + System.out.println( + Thread.currentThread().getName() + " sleep 200ms后运行了异步方法-----------queryResultAsync方法"); + future.complete("异步 result: " + bean); + } catch (Exception e) { + e.printStackTrace(); + } + } + }.start(); + return future; + } + + @Override + public long queryLongResult(String a, int b, long value) { + return value + 1; + } + + @Override + public double queryDoubleResult(String a, int b, double value) { + return value + 1; + } + + @Override + public SncpTestBean insert(SncpTestBean bean) { + bean.setId(System.currentTimeMillis()); + return bean; + } + + public SncpTestBean expand(SncpTestBean bean) { + bean.setId(System.currentTimeMillis()); + return bean; + } + + @Override + public String queryResult(SncpTestBean bean) { + System.out.println(Thread.currentThread().getName() + " 运行了queryResult方法 content-length: " + + bean.getContent().length()); + return "result-content: " + bean.getContent(); + } + + public void queryResult(CompletionHandler handler, @RpcAttachment SncpTestBean bean) { + System.out.println(Thread.currentThread().getName() + " handler 运行了queryResult方法"); + if (handler != null) { + handler.completed("result: " + bean.getId(), bean); + } + } + + @Override + public String updateBean(SncpTestBean bean) { + bean.setId(System.currentTimeMillis()); + System.out.println(Thread.currentThread().getName() + " 运行了updateBean方法"); + return "result: " + bean; + } + + public static void main(String[] args) throws Exception { + + final Application application = Application.create(true); + final AsyncIOGroup asyncGroup = new AsyncIOGroup(8192, 16); + asyncGroup.start(); + final ResourceFactory factory = ResourceFactory.create(); + final SncpRpcGroups rpcGroups = application.getSncpRpcGroups(); + InetSocketAddress sncpAddress = new InetSocketAddress("127.0.0.1", 7070); + rpcGroups.computeIfAbsent("g70", "TCP").putAddress(sncpAddress); + final SncpClient client = + new SncpClient("", asyncGroup, "0", sncpAddress, new ClientAddress(sncpAddress), "TCP", 16, 100); + + Service service = Sncp.createSimpleLocalService(SncpTestServiceImpl.class, factory); + for (Method method : service.getClass().getDeclaredMethods()) { + System.out.println(method); + } + System.out.println("-----------------------------------"); + for (Method method : Sncp.loadRemoteMethodActions(service.getClass()).values()) { + System.out.println(method); + } + System.out.println("-----------------------------------"); + service = Sncp.createSimpleRemoteService(SncpTestServiceImpl.class, factory, rpcGroups, client, "g70"); + for (Method method : service.getClass().getDeclaredMethods()) { + System.out.println(method); + } + System.out.println("-----------------------------------"); + for (Method method : Sncp.loadRemoteMethodActions(service.getClass()).values()) { + System.out.println(method); + } + System.out.println("-----------------------------------"); + service = Sncp.createSimpleRemoteService(SncpTestIService.class, factory, rpcGroups, client, "g70"); + for (Method method : service.getClass().getDeclaredMethods()) { + System.out.println(method); + } + System.out.println("-----------------------------------"); + for (Method method : Sncp.loadRemoteMethodActions(service.getClass()).values()) { + System.out.println(method); + } + System.out.println("-----------------------------------"); + } +} diff --git a/src/test/java/org/redkale/test/sncp/TestService.java b/src/test/java/org/redkale/test/sncp/TestService.java index 927749c0c..4df0d1e84 100644 --- a/src/test/java/org/redkale/test/sncp/TestService.java +++ b/src/test/java/org/redkale/test/sncp/TestService.java @@ -1,166 +1,166 @@ -/* - * - */ -package org.redkale.test.sncp; - -import java.lang.reflect.Method; -import java.nio.channels.CompletionHandler; -import java.util.concurrent.CompletableFuture; -import org.redkale.annotation.ResourceType; -import org.redkale.convert.*; -import org.redkale.net.sncp.*; -import org.redkale.net.sncp.SncpServlet.SncpActionServlet; -import org.redkale.service.Service; -import org.redkale.test.util.TestBean; -import org.redkale.util.Uint128; - -/** @author zhangjx */ -public interface TestService extends Service { - - public boolean change(TestBean bean, String name, int id); - - public void insert(BooleanHandler handler, TestBean bean, String name, int id); - - public void update( - long show, short v2, CompletionHandler handler, TestBean bean, String name, int id); - - public CompletableFuture changeName(TestBean bean, String name, int id); -} - -@ResourceType(TestService.class) -class TestServiceImpl implements TestService { - - @Override - public boolean change(TestBean bean, String name, int id) { - return false; - } - - public void delete(TestBean bean) {} - - @Override - public void insert(BooleanHandler handler, TestBean bean, String name, int id) {} - - @Override - public void update( - long show, short v2, CompletionHandler handler, TestBean bean, String name, int id) {} - - @Override - public CompletableFuture changeName(TestBean bean, String name, int id) { - return null; - } -} - -class BooleanHandler implements CompletionHandler { - - @Override - public void completed(Boolean result, TestBean attachment) {} - - @Override - public void failed(Throwable exc, TestBean attachment) {} -} - -class DynActionTestService_change extends SncpActionServlet { - - public DynActionTestService_change( - String resourceName, - Class resourceType, - Service service, - Uint128 serviceid, - Uint128 actionid, - final Method method) { - super(resourceName, resourceType, service, serviceid, actionid, method); - } - - @Override - public void action(SncpRequest request, SncpResponse response) throws Throwable { - Convert convert = request.getConvert(); - Reader in = request.getReader(); - TestBean arg1 = convert.convertFrom(paramTypes[1], in); - String arg2 = convert.convertFrom(paramTypes[2], in); - int arg3 = convert.convertFrom(paramTypes[3], in); - TestService serviceObj = (TestService) service(); - Object rs = serviceObj.change(arg1, arg2, arg3); - response.finish(boolean.class, rs); - } -} - -class DynActionTestService_insert extends SncpActionServlet { - - public DynActionTestService_insert( - String resourceName, - Class resourceType, - Service service, - Uint128 serviceid, - Uint128 actionid, - final Method method) { - super(resourceName, resourceType, service, serviceid, actionid, method); - } - - @Override - public void action(SncpRequest request, SncpResponse response) throws Throwable { - Convert convert = request.getConvert(); - Reader in = request.getReader(); - BooleanHandler arg0 = response.getParamAsyncHandler(); - convert.convertFrom(CompletionHandler.class, in); - TestBean arg1 = convert.convertFrom(paramTypes[2], in); - String arg2 = convert.convertFrom(paramTypes[3], in); - int arg3 = convert.convertFrom(paramTypes[4], in); - TestService serviceObj = (TestService) service(); - serviceObj.insert(arg0, arg1, arg2, arg3); - response.finishVoid(); - } -} - -class DynActionTestService_update extends SncpActionServlet { - - public DynActionTestService_update( - String resourceName, - Class resourceType, - Service service, - Uint128 serviceid, - Uint128 actionid, - final Method method) { - super(resourceName, resourceType, service, serviceid, actionid, method); - } - - @Override - public void action(SncpRequest request, SncpResponse response) throws Throwable { - Convert convert = request.getConvert(); - Reader in = request.getReader(); - long a1 = convert.convertFrom(paramTypes[1], in); - short a2 = convert.convertFrom(paramTypes[2], in); - CompletionHandler a3 = response.getParamAsyncHandler(); - convert.convertFrom(CompletionHandler.class, in); - TestBean arg1 = convert.convertFrom(paramTypes[4], in); - String arg2 = convert.convertFrom(paramTypes[5], in); - int arg3 = convert.convertFrom(paramTypes[6], in); - TestService serviceObj = (TestService) service(); - serviceObj.update(a1, a2, a3, arg1, arg2, arg3); - response.finishVoid(); - } -} - -class DynActionTestService_changeName extends SncpActionServlet { - - public DynActionTestService_changeName( - String resourceName, - Class resourceType, - Service service, - Uint128 serviceid, - Uint128 actionid, - final Method method) { - super(resourceName, resourceType, service, serviceid, actionid, method); - } - - @Override - public void action(SncpRequest request, SncpResponse response) throws Throwable { - Convert convert = request.getConvert(); - Reader in = request.getReader(); - TestBean arg1 = convert.convertFrom(paramTypes[1], in); - String arg2 = convert.convertFrom(paramTypes[2], in); - int arg3 = convert.convertFrom(paramTypes[3], in); - TestService serviceObj = (TestService) service(); - CompletableFuture future = serviceObj.changeName(arg1, arg2, arg3); - response.finishFuture(paramHandlerResultType, future); - } -} +/* + * + */ +package org.redkale.test.sncp; + +import java.lang.reflect.Method; +import java.nio.channels.CompletionHandler; +import java.util.concurrent.CompletableFuture; +import org.redkale.annotation.ResourceType; +import org.redkale.convert.*; +import org.redkale.net.sncp.*; +import org.redkale.net.sncp.SncpServlet.SncpActionServlet; +import org.redkale.service.Service; +import org.redkale.test.util.TestBean; +import org.redkale.util.Uint128; + +/** @author zhangjx */ +public interface TestService extends Service { + + public boolean change(TestBean bean, String name, int id); + + public void insert(BooleanHandler handler, TestBean bean, String name, int id); + + public void update( + long show, short v2, CompletionHandler handler, TestBean bean, String name, int id); + + public CompletableFuture changeName(TestBean bean, String name, int id); +} + +@ResourceType(TestService.class) +class TestServiceImpl implements TestService { + + @Override + public boolean change(TestBean bean, String name, int id) { + return false; + } + + public void delete(TestBean bean) {} + + @Override + public void insert(BooleanHandler handler, TestBean bean, String name, int id) {} + + @Override + public void update( + long show, short v2, CompletionHandler handler, TestBean bean, String name, int id) {} + + @Override + public CompletableFuture changeName(TestBean bean, String name, int id) { + return null; + } +} + +class BooleanHandler implements CompletionHandler { + + @Override + public void completed(Boolean result, TestBean attachment) {} + + @Override + public void failed(Throwable exc, TestBean attachment) {} +} + +class DynActionTestService_change extends SncpActionServlet { + + public DynActionTestService_change( + String resourceName, + Class resourceType, + Service service, + Uint128 serviceid, + Uint128 actionid, + final Method method) { + super(resourceName, resourceType, service, serviceid, actionid, method); + } + + @Override + public void action(SncpRequest request, SncpResponse response) throws Throwable { + Convert convert = request.getConvert(); + Reader in = request.getReader(); + TestBean arg1 = convert.convertFrom(paramTypes[1], in); + String arg2 = convert.convertFrom(paramTypes[2], in); + int arg3 = convert.convertFrom(paramTypes[3], in); + TestService serviceObj = (TestService) service(); + Object rs = serviceObj.change(arg1, arg2, arg3); + response.finish(boolean.class, rs); + } +} + +class DynActionTestService_insert extends SncpActionServlet { + + public DynActionTestService_insert( + String resourceName, + Class resourceType, + Service service, + Uint128 serviceid, + Uint128 actionid, + final Method method) { + super(resourceName, resourceType, service, serviceid, actionid, method); + } + + @Override + public void action(SncpRequest request, SncpResponse response) throws Throwable { + Convert convert = request.getConvert(); + Reader in = request.getReader(); + BooleanHandler arg0 = response.getParamAsyncHandler(); + convert.convertFrom(CompletionHandler.class, in); + TestBean arg1 = convert.convertFrom(paramTypes[2], in); + String arg2 = convert.convertFrom(paramTypes[3], in); + int arg3 = convert.convertFrom(paramTypes[4], in); + TestService serviceObj = (TestService) service(); + serviceObj.insert(arg0, arg1, arg2, arg3); + response.finishVoid(); + } +} + +class DynActionTestService_update extends SncpActionServlet { + + public DynActionTestService_update( + String resourceName, + Class resourceType, + Service service, + Uint128 serviceid, + Uint128 actionid, + final Method method) { + super(resourceName, resourceType, service, serviceid, actionid, method); + } + + @Override + public void action(SncpRequest request, SncpResponse response) throws Throwable { + Convert convert = request.getConvert(); + Reader in = request.getReader(); + long a1 = convert.convertFrom(paramTypes[1], in); + short a2 = convert.convertFrom(paramTypes[2], in); + CompletionHandler a3 = response.getParamAsyncHandler(); + convert.convertFrom(CompletionHandler.class, in); + TestBean arg1 = convert.convertFrom(paramTypes[4], in); + String arg2 = convert.convertFrom(paramTypes[5], in); + int arg3 = convert.convertFrom(paramTypes[6], in); + TestService serviceObj = (TestService) service(); + serviceObj.update(a1, a2, a3, arg1, arg2, arg3); + response.finishVoid(); + } +} + +class DynActionTestService_changeName extends SncpActionServlet { + + public DynActionTestService_changeName( + String resourceName, + Class resourceType, + Service service, + Uint128 serviceid, + Uint128 actionid, + final Method method) { + super(resourceName, resourceType, service, serviceid, actionid, method); + } + + @Override + public void action(SncpRequest request, SncpResponse response) throws Throwable { + Convert convert = request.getConvert(); + Reader in = request.getReader(); + TestBean arg1 = convert.convertFrom(paramTypes[1], in); + String arg2 = convert.convertFrom(paramTypes[2], in); + int arg3 = convert.convertFrom(paramTypes[3], in); + TestService serviceObj = (TestService) service(); + CompletableFuture future = serviceObj.changeName(arg1, arg2, arg3); + response.finishFuture(paramHandlerResultType, future); + } +} diff --git a/src/test/java/org/redkale/test/sncp/_DynLocalSncpTestService.java b/src/test/java/org/redkale/test/sncp/_DynLocalSncpTestService.java index 1a97b4cf7..e60d81211 100644 --- a/src/test/java/org/redkale/test/sncp/_DynLocalSncpTestService.java +++ b/src/test/java/org/redkale/test/sncp/_DynLocalSncpTestService.java @@ -1,12 +1,12 @@ -/* - * 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.test.sncp; - -import org.redkale.annotation.ResourceType; - -/** @author zhangjx */ -@ResourceType(SncpTestIService.class) -public class _DynLocalSncpTestService extends SncpTestServiceImpl {} +/* + * 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.test.sncp; + +import org.redkale.annotation.ResourceType; + +/** @author zhangjx */ +@ResourceType(SncpTestIService.class) +public class _DynLocalSncpTestService extends SncpTestServiceImpl {} diff --git a/src/test/java/org/redkale/test/source/BaseEntity.java b/src/test/java/org/redkale/test/source/BaseEntity.java index 3fa64c4a3..113df3ab5 100644 --- a/src/test/java/org/redkale/test/source/BaseEntity.java +++ b/src/test/java/org/redkale/test/source/BaseEntity.java @@ -1,18 +1,18 @@ -/* - * 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.test.source; - -import java.io.Serializable; -import org.redkale.convert.json.*; - -/** @author zhangjx */ -public abstract class BaseEntity implements Serializable { - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } -} +/* + * 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.test.source; + +import java.io.Serializable; +import org.redkale.convert.json.*; + +/** @author zhangjx */ +public abstract class BaseEntity implements Serializable { + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } +} diff --git a/src/test/java/org/redkale/test/source/CacheMemorySourceTest.java b/src/test/java/org/redkale/test/source/CacheMemorySourceTest.java index e4cc8afcb..f347ceccc 100644 --- a/src/test/java/org/redkale/test/source/CacheMemorySourceTest.java +++ b/src/test/java/org/redkale/test/source/CacheMemorySourceTest.java @@ -1,663 +1,663 @@ -/* - * - */ -package org.redkale.test.source; - -import java.lang.reflect.Type; -import java.net.InetSocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeSet; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicLong; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import org.redkale.convert.json.JsonConvert; -import org.redkale.source.CacheEventListener; -import org.redkale.source.CacheMemorySource; -import org.redkale.source.CacheScoredValue; -import org.redkale.source.Flipper; -import org.redkale.util.TypeToken; -import org.redkale.util.Utility; - -/** @author zhangjx */ -public class CacheMemorySourceTest { - - public static void main(String[] args) throws Throwable { - CacheMemorySourceTest test = new CacheMemorySourceTest(); - test.run(); - } - - @Test - public void run() throws Exception { - CacheMemorySource source = new CacheMemorySource(""); - source.init(null); - System.out.println("------------------------------------"); - source.del("stritem1", "stritem2", "stritem1x"); - source.setString("stritem1", "value1"); - source.setString("stritem2", "value2"); - Assertions.assertEquals("value2", source.getDelString("stritem2")); - Assertions.assertTrue(source.getDelString("stritem2") == null); - source.setString("stritem2", "value2"); - - List list = source.keysStartsWith("stritem"); - System.out.println("stritem开头的key有两个: " + list); - Assertions.assertTrue(Utility.equalsElement(List.of("stritem2", "stritem1"), list)); - - Map map = source.mgetsString("stritem1", "stritem2"); - System.out.println("[有值] MGET : " + map); - Assertions.assertTrue(Utility.equalsElement(Utility.ofMap("stritem1", "value1", "stritem2", "value2"), map)); - - List array = source.mgetString("stritem1", "stritem2"); - System.out.println("[有值] MGET : " + array); - Assertions.assertTrue(Utility.equalsElement(List.of("value1", "value2"), array)); - - Assertions.assertFalse(source.persist("stritem1")); - Assertions.assertTrue(source.rename("stritem1", "stritem1x")); - Assertions.assertEquals("value1", source.getString("stritem1x")); - Assertions.assertEquals(null, source.getString("stritem1")); - Assertions.assertFalse(source.renamenx("stritem1x", "stritem2")); - Assertions.assertEquals("value2", source.getString("stritem2")); - Assertions.assertTrue(source.renamenx("stritem1x", "stritem1")); - - source.del("intitem1", "intitem2"); - source.setLong("intitem1", 333); - source.setLong("intitem2", 444); - - map = source.mgetsString("intitem1", "intitem22", "intitem2"); - System.out.println("[有值] MGET : " + map); - Assertions.assertTrue(Utility.equalsElement(Utility.ofMap("intitem1", "333", "intitem2", "444"), map)); - - array = source.mgetString("intitem1", "intitem22", "intitem2"); - System.out.println("[有值] MGET : " + array); - List ss = new ArrayList<>(); - ss.add("333"); - ss.add(null); - ss.add("444"); - Assertions.assertTrue(Utility.equalsElement(ss, array)); - - source.del("objitem1", "objitem2"); - source.mset(Utility.ofMap("objitem1", new Flipper(10), "objitem2", new Flipper(20))); - - Map flippermap = source.mgets(Flipper.class, "objitem1", "objitem2"); - System.out.println("[有值] MGET : " + flippermap); - Assertions.assertTrue(Utility.equalsElement( - Utility.ofMap("objitem1", new Flipper(10), "objitem2", new Flipper(20)), flippermap)); - - source.del("key1", "key2", "300"); - source.setex("key1", 1000, String.class, "value1"); - source.set("key1", String.class, "value1"); - source.setString("keystr1", "strvalue1"); - source.setLong("keylong1", 333L); - source.set("300", String.class, "4000"); - Object obj = source.getex("key1", 3500, String.class); - System.out.println("[有值] key1 GET : " + obj); - Assertions.assertEquals("value1", obj); - - obj = source.get("300", String.class); - System.out.println("[有值] 300 GET : " + obj); - Assertions.assertEquals("4000", obj); - - obj = source.get("key1", String.class); - System.out.println("[有值] key1 GET : " + obj); - Assertions.assertEquals("value1", obj); - - obj = source.getSet("key1", String.class, "value11"); - System.out.println("[旧值] key1 GETSET : " + obj); - Assertions.assertEquals("value1", obj); - - obj = source.get("key2", String.class); - System.out.println("[无值] key2 GET : " + obj); - Assertions.assertNull(obj); - - obj = source.getString("keystr1"); - System.out.println("[有值] keystr1 GET : " + obj); - Assertions.assertEquals("strvalue1", obj); - - long num = source.getLong("keylong1", 0L); - System.out.println("[有值] keylong1 GET : " + null); - Assertions.assertEquals(333L, num); - - boolean bool = source.exists("key1"); - System.out.println("[有值] key1 EXISTS : " + bool); - Assertions.assertTrue(bool); - - bool = source.exists("key2"); - System.out.println("[无值] key2 EXISTS : " + bool); - Assertions.assertFalse(bool); - - source.del("keys3"); - source.rpush("keys3", String.class, "vals1"); - source.rpush("keys3", String.class, "vals2"); - System.out.println("-------- keys3 追加了两个值 --------"); - - Collection col = source.lrangeString("keys3"); - System.out.println("[两值] keys3 VALUES : " + col); - Assertions.assertTrue(Utility.equalsElement(List.of("vals1", "vals2"), col)); - - bool = source.exists("keys3"); - System.out.println("[有值] keys3 EXISTS : " + bool); - Assertions.assertTrue(bool); - - source.lrem("keys3", String.class, "vals1"); - col = source.lrangeString("keys3"); - System.out.println("[一值] keys3 VALUES : " + col); - Assertions.assertIterableEquals(List.of("vals2"), col); - source.rpush("keys3", String.class, "vals2"); - source.rpush("keys3", String.class, "vals3"); - source.rpush("keys3", String.class, "vals4"); - Assertions.assertEquals("vals4", source.rpopString("keys3")); - source.lpush("keys3", String.class, "vals0"); - Assertions.assertEquals("vals0", source.lpopString("keys3")); - String rlv = source.rpoplpush("keys3", "keys3-2", String.class); - Assertions.assertEquals("vals3", rlv); - - source.del("keys3"); - source.lpushString("keys3", "vals20"); - source.lpushString("keys3", "vals10"); - System.out.println("keys3-list: " + source.lrangeString("keys3")); - Assertions.assertEquals("vals10", source.lindexString("keys3", 0)); - Assertions.assertEquals("vals20", source.lindexString("keys3", -1)); - source.linsertBeforeString("keys3", "vals10", "vals00"); - source.linsertAfterString("keys3", "vals10", "vals15"); - Assertions.assertEquals(0, source.linsertBeforeString("keys_3", "vals10", "vals00")); - Assertions.assertEquals(-1, source.linsertBeforeString("keys3", "vals90", "vals00")); - Assertions.assertEquals(4, source.llen("keys3")); - Assertions.assertIterableEquals(List.of("vals00", "vals10", "vals15", "vals20"), source.lrangeString("keys3")); - - source.del("stringmap"); - source.sadd("stringmap", JsonConvert.TYPE_MAP_STRING_STRING, Utility.ofMap("a", "aa", "b", "bb")); - source.sadd("stringmap", JsonConvert.TYPE_MAP_STRING_STRING, Utility.ofMap("c", "cc", "d", "dd")); - col = source.smembers("stringmap", JsonConvert.TYPE_MAP_STRING_STRING); - System.out.println("[两值] stringmap VALUES : " + col); - Assertions.assertTrue(Utility.equalsElement( - List.of(Utility.ofMap("c", "cc", "d", "dd"), Utility.ofMap("a", "aa", "b", "bb")), col)); - - source.del("sets3"); - source.del("sets4"); - source.del("sets5"); - source.sadd("sets3", String.class, "setvals1"); - source.sadd("sets3", String.class, "setvals2"); - source.sadd("sets3", String.class, "setvals1"); - source.sadd("sets4", String.class, "setvals2"); - source.sadd("sets4", String.class, "setvals1"); - col = source.smembersString("sets3"); - System.out.println("[两值] sets3 VALUES : " + col); - List col2 = new ArrayList(col); - Collections.sort(col2); - Assertions.assertIterableEquals(List.of("setvals1", "setvals2"), col2); - - bool = source.exists("sets3"); - System.out.println("[有值] sets3 EXISTS : " + bool); - Assertions.assertTrue(bool); - - bool = source.sismember("sets3", String.class, "setvals2"); - System.out.println("[有值] sets3-setvals2 EXISTSITEM : " + bool); - Assertions.assertTrue(bool); - - bool = source.sismember("sets3", String.class, "setvals3"); - System.out.println("[无值] sets3-setvals3 EXISTSITEM : " + bool); - Assertions.assertFalse(bool); - - source.srem("sets3", String.class, "setvals1"); - col = source.smembersString("sets3"); - System.out.println("[一值] sets3 VALUES : " + col); - Assertions.assertIterableEquals(List.of("setvals2"), col); - - long size = source.scard("sets3"); - System.out.println("sets3 大小 : " + size); - Assertions.assertEquals(1, size); - - col = source.keys(); - System.out.println("all keys: " + col); - - col = source.keys("key*"); - Collections.sort((List) col); - System.out.println("key startkeys: " + col); - Assertions.assertIterableEquals(List.of("key1", "keylong1", "keys3", "keys3-2", "keystr1"), col); - - num = source.incr("newnum"); - System.out.println("newnum 值 : " + num); - Assertions.assertEquals(1, num); - - num = source.decr("newnum"); - System.out.println("newnum 值 : " + num); - Assertions.assertEquals(0, num); - - Map mapcol = new LinkedHashMap<>(); - mapcol.put("sets3", source.smembersString("sets3")); - mapcol.put("sets4", source.smembersString("sets4")); - System.out.println("sets3&sets4: " + mapcol); - Map news = new HashMap<>(); - mapcol.forEach((x, y) -> { - if (y instanceof Set) { - List newy = new ArrayList(y); - Collections.sort(newy); - news.put(x, newy); - } else { - Collections.sort((List) y); - } - }); - mapcol.putAll(news); - Assertions.assertEquals( - Utility.ofMap("sets3", List.of("setvals2"), "sets4", List.of("setvals1", "setvals2")) - .toString(), - mapcol.toString()); - - source.del("sets3"); - source.del("sets4"); - source.del("sets5"); - source.del("sets6"); - source.saddString("sets3", "setvals1", "setvals2", "setvals3", "setvals4", "setvals5"); - source.saddString("sets4", "setvals3", "setvals6", "setvals7", "setvals8"); - source.saddString("sets5", "setvals5", "setvals6", "setvals7", "setvals8"); - Set diffanswer = new TreeSet<>(Set.of("setvals1", "setvals2", "setvals4")); - Set diffset = new TreeSet<>(source.sdiffString("sets3", "sets4", "sets5")); - System.out.println("sdiff: " + diffset); - Assertions.assertIterableEquals(diffanswer, diffset); - source.sdiffstore("sets6", "sets3", "sets4", "sets5"); - diffset = new TreeSet<>(source.smembersString("sets6")); - System.out.println("sdiffstore: " + diffset); - Assertions.assertIterableEquals(diffanswer, diffset); - - source.del("sets3"); - source.del("sets4"); - source.del("sets5"); - source.del("sets6"); - source.saddString("sets3", "setvals1", "setvals2", "setvals3", "setvals4", "setvals5"); - source.saddString("sets4", "setvals2", "setvals3", "setvals5", "setvals8"); - source.saddString("sets5", "setvals5", "setvals6", "setvals7", "setvals8"); - Set interanswer = new TreeSet<>(Set.of("setvals5")); - Set interset = new TreeSet<>(source.sinterString("sets3", "sets4", "sets5")); - System.out.println("sinter: " + interset); - Assertions.assertIterableEquals(interanswer, interset); - source.sinterstore("sets6", "sets3", "sets4", "sets5"); - interset = new TreeSet<>(source.smembersString("sets6")); - System.out.println("sinterstore: " + interset); - Assertions.assertIterableEquals(interanswer, interset); - - source.del("sets6"); - Set unionanswer = new TreeSet<>( - Set.of("setvals1", "setvals2", "setvals3", "setvals4", "setvals5", "setvals6", "setvals7", "setvals8")); - Set unionset = new TreeSet<>(source.sunionString("sets3", "sets4", "sets5")); - System.out.println("sunion: " + unionset); - Assertions.assertIterableEquals(unionanswer, unionset); - source.sunionstore("sets6", "sets3", "sets4", "sets5"); - unionset = new TreeSet<>(source.smembersString("sets6")); - System.out.println("sunionstore: " + unionset); - Assertions.assertIterableEquals(unionanswer, unionset); - - List ems = source.smismembers("sets3", "setvals3", "setvals33"); - System.out.println("smismembers: " + ems); - Assertions.assertIterableEquals(List.of(true, false), ems); - List rands = List.of("setvals1", "setvals2", "setvals3", "setvals4", "setvals5"); - List rand2 = (List) source.srandmemberString("sets3", 100); - Collections.sort(rand2); - System.out.println("srandmember: " + rand2); - Assertions.assertIterableEquals(rands, rand2); - - Assertions.assertTrue(source.smoveString("sets4", "sets5", "setvals5")); - Assertions.assertTrue(source.smoveString("sets4", "sets7", "setvals3")); - - System.out.println("------------------------------------"); - InetSocketAddress addr88 = new InetSocketAddress("127.0.0.1", 7788); - InetSocketAddress addr99 = new InetSocketAddress("127.0.0.1", 7799); - source.set("myaddr", InetSocketAddress.class, addr88); - - obj = source.getString("myaddr"); - System.out.println("myaddrstr: " + obj); - Assertions.assertEquals("127.0.0.1:7788", obj); - - obj = source.get("myaddr", InetSocketAddress.class); - System.out.println("myaddr: " + obj); - Assertions.assertEquals(addr88, obj); - - source.del("myaddrs"); - source.del("myaddrs2"); - source.sadd("myaddrs", InetSocketAddress.class, addr88); - source.sadd("myaddrs", InetSocketAddress.class, addr99); - - col = source.smembers("myaddrs", InetSocketAddress.class); - System.out.println("myaddrs: " + col); - List cola2 = new ArrayList(col); - Collections.sort(cola2, (o1, o2) -> o1.toString().compareTo(o2.toString())); - Assertions.assertIterableEquals(cola2, List.of(addr88, addr99)); - - source.srem("myaddrs", InetSocketAddress.class, addr88); - col = source.smembers("myaddrs", InetSocketAddress.class); - System.out.println("myaddrs: " + col); - Assertions.assertIterableEquals(col, List.of(addr99)); - - source.sadd("myaddrs2", InetSocketAddress.class, addr88); - source.sadd("myaddrs2", InetSocketAddress.class, addr99); - mapcol.clear(); - mapcol.put("myaddrs", source.smembers("myaddrs", InetSocketAddress.class)); - mapcol.put("myaddrs2", source.smembers("myaddrs2", InetSocketAddress.class)); - System.out.println("myaddrs&myaddrs2: " + mapcol); - Map news2 = new HashMap<>(); - mapcol.forEach((x, y) -> { - if (y instanceof Set) { - List newy = new ArrayList(y); - Collections.sort(newy, (o1, o2) -> o1.toString().compareTo(o2.toString())); - news2.put(x, newy); - } else { - Collections.sort((List) y, (o1, o2) -> o1.toString().compareTo(o2.toString())); - } - }); - mapcol.putAll(news2); - Assertions.assertEquals( - Utility.ofMap("myaddrs", List.of(addr99), "myaddrs2", List.of(addr88, addr99)) - .toString(), - mapcol.toString()); - - System.out.println("------------------------------------"); - source.del("myaddrs"); - Type mapType = new TypeToken>() {}.getType(); - Map paramap = new HashMap<>(); - paramap.put("a", 1); - paramap.put("b", 2); - source.set("mapvals", mapType, paramap); - - map = source.get("mapvals", mapType); - System.out.println("mapvals: " + map); - Assertions.assertEquals(Utility.ofMap("a", 1, "b", 2).toString(), map.toString()); - - source.del("hmapall"); - source.hmset("hmapall", Utility.ofMap("k1", "111", "k2", "222")); - Assertions.assertIterableEquals(List.of("111", "222"), source.hvals("hmapall", String.class)); - Assertions.assertIterableEquals(List.of("111", "222"), source.hvalsString("hmapall")); - Assertions.assertIterableEquals(List.of(111L, 222L), source.hvalsLong("hmapall")); - Assertions.assertIterableEquals( - List.of("111", "222"), - source.hvalsAsync("hmapall", String.class).join()); - Assertions.assertIterableEquals( - List.of("111", "222"), source.hvalsStringAsync("hmapall").join()); - Assertions.assertIterableEquals( - List.of(111L, 222L), source.hvalsLongAsync("hmapall").join()); - Assertions.assertEquals(Utility.ofMap("k1", "111", "k2", "222"), source.hgetall("hmapall", String.class)); - Assertions.assertEquals(Utility.ofMap("k1", "111", "k2", "222"), source.hgetallString("hmapall")); - Assertions.assertEquals( - JsonConvert.root().convertTo(Utility.ofMap("k1", 111L, "k2", 222L)), - JsonConvert.root().convertTo(source.hgetallLong("hmapall"))); - Assertions.assertEquals( - JsonConvert.root().convertTo(Utility.ofMap("k1", "111", "k2", "222")), - JsonConvert.root() - .convertTo(source.hgetallAsync("hmapall", String.class).join())); - Assertions.assertEquals( - JsonConvert.root().convertTo(Utility.ofMap("k1", "111", "k2", "222")), - JsonConvert.root() - .convertTo(source.hgetallStringAsync("hmapall").join())); - Assertions.assertEquals( - JsonConvert.root().convertTo(Utility.ofMap("k1", 111L, "k2", 222L)), - JsonConvert.root().convertTo(source.hgetallLongAsync("hmapall").join())); - - // h - source.del("hmap"); - source.hincr("hmap", "key1"); - num = source.hgetLong("hmap", "key1", -1); - System.out.println("hmap.key1 值 : " + num); - Assertions.assertEquals(1L, num); - - source.hmset("hmap", Utility.ofMap("key2", "haha", "key3", 333)); - source.hmset("hmap", "sm", (HashMap) Utility.ofMap("a", "aa", "b", "bb")); - - map = source.hget("hmap", "sm", JsonConvert.TYPE_MAP_STRING_STRING); - System.out.println("hmap.sm 值 : " + map); - Assertions.assertEquals(Utility.ofMap("a", "aa", "b", "bb").toString(), map.toString()); - - col = source.hmget("hmap", String.class, "key1", "key2", "key3"); - System.out.println("hmap.[key1,key2,key3] 值 : " + col); - Assertions.assertIterableEquals(col, List.of("1", "haha", "333")); - - col = source.hkeys("hmap"); - System.out.println("hmap.keys 四值 : " + col); - Assertions.assertIterableEquals(col, List.of("key1", "key2", "key3", "sm")); - - source.hdel("hmap", "key1", "key3"); - - col = source.hkeys("hmap"); - System.out.println("hmap.keys 两值 : " + col); - Assertions.assertIterableEquals(col, List.of("key2", "sm")); - - obj = source.hgetString("hmap", "key2"); - System.out.println("hmap.key2 值 : " + obj); - Assertions.assertEquals("haha", obj); - - size = source.hlen("hmap"); - System.out.println("hmap列表(2)大小 : " + size); - Assertions.assertEquals(2, size); - - source.del("hmaplong"); - source.hincrby("hmaplong", "key1", 10); - source.hsetLong("hmaplong", "key2", 30); - AtomicLong cursor = new AtomicLong(); - Map longmap = source.hscan("hmaplong", long.class, cursor, 10); - System.out.println("hmaplong.所有两值 : " + longmap); - Assertions.assertEquals(Utility.ofMap("key1", 10, "key2", 30).toString(), longmap.toString()); - Assertions.assertEquals(2L, source.hstrlen("hmaplong", "key1")); - - source.del("hmapstr"); - source.hsetString("hmapstr", "key1", "str10"); - source.hsetString("hmapstr", "key2", null); - cursor = new AtomicLong(); - map = source.hscan("hmapstr", String.class, cursor, 10); - System.out.println("hmapstr.所有一值 : " + map); - Assertions.assertEquals(Utility.ofMap("key1", "str10").toString(), map.toString()); - - source.del("hmapstrmap"); - source.hset("hmapstrmap", "key1", JsonConvert.TYPE_MAP_STRING_STRING, (HashMap) Utility.ofMap("ks11", "vv11")); - source.hset("hmapstrmap", "key2", JsonConvert.TYPE_MAP_STRING_STRING, null); - cursor = new AtomicLong(); - map = source.hscan("hmapstrmap", JsonConvert.TYPE_MAP_STRING_STRING, cursor, 10, "key2*"); - System.out.println("hmapstrmap.无值 : " + map); - Assertions.assertEquals(Utility.ofMap().toString(), map.toString()); - - source.del("hmap"); - String vpref = "v"; - int ccc = 600; - for (int i = 101; i <= ccc + 100; i++) { - source.hmset("hmap", "k" + i, vpref + i); - } - cursor = new AtomicLong(); - Map smap = source.hscan("hmap", String.class, cursor, 5); - System.out.println("hmap.hscan 长度 : " + smap.size() + ", cursor: " + cursor + ", 内容: " + smap); - // smap.size 是不确定的,可能是全量,也可能比5多,也可能比5少 - Assertions.assertFalse(smap.isEmpty()); - if (smap.size() == ccc) { - Assertions.assertTrue(cursor.get() == 0); - } else { - Assertions.assertTrue(cursor.get() > 0); - } - cursor = new AtomicLong(); - smap = (Map) source.hscanAsync("hmap", String.class, cursor, 5).join(); - Assertions.assertFalse(smap.isEmpty()); - if (smap.size() == ccc) { - Assertions.assertTrue(cursor.get() == 0); - } else { - Assertions.assertTrue(cursor.get() > 0); - } - - source.del("sortset"); - source.zadd("sortset", 100, "key100"); - source.zadd("sortset", 200, "key200"); - source.zadd("sortset", 300, "key300"); - source.zadd("sortset", 400, "key400"); - source.zadd("sortset", 500, "key500"); - System.out.println("sortset 写入5条记录 "); - - Assertions.assertEquals(2L, source.zrank("sortset", "key300")); - Assertions.assertEquals(1L, source.zrevrank("sortset", "key400")); - Assertions.assertEquals(List.of("key100", "key200", "key300"), source.zrange("sortset", 0, 2)); - cursor = new AtomicLong(); - Assertions.assertEquals( - List.of( - CacheScoredValue.create(100, "key100"), - CacheScoredValue.create(200, "key200"), - CacheScoredValue.create(300, "key300"), - CacheScoredValue.create(400, "key400"), - CacheScoredValue.create(500, "key500")), - source.zscanInteger("sortset", cursor, -1)); - - size = source.zcard("sortset"); - Assertions.assertEquals(5, size); - size = source.zrem("sortset", "key400", "key800"); - Assertions.assertTrue(size == 1); - List scores = source.zmscoreLong("sortset", "key200", "key800", "key500"); - List scoreAnswer = new ArrayList<>(); - scoreAnswer.add(200L); - scoreAnswer.add(null); - scoreAnswer.add(500L); - Assertions.assertIterableEquals(scoreAnswer, scores); - source.del("sortnumset"); - source.zincrby("sortnumset", 100, "int100"); - Assertions.assertEquals(100, source.zscoreInteger("sortnumset", "int100")); - source.zincrby("sortnumset", 120.12f, "float120"); - source.zincrby("sortnumset", 130.13f, "float120"); - Assertions.assertEquals(250.25f, source.zscore("sortnumset", float.class, "float120")); - - source.del("popset"); - source.saddString("popset", "111"); - source.saddString("popset", "222"); - source.saddString("popset", "333"); - source.saddString("popset", "444"); - source.saddString("popset", "555"); - - cursor = new AtomicLong(); - Set sset = source.sscan("popset", String.class, cursor, 3); - System.out.println("popset.sscan 长度 : " + sset.size() + ", cursor: " + cursor + ", 内容: " + sset); - // smap.size 是不确定的,可能是全量,也可能比5多,也可能比5少 - Assertions.assertFalse(sset.isEmpty()); - if (sset.size() == 5) { - Assertions.assertTrue(cursor.get() == 0); - } else { - Assertions.assertTrue(cursor.get() > 0); - } - cursor = new AtomicLong(); - sset = (Set) source.sscanAsync("popset", String.class, cursor, 3).join(); - Assertions.assertFalse(smap.isEmpty()); - if (sset.size() == 5) { - Assertions.assertTrue(cursor.get() == 0); - } else { - Assertions.assertTrue(cursor.get() > 0); - } - - obj = source.spopString("popset"); - Assertions.assertTrue(obj != null); - System.out.println("SPOP一个String元素:" + obj); - Assertions.assertTrue(List.of("111", "222", "333", "444", "555").contains(obj)); - size = source.scard("popset"); - System.out.println("popset元素个数:" + size); - Assertions.assertEquals(4, size); - - col = source.spopString("popset", 2); - Assertions.assertEquals(2, col.size()); - System.out.println("SPOP两个String元素:" + col); - col = source.spopString("popset", 5); - Assertions.assertEquals(2, col.size()); - System.out.println("SPOP五个String元素(值两个):" + col); - - source.del("popset"); - source.saddLong("popset", 111L); - source.saddLong("popset", 222L); - source.saddLong("popset", 333L); - source.saddLong("popset", 444L, 555L); - System.out.println("SPOP一个Long元素:" + source.spopLong("popset")); - col = source.spopLong("popset", 2); - Assertions.assertEquals(2, col.size()); - System.out.println("SPOP两个Long元素:" + col); - col = source.spopLong("popset", 5); - Assertions.assertEquals(2, col.size()); - System.out.println("SPOP五个Long元素(值两个):" + col); - obj = source.spopLong("popset"); - Assertions.assertTrue(obj == null); - System.out.println("SPOP一个Long元素:" + obj); - - cursor = new AtomicLong(); - List keys = source.scan(cursor, 5); - System.out.println( - "scan 长度 : " + keys.size() + ", dbsize: " + source.dbsize() + ", cursor: " + cursor + ", 内容: " + keys); - Assertions.assertFalse(keys.isEmpty()); - if (keys.size() == source.dbsize()) { - Assertions.assertTrue(cursor.get() == 0); - } else { - Assertions.assertTrue(cursor.get() > 0); - } - cursor = new AtomicLong(); - keys = (List) source.scanAsync(cursor, 5).join(); - Assertions.assertFalse(keys.isEmpty()); - - long dbsize = source.dbsize(); - System.out.println("keys总数量 : " + dbsize); - // 清除 - long rs = source.del("stritem1"); - System.out.println("删除stritem1个数: " + rs); - source.del("popset"); - source.del("stritem2"); - source.del("intitem1"); - source.del("intitem2"); - source.del("keylong1"); - source.del("keystr1"); - source.del("mapvals"); - source.del("myaddr"); - source.del("myaddrs2"); - source.del("newnum"); - source.del("objitem1"); - source.del("objitem2"); - source.del("key1"); - source.del("key2"); - source.del("keys3", "keys3-2"); - source.del("sets3", "sets4", "sets5", "sets6"); - source.del("myaddrs"); - source.del("300"); - source.del("stringmap"); - source.del("hmap"); - source.del("hmapall"); - source.del("hmaplong"); - source.del("hmapstr"); - source.del("hmapstrmap"); - source.del("byteskey"); - source.del("nxexkey1"); - System.out.println("--------###------- 接口测试结束 --------###-------"); - source.flushdb(); - System.out.println("------订阅发布功能------"); - final CountDownLatch cdl = new CountDownLatch(2); - final String channel = "hello_topic"; - final String content = "this is a message content"; - CacheEventListener listener = new CacheEventListener() { - @Override - public void onMessage(String topic, byte[] message) { - String msg = new String(message, StandardCharsets.UTF_8); - System.out.println("订阅到主题: " + topic + ", 消息: " + msg); - Assertions.assertEquals(channel, topic); - Assertions.assertEquals(content, msg); - cdl.countDown(); - } - }; - source.subscribe(listener, channel); - System.out.println("订阅结束"); - source.publish(channel, content); - System.out.println("发布结束"); - if (!source.getClass().getName().contains("Redisson")) { // Redisson不支持 - List channels = source.pubsubChannels(null); - Assertions.assertEquals(List.of(channel), channels); - } - source.unsubscribe(listener, channel); - System.out.println("取消订阅结束"); - source.publish(channel, content); - System.out.println("再次发布结束"); - source.subscribe(listener, channel); - System.out.println("再次订阅结束"); - source.publish(channel, content); - System.out.println("再次发布结束"); - cdl.await(); - source.unsubscribe(listener, channel); - System.out.println("取消订阅结束"); - } -} +/* + * + */ +package org.redkale.test.source; + +import java.lang.reflect.Type; +import java.net.InetSocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicLong; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.redkale.convert.json.JsonConvert; +import org.redkale.source.CacheEventListener; +import org.redkale.source.CacheMemorySource; +import org.redkale.source.CacheScoredValue; +import org.redkale.source.Flipper; +import org.redkale.util.TypeToken; +import org.redkale.util.Utility; + +/** @author zhangjx */ +public class CacheMemorySourceTest { + + public static void main(String[] args) throws Throwable { + CacheMemorySourceTest test = new CacheMemorySourceTest(); + test.run(); + } + + @Test + public void run() throws Exception { + CacheMemorySource source = new CacheMemorySource(""); + source.init(null); + System.out.println("------------------------------------"); + source.del("stritem1", "stritem2", "stritem1x"); + source.setString("stritem1", "value1"); + source.setString("stritem2", "value2"); + Assertions.assertEquals("value2", source.getDelString("stritem2")); + Assertions.assertTrue(source.getDelString("stritem2") == null); + source.setString("stritem2", "value2"); + + List list = source.keysStartsWith("stritem"); + System.out.println("stritem开头的key有两个: " + list); + Assertions.assertTrue(Utility.equalsElement(List.of("stritem2", "stritem1"), list)); + + Map map = source.mgetsString("stritem1", "stritem2"); + System.out.println("[有值] MGET : " + map); + Assertions.assertTrue(Utility.equalsElement(Utility.ofMap("stritem1", "value1", "stritem2", "value2"), map)); + + List array = source.mgetString("stritem1", "stritem2"); + System.out.println("[有值] MGET : " + array); + Assertions.assertTrue(Utility.equalsElement(List.of("value1", "value2"), array)); + + Assertions.assertFalse(source.persist("stritem1")); + Assertions.assertTrue(source.rename("stritem1", "stritem1x")); + Assertions.assertEquals("value1", source.getString("stritem1x")); + Assertions.assertEquals(null, source.getString("stritem1")); + Assertions.assertFalse(source.renamenx("stritem1x", "stritem2")); + Assertions.assertEquals("value2", source.getString("stritem2")); + Assertions.assertTrue(source.renamenx("stritem1x", "stritem1")); + + source.del("intitem1", "intitem2"); + source.setLong("intitem1", 333); + source.setLong("intitem2", 444); + + map = source.mgetsString("intitem1", "intitem22", "intitem2"); + System.out.println("[有值] MGET : " + map); + Assertions.assertTrue(Utility.equalsElement(Utility.ofMap("intitem1", "333", "intitem2", "444"), map)); + + array = source.mgetString("intitem1", "intitem22", "intitem2"); + System.out.println("[有值] MGET : " + array); + List ss = new ArrayList<>(); + ss.add("333"); + ss.add(null); + ss.add("444"); + Assertions.assertTrue(Utility.equalsElement(ss, array)); + + source.del("objitem1", "objitem2"); + source.mset(Utility.ofMap("objitem1", new Flipper(10), "objitem2", new Flipper(20))); + + Map flippermap = source.mgets(Flipper.class, "objitem1", "objitem2"); + System.out.println("[有值] MGET : " + flippermap); + Assertions.assertTrue(Utility.equalsElement( + Utility.ofMap("objitem1", new Flipper(10), "objitem2", new Flipper(20)), flippermap)); + + source.del("key1", "key2", "300"); + source.setex("key1", 1000, String.class, "value1"); + source.set("key1", String.class, "value1"); + source.setString("keystr1", "strvalue1"); + source.setLong("keylong1", 333L); + source.set("300", String.class, "4000"); + Object obj = source.getex("key1", 3500, String.class); + System.out.println("[有值] key1 GET : " + obj); + Assertions.assertEquals("value1", obj); + + obj = source.get("300", String.class); + System.out.println("[有值] 300 GET : " + obj); + Assertions.assertEquals("4000", obj); + + obj = source.get("key1", String.class); + System.out.println("[有值] key1 GET : " + obj); + Assertions.assertEquals("value1", obj); + + obj = source.getSet("key1", String.class, "value11"); + System.out.println("[旧值] key1 GETSET : " + obj); + Assertions.assertEquals("value1", obj); + + obj = source.get("key2", String.class); + System.out.println("[无值] key2 GET : " + obj); + Assertions.assertNull(obj); + + obj = source.getString("keystr1"); + System.out.println("[有值] keystr1 GET : " + obj); + Assertions.assertEquals("strvalue1", obj); + + long num = source.getLong("keylong1", 0L); + System.out.println("[有值] keylong1 GET : " + null); + Assertions.assertEquals(333L, num); + + boolean bool = source.exists("key1"); + System.out.println("[有值] key1 EXISTS : " + bool); + Assertions.assertTrue(bool); + + bool = source.exists("key2"); + System.out.println("[无值] key2 EXISTS : " + bool); + Assertions.assertFalse(bool); + + source.del("keys3"); + source.rpush("keys3", String.class, "vals1"); + source.rpush("keys3", String.class, "vals2"); + System.out.println("-------- keys3 追加了两个值 --------"); + + Collection col = source.lrangeString("keys3"); + System.out.println("[两值] keys3 VALUES : " + col); + Assertions.assertTrue(Utility.equalsElement(List.of("vals1", "vals2"), col)); + + bool = source.exists("keys3"); + System.out.println("[有值] keys3 EXISTS : " + bool); + Assertions.assertTrue(bool); + + source.lrem("keys3", String.class, "vals1"); + col = source.lrangeString("keys3"); + System.out.println("[一值] keys3 VALUES : " + col); + Assertions.assertIterableEquals(List.of("vals2"), col); + source.rpush("keys3", String.class, "vals2"); + source.rpush("keys3", String.class, "vals3"); + source.rpush("keys3", String.class, "vals4"); + Assertions.assertEquals("vals4", source.rpopString("keys3")); + source.lpush("keys3", String.class, "vals0"); + Assertions.assertEquals("vals0", source.lpopString("keys3")); + String rlv = source.rpoplpush("keys3", "keys3-2", String.class); + Assertions.assertEquals("vals3", rlv); + + source.del("keys3"); + source.lpushString("keys3", "vals20"); + source.lpushString("keys3", "vals10"); + System.out.println("keys3-list: " + source.lrangeString("keys3")); + Assertions.assertEquals("vals10", source.lindexString("keys3", 0)); + Assertions.assertEquals("vals20", source.lindexString("keys3", -1)); + source.linsertBeforeString("keys3", "vals10", "vals00"); + source.linsertAfterString("keys3", "vals10", "vals15"); + Assertions.assertEquals(0, source.linsertBeforeString("keys_3", "vals10", "vals00")); + Assertions.assertEquals(-1, source.linsertBeforeString("keys3", "vals90", "vals00")); + Assertions.assertEquals(4, source.llen("keys3")); + Assertions.assertIterableEquals(List.of("vals00", "vals10", "vals15", "vals20"), source.lrangeString("keys3")); + + source.del("stringmap"); + source.sadd("stringmap", JsonConvert.TYPE_MAP_STRING_STRING, Utility.ofMap("a", "aa", "b", "bb")); + source.sadd("stringmap", JsonConvert.TYPE_MAP_STRING_STRING, Utility.ofMap("c", "cc", "d", "dd")); + col = source.smembers("stringmap", JsonConvert.TYPE_MAP_STRING_STRING); + System.out.println("[两值] stringmap VALUES : " + col); + Assertions.assertTrue(Utility.equalsElement( + List.of(Utility.ofMap("c", "cc", "d", "dd"), Utility.ofMap("a", "aa", "b", "bb")), col)); + + source.del("sets3"); + source.del("sets4"); + source.del("sets5"); + source.sadd("sets3", String.class, "setvals1"); + source.sadd("sets3", String.class, "setvals2"); + source.sadd("sets3", String.class, "setvals1"); + source.sadd("sets4", String.class, "setvals2"); + source.sadd("sets4", String.class, "setvals1"); + col = source.smembersString("sets3"); + System.out.println("[两值] sets3 VALUES : " + col); + List col2 = new ArrayList(col); + Collections.sort(col2); + Assertions.assertIterableEquals(List.of("setvals1", "setvals2"), col2); + + bool = source.exists("sets3"); + System.out.println("[有值] sets3 EXISTS : " + bool); + Assertions.assertTrue(bool); + + bool = source.sismember("sets3", String.class, "setvals2"); + System.out.println("[有值] sets3-setvals2 EXISTSITEM : " + bool); + Assertions.assertTrue(bool); + + bool = source.sismember("sets3", String.class, "setvals3"); + System.out.println("[无值] sets3-setvals3 EXISTSITEM : " + bool); + Assertions.assertFalse(bool); + + source.srem("sets3", String.class, "setvals1"); + col = source.smembersString("sets3"); + System.out.println("[一值] sets3 VALUES : " + col); + Assertions.assertIterableEquals(List.of("setvals2"), col); + + long size = source.scard("sets3"); + System.out.println("sets3 大小 : " + size); + Assertions.assertEquals(1, size); + + col = source.keys(); + System.out.println("all keys: " + col); + + col = source.keys("key*"); + Collections.sort((List) col); + System.out.println("key startkeys: " + col); + Assertions.assertIterableEquals(List.of("key1", "keylong1", "keys3", "keys3-2", "keystr1"), col); + + num = source.incr("newnum"); + System.out.println("newnum 值 : " + num); + Assertions.assertEquals(1, num); + + num = source.decr("newnum"); + System.out.println("newnum 值 : " + num); + Assertions.assertEquals(0, num); + + Map mapcol = new LinkedHashMap<>(); + mapcol.put("sets3", source.smembersString("sets3")); + mapcol.put("sets4", source.smembersString("sets4")); + System.out.println("sets3&sets4: " + mapcol); + Map news = new HashMap<>(); + mapcol.forEach((x, y) -> { + if (y instanceof Set) { + List newy = new ArrayList(y); + Collections.sort(newy); + news.put(x, newy); + } else { + Collections.sort((List) y); + } + }); + mapcol.putAll(news); + Assertions.assertEquals( + Utility.ofMap("sets3", List.of("setvals2"), "sets4", List.of("setvals1", "setvals2")) + .toString(), + mapcol.toString()); + + source.del("sets3"); + source.del("sets4"); + source.del("sets5"); + source.del("sets6"); + source.saddString("sets3", "setvals1", "setvals2", "setvals3", "setvals4", "setvals5"); + source.saddString("sets4", "setvals3", "setvals6", "setvals7", "setvals8"); + source.saddString("sets5", "setvals5", "setvals6", "setvals7", "setvals8"); + Set diffanswer = new TreeSet<>(Set.of("setvals1", "setvals2", "setvals4")); + Set diffset = new TreeSet<>(source.sdiffString("sets3", "sets4", "sets5")); + System.out.println("sdiff: " + diffset); + Assertions.assertIterableEquals(diffanswer, diffset); + source.sdiffstore("sets6", "sets3", "sets4", "sets5"); + diffset = new TreeSet<>(source.smembersString("sets6")); + System.out.println("sdiffstore: " + diffset); + Assertions.assertIterableEquals(diffanswer, diffset); + + source.del("sets3"); + source.del("sets4"); + source.del("sets5"); + source.del("sets6"); + source.saddString("sets3", "setvals1", "setvals2", "setvals3", "setvals4", "setvals5"); + source.saddString("sets4", "setvals2", "setvals3", "setvals5", "setvals8"); + source.saddString("sets5", "setvals5", "setvals6", "setvals7", "setvals8"); + Set interanswer = new TreeSet<>(Set.of("setvals5")); + Set interset = new TreeSet<>(source.sinterString("sets3", "sets4", "sets5")); + System.out.println("sinter: " + interset); + Assertions.assertIterableEquals(interanswer, interset); + source.sinterstore("sets6", "sets3", "sets4", "sets5"); + interset = new TreeSet<>(source.smembersString("sets6")); + System.out.println("sinterstore: " + interset); + Assertions.assertIterableEquals(interanswer, interset); + + source.del("sets6"); + Set unionanswer = new TreeSet<>( + Set.of("setvals1", "setvals2", "setvals3", "setvals4", "setvals5", "setvals6", "setvals7", "setvals8")); + Set unionset = new TreeSet<>(source.sunionString("sets3", "sets4", "sets5")); + System.out.println("sunion: " + unionset); + Assertions.assertIterableEquals(unionanswer, unionset); + source.sunionstore("sets6", "sets3", "sets4", "sets5"); + unionset = new TreeSet<>(source.smembersString("sets6")); + System.out.println("sunionstore: " + unionset); + Assertions.assertIterableEquals(unionanswer, unionset); + + List ems = source.smismembers("sets3", "setvals3", "setvals33"); + System.out.println("smismembers: " + ems); + Assertions.assertIterableEquals(List.of(true, false), ems); + List rands = List.of("setvals1", "setvals2", "setvals3", "setvals4", "setvals5"); + List rand2 = (List) source.srandmemberString("sets3", 100); + Collections.sort(rand2); + System.out.println("srandmember: " + rand2); + Assertions.assertIterableEquals(rands, rand2); + + Assertions.assertTrue(source.smoveString("sets4", "sets5", "setvals5")); + Assertions.assertTrue(source.smoveString("sets4", "sets7", "setvals3")); + + System.out.println("------------------------------------"); + InetSocketAddress addr88 = new InetSocketAddress("127.0.0.1", 7788); + InetSocketAddress addr99 = new InetSocketAddress("127.0.0.1", 7799); + source.set("myaddr", InetSocketAddress.class, addr88); + + obj = source.getString("myaddr"); + System.out.println("myaddrstr: " + obj); + Assertions.assertEquals("127.0.0.1:7788", obj); + + obj = source.get("myaddr", InetSocketAddress.class); + System.out.println("myaddr: " + obj); + Assertions.assertEquals(addr88, obj); + + source.del("myaddrs"); + source.del("myaddrs2"); + source.sadd("myaddrs", InetSocketAddress.class, addr88); + source.sadd("myaddrs", InetSocketAddress.class, addr99); + + col = source.smembers("myaddrs", InetSocketAddress.class); + System.out.println("myaddrs: " + col); + List cola2 = new ArrayList(col); + Collections.sort(cola2, (o1, o2) -> o1.toString().compareTo(o2.toString())); + Assertions.assertIterableEquals(cola2, List.of(addr88, addr99)); + + source.srem("myaddrs", InetSocketAddress.class, addr88); + col = source.smembers("myaddrs", InetSocketAddress.class); + System.out.println("myaddrs: " + col); + Assertions.assertIterableEquals(col, List.of(addr99)); + + source.sadd("myaddrs2", InetSocketAddress.class, addr88); + source.sadd("myaddrs2", InetSocketAddress.class, addr99); + mapcol.clear(); + mapcol.put("myaddrs", source.smembers("myaddrs", InetSocketAddress.class)); + mapcol.put("myaddrs2", source.smembers("myaddrs2", InetSocketAddress.class)); + System.out.println("myaddrs&myaddrs2: " + mapcol); + Map news2 = new HashMap<>(); + mapcol.forEach((x, y) -> { + if (y instanceof Set) { + List newy = new ArrayList(y); + Collections.sort(newy, (o1, o2) -> o1.toString().compareTo(o2.toString())); + news2.put(x, newy); + } else { + Collections.sort((List) y, (o1, o2) -> o1.toString().compareTo(o2.toString())); + } + }); + mapcol.putAll(news2); + Assertions.assertEquals( + Utility.ofMap("myaddrs", List.of(addr99), "myaddrs2", List.of(addr88, addr99)) + .toString(), + mapcol.toString()); + + System.out.println("------------------------------------"); + source.del("myaddrs"); + Type mapType = new TypeToken>() {}.getType(); + Map paramap = new HashMap<>(); + paramap.put("a", 1); + paramap.put("b", 2); + source.set("mapvals", mapType, paramap); + + map = source.get("mapvals", mapType); + System.out.println("mapvals: " + map); + Assertions.assertEquals(Utility.ofMap("a", 1, "b", 2).toString(), map.toString()); + + source.del("hmapall"); + source.hmset("hmapall", Utility.ofMap("k1", "111", "k2", "222")); + Assertions.assertIterableEquals(List.of("111", "222"), source.hvals("hmapall", String.class)); + Assertions.assertIterableEquals(List.of("111", "222"), source.hvalsString("hmapall")); + Assertions.assertIterableEquals(List.of(111L, 222L), source.hvalsLong("hmapall")); + Assertions.assertIterableEquals( + List.of("111", "222"), + source.hvalsAsync("hmapall", String.class).join()); + Assertions.assertIterableEquals( + List.of("111", "222"), source.hvalsStringAsync("hmapall").join()); + Assertions.assertIterableEquals( + List.of(111L, 222L), source.hvalsLongAsync("hmapall").join()); + Assertions.assertEquals(Utility.ofMap("k1", "111", "k2", "222"), source.hgetall("hmapall", String.class)); + Assertions.assertEquals(Utility.ofMap("k1", "111", "k2", "222"), source.hgetallString("hmapall")); + Assertions.assertEquals( + JsonConvert.root().convertTo(Utility.ofMap("k1", 111L, "k2", 222L)), + JsonConvert.root().convertTo(source.hgetallLong("hmapall"))); + Assertions.assertEquals( + JsonConvert.root().convertTo(Utility.ofMap("k1", "111", "k2", "222")), + JsonConvert.root() + .convertTo(source.hgetallAsync("hmapall", String.class).join())); + Assertions.assertEquals( + JsonConvert.root().convertTo(Utility.ofMap("k1", "111", "k2", "222")), + JsonConvert.root() + .convertTo(source.hgetallStringAsync("hmapall").join())); + Assertions.assertEquals( + JsonConvert.root().convertTo(Utility.ofMap("k1", 111L, "k2", 222L)), + JsonConvert.root().convertTo(source.hgetallLongAsync("hmapall").join())); + + // h + source.del("hmap"); + source.hincr("hmap", "key1"); + num = source.hgetLong("hmap", "key1", -1); + System.out.println("hmap.key1 值 : " + num); + Assertions.assertEquals(1L, num); + + source.hmset("hmap", Utility.ofMap("key2", "haha", "key3", 333)); + source.hmset("hmap", "sm", (HashMap) Utility.ofMap("a", "aa", "b", "bb")); + + map = source.hget("hmap", "sm", JsonConvert.TYPE_MAP_STRING_STRING); + System.out.println("hmap.sm 值 : " + map); + Assertions.assertEquals(Utility.ofMap("a", "aa", "b", "bb").toString(), map.toString()); + + col = source.hmget("hmap", String.class, "key1", "key2", "key3"); + System.out.println("hmap.[key1,key2,key3] 值 : " + col); + Assertions.assertIterableEquals(col, List.of("1", "haha", "333")); + + col = source.hkeys("hmap"); + System.out.println("hmap.keys 四值 : " + col); + Assertions.assertIterableEquals(col, List.of("key1", "key2", "key3", "sm")); + + source.hdel("hmap", "key1", "key3"); + + col = source.hkeys("hmap"); + System.out.println("hmap.keys 两值 : " + col); + Assertions.assertIterableEquals(col, List.of("key2", "sm")); + + obj = source.hgetString("hmap", "key2"); + System.out.println("hmap.key2 值 : " + obj); + Assertions.assertEquals("haha", obj); + + size = source.hlen("hmap"); + System.out.println("hmap列表(2)大小 : " + size); + Assertions.assertEquals(2, size); + + source.del("hmaplong"); + source.hincrby("hmaplong", "key1", 10); + source.hsetLong("hmaplong", "key2", 30); + AtomicLong cursor = new AtomicLong(); + Map longmap = source.hscan("hmaplong", long.class, cursor, 10); + System.out.println("hmaplong.所有两值 : " + longmap); + Assertions.assertEquals(Utility.ofMap("key1", 10, "key2", 30).toString(), longmap.toString()); + Assertions.assertEquals(2L, source.hstrlen("hmaplong", "key1")); + + source.del("hmapstr"); + source.hsetString("hmapstr", "key1", "str10"); + source.hsetString("hmapstr", "key2", null); + cursor = new AtomicLong(); + map = source.hscan("hmapstr", String.class, cursor, 10); + System.out.println("hmapstr.所有一值 : " + map); + Assertions.assertEquals(Utility.ofMap("key1", "str10").toString(), map.toString()); + + source.del("hmapstrmap"); + source.hset("hmapstrmap", "key1", JsonConvert.TYPE_MAP_STRING_STRING, (HashMap) Utility.ofMap("ks11", "vv11")); + source.hset("hmapstrmap", "key2", JsonConvert.TYPE_MAP_STRING_STRING, null); + cursor = new AtomicLong(); + map = source.hscan("hmapstrmap", JsonConvert.TYPE_MAP_STRING_STRING, cursor, 10, "key2*"); + System.out.println("hmapstrmap.无值 : " + map); + Assertions.assertEquals(Utility.ofMap().toString(), map.toString()); + + source.del("hmap"); + String vpref = "v"; + int ccc = 600; + for (int i = 101; i <= ccc + 100; i++) { + source.hmset("hmap", "k" + i, vpref + i); + } + cursor = new AtomicLong(); + Map smap = source.hscan("hmap", String.class, cursor, 5); + System.out.println("hmap.hscan 长度 : " + smap.size() + ", cursor: " + cursor + ", 内容: " + smap); + // smap.size 是不确定的,可能是全量,也可能比5多,也可能比5少 + Assertions.assertFalse(smap.isEmpty()); + if (smap.size() == ccc) { + Assertions.assertTrue(cursor.get() == 0); + } else { + Assertions.assertTrue(cursor.get() > 0); + } + cursor = new AtomicLong(); + smap = (Map) source.hscanAsync("hmap", String.class, cursor, 5).join(); + Assertions.assertFalse(smap.isEmpty()); + if (smap.size() == ccc) { + Assertions.assertTrue(cursor.get() == 0); + } else { + Assertions.assertTrue(cursor.get() > 0); + } + + source.del("sortset"); + source.zadd("sortset", 100, "key100"); + source.zadd("sortset", 200, "key200"); + source.zadd("sortset", 300, "key300"); + source.zadd("sortset", 400, "key400"); + source.zadd("sortset", 500, "key500"); + System.out.println("sortset 写入5条记录 "); + + Assertions.assertEquals(2L, source.zrank("sortset", "key300")); + Assertions.assertEquals(1L, source.zrevrank("sortset", "key400")); + Assertions.assertEquals(List.of("key100", "key200", "key300"), source.zrange("sortset", 0, 2)); + cursor = new AtomicLong(); + Assertions.assertEquals( + List.of( + CacheScoredValue.create(100, "key100"), + CacheScoredValue.create(200, "key200"), + CacheScoredValue.create(300, "key300"), + CacheScoredValue.create(400, "key400"), + CacheScoredValue.create(500, "key500")), + source.zscanInteger("sortset", cursor, -1)); + + size = source.zcard("sortset"); + Assertions.assertEquals(5, size); + size = source.zrem("sortset", "key400", "key800"); + Assertions.assertTrue(size == 1); + List scores = source.zmscoreLong("sortset", "key200", "key800", "key500"); + List scoreAnswer = new ArrayList<>(); + scoreAnswer.add(200L); + scoreAnswer.add(null); + scoreAnswer.add(500L); + Assertions.assertIterableEquals(scoreAnswer, scores); + source.del("sortnumset"); + source.zincrby("sortnumset", 100, "int100"); + Assertions.assertEquals(100, source.zscoreInteger("sortnumset", "int100")); + source.zincrby("sortnumset", 120.12f, "float120"); + source.zincrby("sortnumset", 130.13f, "float120"); + Assertions.assertEquals(250.25f, source.zscore("sortnumset", float.class, "float120")); + + source.del("popset"); + source.saddString("popset", "111"); + source.saddString("popset", "222"); + source.saddString("popset", "333"); + source.saddString("popset", "444"); + source.saddString("popset", "555"); + + cursor = new AtomicLong(); + Set sset = source.sscan("popset", String.class, cursor, 3); + System.out.println("popset.sscan 长度 : " + sset.size() + ", cursor: " + cursor + ", 内容: " + sset); + // smap.size 是不确定的,可能是全量,也可能比5多,也可能比5少 + Assertions.assertFalse(sset.isEmpty()); + if (sset.size() == 5) { + Assertions.assertTrue(cursor.get() == 0); + } else { + Assertions.assertTrue(cursor.get() > 0); + } + cursor = new AtomicLong(); + sset = (Set) source.sscanAsync("popset", String.class, cursor, 3).join(); + Assertions.assertFalse(smap.isEmpty()); + if (sset.size() == 5) { + Assertions.assertTrue(cursor.get() == 0); + } else { + Assertions.assertTrue(cursor.get() > 0); + } + + obj = source.spopString("popset"); + Assertions.assertTrue(obj != null); + System.out.println("SPOP一个String元素:" + obj); + Assertions.assertTrue(List.of("111", "222", "333", "444", "555").contains(obj)); + size = source.scard("popset"); + System.out.println("popset元素个数:" + size); + Assertions.assertEquals(4, size); + + col = source.spopString("popset", 2); + Assertions.assertEquals(2, col.size()); + System.out.println("SPOP两个String元素:" + col); + col = source.spopString("popset", 5); + Assertions.assertEquals(2, col.size()); + System.out.println("SPOP五个String元素(值两个):" + col); + + source.del("popset"); + source.saddLong("popset", 111L); + source.saddLong("popset", 222L); + source.saddLong("popset", 333L); + source.saddLong("popset", 444L, 555L); + System.out.println("SPOP一个Long元素:" + source.spopLong("popset")); + col = source.spopLong("popset", 2); + Assertions.assertEquals(2, col.size()); + System.out.println("SPOP两个Long元素:" + col); + col = source.spopLong("popset", 5); + Assertions.assertEquals(2, col.size()); + System.out.println("SPOP五个Long元素(值两个):" + col); + obj = source.spopLong("popset"); + Assertions.assertTrue(obj == null); + System.out.println("SPOP一个Long元素:" + obj); + + cursor = new AtomicLong(); + List keys = source.scan(cursor, 5); + System.out.println( + "scan 长度 : " + keys.size() + ", dbsize: " + source.dbsize() + ", cursor: " + cursor + ", 内容: " + keys); + Assertions.assertFalse(keys.isEmpty()); + if (keys.size() == source.dbsize()) { + Assertions.assertTrue(cursor.get() == 0); + } else { + Assertions.assertTrue(cursor.get() > 0); + } + cursor = new AtomicLong(); + keys = (List) source.scanAsync(cursor, 5).join(); + Assertions.assertFalse(keys.isEmpty()); + + long dbsize = source.dbsize(); + System.out.println("keys总数量 : " + dbsize); + // 清除 + long rs = source.del("stritem1"); + System.out.println("删除stritem1个数: " + rs); + source.del("popset"); + source.del("stritem2"); + source.del("intitem1"); + source.del("intitem2"); + source.del("keylong1"); + source.del("keystr1"); + source.del("mapvals"); + source.del("myaddr"); + source.del("myaddrs2"); + source.del("newnum"); + source.del("objitem1"); + source.del("objitem2"); + source.del("key1"); + source.del("key2"); + source.del("keys3", "keys3-2"); + source.del("sets3", "sets4", "sets5", "sets6"); + source.del("myaddrs"); + source.del("300"); + source.del("stringmap"); + source.del("hmap"); + source.del("hmapall"); + source.del("hmaplong"); + source.del("hmapstr"); + source.del("hmapstrmap"); + source.del("byteskey"); + source.del("nxexkey1"); + System.out.println("--------###------- 接口测试结束 --------###-------"); + source.flushdb(); + System.out.println("------订阅发布功能------"); + final CountDownLatch cdl = new CountDownLatch(2); + final String channel = "hello_topic"; + final String content = "this is a message content"; + CacheEventListener listener = new CacheEventListener() { + @Override + public void onMessage(String topic, byte[] message) { + String msg = new String(message, StandardCharsets.UTF_8); + System.out.println("订阅到主题: " + topic + ", 消息: " + msg); + Assertions.assertEquals(channel, topic); + Assertions.assertEquals(content, msg); + cdl.countDown(); + } + }; + source.subscribe(listener, channel); + System.out.println("订阅结束"); + source.publish(channel, content); + System.out.println("发布结束"); + if (!source.getClass().getName().contains("Redisson")) { // Redisson不支持 + List channels = source.pubsubChannels(null); + Assertions.assertEquals(List.of(channel), channels); + } + source.unsubscribe(listener, channel); + System.out.println("取消订阅结束"); + source.publish(channel, content); + System.out.println("再次发布结束"); + source.subscribe(listener, channel); + System.out.println("再次订阅结束"); + source.publish(channel, content); + System.out.println("再次发布结束"); + cdl.await(); + source.unsubscribe(listener, channel); + System.out.println("取消订阅结束"); + } +} diff --git a/src/test/java/org/redkale/test/source/CacheTestBean.java b/src/test/java/org/redkale/test/source/CacheTestBean.java index feab92378..2068a0193 100644 --- a/src/test/java/org/redkale/test/source/CacheTestBean.java +++ b/src/test/java/org/redkale/test/source/CacheTestBean.java @@ -1,101 +1,101 @@ -/* - * 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.test.source; - -import java.lang.reflect.Method; -import java.util.*; -import java.util.concurrent.CompletableFuture; -import java.util.function.BiFunction; -import org.redkale.convert.json.JsonConvert; -import org.redkale.persistence.*; -import org.redkale.persistence.VirtualEntity; -import org.redkale.source.*; - -/** @author zhangjx */ -@VirtualEntity(loader = CacheTestBean.DefaultBeanLoader.class) -public class CacheTestBean { - - @Id - private long pkgid; - - private String name; - - private long price; - - public static void main(String[] args) throws Exception { - Method method = EntityInfo.class.getDeclaredMethod( - "load", Class.class, boolean.class, Properties.class, DataSource.class, BiFunction.class); - method.setAccessible(true); - final EntityInfo info = (EntityInfo) method.invoke( - null, CacheTestBean.class, true, new Properties(), null, new CacheTestBean.DefaultBeanLoader()); - EntityCache cache = new EntityCache(info, null); - cache.fullLoadAsync(); - - System.out.println(cache.queryColumnMap("pkgid", FilterFunc.COUNT, "name", null)); - System.out.println(cache.queryColumnMap("pkgid", FilterFunc.DISTINCTCOUNT, "name", null)); - System.out.println(cache.queryColumnMap("pkgid", FilterFunc.AVG, "price", null)); - System.out.println(cache.queryColumnMap("pkgid", FilterFunc.SUM, "price", null)); - System.out.println(cache.queryColumnMap("pkgid", FilterFunc.MAX, "price", null)); - System.out.println(cache.queryColumnMap("pkgid", FilterFunc.MIN, "price", null)); - - System.out.println(cache.find(null, FilterNodes.eq("name", "BB"))); - System.out.println(cache.find(null, FilterNodes.igEq("name", "BB"))); - System.out.println(cache.querySheet(null, null, FilterNodes.igNotLike("name", "B"))); - System.out.println(cache.find(null, FilterNodes.eq(CacheTestBean::getName, "BB"))); - System.out.println(cache.find(null, FilterNodes.igEq(CacheTestBean::getName, "BB"))); - System.out.println(cache.querySheet(null, null, FilterNodes.igNotLike(CacheTestBean::getName, "B"))); - } - - public CacheTestBean() {} - - public CacheTestBean(long pkgid, String name, long price) { - this.pkgid = pkgid; - this.name = name; - this.price = price; - } - - public long getPkgid() { - return pkgid; - } - - public void setPkgid(long pkgid) { - this.pkgid = pkgid; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public long getPrice() { - return price; - } - - public void setPrice(long price) { - this.price = price; - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } - - public static class DefaultBeanLoader implements BiFunction> { - - @Override - public CompletableFuture apply(DataSource t, EntityInfo u) { - final List list = new ArrayList<>(); - list.add(new CacheTestBean(1, "a", 12)); - list.add(new CacheTestBean(1, "a", 18)); - list.add(new CacheTestBean(2, "b", 20)); - list.add(new CacheTestBean(2, "bb", 60)); - return CompletableFuture.completedFuture(list); - } - } -} +/* + * 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.test.source; + +import java.lang.reflect.Method; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.function.BiFunction; +import org.redkale.convert.json.JsonConvert; +import org.redkale.persistence.*; +import org.redkale.persistence.VirtualEntity; +import org.redkale.source.*; + +/** @author zhangjx */ +@VirtualEntity(loader = CacheTestBean.DefaultBeanLoader.class) +public class CacheTestBean { + + @Id + private long pkgid; + + private String name; + + private long price; + + public static void main(String[] args) throws Exception { + Method method = EntityInfo.class.getDeclaredMethod( + "load", Class.class, boolean.class, Properties.class, DataSource.class, BiFunction.class); + method.setAccessible(true); + final EntityInfo info = (EntityInfo) method.invoke( + null, CacheTestBean.class, true, new Properties(), null, new CacheTestBean.DefaultBeanLoader()); + EntityCache cache = new EntityCache(info, null); + cache.fullLoadAsync(); + + System.out.println(cache.queryColumnMap("pkgid", FilterFunc.COUNT, "name", null)); + System.out.println(cache.queryColumnMap("pkgid", FilterFunc.DISTINCTCOUNT, "name", null)); + System.out.println(cache.queryColumnMap("pkgid", FilterFunc.AVG, "price", null)); + System.out.println(cache.queryColumnMap("pkgid", FilterFunc.SUM, "price", null)); + System.out.println(cache.queryColumnMap("pkgid", FilterFunc.MAX, "price", null)); + System.out.println(cache.queryColumnMap("pkgid", FilterFunc.MIN, "price", null)); + + System.out.println(cache.find(null, FilterNodes.eq("name", "BB"))); + System.out.println(cache.find(null, FilterNodes.igEq("name", "BB"))); + System.out.println(cache.querySheet(null, null, FilterNodes.igNotLike("name", "B"))); + System.out.println(cache.find(null, FilterNodes.eq(CacheTestBean::getName, "BB"))); + System.out.println(cache.find(null, FilterNodes.igEq(CacheTestBean::getName, "BB"))); + System.out.println(cache.querySheet(null, null, FilterNodes.igNotLike(CacheTestBean::getName, "B"))); + } + + public CacheTestBean() {} + + public CacheTestBean(long pkgid, String name, long price) { + this.pkgid = pkgid; + this.name = name; + this.price = price; + } + + public long getPkgid() { + return pkgid; + } + + public void setPkgid(long pkgid) { + this.pkgid = pkgid; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public long getPrice() { + return price; + } + + public void setPrice(long price) { + this.price = price; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + + public static class DefaultBeanLoader implements BiFunction> { + + @Override + public CompletableFuture apply(DataSource t, EntityInfo u) { + final List list = new ArrayList<>(); + list.add(new CacheTestBean(1, "a", 12)); + list.add(new CacheTestBean(1, "a", 18)); + list.add(new CacheTestBean(2, "b", 20)); + list.add(new CacheTestBean(2, "bb", 60)); + return CompletableFuture.completedFuture(list); + } + } +} diff --git a/src/test/java/org/redkale/test/source/FilterNodeTest.java b/src/test/java/org/redkale/test/source/FilterNodeTest.java index d0083e0aa..775c96150 100644 --- a/src/test/java/org/redkale/test/source/FilterNodeTest.java +++ b/src/test/java/org/redkale/test/source/FilterNodeTest.java @@ -1,440 +1,440 @@ -/* - * 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.test.source; - -import static org.redkale.source.FilterExpress.*; - -import java.lang.reflect.Method; -import java.util.*; -import java.util.concurrent.CompletableFuture; -import java.util.function.*; -import org.junit.jupiter.api.*; -import org.redkale.annotation.AutoLoad; -import org.redkale.convert.json.*; -import org.redkale.persistence.Entity; -import org.redkale.persistence.Id; -import org.redkale.persistence.Transient; -import org.redkale.source.*; - -/** @author zhangjx */ -public class FilterNodeTest { - - private static Function func; - - private static EntityInfo carEntity; - - public static void main(String[] args) throws Throwable { - FilterNodeTest test = new FilterNodeTest(); - test.init(); - test.run(); - } - - @BeforeAll - public static void init() throws Exception { - final Properties props = new Properties(); - final BiFunction> fullloader = - (s, t) -> CompletableFuture.completedFuture(new ArrayList()); - func = (Class t) -> loadEntityInfo(t, false, props, null, fullloader); - carEntity = loadEntityInfo( - CarTestTable.class, - false, - props, - null, - (s, t) -> CompletableFuture.completedFuture(CarTestTable.createList())); - final EntityInfo userEntity = loadEntityInfo( - UserTestTable.class, - false, - props, - null, - (s, t) -> CompletableFuture.completedFuture(UserTestTable.createList())); - final EntityInfo typeEntity = loadEntityInfo( - CarTypeTable.class, - false, - props, - null, - (s, t) -> CompletableFuture.completedFuture(CarTypeTable.createList())); - } - - private static EntityInfo loadEntityInfo( - Class clazz, - final boolean cacheForbidden, - final Properties conf, - DataSource source, - BiFunction> fullloader) { - try { - Method loadMethod = EntityInfo.class.getDeclaredMethod( - "load", Class.class, boolean.class, Properties.class, DataSource.class, BiFunction.class); - loadMethod.setAccessible(true); - return (EntityInfo) loadMethod.invoke(null, clazz, cacheForbidden, conf, source, fullloader); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - private static Map getJoinTabalis(FilterNode node) { - try { - Method method = FilterNode.class.getDeclaredMethod("getJoinTabalis"); - method.setAccessible(true); - return (Map) method.invoke(node); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - private static CharSequence createSQLJoin( - FilterNode node, - Function func, - final boolean update, - final Map joinTabalis, - final Set haset, - final EntityInfo info) { - try { - Method method = FilterNode.class.getDeclaredMethod( - "createSQLJoin", Function.class, boolean.class, Map.class, Set.class, EntityInfo.class); - method.setAccessible(true); - return (CharSequence) method.invoke(node, func, update, joinTabalis, haset, info); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - private static CharSequence createSQLExpress( - FilterNode node, - AbstractDataSqlSource source, - final EntityInfo info, - final Map joinTabalis) { - try { - Method method = FilterNode.class.getDeclaredMethod( - "createSQLExpress", AbstractDataSqlSource.class, EntityInfo.class, Map.class); - method.setAccessible(true); - return (CharSequence) method.invoke(node, source, info, joinTabalis); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - private static boolean isCacheUseable(FilterNode node, final Function entityApplyer) { - try { - Method method = FilterNode.class.getDeclaredMethod("isCacheUseable", Function.class); - method.setAccessible(true); - return (Boolean) method.invoke(node, entityApplyer); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - private static Predicate createPredicate(FilterNode node, final EntityCache cache) { - try { - Method method = FilterNode.class.getDeclaredMethod("createPredicate", EntityCache.class); - method.setAccessible(true); - return (Predicate) method.invoke(node, cache); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - @Test - public void run() throws Exception { - final CarTestBean bean = CarTestBean.create(); - FilterNode joinNode1 = FilterNodes.joinInner( - UserTestTable.class, new String[] {"userid", "username"}, "username", LIKE, bean.username) - .or(FilterNodes.joinInner( - UserTestTable.class, new String[] {"userid", "username"}, "createtime", GT, bean.createtime)); - FilterNode joinNode2 = FilterNodes.joinInner(CarTypeTable.class, "cartype", "typename", LIKE, bean.typename); - final FilterNode node = CarTestBean.caridTransient() - ? (joinNode2.or(joinNode1)) - : FilterNodes.gt("carid", bean.carid).and(joinNode1).or(joinNode2); - final FilterNode beanNode = FilterNodeBean.createFilterNode(bean); - System.out.println("node.string = " + node); - System.out.println("bean.string = " + beanNode); - Assertions.assertEquals( - "(CarTypeTable.typename LIKE '%法拉利%' OR (UserTestTable.username LIKE '%用户1%' OR UserTestTable.createtime > 500))", - node.toString()); - Assertions.assertEquals(node.toString(), beanNode.toString()); - Map nodeJoinTabalis = getJoinTabalis(node); - Map beanJoinTabalis = getJoinTabalis(beanNode); - System.out.println("nodeJoinTabalis: " + nodeJoinTabalis); - System.out.println("beanJoinTabalis: " + beanJoinTabalis); - CharSequence nodeJoinsql = createSQLJoin(node, func, false, nodeJoinTabalis, new HashSet<>(), carEntity); - CharSequence beanJoinsql = createSQLJoin(beanNode, func, false, beanJoinTabalis, new HashSet<>(), carEntity); - CharSequence nodeWhere = createSQLExpress(node, null, carEntity, nodeJoinTabalis); - CharSequence beanWhere = createSQLExpress(beanNode, null, carEntity, beanJoinTabalis); - String expect = - "SELECT a.* FROM cartesttable a INNER JOIN cartypetable ctt ON a.cartype = ctt.cartype INNER JOIN usertesttable utt ON a.userid = utt.userid AND a.username = utt.username WHERE (ctt.typename LIKE '%法拉利%' OR (utt.username LIKE '%用户1%' OR utt.createtime > 500))"; - System.out.println("node.sql = SELECT a.* FROM " - + CarTestTable.class.getSimpleName().toLowerCase() + " a" + (nodeJoinsql == null ? "" : nodeJoinsql) - + " WHERE " + nodeWhere); - System.out.println("bean.sql = SELECT a.* FROM " - + CarTestTable.class.getSimpleName().toLowerCase() + " a" + (beanJoinsql == null ? "" : beanJoinsql) - + " WHERE " + beanWhere); - boolean r1 = isCacheUseable(node, func); - Assertions.assertTrue(r1); - if (!r1) { - System.err.println("node.isCacheUseable 应该是true"); - } - boolean r2 = isCacheUseable(beanNode, func); - Assertions.assertTrue(r2); - - System.out.println("node.Predicate = " + createPredicate(node, carEntity.getCache())); - System.out.println("bean.Predicate = " + createPredicate(beanNode, carEntity.getCache())); - System.out.println("node.sheet = " + carEntity.getCache().querySheet(null, new Flipper(), node)); - System.out.println("bean.sheet = " + carEntity.getCache().querySheet(null, new Flipper(), beanNode)); - } - - public static class CarTestBean implements FilterBean { - - @FilterGroup("[OR].[AND]a") - @FilterColumn(express = GT) - @Transient - public long carid; - - @FilterGroup("[OR].[AND]a.[OR]c") - @FilterColumn(express = LIKE) - @FilterJoinColumn( - table = UserTestTable.class, - columns = {"userid", "username"}) - public String username; - - @FilterGroup("[OR].[AND]a.[OR]c") - @FilterColumn(express = GT) - @FilterJoinColumn( - table = UserTestTable.class, - columns = {"userid", "username"}) - public long createtime; - - @FilterGroup("[OR]") - @FilterColumn(express = LIKE) - @FilterJoinColumn( - table = CarTypeTable.class, - columns = {"cartype"}) - public String typename; - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } - - public static boolean caridTransient() { - try { - return CarTestBean.class.getDeclaredField("carid").getAnnotation(Transient.class) != null; - } catch (Exception e) { - e.printStackTrace(); - return true; - } - } - - public static CarTestBean create() { - final CarTestBean bean = new CarTestBean(); - bean.carid = 70002; - bean.username = "用户1"; - bean.createtime = 500; - bean.typename = "法拉利"; - return bean; - } - } - - @AutoLoad - @Entity(cacheable = true) - public static class CarTestTable { - - public static List createList() { - List list = new ArrayList<>(); - - list.add(new CarTestTable(70001, 101, 1000011, "我的车")); - list.add(new CarTestTable(70002, 102, 1000012, "我的车")); - list.add(new CarTestTable(70003, 103, 1000013, "我的车")); - list.add(new CarTestTable(70004, 104, 1000014, "我的车")); - list.add(new CarTestTable(70005, 105, 1000015, "我的车")); - - list.add(new CarTestTable(70201, 201, 1000031, "我的车")); - list.add(new CarTestTable(70202, 202, 1000032, "我的车")); - list.add(new CarTestTable(70203, 203, 1000033, "我的车")); - list.add(new CarTestTable(70204, 204, 1000034, "我的车")); - list.add(new CarTestTable(70205, 205, 1000035, "我的车")); - list.add(new CarTestTable(70505, 301, 1008000, "我的车")); - - return list; - } - - @Id - private long carid; - - private int cartype; - - private int userid; - - private String username; - - private String cartitle; - - public CarTestTable() {} - - public CarTestTable(long carid, int cartype, int userid, String cartitle) { - this.carid = carid; - this.cartype = cartype; - this.userid = userid; - this.username = "用户" + userid % 1000; - this.cartitle = cartitle; - } - - public long getCarid() { - return carid; - } - - public void setCarid(long carid) { - this.carid = carid; - } - - public int getUserid() { - return userid; - } - - public void setUserid(int userid) { - this.userid = userid; - } - - public String getCartitle() { - return cartitle; - } - - public void setCartitle(String cartitle) { - this.cartitle = cartitle; - } - - public int getCartype() { - return cartype; - } - - public void setCartype(int cartype) { - this.cartype = cartype; - } - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } - } - - @AutoLoad - @Entity(cacheable = true) - public static class CarTypeTable { - - public static List createList() { - List list = new ArrayList<>(); - list.add(new CarTypeTable(101, "奥迪A1")); - list.add(new CarTypeTable(102, "奥迪A2")); - list.add(new CarTypeTable(103, "奥迪A3")); - list.add(new CarTypeTable(104, "奥迪A4")); - list.add(new CarTypeTable(105, "奥迪A5")); - list.add(new CarTypeTable(201, "奔驰S1")); - list.add(new CarTypeTable(202, "奔驰S2")); - list.add(new CarTypeTable(203, "奔驰S3")); - list.add(new CarTypeTable(204, "奔驰S4")); - list.add(new CarTypeTable(205, "奔驰S5")); - list.add(new CarTypeTable(301, "法拉利")); - return list; - } - - @Id - private int cartype; - - private String typename; - - public CarTypeTable() {} - - public CarTypeTable(int cartype, String typename) { - this.cartype = cartype; - this.typename = typename; - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } - - public int getCartype() { - return cartype; - } - - public void setCartype(int cartype) { - this.cartype = cartype; - } - - public String getTypename() { - return typename; - } - - public void setTypename(String typename) { - this.typename = typename; - } - } - - @AutoLoad - @Entity(cacheable = true) - public static class UserTestTable { - - public static List createList() { - List list = new ArrayList<>(); - for (int i = 11; i <= 50; i++) { - list.add(new UserTestTable(1000000 + i, "用户" + i, i * 20)); - } - list.add(new UserTestTable(1008000, "车主A", 20)); - return list; - } - - @Id - private int userid; - - private String username; - - private long createtime; - - public UserTestTable() {} - - public UserTestTable(int userid, String username, long createtime) { - this.userid = userid; - this.username = username; - this.createtime = createtime; - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } - - public int getUserid() { - return userid; - } - - public void setUserid(int userid) { - this.userid = userid; - } - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - public long getCreatetime() { - return createtime; - } - - public void setCreatetime(long createtime) { - this.createtime = createtime; - } - } -} +/* + * 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.test.source; + +import static org.redkale.source.FilterExpress.*; + +import java.lang.reflect.Method; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.function.*; +import org.junit.jupiter.api.*; +import org.redkale.annotation.AutoLoad; +import org.redkale.convert.json.*; +import org.redkale.persistence.Entity; +import org.redkale.persistence.Id; +import org.redkale.persistence.Transient; +import org.redkale.source.*; + +/** @author zhangjx */ +public class FilterNodeTest { + + private static Function func; + + private static EntityInfo carEntity; + + public static void main(String[] args) throws Throwable { + FilterNodeTest test = new FilterNodeTest(); + test.init(); + test.run(); + } + + @BeforeAll + public static void init() throws Exception { + final Properties props = new Properties(); + final BiFunction> fullloader = + (s, t) -> CompletableFuture.completedFuture(new ArrayList()); + func = (Class t) -> loadEntityInfo(t, false, props, null, fullloader); + carEntity = loadEntityInfo( + CarTestTable.class, + false, + props, + null, + (s, t) -> CompletableFuture.completedFuture(CarTestTable.createList())); + final EntityInfo userEntity = loadEntityInfo( + UserTestTable.class, + false, + props, + null, + (s, t) -> CompletableFuture.completedFuture(UserTestTable.createList())); + final EntityInfo typeEntity = loadEntityInfo( + CarTypeTable.class, + false, + props, + null, + (s, t) -> CompletableFuture.completedFuture(CarTypeTable.createList())); + } + + private static EntityInfo loadEntityInfo( + Class clazz, + final boolean cacheForbidden, + final Properties conf, + DataSource source, + BiFunction> fullloader) { + try { + Method loadMethod = EntityInfo.class.getDeclaredMethod( + "load", Class.class, boolean.class, Properties.class, DataSource.class, BiFunction.class); + loadMethod.setAccessible(true); + return (EntityInfo) loadMethod.invoke(null, clazz, cacheForbidden, conf, source, fullloader); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private static Map getJoinTabalis(FilterNode node) { + try { + Method method = FilterNode.class.getDeclaredMethod("getJoinTabalis"); + method.setAccessible(true); + return (Map) method.invoke(node); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private static CharSequence createSQLJoin( + FilterNode node, + Function func, + final boolean update, + final Map joinTabalis, + final Set haset, + final EntityInfo info) { + try { + Method method = FilterNode.class.getDeclaredMethod( + "createSQLJoin", Function.class, boolean.class, Map.class, Set.class, EntityInfo.class); + method.setAccessible(true); + return (CharSequence) method.invoke(node, func, update, joinTabalis, haset, info); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private static CharSequence createSQLExpress( + FilterNode node, + AbstractDataSqlSource source, + final EntityInfo info, + final Map joinTabalis) { + try { + Method method = FilterNode.class.getDeclaredMethod( + "createSQLExpress", AbstractDataSqlSource.class, EntityInfo.class, Map.class); + method.setAccessible(true); + return (CharSequence) method.invoke(node, source, info, joinTabalis); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private static boolean isCacheUseable(FilterNode node, final Function entityApplyer) { + try { + Method method = FilterNode.class.getDeclaredMethod("isCacheUseable", Function.class); + method.setAccessible(true); + return (Boolean) method.invoke(node, entityApplyer); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private static Predicate createPredicate(FilterNode node, final EntityCache cache) { + try { + Method method = FilterNode.class.getDeclaredMethod("createPredicate", EntityCache.class); + method.setAccessible(true); + return (Predicate) method.invoke(node, cache); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Test + public void run() throws Exception { + final CarTestBean bean = CarTestBean.create(); + FilterNode joinNode1 = FilterNodes.joinInner( + UserTestTable.class, new String[] {"userid", "username"}, "username", LIKE, bean.username) + .or(FilterNodes.joinInner( + UserTestTable.class, new String[] {"userid", "username"}, "createtime", GT, bean.createtime)); + FilterNode joinNode2 = FilterNodes.joinInner(CarTypeTable.class, "cartype", "typename", LIKE, bean.typename); + final FilterNode node = CarTestBean.caridTransient() + ? (joinNode2.or(joinNode1)) + : FilterNodes.gt("carid", bean.carid).and(joinNode1).or(joinNode2); + final FilterNode beanNode = FilterNodeBean.createFilterNode(bean); + System.out.println("node.string = " + node); + System.out.println("bean.string = " + beanNode); + Assertions.assertEquals( + "(CarTypeTable.typename LIKE '%法拉利%' OR (UserTestTable.username LIKE '%用户1%' OR UserTestTable.createtime > 500))", + node.toString()); + Assertions.assertEquals(node.toString(), beanNode.toString()); + Map nodeJoinTabalis = getJoinTabalis(node); + Map beanJoinTabalis = getJoinTabalis(beanNode); + System.out.println("nodeJoinTabalis: " + nodeJoinTabalis); + System.out.println("beanJoinTabalis: " + beanJoinTabalis); + CharSequence nodeJoinsql = createSQLJoin(node, func, false, nodeJoinTabalis, new HashSet<>(), carEntity); + CharSequence beanJoinsql = createSQLJoin(beanNode, func, false, beanJoinTabalis, new HashSet<>(), carEntity); + CharSequence nodeWhere = createSQLExpress(node, null, carEntity, nodeJoinTabalis); + CharSequence beanWhere = createSQLExpress(beanNode, null, carEntity, beanJoinTabalis); + String expect = + "SELECT a.* FROM cartesttable a INNER JOIN cartypetable ctt ON a.cartype = ctt.cartype INNER JOIN usertesttable utt ON a.userid = utt.userid AND a.username = utt.username WHERE (ctt.typename LIKE '%法拉利%' OR (utt.username LIKE '%用户1%' OR utt.createtime > 500))"; + System.out.println("node.sql = SELECT a.* FROM " + + CarTestTable.class.getSimpleName().toLowerCase() + " a" + (nodeJoinsql == null ? "" : nodeJoinsql) + + " WHERE " + nodeWhere); + System.out.println("bean.sql = SELECT a.* FROM " + + CarTestTable.class.getSimpleName().toLowerCase() + " a" + (beanJoinsql == null ? "" : beanJoinsql) + + " WHERE " + beanWhere); + boolean r1 = isCacheUseable(node, func); + Assertions.assertTrue(r1); + if (!r1) { + System.err.println("node.isCacheUseable 应该是true"); + } + boolean r2 = isCacheUseable(beanNode, func); + Assertions.assertTrue(r2); + + System.out.println("node.Predicate = " + createPredicate(node, carEntity.getCache())); + System.out.println("bean.Predicate = " + createPredicate(beanNode, carEntity.getCache())); + System.out.println("node.sheet = " + carEntity.getCache().querySheet(null, new Flipper(), node)); + System.out.println("bean.sheet = " + carEntity.getCache().querySheet(null, new Flipper(), beanNode)); + } + + public static class CarTestBean implements FilterBean { + + @FilterGroup("[OR].[AND]a") + @FilterColumn(express = GT) + @Transient + public long carid; + + @FilterGroup("[OR].[AND]a.[OR]c") + @FilterColumn(express = LIKE) + @FilterJoinColumn( + table = UserTestTable.class, + columns = {"userid", "username"}) + public String username; + + @FilterGroup("[OR].[AND]a.[OR]c") + @FilterColumn(express = GT) + @FilterJoinColumn( + table = UserTestTable.class, + columns = {"userid", "username"}) + public long createtime; + + @FilterGroup("[OR]") + @FilterColumn(express = LIKE) + @FilterJoinColumn( + table = CarTypeTable.class, + columns = {"cartype"}) + public String typename; + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + + public static boolean caridTransient() { + try { + return CarTestBean.class.getDeclaredField("carid").getAnnotation(Transient.class) != null; + } catch (Exception e) { + e.printStackTrace(); + return true; + } + } + + public static CarTestBean create() { + final CarTestBean bean = new CarTestBean(); + bean.carid = 70002; + bean.username = "用户1"; + bean.createtime = 500; + bean.typename = "法拉利"; + return bean; + } + } + + @AutoLoad + @Entity(cacheable = true) + public static class CarTestTable { + + public static List createList() { + List list = new ArrayList<>(); + + list.add(new CarTestTable(70001, 101, 1000011, "我的车")); + list.add(new CarTestTable(70002, 102, 1000012, "我的车")); + list.add(new CarTestTable(70003, 103, 1000013, "我的车")); + list.add(new CarTestTable(70004, 104, 1000014, "我的车")); + list.add(new CarTestTable(70005, 105, 1000015, "我的车")); + + list.add(new CarTestTable(70201, 201, 1000031, "我的车")); + list.add(new CarTestTable(70202, 202, 1000032, "我的车")); + list.add(new CarTestTable(70203, 203, 1000033, "我的车")); + list.add(new CarTestTable(70204, 204, 1000034, "我的车")); + list.add(new CarTestTable(70205, 205, 1000035, "我的车")); + list.add(new CarTestTable(70505, 301, 1008000, "我的车")); + + return list; + } + + @Id + private long carid; + + private int cartype; + + private int userid; + + private String username; + + private String cartitle; + + public CarTestTable() {} + + public CarTestTable(long carid, int cartype, int userid, String cartitle) { + this.carid = carid; + this.cartype = cartype; + this.userid = userid; + this.username = "用户" + userid % 1000; + this.cartitle = cartitle; + } + + public long getCarid() { + return carid; + } + + public void setCarid(long carid) { + this.carid = carid; + } + + public int getUserid() { + return userid; + } + + public void setUserid(int userid) { + this.userid = userid; + } + + public String getCartitle() { + return cartitle; + } + + public void setCartitle(String cartitle) { + this.cartitle = cartitle; + } + + public int getCartype() { + return cartype; + } + + public void setCartype(int cartype) { + this.cartype = cartype; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + } + + @AutoLoad + @Entity(cacheable = true) + public static class CarTypeTable { + + public static List createList() { + List list = new ArrayList<>(); + list.add(new CarTypeTable(101, "奥迪A1")); + list.add(new CarTypeTable(102, "奥迪A2")); + list.add(new CarTypeTable(103, "奥迪A3")); + list.add(new CarTypeTable(104, "奥迪A4")); + list.add(new CarTypeTable(105, "奥迪A5")); + list.add(new CarTypeTable(201, "奔驰S1")); + list.add(new CarTypeTable(202, "奔驰S2")); + list.add(new CarTypeTable(203, "奔驰S3")); + list.add(new CarTypeTable(204, "奔驰S4")); + list.add(new CarTypeTable(205, "奔驰S5")); + list.add(new CarTypeTable(301, "法拉利")); + return list; + } + + @Id + private int cartype; + + private String typename; + + public CarTypeTable() {} + + public CarTypeTable(int cartype, String typename) { + this.cartype = cartype; + this.typename = typename; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + + public int getCartype() { + return cartype; + } + + public void setCartype(int cartype) { + this.cartype = cartype; + } + + public String getTypename() { + return typename; + } + + public void setTypename(String typename) { + this.typename = typename; + } + } + + @AutoLoad + @Entity(cacheable = true) + public static class UserTestTable { + + public static List createList() { + List list = new ArrayList<>(); + for (int i = 11; i <= 50; i++) { + list.add(new UserTestTable(1000000 + i, "用户" + i, i * 20)); + } + list.add(new UserTestTable(1008000, "车主A", 20)); + return list; + } + + @Id + private int userid; + + private String username; + + private long createtime; + + public UserTestTable() {} + + public UserTestTable(int userid, String username, long createtime) { + this.userid = userid; + this.username = username; + this.createtime = createtime; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + + public int getUserid() { + return userid; + } + + public void setUserid(int userid) { + this.userid = userid; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public long getCreatetime() { + return createtime; + } + + public void setCreatetime(long createtime) { + this.createtime = createtime; + } + } +} diff --git a/src/test/java/org/redkale/test/source/JsonRecord.java b/src/test/java/org/redkale/test/source/JsonRecord.java index 3f9a09f61..610513340 100644 --- a/src/test/java/org/redkale/test/source/JsonRecord.java +++ b/src/test/java/org/redkale/test/source/JsonRecord.java @@ -1,125 +1,125 @@ -/* - * 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.test.source; - -import java.io.Serializable; -import java.util.*; -import org.redkale.convert.json.JsonConvert; -import org.redkale.persistence.Column; -import org.redkale.persistence.Id; -import org.redkale.source.*; -import org.redkale.util.AnyValueWriter; - -/** @author zhangjx */ -// @Cacheable -public class JsonRecord { - - @SourceConvert - private static JsonConvert createConvert() { - return JsonConvert.root(); - } - - @Id - @Column(comment = "主键ID;") - private long recordid; - - @Column(comment = ";") - private String recordname = ""; - - @Column(comment = ";") - private Map rmap; - - @Column(comment = ";") - private List rlist; - - @Column(comment = ";") - private Set rset; - - public static JsonRecord create() { - JsonRecord record = new JsonRecord(); - record.setRecordid(System.currentTimeMillis()); - record.setRecordname("my name"); - Map map = new HashMap<>(); - map.put("str111", 10000); - map.put("str222", 20000); - record.setRmap(map); - List list = new ArrayList<>(); - list.add("item11"); - list.add("item22"); - list.add("item11"); - record.setRlist(list); - Set set = new HashSet<>(); - set.add("r1"); - set.add("r2"); - record.setRset(set); - return record; - } - - public static void main(String[] args) throws Throwable { - AnyValueWriter conf = AnyValueWriter.create(); - conf.addValue("name", ""); - conf.addValue( - "url", - "jdbc:mysql://localhost:3306/center?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true"); - conf.addValue("user", "root"); - conf.addValue("password", ""); - DataJdbcSource source = new DataJdbcSource(); - source.init(conf); - JsonRecord record = JsonRecord.create(); - source.insert(record); - source.updateColumn(JsonRecord.class, record.getRecordid(), ColumnValue.set("recordname", "my name 2")); - record.getRmap().put("haha", 2222); - source.updateColumn(JsonRecord.class, record.getRecordid(), ColumnValue.set("rmap", (Serializable) - (Object) record.getRmap())); - System.out.println(source.find(JsonRecord.class, record.getRecordid())); - System.out.println(source.findColumn(JsonRecord.class, "rmap", record.getRecordid())); - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } - - public long getRecordid() { - return recordid; - } - - public void setRecordid(long recordid) { - this.recordid = recordid; - } - - public String getRecordname() { - return recordname; - } - - public void setRecordname(String recordname) { - this.recordname = recordname; - } - - public Map getRmap() { - return rmap; - } - - public void setRmap(Map rmap) { - this.rmap = rmap; - } - - public List getRlist() { - return rlist; - } - - public void setRlist(List rlist) { - this.rlist = rlist; - } - - public Set getRset() { - return rset; - } - - public void setRset(Set rset) { - this.rset = rset; - } -} +/* + * 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.test.source; + +import java.io.Serializable; +import java.util.*; +import org.redkale.convert.json.JsonConvert; +import org.redkale.persistence.Column; +import org.redkale.persistence.Id; +import org.redkale.source.*; +import org.redkale.util.AnyValueWriter; + +/** @author zhangjx */ +// @Cacheable +public class JsonRecord { + + @SourceConvert + private static JsonConvert createConvert() { + return JsonConvert.root(); + } + + @Id + @Column(comment = "主键ID;") + private long recordid; + + @Column(comment = ";") + private String recordname = ""; + + @Column(comment = ";") + private Map rmap; + + @Column(comment = ";") + private List rlist; + + @Column(comment = ";") + private Set rset; + + public static JsonRecord create() { + JsonRecord record = new JsonRecord(); + record.setRecordid(System.currentTimeMillis()); + record.setRecordname("my name"); + Map map = new HashMap<>(); + map.put("str111", 10000); + map.put("str222", 20000); + record.setRmap(map); + List list = new ArrayList<>(); + list.add("item11"); + list.add("item22"); + list.add("item11"); + record.setRlist(list); + Set set = new HashSet<>(); + set.add("r1"); + set.add("r2"); + record.setRset(set); + return record; + } + + public static void main(String[] args) throws Throwable { + AnyValueWriter conf = AnyValueWriter.create(); + conf.addValue("name", ""); + conf.addValue( + "url", + "jdbc:mysql://localhost:3306/center?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true"); + conf.addValue("user", "root"); + conf.addValue("password", ""); + DataJdbcSource source = new DataJdbcSource(); + source.init(conf); + JsonRecord record = JsonRecord.create(); + source.insert(record); + source.updateColumn(JsonRecord.class, record.getRecordid(), ColumnValue.set("recordname", "my name 2")); + record.getRmap().put("haha", 2222); + source.updateColumn(JsonRecord.class, record.getRecordid(), ColumnValue.set("rmap", (Serializable) + (Object) record.getRmap())); + System.out.println(source.find(JsonRecord.class, record.getRecordid())); + System.out.println(source.findColumn(JsonRecord.class, "rmap", record.getRecordid())); + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + + public long getRecordid() { + return recordid; + } + + public void setRecordid(long recordid) { + this.recordid = recordid; + } + + public String getRecordname() { + return recordname; + } + + public void setRecordname(String recordname) { + this.recordname = recordname; + } + + public Map getRmap() { + return rmap; + } + + public void setRmap(Map rmap) { + this.rmap = rmap; + } + + public List getRlist() { + return rlist; + } + + public void setRlist(List rlist) { + this.rlist = rlist; + } + + public Set getRset() { + return rset; + } + + public void setRset(Set rset) { + this.rset = rset; + } +} diff --git a/src/test/java/org/redkale/test/source/LoginRecord.java b/src/test/java/org/redkale/test/source/LoginRecord.java index f7a3ae506..4be7362cd 100644 --- a/src/test/java/org/redkale/test/source/LoginRecord.java +++ b/src/test/java/org/redkale/test/source/LoginRecord.java @@ -1,161 +1,161 @@ -/* - * 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.test.source; - -import java.io.Serializable; -import org.redkale.persistence.*; -import org.redkale.source.*; -import org.redkale.util.Times; -import org.redkale.util.Utility; - -/** @author zhangjx */ -@DistributeTable(strategy = LoginRecord.TableStrategy.class) -public class LoginRecord extends BaseEntity { - - @Id - @Column(comment = "主键ID; 值=create36time(9位)+'-'+UUID(32位)") - private String loginid = ""; // 主键ID; 值=create36time(9位)+'-'+UUID(32位) - - @Column(updatable = false, comment = "C端用户ID") - private long userid; // C端用户ID - - @Column(updatable = false, comment = "登录网络类型; wifi/4g/3g") - private String netmode = ""; // 登录网络类型; wifi/4g/3g - - @Column(updatable = false, comment = "APP版本信息") - private String appversion = ""; // APP版本信息 - - @Column(updatable = false, comment = "APP操作系统信息") - private String appos = ""; // APP操作系统信息 - - @Column(updatable = false, comment = "登录时客户端信息") - private String loginagent = ""; // 登录时客户端信息 - - @Column(updatable = false, comment = "登录时的IP") - private String loginaddr = ""; // 登录时的IP - - @Column(updatable = false, comment = "创建时间") - private long createtime; // 创建时间 - - /** 以下省略getter setter方法 */ - // - public void setLoginid(String loginid) { - this.loginid = loginid; - } - - public String getLoginid() { - return this.loginid; - } - - public void setUserid(long userid) { - this.userid = userid; - } - - public long getUserid() { - return this.userid; - } - - public void setNetmode(String netmode) { - this.netmode = netmode; - } - - public String getNetmode() { - return this.netmode; - } - - public String getAppversion() { - return appversion; - } - - public void setAppversion(String appversion) { - this.appversion = appversion; - } - - public String getAppos() { - return appos; - } - - public void setAppos(String appos) { - this.appos = appos; - } - - public void setLoginagent(String loginagent) { - this.loginagent = loginagent; - } - - public String getLoginagent() { - return this.loginagent; - } - - public void setLoginaddr(String loginaddr) { - this.loginaddr = loginaddr; - } - - public String getLoginaddr() { - return this.loginaddr; - } - - public void setCreatetime(long createtime) { - this.createtime = createtime; - } - - public long getCreatetime() { - return this.createtime; - } - - private static DataSource source; - - // 创建对象 - public static void main(String[] args) throws Throwable { - LoginRecord record = new LoginRecord(); - long now = System.currentTimeMillis(); - record.setCreatetime(now); // 设置创建时间 - record.setLoginid(Times.format36time(now) + "-" + Utility.uuid()); // 主键的生成规则 - // .... 填充其他字段 - source.insert(record); - } - - public static class TableStrategy implements DistributeTableStrategy { - - private static final String dayformat = "%1$tY%1$tm%1$td"; // 一天一个表 - - private static final String yearformat = "%1$tY"; // 一年一个库 - - // 过滤查询时调用本方法 - @Override - public String[] getTables(String table, FilterNode node) { - Serializable day = node.findValue("#day"); // LoginRecord没有day字段,所以前面要加#,表示虚拟字段, 值为yyyyMMdd格式 - if (day != null) getTable(table, (Integer) day, 0L); // 存在#day参数则直接使用day值 - Serializable time = node.findValue("createtime"); // 存在createtime则使用最小时间,且createtime的范围必须在一天内,因为本表以天为单位建表 - if (time instanceof Long) { - return new String[] {getTable(table, 0, (Long) time)}; - } - Range.LongRange createTime = (Range.LongRange) time; - return new String[] {getTable(table, 0, createTime.getMin())}; - } - - // 创建或单个查询时调用本方法 - @Override - public String getTable(String table, LoginRecord bean) { - return getTable(table, 0, bean.getCreatetime()); - } - - // 根据主键ID查询单个记录时调用本方法 - @Override - public String getTable(String table, Serializable primary) { - String id = (String) primary; - return getTable(table, 0, Long.parseLong(id.substring(0, 9), 36)); - } - - private String getTable(String table, int day, long createtime) { // day为0或yyyyMMdd格式数据 - int pos = table.indexOf('.'); - String year = - day > 0 ? String.valueOf(day / 10000) : String.format(yearformat, createtime); // 没有day取createtime - return "platf_login_" + year + "." + table.substring(pos + 1) + "_" - + (day > 0 ? day : String.format(dayformat, createtime)); - } - } -} +/* + * 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.test.source; + +import java.io.Serializable; +import org.redkale.persistence.*; +import org.redkale.source.*; +import org.redkale.util.Times; +import org.redkale.util.Utility; + +/** @author zhangjx */ +@DistributeTable(strategy = LoginRecord.TableStrategy.class) +public class LoginRecord extends BaseEntity { + + @Id + @Column(comment = "主键ID; 值=create36time(9位)+'-'+UUID(32位)") + private String loginid = ""; // 主键ID; 值=create36time(9位)+'-'+UUID(32位) + + @Column(updatable = false, comment = "C端用户ID") + private long userid; // C端用户ID + + @Column(updatable = false, comment = "登录网络类型; wifi/4g/3g") + private String netmode = ""; // 登录网络类型; wifi/4g/3g + + @Column(updatable = false, comment = "APP版本信息") + private String appversion = ""; // APP版本信息 + + @Column(updatable = false, comment = "APP操作系统信息") + private String appos = ""; // APP操作系统信息 + + @Column(updatable = false, comment = "登录时客户端信息") + private String loginagent = ""; // 登录时客户端信息 + + @Column(updatable = false, comment = "登录时的IP") + private String loginaddr = ""; // 登录时的IP + + @Column(updatable = false, comment = "创建时间") + private long createtime; // 创建时间 + + /** 以下省略getter setter方法 */ + // + public void setLoginid(String loginid) { + this.loginid = loginid; + } + + public String getLoginid() { + return this.loginid; + } + + public void setUserid(long userid) { + this.userid = userid; + } + + public long getUserid() { + return this.userid; + } + + public void setNetmode(String netmode) { + this.netmode = netmode; + } + + public String getNetmode() { + return this.netmode; + } + + public String getAppversion() { + return appversion; + } + + public void setAppversion(String appversion) { + this.appversion = appversion; + } + + public String getAppos() { + return appos; + } + + public void setAppos(String appos) { + this.appos = appos; + } + + public void setLoginagent(String loginagent) { + this.loginagent = loginagent; + } + + public String getLoginagent() { + return this.loginagent; + } + + public void setLoginaddr(String loginaddr) { + this.loginaddr = loginaddr; + } + + public String getLoginaddr() { + return this.loginaddr; + } + + public void setCreatetime(long createtime) { + this.createtime = createtime; + } + + public long getCreatetime() { + return this.createtime; + } + + private static DataSource source; + + // 创建对象 + public static void main(String[] args) throws Throwable { + LoginRecord record = new LoginRecord(); + long now = System.currentTimeMillis(); + record.setCreatetime(now); // 设置创建时间 + record.setLoginid(Times.format36time(now) + "-" + Utility.uuid()); // 主键的生成规则 + // .... 填充其他字段 + source.insert(record); + } + + public static class TableStrategy implements DistributeTableStrategy { + + private static final String dayformat = "%1$tY%1$tm%1$td"; // 一天一个表 + + private static final String yearformat = "%1$tY"; // 一年一个库 + + // 过滤查询时调用本方法 + @Override + public String[] getTables(String table, FilterNode node) { + Serializable day = node.findValue("#day"); // LoginRecord没有day字段,所以前面要加#,表示虚拟字段, 值为yyyyMMdd格式 + if (day != null) getTable(table, (Integer) day, 0L); // 存在#day参数则直接使用day值 + Serializable time = node.findValue("createtime"); // 存在createtime则使用最小时间,且createtime的范围必须在一天内,因为本表以天为单位建表 + if (time instanceof Long) { + return new String[] {getTable(table, 0, (Long) time)}; + } + Range.LongRange createTime = (Range.LongRange) time; + return new String[] {getTable(table, 0, createTime.getMin())}; + } + + // 创建或单个查询时调用本方法 + @Override + public String getTable(String table, LoginRecord bean) { + return getTable(table, 0, bean.getCreatetime()); + } + + // 根据主键ID查询单个记录时调用本方法 + @Override + public String getTable(String table, Serializable primary) { + String id = (String) primary; + return getTable(table, 0, Long.parseLong(id.substring(0, 9), 36)); + } + + private String getTable(String table, int day, long createtime) { // day为0或yyyyMMdd格式数据 + int pos = table.indexOf('.'); + String year = + day > 0 ? String.valueOf(day / 10000) : String.format(yearformat, createtime); // 没有day取createtime + return "platf_login_" + year + "." + table.substring(pos + 1) + "_" + + (day > 0 ? day : String.format(dayformat, createtime)); + } + } +} diff --git a/src/test/java/org/redkale/test/source/LoginTestBean.java b/src/test/java/org/redkale/test/source/LoginTestBean.java index 233961428..467d46391 100644 --- a/src/test/java/org/redkale/test/source/LoginTestBean.java +++ b/src/test/java/org/redkale/test/source/LoginTestBean.java @@ -1,54 +1,54 @@ -/* - * 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.test.source; - -import java.lang.reflect.Method; -import java.util.*; -import java.util.function.BiFunction; -import org.redkale.source.*; - -/** @author zhangjx */ -public class LoginTestBean implements FilterBean { - - private String sessionid; - - private int sid; - - public static void main(String[] args) throws Throwable { - LoginTestBean bean = new LoginTestBean(); - bean.setSessionid("xxx"); - bean.setSid(23333); - BiFunction fullloader = (s, z) -> new ArrayList(); - Method method = EntityInfo.class.getDeclaredMethod( - "load", Class.class, boolean.class, Properties.class, DataSource.class, BiFunction.class); - method.setAccessible(true); - final EntityInfo info = (EntityInfo) - method.invoke(null, CacheTestBean.class, true, new Properties(), null, fullloader); - EntityCache cache = new EntityCache(info, null); - FilterNode node = FilterNodeBean.createFilterNode(bean); - System.out.println("cache = " + cache + ", node = " + node); - Method pre = FilterNode.class.getDeclaredMethod("createPredicate", EntityCache.class); - pre.setAccessible(true); - // 为null是因为CacheTestBean 没有sid和sessionid这两个字段 - System.out.println(pre.invoke(node, cache)); - } - - public String getSessionid() { - return sessionid; - } - - public void setSessionid(String sessionid) { - this.sessionid = sessionid; - } - - public int getSid() { - return sid; - } - - public void setSid(int sid) { - this.sid = sid; - } -} +/* + * 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.test.source; + +import java.lang.reflect.Method; +import java.util.*; +import java.util.function.BiFunction; +import org.redkale.source.*; + +/** @author zhangjx */ +public class LoginTestBean implements FilterBean { + + private String sessionid; + + private int sid; + + public static void main(String[] args) throws Throwable { + LoginTestBean bean = new LoginTestBean(); + bean.setSessionid("xxx"); + bean.setSid(23333); + BiFunction fullloader = (s, z) -> new ArrayList(); + Method method = EntityInfo.class.getDeclaredMethod( + "load", Class.class, boolean.class, Properties.class, DataSource.class, BiFunction.class); + method.setAccessible(true); + final EntityInfo info = (EntityInfo) + method.invoke(null, CacheTestBean.class, true, new Properties(), null, fullloader); + EntityCache cache = new EntityCache(info, null); + FilterNode node = FilterNodeBean.createFilterNode(bean); + System.out.println("cache = " + cache + ", node = " + node); + Method pre = FilterNode.class.getDeclaredMethod("createPredicate", EntityCache.class); + pre.setAccessible(true); + // 为null是因为CacheTestBean 没有sid和sessionid这两个字段 + System.out.println(pre.invoke(node, cache)); + } + + public String getSessionid() { + return sessionid; + } + + public void setSessionid(String sessionid) { + this.sessionid = sessionid; + } + + public int getSid() { + return sid; + } + + public void setSid(int sid) { + this.sid = sid; + } +} diff --git a/src/test/java/org/redkale/test/source/LoginTestRecord.java b/src/test/java/org/redkale/test/source/LoginTestRecord.java index 9c9cc1aae..3732f904a 100644 --- a/src/test/java/org/redkale/test/source/LoginTestRecord.java +++ b/src/test/java/org/redkale/test/source/LoginTestRecord.java @@ -1,86 +1,86 @@ -/* - * 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.test.source; - -import org.redkale.convert.json.*; -import org.redkale.persistence.Id; - -/** - * CREATE TABLE `LoginTestRecord` ( `sessionid` VARCHAR(64) NOT NULL COMMENT '登录会话ID', `userid` INT(11) NOT NULL COMMENT - * '登录用户ID', `loginagent` VARCHAR(128) NOT NULL COMMENT '登录端信息', `loginip` VARCHAR(255) NOT NULL COMMENT '登录IP', - * `logintime` BIGINT(20) NOT NULL COMMENT '登录时间', `logouttime` BIGINT(20) NOT NULL COMMENT '注销时间', PRIMARY KEY - * (`sessionid`) ) ENGINE=INNODB DEFAULT CHARSET=utf8; - * - * @author zhangjx - */ -public class LoginTestRecord { - - @Id - private String sessionid; - - private int userid; - - private String loginagent; - - private String loginip; - - private long logintime; - - private long logouttime; - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } - - public String getSessionid() { - return sessionid; - } - - public void setSessionid(String sessionid) { - this.sessionid = sessionid; - } - - public int getUserid() { - return userid; - } - - public void setUserid(int userid) { - this.userid = userid; - } - - public String getLoginagent() { - return loginagent; - } - - public void setLoginagent(String loginagent) { - this.loginagent = loginagent; - } - - public String getLoginip() { - return loginip; - } - - public void setLoginip(String loginip) { - this.loginip = loginip; - } - - public long getLogintime() { - return logintime; - } - - public void setLogintime(long logintime) { - this.logintime = logintime; - } - - public long getLogouttime() { - return logouttime; - } - - public void setLogouttime(long logouttime) { - this.logouttime = logouttime; - } -} +/* + * 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.test.source; + +import org.redkale.convert.json.*; +import org.redkale.persistence.Id; + +/** + * CREATE TABLE `LoginTestRecord` ( `sessionid` VARCHAR(64) NOT NULL COMMENT '登录会话ID', `userid` INT(11) NOT NULL COMMENT + * '登录用户ID', `loginagent` VARCHAR(128) NOT NULL COMMENT '登录端信息', `loginip` VARCHAR(255) NOT NULL COMMENT '登录IP', + * `logintime` BIGINT(20) NOT NULL COMMENT '登录时间', `logouttime` BIGINT(20) NOT NULL COMMENT '注销时间', PRIMARY KEY + * (`sessionid`) ) ENGINE=INNODB DEFAULT CHARSET=utf8; + * + * @author zhangjx + */ +public class LoginTestRecord { + + @Id + private String sessionid; + + private int userid; + + private String loginagent; + + private String loginip; + + private long logintime; + + private long logouttime; + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + + public String getSessionid() { + return sessionid; + } + + public void setSessionid(String sessionid) { + this.sessionid = sessionid; + } + + public int getUserid() { + return userid; + } + + public void setUserid(int userid) { + this.userid = userid; + } + + public String getLoginagent() { + return loginagent; + } + + public void setLoginagent(String loginagent) { + this.loginagent = loginagent; + } + + public String getLoginip() { + return loginip; + } + + public void setLoginip(String loginip) { + this.loginip = loginip; + } + + public long getLogintime() { + return logintime; + } + + public void setLogintime(long logintime) { + this.logintime = logintime; + } + + public long getLogouttime() { + return logouttime; + } + + public void setLogouttime(long logouttime) { + this.logouttime = logouttime; + } +} diff --git a/src/test/java/org/redkale/test/source/LoginUserRecord.java b/src/test/java/org/redkale/test/source/LoginUserRecord.java index e03e6c9a6..62e77caa5 100644 --- a/src/test/java/org/redkale/test/source/LoginUserRecord.java +++ b/src/test/java/org/redkale/test/source/LoginUserRecord.java @@ -1,88 +1,88 @@ -/* - * 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.test.source; - -import java.io.Serializable; -import org.redkale.persistence.*; -import org.redkale.source.*; - -/** @author zhangjx */ -@DistributeTable(strategy = LoginUserRecord.TableStrategy.class) -public class LoginUserRecord extends BaseEntity { - - @Id - @Column(comment = "记录ID; 值=userid+'-'+UUID") - private String seqid = ""; // 记录ID; 值=userid+'-'+UUID - - @Column(updatable = false, comment = "C端用户ID") - private long userid; // C端用户ID - - @Column(comment = "LoginRecord主键") - private String loginid = ""; // LoginRecord主键 - - @Column(updatable = false, comment = "创建时间") - private long createtime; // 创建时间 - - /** 以下省略getter setter方法 */ - // - public String getSeqid() { - return seqid; - } - - public void setSeqid(String seqid) { - this.seqid = seqid; - } - - public long getUserid() { - return userid; - } - - public void setUserid(long userid) { - this.userid = userid; - } - - public String getLoginid() { - return loginid; - } - - public void setLoginid(String loginid) { - this.loginid = loginid; - } - - public long getCreatetime() { - return createtime; - } - - public void setCreatetime(long createtime) { - this.createtime = createtime; - } - - public static class TableStrategy implements DistributeTableStrategy { - - @Override - public String getTable(String table, LoginUserRecord bean) { - return getTable(table, bean.getUserid()); - } - - @Override - public String[] getTables(String table, FilterNode node) { - Serializable id = node.findValue("userid"); - if (id != null) return new String[] {getTable(table, id)}; - return new String[] {getHashTable(table, (Integer) node.findValue("#hash"))}; - } - - @Override - public String getTable(String table, Serializable primary) { - String id = (String) primary; - return getHashTable(table, (int) (Long.parseLong(id.substring(0, id.indexOf('-'))) % 100)); - } - - private String getHashTable(String table, int hash) { - int pos = table.indexOf('.'); - return "platf_login." + table.substring(pos + 1) + "_" + (hash > 9 ? hash : ("0" + hash)); - } - } -} +/* + * 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.test.source; + +import java.io.Serializable; +import org.redkale.persistence.*; +import org.redkale.source.*; + +/** @author zhangjx */ +@DistributeTable(strategy = LoginUserRecord.TableStrategy.class) +public class LoginUserRecord extends BaseEntity { + + @Id + @Column(comment = "记录ID; 值=userid+'-'+UUID") + private String seqid = ""; // 记录ID; 值=userid+'-'+UUID + + @Column(updatable = false, comment = "C端用户ID") + private long userid; // C端用户ID + + @Column(comment = "LoginRecord主键") + private String loginid = ""; // LoginRecord主键 + + @Column(updatable = false, comment = "创建时间") + private long createtime; // 创建时间 + + /** 以下省略getter setter方法 */ + // + public String getSeqid() { + return seqid; + } + + public void setSeqid(String seqid) { + this.seqid = seqid; + } + + public long getUserid() { + return userid; + } + + public void setUserid(long userid) { + this.userid = userid; + } + + public String getLoginid() { + return loginid; + } + + public void setLoginid(String loginid) { + this.loginid = loginid; + } + + public long getCreatetime() { + return createtime; + } + + public void setCreatetime(long createtime) { + this.createtime = createtime; + } + + public static class TableStrategy implements DistributeTableStrategy { + + @Override + public String getTable(String table, LoginUserRecord bean) { + return getTable(table, bean.getUserid()); + } + + @Override + public String[] getTables(String table, FilterNode node) { + Serializable id = node.findValue("userid"); + if (id != null) return new String[] {getTable(table, id)}; + return new String[] {getHashTable(table, (Integer) node.findValue("#hash"))}; + } + + @Override + public String getTable(String table, Serializable primary) { + String id = (String) primary; + return getHashTable(table, (int) (Long.parseLong(id.substring(0, id.indexOf('-'))) % 100)); + } + + private String getHashTable(String table, int hash) { + int pos = table.indexOf('.'); + return "platf_login." + table.substring(pos + 1) + "_" + (hash > 9 ? hash : ("0" + hash)); + } + } +} diff --git a/src/test/java/org/redkale/test/source/TestSourceCache.java b/src/test/java/org/redkale/test/source/TestSourceCache.java index ed295e8fd..c61bbd4e3 100644 --- a/src/test/java/org/redkale/test/source/TestSourceCache.java +++ b/src/test/java/org/redkale/test/source/TestSourceCache.java @@ -1,134 +1,134 @@ -/* - * 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.test.source; - -import java.lang.reflect.Method; -import java.util.*; -import java.util.concurrent.CountDownLatch; -import java.util.function.BiFunction; -import org.junit.jupiter.api.Assertions; -import org.redkale.convert.json.JsonConvert; -import org.redkale.persistence.*; -import org.redkale.persistence.VirtualEntity; -import org.redkale.source.*; -import org.redkale.util.Sheet; - -/** @author zhangjx */ -public class TestSourceCache { - - public static class TestEntityBean implements FilterBean { - - @FilterColumn(express = FilterExpress.GT) - public int userid; - - @FilterColumn(express = FilterExpress.LIKE) - public String username; - - public TestEntityBean(int userid, String username) { - this.userid = userid; - this.username = username; - } - } - - public static void main(String[] args) throws Exception { - final BiFunction fullloader = (DataSource t, Class u) -> null; - Method method = EntityInfo.class.getDeclaredMethod( - "load", Class.class, boolean.class, Properties.class, DataSource.class, BiFunction.class); - method.setAccessible(true); - final EntityInfo info = (EntityInfo) - method.invoke(null, TestEntity.class, false, new Properties(), null, fullloader); - TestEntity[] entitys = new TestEntity[10_0000]; - for (int i = 0; i < entitys.length; i++) { - entitys[i] = new TestEntity(i + 1, "用户_" + (i + 1)); - } - long s = System.currentTimeMillis(); - for (TestEntity en : entitys) { - info.getCache().insert(en); - } - long e = System.currentTimeMillis() - s; - System.out.println("插入十万条记录耗时: " + e / 1000.0 + " 秒"); - - s = System.currentTimeMillis(); - TestEntity one = info.getCache().find(9999); - e = System.currentTimeMillis() - s; - System.out.println("十万条数据中查询一条记录耗时: " + e / 1000.0 + " 秒 " + one); - - final Flipper flipper = new Flipper(2); - flipper.setSort("userid DESC, createtime DESC"); - final FilterNode node = FilterNodes.gt("userid", 1000).like("username", "用户"); - System.out.println("node = " + node); - final FilterNode node2 = FilterNodes.gt(TestEntity::getUserid, 1000).like("username", "用户"); - Assertions.assertEquals(node.toString(), node2.toString()); - Sheet sheet = info.getCache().querySheet(null, flipper, node); - System.out.println(sheet); - System.out.println(info.getCache() - .querySheet(null, flipper, FilterNodeBean.createFilterNode(new TestEntityBean(1000, "用户")))); - final CountDownLatch cdl = new CountDownLatch(100); - s = System.currentTimeMillis(); - for (int i = 0; i < 100; i++) { - new Thread() { - @Override - public void run() { - for (int k = 0; k < 10; k++) { - info.getCache().querySheet(true, false, null, flipper, node); - } - cdl.countDown(); - } - }.start(); - } - cdl.await(); - e = System.currentTimeMillis() - s; - System.out.println("十万条数据中100并发查询一页循环10次记录耗时: " + e / 1000.0 + " 秒 " - + sheet); // CopyOnWriteArrayList 0.798 ConcurrentLinkedQueue 1.063 - } - - @VirtualEntity - public static class TestEntity { - - @Id - private int userid; - - private String username; - - private long createtime = System.currentTimeMillis(); - - public TestEntity() {} - - public TestEntity(int userid, String username) { - this.userid = userid; - this.username = username; - } - - public int getUserid() { - return userid; - } - - public void setUserid(int userid) { - this.userid = userid; - } - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - public long getCreatetime() { - return createtime; - } - - public void setCreatetime(long createtime) { - this.createtime = createtime; - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } - } -} +/* + * 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.test.source; + +import java.lang.reflect.Method; +import java.util.*; +import java.util.concurrent.CountDownLatch; +import java.util.function.BiFunction; +import org.junit.jupiter.api.Assertions; +import org.redkale.convert.json.JsonConvert; +import org.redkale.persistence.*; +import org.redkale.persistence.VirtualEntity; +import org.redkale.source.*; +import org.redkale.util.Sheet; + +/** @author zhangjx */ +public class TestSourceCache { + + public static class TestEntityBean implements FilterBean { + + @FilterColumn(express = FilterExpress.GT) + public int userid; + + @FilterColumn(express = FilterExpress.LIKE) + public String username; + + public TestEntityBean(int userid, String username) { + this.userid = userid; + this.username = username; + } + } + + public static void main(String[] args) throws Exception { + final BiFunction fullloader = (DataSource t, Class u) -> null; + Method method = EntityInfo.class.getDeclaredMethod( + "load", Class.class, boolean.class, Properties.class, DataSource.class, BiFunction.class); + method.setAccessible(true); + final EntityInfo info = (EntityInfo) + method.invoke(null, TestEntity.class, false, new Properties(), null, fullloader); + TestEntity[] entitys = new TestEntity[10_0000]; + for (int i = 0; i < entitys.length; i++) { + entitys[i] = new TestEntity(i + 1, "用户_" + (i + 1)); + } + long s = System.currentTimeMillis(); + for (TestEntity en : entitys) { + info.getCache().insert(en); + } + long e = System.currentTimeMillis() - s; + System.out.println("插入十万条记录耗时: " + e / 1000.0 + " 秒"); + + s = System.currentTimeMillis(); + TestEntity one = info.getCache().find(9999); + e = System.currentTimeMillis() - s; + System.out.println("十万条数据中查询一条记录耗时: " + e / 1000.0 + " 秒 " + one); + + final Flipper flipper = new Flipper(2); + flipper.setSort("userid DESC, createtime DESC"); + final FilterNode node = FilterNodes.gt("userid", 1000).like("username", "用户"); + System.out.println("node = " + node); + final FilterNode node2 = FilterNodes.gt(TestEntity::getUserid, 1000).like("username", "用户"); + Assertions.assertEquals(node.toString(), node2.toString()); + Sheet sheet = info.getCache().querySheet(null, flipper, node); + System.out.println(sheet); + System.out.println(info.getCache() + .querySheet(null, flipper, FilterNodeBean.createFilterNode(new TestEntityBean(1000, "用户")))); + final CountDownLatch cdl = new CountDownLatch(100); + s = System.currentTimeMillis(); + for (int i = 0; i < 100; i++) { + new Thread() { + @Override + public void run() { + for (int k = 0; k < 10; k++) { + info.getCache().querySheet(true, false, null, flipper, node); + } + cdl.countDown(); + } + }.start(); + } + cdl.await(); + e = System.currentTimeMillis() - s; + System.out.println("十万条数据中100并发查询一页循环10次记录耗时: " + e / 1000.0 + " 秒 " + + sheet); // CopyOnWriteArrayList 0.798 ConcurrentLinkedQueue 1.063 + } + + @VirtualEntity + public static class TestEntity { + + @Id + private int userid; + + private String username; + + private long createtime = System.currentTimeMillis(); + + public TestEntity() {} + + public TestEntity(int userid, String username) { + this.userid = userid; + this.username = username; + } + + public int getUserid() { + return userid; + } + + public void setUserid(int userid) { + this.userid = userid; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public long getCreatetime() { + return createtime; + } + + public void setCreatetime(long createtime) { + this.createtime = createtime; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + } +} diff --git a/src/test/java/org/redkale/test/source/UserDetail.java b/src/test/java/org/redkale/test/source/UserDetail.java index 68a56f525..438787533 100644 --- a/src/test/java/org/redkale/test/source/UserDetail.java +++ b/src/test/java/org/redkale/test/source/UserDetail.java @@ -1,109 +1,109 @@ -/* - * 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.test.source; - -import java.io.Serializable; -import org.redkale.convert.*; -import org.redkale.persistence.*; -import org.redkale.source.*; - -/** @author zhangjx */ -@DistributeTable(strategy = UserDetail.TableStrategy.class) -public class UserDetail extends BaseEntity { - - public static class TableStrategy implements DistributeTableStrategy { - - @Override - public String getTable(String table, UserDetail bean) { - return getTable(table, bean.getUserid()); - } - - @Override - public String[] getTables(String table, FilterNode node) { - Serializable id = node.findValue("userid"); - if (id != null) return new String[] {getTable(table, id)}; - return new String[] {getHashTable(table, (Integer) node.findValue("#hash"))}; - } - - @Override - public String getTable(String table, Serializable userid) { - return getHashTable(table, (int) (((Long) userid) % 100)); - } - - private String getHashTable(String table, int hash) { - int pos = table.indexOf('.'); - return "platf_user." + table.substring(pos + 1) + "_" + (hash > 9 ? hash : ("0" + hash)); - } - } - - @Id - private long userid; // 用户ID - - @Column(length = 64, comment = "用户昵称") - private String username = ""; // 用户昵称 - - @Column(length = 32, comment = "手机号码") - private String mobile = ""; // 手机号码 - - @Column(length = 64, comment = "密码") - @ConvertColumn(ignore = true, type = ConvertType.ALL) - private String password = ""; // 密码 - - @Column(length = 128, comment = "备注") - private String remark = ""; // 备注 - - @Column(updatable = false, comment = "创建时间") - private long createtime; // 创建时间 - - /** 以下省略getter setter方法 */ - public long getUserid() { - return userid; - } - - public void setUserid(long userid) { - this.userid = userid; - } - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - public String getMobile() { - return mobile; - } - - public void setMobile(String mobile) { - this.mobile = mobile; - } - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } - - public String getRemark() { - return remark; - } - - public void setRemark(String remark) { - this.remark = remark; - } - - public long getCreatetime() { - return createtime; - } - - public void setCreatetime(long createtime) { - this.createtime = createtime; - } -} +/* + * 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.test.source; + +import java.io.Serializable; +import org.redkale.convert.*; +import org.redkale.persistence.*; +import org.redkale.source.*; + +/** @author zhangjx */ +@DistributeTable(strategy = UserDetail.TableStrategy.class) +public class UserDetail extends BaseEntity { + + public static class TableStrategy implements DistributeTableStrategy { + + @Override + public String getTable(String table, UserDetail bean) { + return getTable(table, bean.getUserid()); + } + + @Override + public String[] getTables(String table, FilterNode node) { + Serializable id = node.findValue("userid"); + if (id != null) return new String[] {getTable(table, id)}; + return new String[] {getHashTable(table, (Integer) node.findValue("#hash"))}; + } + + @Override + public String getTable(String table, Serializable userid) { + return getHashTable(table, (int) (((Long) userid) % 100)); + } + + private String getHashTable(String table, int hash) { + int pos = table.indexOf('.'); + return "platf_user." + table.substring(pos + 1) + "_" + (hash > 9 ? hash : ("0" + hash)); + } + } + + @Id + private long userid; // 用户ID + + @Column(length = 64, comment = "用户昵称") + private String username = ""; // 用户昵称 + + @Column(length = 32, comment = "手机号码") + private String mobile = ""; // 手机号码 + + @Column(length = 64, comment = "密码") + @ConvertColumn(ignore = true, type = ConvertType.ALL) + private String password = ""; // 密码 + + @Column(length = 128, comment = "备注") + private String remark = ""; // 备注 + + @Column(updatable = false, comment = "创建时间") + private long createtime; // 创建时间 + + /** 以下省略getter setter方法 */ + public long getUserid() { + return userid; + } + + public void setUserid(long userid) { + this.userid = userid; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getMobile() { + return mobile; + } + + public void setMobile(String mobile) { + this.mobile = mobile; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getRemark() { + return remark; + } + + public void setRemark(String remark) { + this.remark = remark; + } + + public long getCreatetime() { + return createtime; + } + + public void setCreatetime(long createtime) { + this.createtime = createtime; + } +} diff --git a/src/test/java/org/redkale/test/source/parser/BaseEntity.java b/src/test/java/org/redkale/test/source/parser/BaseEntity.java index e0a81d5a1..89f2141a7 100644 --- a/src/test/java/org/redkale/test/source/parser/BaseEntity.java +++ b/src/test/java/org/redkale/test/source/parser/BaseEntity.java @@ -1,20 +1,20 @@ -/* - * 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.test.source.parser; - -import java.io.*; -import org.redkale.convert.json.*; -import org.redkale.persistence.*; - -/** @author zhangjx */ -@Entity -public abstract class BaseEntity implements Serializable { - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } -} +/* + * 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.test.source.parser; + +import java.io.*; +import org.redkale.convert.json.*; +import org.redkale.persistence.*; + +/** @author zhangjx */ +@Entity +public abstract class BaseEntity implements Serializable { + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } +} diff --git a/src/test/java/org/redkale/test/source/parser/BaseMapper.java b/src/test/java/org/redkale/test/source/parser/BaseMapper.java index 8f984605c..315e5fca7 100644 --- a/src/test/java/org/redkale/test/source/parser/BaseMapper.java +++ b/src/test/java/org/redkale/test/source/parser/BaseMapper.java @@ -1,9 +1,9 @@ -/* - * - */ -package org.redkale.test.source.parser; - -import org.redkale.source.DataSqlMapper; - -/** @author zhangjx */ -public interface BaseMapper extends DataSqlMapper {} +/* + * + */ +package org.redkale.test.source.parser; + +import org.redkale.source.DataSqlMapper; + +/** @author zhangjx */ +public interface BaseMapper extends DataSqlMapper {} diff --git a/src/test/java/org/redkale/test/source/parser/DataSqlMapperTest.java b/src/test/java/org/redkale/test/source/parser/DataSqlMapperTest.java index ff7ed911a..6e04f080f 100644 --- a/src/test/java/org/redkale/test/source/parser/DataSqlMapperTest.java +++ b/src/test/java/org/redkale/test/source/parser/DataSqlMapperTest.java @@ -1,31 +1,31 @@ -/* - * - */ -package org.redkale.test.source.parser; - -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.redkale.source.DataJdbcSource; -import org.redkale.source.DataSqlSource; - -/** @author zhangjx */ -public class DataSqlMapperTest { - - private static DataSqlSource source = new DataJdbcSource(); - - public static void main(String[] args) throws Throwable { - DataSqlMapperTest test = new DataSqlMapperTest(); - test.init(); - test.run(); - } - - @BeforeAll - public static void init() throws Exception { - // do - } - - @Test - public void run() throws Exception { - // do - } -} +/* + * + */ +package org.redkale.test.source.parser; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.redkale.source.DataJdbcSource; +import org.redkale.source.DataSqlSource; + +/** @author zhangjx */ +public class DataSqlMapperTest { + + private static DataSqlSource source = new DataJdbcSource(); + + public static void main(String[] args) throws Throwable { + DataSqlMapperTest test = new DataSqlMapperTest(); + test.init(); + test.run(); + } + + @BeforeAll + public static void init() throws Exception { + // do + } + + @Test + public void run() throws Exception { + // do + } +} diff --git a/src/test/java/org/redkale/test/source/parser/DynForumInfoMapperImpl.java b/src/test/java/org/redkale/test/source/parser/DynForumInfoMapperImpl.java index dc5536119..f4ed6709b 100644 --- a/src/test/java/org/redkale/test/source/parser/DynForumInfoMapperImpl.java +++ b/src/test/java/org/redkale/test/source/parser/DynForumInfoMapperImpl.java @@ -1,62 +1,62 @@ -/* - * - */ -package org.redkale.test.source.parser; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CompletableFuture; -import org.redkale.source.DataSqlSource; - -/** @author zhangjx */ -public class DynForumInfoMapperImpl implements ForumInfoMapper { - - private DataSqlSource _source; - - private Class _type; - - @Override - public ForumResult findForumResult(ForumBean bean) { - String sql = - "SELECT f.forum_groupid, s.forum_section_color FROM forum_info f, forum_section s WHERE f.forumid = s.forumid"; - Map params = new HashMap<>(); - params.put("bean", bean); - return dataSource().nativeQueryOne(ForumResult.class, sql, params); - } - - public CompletableFuture findForumResultAsync(ForumBean bean) { - String sql = - "SELECT f.forum_groupid, s.forum_section_color FROM forum_info f, forum_section s WHERE f.forumid = s.forumid"; - Map params = new HashMap<>(); - params.put("bean", bean); - return dataSource().nativeQueryOneAsync(ForumResult.class, sql, params); - } - - @Override - public List queryForumResult(ForumBean bean) { - String sql = - "SELECT f.forum_groupid, s.forum_section_color FROM forum_info f, forum_section s WHERE f.forumid = s.forumid"; - Map params = new HashMap<>(); - params.put("bean", bean); - return dataSource().nativeQueryList(ForumResult.class, sql, params); - } - - public CompletableFuture> queryForumResultAsync(ForumBean bean) { - String sql = - "SELECT f.forum_groupid, s.forum_section_color FROM forum_info f, forum_section s WHERE f.forumid = s.forumid"; - Map params = new HashMap<>(); - params.put("bean", bean); - return dataSource().nativeQueryListAsync(ForumResult.class, sql, params); - } - - @Override - public DataSqlSource dataSource() { - return _source; - } - - @Override - public Class entityType() { - return _type; - } -} +/* + * + */ +package org.redkale.test.source.parser; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import org.redkale.source.DataSqlSource; + +/** @author zhangjx */ +public class DynForumInfoMapperImpl implements ForumInfoMapper { + + private DataSqlSource _source; + + private Class _type; + + @Override + public ForumResult findForumResult(ForumBean bean) { + String sql = + "SELECT f.forum_groupid, s.forum_section_color FROM forum_info f, forum_section s WHERE f.forumid = s.forumid"; + Map params = new HashMap<>(); + params.put("bean", bean); + return dataSource().nativeQueryOne(ForumResult.class, sql, params); + } + + public CompletableFuture findForumResultAsync(ForumBean bean) { + String sql = + "SELECT f.forum_groupid, s.forum_section_color FROM forum_info f, forum_section s WHERE f.forumid = s.forumid"; + Map params = new HashMap<>(); + params.put("bean", bean); + return dataSource().nativeQueryOneAsync(ForumResult.class, sql, params); + } + + @Override + public List queryForumResult(ForumBean bean) { + String sql = + "SELECT f.forum_groupid, s.forum_section_color FROM forum_info f, forum_section s WHERE f.forumid = s.forumid"; + Map params = new HashMap<>(); + params.put("bean", bean); + return dataSource().nativeQueryList(ForumResult.class, sql, params); + } + + public CompletableFuture> queryForumResultAsync(ForumBean bean) { + String sql = + "SELECT f.forum_groupid, s.forum_section_color FROM forum_info f, forum_section s WHERE f.forumid = s.forumid"; + Map params = new HashMap<>(); + params.put("bean", bean); + return dataSource().nativeQueryListAsync(ForumResult.class, sql, params); + } + + @Override + public DataSqlSource dataSource() { + return _source; + } + + @Override + public Class entityType() { + return _type; + } +} diff --git a/src/test/java/org/redkale/test/source/parser/ForumBean.java b/src/test/java/org/redkale/test/source/parser/ForumBean.java index b9eee6ea4..bab995ea1 100644 --- a/src/test/java/org/redkale/test/source/parser/ForumBean.java +++ b/src/test/java/org/redkale/test/source/parser/ForumBean.java @@ -1,40 +1,40 @@ -/* - * - */ -package org.redkale.test.source.parser; - -import java.io.Serializable; - -/** @author zhangjx */ -public class ForumBean implements Serializable { - - private String forumSectionid; - - private String forumSectionColor; - - private String forumid; - - public String getForumSectionid() { - return forumSectionid; - } - - public void setForumSectionid(String forumSectionid) { - this.forumSectionid = forumSectionid; - } - - public String getForumSectionColor() { - return forumSectionColor; - } - - public void setForumSectionColor(String forumSectionColor) { - this.forumSectionColor = forumSectionColor; - } - - public String getForumid() { - return forumid; - } - - public void setForumid(String forumid) { - this.forumid = forumid; - } -} +/* + * + */ +package org.redkale.test.source.parser; + +import java.io.Serializable; + +/** @author zhangjx */ +public class ForumBean implements Serializable { + + private String forumSectionid; + + private String forumSectionColor; + + private String forumid; + + public String getForumSectionid() { + return forumSectionid; + } + + public void setForumSectionid(String forumSectionid) { + this.forumSectionid = forumSectionid; + } + + public String getForumSectionColor() { + return forumSectionColor; + } + + public void setForumSectionColor(String forumSectionColor) { + this.forumSectionColor = forumSectionColor; + } + + public String getForumid() { + return forumid; + } + + public void setForumid(String forumid) { + this.forumid = forumid; + } +} diff --git a/src/test/java/org/redkale/test/source/parser/ForumInfo.java b/src/test/java/org/redkale/test/source/parser/ForumInfo.java index 476bc8412..1878b160e 100644 --- a/src/test/java/org/redkale/test/source/parser/ForumInfo.java +++ b/src/test/java/org/redkale/test/source/parser/ForumInfo.java @@ -1,255 +1,255 @@ -package org.redkale.test.source.parser; - -import java.util.*; -import org.redkale.convert.*; -import org.redkale.persistence.*; -import org.redkale.util.Utility; - -/** @author zhangjx */ -@Table(name = "forum_info", comment = "论坛信息表") -public class ForumInfo extends BaseEntity implements Comparable { - - @Id - @Column(name = "forum_id", length = 64, comment = "论坛ID") - private String forumid; - - @Column(name = "forum_name", length = 128, comment = "论坛的名称") - private String forumName; - - @Column(name = "forum_groupid", length = 64, comment = "论坛分类的ID") - private String forumGroupid; - - @Column(name = "forum_sections", length = 1024, comment = "论坛小版块的ID集合") - private String[] forumSections; - - @Column(name = "forum_managerids", length = 1024, comment = "论坛小版块的ID集合") - private Set forumManagerids; - - @Column(name = "forum_face_url", length = 255, comment = "论坛的图片url") - private String forumFaceUrl; - - @Column(name = "forum_css_img_url", length = 255, comment = "论坛的背景图url") - private String forumCssImgUrl; - - @Column(name = "forum_css_url", length = 255, comment = "论坛的样式url") - private String forumCssUrl; - - @Column(name = "forum_css_content", length = 10240, comment = "论坛的css内容") - private String forumCssContent; - - @Column(name = "forum_bar_html", length = 1024, comment = "版块的提示栏") - private String forumBarHtml; - - @Column(name = "forum_desc", length = 255, comment = "论坛说明") - private String forumDesc; - - @Column(name = "forum_notice", length = 1024, comment = "论坛公告") - private String forumNotice; - - @Column(comment = "被关注的用户数") - private long followers; - - @Column(name = "post_count", comment = "帖子数") - private long postCount; - - @Column(name = "like_count", comment = "关注数") - private long likeCount; - - @Column(comment = "排序顺序,值小靠前") - private int display = 1000; - - @Transient - private Map sections; - - public ForumSection findForumSection(String forumSectionid) { - return sections == null ? null : sections.get(forumSectionid); - } - - public synchronized void increLikeCount() { - this.likeCount++; - } - - public synchronized void increPostCount(String sectionid) { - this.postCount++; - if (sections != null && sectionid != null && !sectionid.isEmpty()) { - ForumSection section = sections.get(sectionid); - if (section != null) { - section.increPostCount(); - } - } - } - - public synchronized void increFollowers() { - this.followers++; - } - - public synchronized void decreFollowers() { - this.followers--; - } - - public boolean containsManagerid(int userid) { - return forumManagerids != null && forumManagerids.contains(userid); - } - - public boolean containsSection(String forumSectionid) { - return forumSections != null && forumSectionid != null && Utility.contains(forumSections, forumSectionid); - } - - public boolean emptyForumNotice() { - return this.forumNotice == null || this.forumNotice.isEmpty(); - } - - public boolean emptyCssImgUrl() { - return this.forumCssImgUrl == null || this.forumCssImgUrl.isEmpty(); - } - - public boolean emptyCssUrl() { - return this.forumCssUrl == null || this.forumCssUrl.isEmpty(); - } - - public boolean emptyCssContent() { - return this.forumCssContent == null || this.forumCssContent.isEmpty(); - } - - public void setForumid(String forumid) { - this.forumid = forumid; - } - - public String getForumid() { - return this.forumid; - } - - public void setForumName(String forumName) { - this.forumName = forumName; - } - - public String getForumName() { - return this.forumName; - } - - public void setForumFaceUrl(String forumFaceUrl) { - this.forumFaceUrl = forumFaceUrl; - } - - public String getForumFaceUrl() { - return this.forumFaceUrl; - } - - public String getForumCssImgUrl() { - return forumCssImgUrl; - } - - public void setForumCssImgUrl(String forumCssImgUrl) { - this.forumCssImgUrl = forumCssImgUrl; - } - - public String getForumCssUrl() { - return forumCssUrl; - } - - public void setForumCssUrl(String forumCssUrl) { - this.forumCssUrl = forumCssUrl; - } - - public String getForumCssContent() { - return forumCssContent; - } - - public void setForumCssContent(String forumCssContent) { - this.forumCssContent = forumCssContent; - } - - public String[] getForumSections() { - return forumSections; - } - - public void setForumSections(String[] forumSections) { - this.forumSections = forumSections; - } - - public Set getForumManagerids() { - return forumManagerids; - } - - public void setForumManagerids(Set forumManagerids) { - this.forumManagerids = forumManagerids; - } - - public String getForumGroupid() { - return forumGroupid; - } - - public void setForumGroupid(String forumGroupid) { - this.forumGroupid = forumGroupid; - } - - public String getForumDesc() { - return forumDesc; - } - - public void setForumDesc(String forumDesc) { - this.forumDesc = forumDesc; - } - - public String getForumNotice() { - return forumNotice; - } - - public void setForumNotice(String forumNotice) { - this.forumNotice = forumNotice; - } - - public long getFollowers() { - return followers; - } - - public void setFollowers(long followers) { - this.followers = followers; - } - - public void setPostCount(long postCount) { - this.postCount = postCount; - } - - public long getPostCount() { - return this.postCount; - } - - public long getLikeCount() { - return likeCount; - } - - public void setLikeCount(long likeCount) { - this.likeCount = likeCount; - } - - public void setDisplay(int display) { - this.display = display; - } - - @ConvertColumn(ignore = true, type = ConvertType.PROTOBUF_JSON) - public int getDisplay() { - return this.display; - } - - @Override - public int compareTo(ForumInfo o) { - return this.display - o.display; - } - - public Map getSections() { - return sections; - } - - public void setSections(Map sections) { - this.sections = sections; - } - - public String getForumBarHtml() { - return forumBarHtml; - } - - public void setForumBarHtml(String forumBarHtml) { - this.forumBarHtml = forumBarHtml; - } -} +package org.redkale.test.source.parser; + +import java.util.*; +import org.redkale.convert.*; +import org.redkale.persistence.*; +import org.redkale.util.Utility; + +/** @author zhangjx */ +@Table(name = "forum_info", comment = "论坛信息表") +public class ForumInfo extends BaseEntity implements Comparable { + + @Id + @Column(name = "forum_id", length = 64, comment = "论坛ID") + private String forumid; + + @Column(name = "forum_name", length = 128, comment = "论坛的名称") + private String forumName; + + @Column(name = "forum_groupid", length = 64, comment = "论坛分类的ID") + private String forumGroupid; + + @Column(name = "forum_sections", length = 1024, comment = "论坛小版块的ID集合") + private String[] forumSections; + + @Column(name = "forum_managerids", length = 1024, comment = "论坛小版块的ID集合") + private Set forumManagerids; + + @Column(name = "forum_face_url", length = 255, comment = "论坛的图片url") + private String forumFaceUrl; + + @Column(name = "forum_css_img_url", length = 255, comment = "论坛的背景图url") + private String forumCssImgUrl; + + @Column(name = "forum_css_url", length = 255, comment = "论坛的样式url") + private String forumCssUrl; + + @Column(name = "forum_css_content", length = 10240, comment = "论坛的css内容") + private String forumCssContent; + + @Column(name = "forum_bar_html", length = 1024, comment = "版块的提示栏") + private String forumBarHtml; + + @Column(name = "forum_desc", length = 255, comment = "论坛说明") + private String forumDesc; + + @Column(name = "forum_notice", length = 1024, comment = "论坛公告") + private String forumNotice; + + @Column(comment = "被关注的用户数") + private long followers; + + @Column(name = "post_count", comment = "帖子数") + private long postCount; + + @Column(name = "like_count", comment = "关注数") + private long likeCount; + + @Column(comment = "排序顺序,值小靠前") + private int display = 1000; + + @Transient + private Map sections; + + public ForumSection findForumSection(String forumSectionid) { + return sections == null ? null : sections.get(forumSectionid); + } + + public synchronized void increLikeCount() { + this.likeCount++; + } + + public synchronized void increPostCount(String sectionid) { + this.postCount++; + if (sections != null && sectionid != null && !sectionid.isEmpty()) { + ForumSection section = sections.get(sectionid); + if (section != null) { + section.increPostCount(); + } + } + } + + public synchronized void increFollowers() { + this.followers++; + } + + public synchronized void decreFollowers() { + this.followers--; + } + + public boolean containsManagerid(int userid) { + return forumManagerids != null && forumManagerids.contains(userid); + } + + public boolean containsSection(String forumSectionid) { + return forumSections != null && forumSectionid != null && Utility.contains(forumSections, forumSectionid); + } + + public boolean emptyForumNotice() { + return this.forumNotice == null || this.forumNotice.isEmpty(); + } + + public boolean emptyCssImgUrl() { + return this.forumCssImgUrl == null || this.forumCssImgUrl.isEmpty(); + } + + public boolean emptyCssUrl() { + return this.forumCssUrl == null || this.forumCssUrl.isEmpty(); + } + + public boolean emptyCssContent() { + return this.forumCssContent == null || this.forumCssContent.isEmpty(); + } + + public void setForumid(String forumid) { + this.forumid = forumid; + } + + public String getForumid() { + return this.forumid; + } + + public void setForumName(String forumName) { + this.forumName = forumName; + } + + public String getForumName() { + return this.forumName; + } + + public void setForumFaceUrl(String forumFaceUrl) { + this.forumFaceUrl = forumFaceUrl; + } + + public String getForumFaceUrl() { + return this.forumFaceUrl; + } + + public String getForumCssImgUrl() { + return forumCssImgUrl; + } + + public void setForumCssImgUrl(String forumCssImgUrl) { + this.forumCssImgUrl = forumCssImgUrl; + } + + public String getForumCssUrl() { + return forumCssUrl; + } + + public void setForumCssUrl(String forumCssUrl) { + this.forumCssUrl = forumCssUrl; + } + + public String getForumCssContent() { + return forumCssContent; + } + + public void setForumCssContent(String forumCssContent) { + this.forumCssContent = forumCssContent; + } + + public String[] getForumSections() { + return forumSections; + } + + public void setForumSections(String[] forumSections) { + this.forumSections = forumSections; + } + + public Set getForumManagerids() { + return forumManagerids; + } + + public void setForumManagerids(Set forumManagerids) { + this.forumManagerids = forumManagerids; + } + + public String getForumGroupid() { + return forumGroupid; + } + + public void setForumGroupid(String forumGroupid) { + this.forumGroupid = forumGroupid; + } + + public String getForumDesc() { + return forumDesc; + } + + public void setForumDesc(String forumDesc) { + this.forumDesc = forumDesc; + } + + public String getForumNotice() { + return forumNotice; + } + + public void setForumNotice(String forumNotice) { + this.forumNotice = forumNotice; + } + + public long getFollowers() { + return followers; + } + + public void setFollowers(long followers) { + this.followers = followers; + } + + public void setPostCount(long postCount) { + this.postCount = postCount; + } + + public long getPostCount() { + return this.postCount; + } + + public long getLikeCount() { + return likeCount; + } + + public void setLikeCount(long likeCount) { + this.likeCount = likeCount; + } + + public void setDisplay(int display) { + this.display = display; + } + + @ConvertColumn(ignore = true, type = ConvertType.PROTOBUF_JSON) + public int getDisplay() { + return this.display; + } + + @Override + public int compareTo(ForumInfo o) { + return this.display - o.display; + } + + public Map getSections() { + return sections; + } + + public void setSections(Map sections) { + this.sections = sections; + } + + public String getForumBarHtml() { + return forumBarHtml; + } + + public void setForumBarHtml(String forumBarHtml) { + this.forumBarHtml = forumBarHtml; + } +} diff --git a/src/test/java/org/redkale/test/source/parser/ForumInfoMapper.java b/src/test/java/org/redkale/test/source/parser/ForumInfoMapper.java index 1b451c4a4..a403e887a 100644 --- a/src/test/java/org/redkale/test/source/parser/ForumInfoMapper.java +++ b/src/test/java/org/redkale/test/source/parser/ForumInfoMapper.java @@ -1,41 +1,41 @@ -/* - * - */ -package org.redkale.test.source.parser; - -import java.util.List; -import java.util.concurrent.CompletableFuture; -import org.redkale.annotation.Param; -import org.redkale.persistence.Sql; - -/** @author zhangjx */ -public interface ForumInfoMapper extends BaseMapper { - - @Sql("SELECT f.forum_groupid, s.forum_section_color " - + "FROM forum_info f, forum_section s " - + " WHERE f.forumid = s.forumid AND " - + "s.forum_sectionid = #{bean.forumSectionid} AND " - + "f.forumid = #{bean.forumid} AND s.forum_section_color = #{bean.forumSectionColor}") - public ForumResult findForumResult(ForumBean bean); - - @Sql("SELECT f.forum_groupid, s.forum_section_color " - + "FROM forum_info f, forum_section s " - + " WHERE f.forumid = s.forumid AND " - + "s.forum_sectionid = #{bean.forumSectionid} AND " - + "f.forumid = #{bean.forumid} AND s.forum_section_color = #{bean.forumSectionColor}") - public CompletableFuture findForumResultAsync(ForumBean bean); - - @Sql("SELECT f.forum_groupid, s.forum_section_color " - + "FROM forum_info f, forum_section s " - + " WHERE f.forumid = s.forumid AND " - + "s.forum_sectionid = #{bean.forumSectionid} AND " - + "f.forumid = #{bean.forumid} AND s.forum_section_color = #{bean.forumSectionColor}") - public List queryForumResult(@Param("bean") ForumBean bean0); - - @Sql("SELECT f.forum_groupid, s.forum_section_color " - + "FROM forum_info f, forum_section s " - + " WHERE f.forumid = s.forumid AND " - + "s.forum_sectionid = #{bean.forumSectionid} AND " - + "f.forumid = #{bean.forumid} AND s.forum_section_color = #{bean.forumSectionColor}") - public CompletableFuture> queryForumResultAsync(ForumBean bean); -} +/* + * + */ +package org.redkale.test.source.parser; + +import java.util.List; +import java.util.concurrent.CompletableFuture; +import org.redkale.annotation.Param; +import org.redkale.persistence.Sql; + +/** @author zhangjx */ +public interface ForumInfoMapper extends BaseMapper { + + @Sql("SELECT f.forum_groupid, s.forum_section_color " + + "FROM forum_info f, forum_section s " + + " WHERE f.forumid = s.forumid AND " + + "s.forum_sectionid = #{bean.forumSectionid} AND " + + "f.forumid = #{bean.forumid} AND s.forum_section_color = #{bean.forumSectionColor}") + public ForumResult findForumResult(ForumBean bean); + + @Sql("SELECT f.forum_groupid, s.forum_section_color " + + "FROM forum_info f, forum_section s " + + " WHERE f.forumid = s.forumid AND " + + "s.forum_sectionid = #{bean.forumSectionid} AND " + + "f.forumid = #{bean.forumid} AND s.forum_section_color = #{bean.forumSectionColor}") + public CompletableFuture findForumResultAsync(ForumBean bean); + + @Sql("SELECT f.forum_groupid, s.forum_section_color " + + "FROM forum_info f, forum_section s " + + " WHERE f.forumid = s.forumid AND " + + "s.forum_sectionid = #{bean.forumSectionid} AND " + + "f.forumid = #{bean.forumid} AND s.forum_section_color = #{bean.forumSectionColor}") + public List queryForumResult(@Param("bean") ForumBean bean0); + + @Sql("SELECT f.forum_groupid, s.forum_section_color " + + "FROM forum_info f, forum_section s " + + " WHERE f.forumid = s.forumid AND " + + "s.forum_sectionid = #{bean.forumSectionid} AND " + + "f.forumid = #{bean.forumid} AND s.forum_section_color = #{bean.forumSectionColor}") + public CompletableFuture> queryForumResultAsync(ForumBean bean); +} diff --git a/src/test/java/org/redkale/test/source/parser/ForumResult.java b/src/test/java/org/redkale/test/source/parser/ForumResult.java index 367ba31a9..b53e1858d 100644 --- a/src/test/java/org/redkale/test/source/parser/ForumResult.java +++ b/src/test/java/org/redkale/test/source/parser/ForumResult.java @@ -1,35 +1,35 @@ -/* - * - */ -package org.redkale.test.source.parser; - -import org.redkale.convert.json.JsonConvert; - -/** @author zhangjx */ -public class ForumResult { - - private String forumGroupid; - - private String forumSectionColor; - - public String getForumGroupid() { - return forumGroupid; - } - - public void setForumGroupid(String forumGroupid) { - this.forumGroupid = forumGroupid; - } - - public String getForumSectionColor() { - return forumSectionColor; - } - - public void setForumSectionColor(String forumSectionColor) { - this.forumSectionColor = forumSectionColor; - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } -} +/* + * + */ +package org.redkale.test.source.parser; + +import org.redkale.convert.json.JsonConvert; + +/** @author zhangjx */ +public class ForumResult { + + private String forumGroupid; + + private String forumSectionColor; + + public String getForumGroupid() { + return forumGroupid; + } + + public void setForumGroupid(String forumGroupid) { + this.forumGroupid = forumGroupid; + } + + public String getForumSectionColor() { + return forumSectionColor; + } + + public void setForumSectionColor(String forumSectionColor) { + this.forumSectionColor = forumSectionColor; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } +} diff --git a/src/test/java/org/redkale/test/source/parser/ForumSection.java b/src/test/java/org/redkale/test/source/parser/ForumSection.java index 7ffed2ccb..a836f659a 100644 --- a/src/test/java/org/redkale/test/source/parser/ForumSection.java +++ b/src/test/java/org/redkale/test/source/parser/ForumSection.java @@ -1,130 +1,130 @@ -package org.redkale.test.source.parser; - -import java.util.Set; -import org.redkale.convert.*; -import org.redkale.persistence.*; - -/** @author zhangjx */ -@Table(name = "forum_section", comment = "论坛小版块信息表") -public class ForumSection extends BaseEntity { - - @Id - @Column(name = "forum_sectionid", length = 64, comment = "论坛小版块ID") - private String forumSectionid; - - @Column(length = 64, comment = "论坛ID") - private String forumid; - - @Column(name = "forum_section_name", length = 128, comment = "论坛小版块的名称") - private String forumSectionName; - - @Column(name = "forum_section_face_url", length = 255, comment = "论坛小版块的图标url") - private String forumSectionFaceUrl; - - @Column(name = "forum_section_managerids", length = 1024, comment = "论坛小版块的ID集合") - private Set forumSectionManagerids; - - @Column(name = "forum_section_desc", length = 32, comment = "论坛小版块说明") - private String forumSectionDesc; - - @Column(name = "forum_section_color", length = 255, comment = "论坛小版块小标题的背景色") - private String forumSectionColor; - - @Column(name = "forum_section_bar_html", length = 1024, comment = "版块的提示栏") - private String forumSectionBarHtml; - - @Column(name = "post_count", comment = "帖子数") - private long postCount; - - @Column(comment = "排序顺序,值小靠前") - private int display = 1000; - - public void increPostCount() { - this.postCount++; - } - - public boolean containsSectionManagerid(int userid) { - return forumSectionManagerids != null && forumSectionManagerids.contains(userid); - } - - public void setForumSectionid(String forumSectionid) { - this.forumSectionid = forumSectionid; - } - - public String getForumSectionid() { - return this.forumSectionid; - } - - public String getForumid() { - return forumid; - } - - public void setForumid(String forumid) { - this.forumid = forumid; - } - - public void setForumSectionName(String forumSectionName) { - this.forumSectionName = forumSectionName; - } - - public String getForumSectionName() { - return this.forumSectionName; - } - - public void setForumSectionFaceUrl(String forumSectionFaceUrl) { - this.forumSectionFaceUrl = forumSectionFaceUrl; - } - - public String getForumSectionFaceUrl() { - return this.forumSectionFaceUrl; - } - - public String getForumSectionColor() { - return forumSectionColor; - } - - public void setForumSectionColor(String forumSectionColor) { - this.forumSectionColor = forumSectionColor; - } - - public void setForumSectionDesc(String forumSectionDesc) { - this.forumSectionDesc = forumSectionDesc; - } - - public Set getForumSectionManagerids() { - return forumSectionManagerids; - } - - public void setForumSectionManagerids(Set forumSectionManagerids) { - this.forumSectionManagerids = forumSectionManagerids; - } - - public String getForumSectionDesc() { - return this.forumSectionDesc; - } - - public void setPostCount(long postCount) { - this.postCount = postCount; - } - - public long getPostCount() { - return this.postCount; - } - - public void setDisplay(int display) { - this.display = display; - } - - @ConvertColumn(ignore = true, type = ConvertType.PROTOBUF_JSON) - public int getDisplay() { - return this.display; - } - - public String getForumSectionBarHtml() { - return forumSectionBarHtml; - } - - public void setForumSectionBarHtml(String forumSectionBarHtml) { - this.forumSectionBarHtml = forumSectionBarHtml; - } -} +package org.redkale.test.source.parser; + +import java.util.Set; +import org.redkale.convert.*; +import org.redkale.persistence.*; + +/** @author zhangjx */ +@Table(name = "forum_section", comment = "论坛小版块信息表") +public class ForumSection extends BaseEntity { + + @Id + @Column(name = "forum_sectionid", length = 64, comment = "论坛小版块ID") + private String forumSectionid; + + @Column(length = 64, comment = "论坛ID") + private String forumid; + + @Column(name = "forum_section_name", length = 128, comment = "论坛小版块的名称") + private String forumSectionName; + + @Column(name = "forum_section_face_url", length = 255, comment = "论坛小版块的图标url") + private String forumSectionFaceUrl; + + @Column(name = "forum_section_managerids", length = 1024, comment = "论坛小版块的ID集合") + private Set forumSectionManagerids; + + @Column(name = "forum_section_desc", length = 32, comment = "论坛小版块说明") + private String forumSectionDesc; + + @Column(name = "forum_section_color", length = 255, comment = "论坛小版块小标题的背景色") + private String forumSectionColor; + + @Column(name = "forum_section_bar_html", length = 1024, comment = "版块的提示栏") + private String forumSectionBarHtml; + + @Column(name = "post_count", comment = "帖子数") + private long postCount; + + @Column(comment = "排序顺序,值小靠前") + private int display = 1000; + + public void increPostCount() { + this.postCount++; + } + + public boolean containsSectionManagerid(int userid) { + return forumSectionManagerids != null && forumSectionManagerids.contains(userid); + } + + public void setForumSectionid(String forumSectionid) { + this.forumSectionid = forumSectionid; + } + + public String getForumSectionid() { + return this.forumSectionid; + } + + public String getForumid() { + return forumid; + } + + public void setForumid(String forumid) { + this.forumid = forumid; + } + + public void setForumSectionName(String forumSectionName) { + this.forumSectionName = forumSectionName; + } + + public String getForumSectionName() { + return this.forumSectionName; + } + + public void setForumSectionFaceUrl(String forumSectionFaceUrl) { + this.forumSectionFaceUrl = forumSectionFaceUrl; + } + + public String getForumSectionFaceUrl() { + return this.forumSectionFaceUrl; + } + + public String getForumSectionColor() { + return forumSectionColor; + } + + public void setForumSectionColor(String forumSectionColor) { + this.forumSectionColor = forumSectionColor; + } + + public void setForumSectionDesc(String forumSectionDesc) { + this.forumSectionDesc = forumSectionDesc; + } + + public Set getForumSectionManagerids() { + return forumSectionManagerids; + } + + public void setForumSectionManagerids(Set forumSectionManagerids) { + this.forumSectionManagerids = forumSectionManagerids; + } + + public String getForumSectionDesc() { + return this.forumSectionDesc; + } + + public void setPostCount(long postCount) { + this.postCount = postCount; + } + + public long getPostCount() { + return this.postCount; + } + + public void setDisplay(int display) { + this.display = display; + } + + @ConvertColumn(ignore = true, type = ConvertType.PROTOBUF_JSON) + public int getDisplay() { + return this.display; + } + + public String getForumSectionBarHtml() { + return forumSectionBarHtml; + } + + public void setForumSectionBarHtml(String forumSectionBarHtml) { + this.forumSectionBarHtml = forumSectionBarHtml; + } +} diff --git a/src/test/java/org/redkale/test/type/OneBean.java b/src/test/java/org/redkale/test/type/OneBean.java index 2d90d76bb..29d9fa1b2 100644 --- a/src/test/java/org/redkale/test/type/OneBean.java +++ b/src/test/java/org/redkale/test/type/OneBean.java @@ -1,12 +1,12 @@ -/* - * 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.test.type; - -/** @author zhangjx */ -public class OneBean { - - public int id; -} +/* + * 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.test.type; + +/** @author zhangjx */ +public class OneBean { + + public int id; +} diff --git a/src/test/java/org/redkale/test/type/OneRound.java b/src/test/java/org/redkale/test/type/OneRound.java index 67c1806d4..d6b37c4d3 100644 --- a/src/test/java/org/redkale/test/type/OneRound.java +++ b/src/test/java/org/redkale/test/type/OneRound.java @@ -1,9 +1,9 @@ -/* - * 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.test.type; - -/** @author zhangjx */ -public class OneRound {} +/* + * 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.test.type; + +/** @author zhangjx */ +public class OneRound {} diff --git a/src/test/java/org/redkale/test/type/OneService.java b/src/test/java/org/redkale/test/type/OneService.java index 3ac1eda3d..6853220ee 100644 --- a/src/test/java/org/redkale/test/type/OneService.java +++ b/src/test/java/org/redkale/test/type/OneService.java @@ -1,20 +1,20 @@ -/* - * 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.test.type; - -import org.redkale.service.RetResult; - -/** - * @author zhangjx - * @param - * @param - */ -public class OneService { - - public RetResult run(OR round, OB bean) { - return RetResult.success(); - } -} +/* + * 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.test.type; + +import org.redkale.service.RetResult; + +/** + * @author zhangjx + * @param + * @param + */ +public class OneService { + + public RetResult run(OR round, OB bean) { + return RetResult.success(); + } +} diff --git a/src/test/java/org/redkale/test/type/ThreeBean.java b/src/test/java/org/redkale/test/type/ThreeBean.java index 22af5a7c5..b985c36d6 100644 --- a/src/test/java/org/redkale/test/type/ThreeBean.java +++ b/src/test/java/org/redkale/test/type/ThreeBean.java @@ -1,12 +1,12 @@ -/* - * 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.test.type; - -/** @author zhangjx */ -public class ThreeBean extends TwoBean { - - public String desc; -} +/* + * 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.test.type; + +/** @author zhangjx */ +public class ThreeBean extends TwoBean { + + public String desc; +} diff --git a/src/test/java/org/redkale/test/type/ThreeRound.java b/src/test/java/org/redkale/test/type/ThreeRound.java index e8d23ff1a..1e4eaab1f 100644 --- a/src/test/java/org/redkale/test/type/ThreeRound.java +++ b/src/test/java/org/redkale/test/type/ThreeRound.java @@ -1,9 +1,9 @@ -/* - * 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.test.type; - -/** @author zhangjx */ -public class ThreeRound extends TwoRound {} +/* + * 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.test.type; + +/** @author zhangjx */ +public class ThreeRound extends TwoRound {} diff --git a/src/test/java/org/redkale/test/type/ThreeService.java b/src/test/java/org/redkale/test/type/ThreeService.java index 3b60206df..df197ed7a 100644 --- a/src/test/java/org/redkale/test/type/ThreeService.java +++ b/src/test/java/org/redkale/test/type/ThreeService.java @@ -1,20 +1,20 @@ -/* - * 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.test.type; - -/** - * @author zhangjx - * @param - * @param - * @param - */ -public class ThreeService - extends OneService { - - public String key(K key) { - return "" + key; - } -} +/* + * 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.test.type; + +/** + * @author zhangjx + * @param + * @param + * @param + */ +public class ThreeService + extends OneService { + + public String key(K key) { + return "" + key; + } +} diff --git a/src/test/java/org/redkale/test/type/TwoBean.java b/src/test/java/org/redkale/test/type/TwoBean.java index 807854261..c31ca1368 100644 --- a/src/test/java/org/redkale/test/type/TwoBean.java +++ b/src/test/java/org/redkale/test/type/TwoBean.java @@ -1,12 +1,12 @@ -/* - * 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.test.type; - -/** @author zhangjx */ -public class TwoBean extends OneBean { - - public String name; -} +/* + * 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.test.type; + +/** @author zhangjx */ +public class TwoBean extends OneBean { + + public String name; +} diff --git a/src/test/java/org/redkale/test/type/TwoRound.java b/src/test/java/org/redkale/test/type/TwoRound.java index 96b7deb42..d2b18307d 100644 --- a/src/test/java/org/redkale/test/type/TwoRound.java +++ b/src/test/java/org/redkale/test/type/TwoRound.java @@ -1,9 +1,9 @@ -/* - * 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.test.type; - -/** @author zhangjx */ -public class TwoRound extends OneRound {} +/* + * 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.test.type; + +/** @author zhangjx */ +public class TwoRound extends OneRound {} diff --git a/src/test/java/org/redkale/test/type/TwoService.java b/src/test/java/org/redkale/test/type/TwoService.java index 4c7423c07..8e11f1bdd 100644 --- a/src/test/java/org/redkale/test/type/TwoService.java +++ b/src/test/java/org/redkale/test/type/TwoService.java @@ -1,13 +1,13 @@ -/* - * 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.test.type; - -/** - * @author zhangjx - * @param - * @param - */ -public class TwoService extends OneService {} +/* + * 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.test.type; + +/** + * @author zhangjx + * @param + * @param + */ +public class TwoService extends OneService {} diff --git a/src/test/java/org/redkale/test/type/TypeTokenTest.java b/src/test/java/org/redkale/test/type/TypeTokenTest.java index 40bc83b4e..56e99a9da 100644 --- a/src/test/java/org/redkale/test/type/TypeTokenTest.java +++ b/src/test/java/org/redkale/test/type/TypeTokenTest.java @@ -1,43 +1,43 @@ -/* - * 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.test.type; - -import java.lang.reflect.*; -import org.junit.jupiter.api.*; -import org.redkale.util.TypeToken; - -/** @author zhangjx */ -public class TypeTokenTest { - - private boolean main; - - public static void main(String[] args) throws Throwable { - TypeTokenTest test = new TypeTokenTest(); - test.main = true; - test.run(); - } - - @Test - public void run() throws Exception { - Class declaringClass = ThreeService.class; - ParameterizedType declaringType = (ParameterizedType) declaringClass.getGenericSuperclass(); - System.out.println("getRawType:" + declaringType.getRawType()); - TypeVariable argType0 = (TypeVariable) declaringType.getActualTypeArguments()[0]; - System.out.println("argType0.getBounds[0]:" + argType0.getBounds()[0]); - - for (Method method : declaringClass.getMethods()) { - if (!"run".equals(method.getName())) continue; - if (!main) - Assertions.assertEquals( - ThreeRound.class, - TypeToken.getGenericType(method.getGenericParameterTypes()[0], declaringClass)); - System.out.println("返回值应该是: " + ThreeRound.class); - System.out.println( - "返回值结果是: " + TypeToken.getGenericType(method.getGenericParameterTypes()[0], declaringClass)); - break; - } - } -} +/* + * 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.test.type; + +import java.lang.reflect.*; +import org.junit.jupiter.api.*; +import org.redkale.util.TypeToken; + +/** @author zhangjx */ +public class TypeTokenTest { + + private boolean main; + + public static void main(String[] args) throws Throwable { + TypeTokenTest test = new TypeTokenTest(); + test.main = true; + test.run(); + } + + @Test + public void run() throws Exception { + Class declaringClass = ThreeService.class; + ParameterizedType declaringType = (ParameterizedType) declaringClass.getGenericSuperclass(); + System.out.println("getRawType:" + declaringType.getRawType()); + TypeVariable argType0 = (TypeVariable) declaringType.getActualTypeArguments()[0]; + System.out.println("argType0.getBounds[0]:" + argType0.getBounds()[0]); + + for (Method method : declaringClass.getMethods()) { + if (!"run".equals(method.getName())) continue; + if (!main) + Assertions.assertEquals( + ThreeRound.class, + TypeToken.getGenericType(method.getGenericParameterTypes()[0], declaringClass)); + System.out.println("返回值应该是: " + ThreeRound.class); + System.out.println( + "返回值结果是: " + TypeToken.getGenericType(method.getGenericParameterTypes()[0], declaringClass)); + break; + } + } +} diff --git a/src/test/java/org/redkale/test/util/CopierBeanMap.java b/src/test/java/org/redkale/test/util/CopierBeanMap.java index c0ce78d1f..b82495cd4 100644 --- a/src/test/java/org/redkale/test/util/CopierBeanMap.java +++ b/src/test/java/org/redkale/test/util/CopierBeanMap.java @@ -1,48 +1,48 @@ -/* - * 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.test.util; - -import java.util.Map; -import org.redkale.util.Copier; - -/** @author zhangjx */ -public class CopierBeanMap implements Copier> { - - @Override - public Map apply(TestInterface src, Map dest) { - Object v; - dest.put("id", src.getId()); - - v = src.getMap(); - if (v != null) { - dest.put("map", v); - } - return dest; - } - - public Map run(TestBean src, Map dest) { - Object v; - - v = src.getName(); - if (v != null) { - dest.put("name", v); - } - - v = src.time; - if (v != null) { - dest.put("time", v); - } - - dest.put("id", src.getId()); - - v = src.getName(); - if (v != null) { - dest.put("name", v); - } - // - return dest; - } -} +/* + * 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.test.util; + +import java.util.Map; +import org.redkale.util.Copier; + +/** @author zhangjx */ +public class CopierBeanMap implements Copier> { + + @Override + public Map apply(TestInterface src, Map dest) { + Object v; + dest.put("id", src.getId()); + + v = src.getMap(); + if (v != null) { + dest.put("map", v); + } + return dest; + } + + public Map run(TestBean src, Map dest) { + Object v; + + v = src.getName(); + if (v != null) { + dest.put("name", v); + } + + v = src.time; + if (v != null) { + dest.put("time", v); + } + + dest.put("id", src.getId()); + + v = src.getName(); + if (v != null) { + dest.put("name", v); + } + // + return dest; + } +} diff --git a/src/test/java/org/redkale/test/util/CopierMapBean.java b/src/test/java/org/redkale/test/util/CopierMapBean.java index 76a1c60c1..7eee447d2 100644 --- a/src/test/java/org/redkale/test/util/CopierMapBean.java +++ b/src/test/java/org/redkale/test/util/CopierMapBean.java @@ -1,31 +1,31 @@ -/* - * 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.test.util; - -import java.util.*; -import org.redkale.util.*; - -/** @author zhangjx */ -public class CopierMapBean implements Copier { - - @Override - public TestBean apply(HashMap src, TestBean dest) { - src.forEach((k, v) -> { - if ("id".equals(k) && v != null) { - dest.setId(Utility.convertValue(int.class, v)); - } else if ("map".equals(k)) { - dest.setMap(Utility.convertValue(Map.class, v)); - } else if ("map2".equals(k) && v != null) { - dest.setMap(Utility.convertValue(Map.class, v)); - } else if ("time".equals(k)) { - dest.time = Utility.convertValue(long.class, v); - } else { - - } - }); - return dest; - } -} +/* + * 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.test.util; + +import java.util.*; +import org.redkale.util.*; + +/** @author zhangjx */ +public class CopierMapBean implements Copier { + + @Override + public TestBean apply(HashMap src, TestBean dest) { + src.forEach((k, v) -> { + if ("id".equals(k) && v != null) { + dest.setId(Utility.convertValue(int.class, v)); + } else if ("map".equals(k)) { + dest.setMap(Utility.convertValue(Map.class, v)); + } else if ("map2".equals(k) && v != null) { + dest.setMap(Utility.convertValue(Map.class, v)); + } else if ("time".equals(k)) { + dest.time = Utility.convertValue(long.class, v); + } else { + + } + }); + return dest; + } +} diff --git a/src/test/java/org/redkale/test/util/CopierTest.java b/src/test/java/org/redkale/test/util/CopierTest.java index 7e5ff8e8e..fbdb5e2ce 100644 --- a/src/test/java/org/redkale/test/util/CopierTest.java +++ b/src/test/java/org/redkale/test/util/CopierTest.java @@ -1,623 +1,623 @@ -/* - * 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.test.util; - -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Function; -import org.junit.jupiter.api.*; -import org.redkale.convert.json.JsonConvert; -import org.redkale.util.*; - -/** @author zhangjx */ -public class CopierTest { - - public static void main(String[] args) throws Throwable { - CopierTest test = new CopierTest(); - test.run1(); - test.run2(); - test.run3(); - test.run4(); - test.run5(); - test.run6(); - test.run7(); - test.run8(); - test.run9(); - test.run10(); - test.run11(); - test.run12(); - test.run13(); - test.run14(); - test.run15(); - test.run16(); - test.run17(); - test.run18(); - test.run19(); - test.run20(); - test.run21(); - } - - @Test - public void run1() throws Exception { - TestBean bean = new TestBean(); - bean.setId(222); - bean.time = 55555L; - bean.setName("haha"); - bean.setMap(Utility.ofMap("aa", "bbb")); - Map map = new TreeMap(Copier.copy(bean, Map.class)); - System.out.println(JsonConvert.root().convertTo(map)); - TreeMap rs = Copier.copy(bean, TreeMap.class); - rs.remove("remark"); - rs.remove("seqno"); - Assertions.assertEquals(bean.toString(), JsonConvert.root().convertTo(rs)); - } - - @Test - public void run2() throws Exception { - TestBean bean = new TestBean(); - bean.setId(222); - bean.time = 55555L; - bean.setName("haha"); - bean.setMap(Utility.ofMap("aa", "bbb")); - TreeMap rs = new TreeMap(); - Copier.load(TestInterface.class, Map.class).apply(bean, rs); - System.out.println(JsonConvert.root().convertTo(rs)); - } - - @Test - public void run3() throws Exception { - Map map = new LinkedHashMap(); - map.put("name", "haha"); - map.put("time", "55555"); - map.put("id", "222"); - map.put("map", Utility.ofMap("aa", "bbb")); - TestBean bean = new TestBean(); - TestInterface ti = Copier.load(Map.class, TestInterface.class).apply(map, new TestBean()); - ; - Assertions.assertEquals( - "{\"id\":222,\"map\":{\"aa\":\"bbb\"},\"time\":0}", - JsonConvert.root().convertTo(ti)); - } - - @Test - public void run4() throws Exception { - TestBean bean = new TestBean(); - Map map = new TreeMap(); - map.put("name", "haha"); - map.put("time", "55555"); - map.put("id", "222"); - map.put("map", Utility.ofMap("aa", "bbb")); - Copier.load(Map.class, TestBean.class).apply(map, bean); - System.out.println(JsonConvert.root().convertTo(bean)); - map.put("time", 55555L); - map.put("id", 222); - Assertions.assertEquals(bean.toString(), JsonConvert.root().convertTo(map)); - } - - @Test - public void run5() throws Exception { - Map map = new TreeMap(); - map.put("name", "haha"); - map.put("time", "55555"); - map.put("id", "222"); - map.put("map", Utility.ofMap("aa", "bbb")); - Map rs = new TreeMap(); - Copier.load(Map.class, Map.class).apply(map, rs); - System.out.println("Map: " + JsonConvert.root().convertTo(rs)); - Assertions.assertEquals( - JsonConvert.root().convertTo(map), JsonConvert.root().convertTo(rs)); - } - - @Test - public void run6() throws Exception { - TestBean bean = new TestBean(); - bean.setId(222); - bean.time = 55555L; - bean.setName(null); - bean.setMap(Utility.ofMap("aa", "bbb")); - ConcurrentHashMap rs = Copier.copy(bean, ConcurrentHashMap.class); - System.out.println(JsonConvert.root().convertTo(rs)); - System.out.println("------------------------------------------"); - } - - @Test - public void run7() throws Exception { - TestBean bean = new TestBean(); - Map map = new TreeMap(); - map.put("name", "haha"); - map.put("time", "55555"); - map.put("id", null); - map.put("map", Utility.ofMap("aa", "bbb")); - Copier.load(Map.class, TestBean.class).apply(map, bean); - System.out.println(JsonConvert.root().convertTo(bean)); - System.out.println("------------------------------------------"); - } - - @Test - public void run8() throws Exception { - TestBean bean = new TestBean(); - Map map = new TreeMap(); - map.put("name", ""); - map.put("time", "55555"); - map.put("id", null); - map.put("map", Utility.ofMap("aa", "bbb")); - Copier.load(Map.class, TestBean.class, Copier.OPTION_SKIP_EMPTY_STRING).apply(map, bean); - System.out.println(JsonConvert.root().convertTo(bean)); - Assertions.assertTrue(bean.getName() == null); - } - - @Test - public void run9() throws Exception { - TestBean bean = new TestBean(); - bean.remark = "hehehoho"; - Map map = new TreeMap(); - map.put("name", ""); - map.put("time", "55555"); - map.put("id", null); - map.put("remark", null); - map.put("map", Utility.ofMap("aa", "bbb")); - Copier.load(Map.class, TestBean.class).apply(map, bean); - System.out.println(JsonConvert.root().convertTo(bean)); - Assertions.assertTrue(bean.remark == null); - - bean.remark = "hehehoho"; - Copier.load(Map.class, TestBean.class, Copier.OPTION_SKIP_NULL_VALUE).apply(map, bean); - System.out.println(JsonConvert.root().convertTo(bean)); - Assertions.assertTrue(bean.remark != null); - } - - @Test - public void run10() throws Exception { - TestBean bean = new TestBean(); - bean.remark = "hehehoho"; - TestXBean srcBean = new TestXBean(); - srcBean.setName(""); - srcBean.time = 55555; - srcBean.remark = null; - srcBean.setMap(Utility.ofMap("aa", "bbb")); - Copier.load(TestXBean.class, TestBean.class).apply(srcBean, bean); - System.out.println(JsonConvert.root().convertTo(bean)); - Assertions.assertTrue(bean.remark == null); - - bean.remark = "hehehoho"; - Copier.load(TestXBean.class, TestBean.class, Copier.OPTION_SKIP_NULL_VALUE) - .apply(srcBean, bean); - System.out.println(JsonConvert.root().convertTo(bean)); - Assertions.assertTrue(bean.remark != null); - } - - @Test - public void run11() throws Exception { - TestBean bean = new TestBean(); - TestXBean srcBean = new TestXBean(); - srcBean.setName(""); - srcBean.time = 55555; - srcBean.remark = null; - srcBean.setMap(Utility.ofMap("aa", "bbb")); - Copier.load(TestXBean.class, TestBean.class, Copier.OPTION_SKIP_EMPTY_STRING) - .apply(srcBean, bean); - System.out.println(JsonConvert.root().convertTo(bean)); - Assertions.assertTrue(bean.getName() == null); - } - - @Test - public void run12() throws Exception { - TestBean bean = new TestBean(); - bean.remark = "hehehoho"; - TestXBean srcBean = new TestXBean(); - srcBean.setName(""); - srcBean.time = 55555; - srcBean.remark = null; - srcBean.setMap(Utility.ofMap("aa", "bbb")); - Copier.load(TestXBean.class, TestBean.class).apply(srcBean, bean); - System.out.println(JsonConvert.root().convertTo(bean)); - Assertions.assertTrue(bean.remark == null); - - bean.setName(null); - bean.remark = "hehehoho"; - Copier.load(TestXBean.class, TestBean.class, Copier.OPTION_SKIP_NULL_VALUE | Copier.OPTION_SKIP_EMPTY_STRING) - .apply(srcBean, bean); - System.out.println(JsonConvert.root().convertTo(bean)); - Assertions.assertTrue(bean.getName() == null); - } - - @Test - public void run13() throws Exception { - TestBean bean = new TestBean(); - bean.setSeqno(6666L); - // public String remark; - // private Long seqno; - TestX2Bean destBean = new TestX2Bean(); - // public int remark; - // private String seqno; - - Copier.load(TestBean.class, TestX2Bean.class, Copier.OPTION_ALLOW_TYPE_CAST) - .apply(bean, destBean); - System.out.println(JsonConvert.root().convertTo(destBean)); - Assertions.assertEquals("6666", destBean.getSeqno()); - } - - @Test - public void run14() throws Exception { - TestBean bean = new TestBean(); - bean.remark = "444"; - TestX2Bean destBean = new TestX2Bean(); - Copier.load(TestBean.class, TestX2Bean.class, Copier.OPTION_SKIP_NULL_VALUE | Copier.OPTION_ALLOW_TYPE_CAST) - .apply(bean, destBean); - System.out.println(JsonConvert.root().convertTo(destBean)); - Assertions.assertTrue(destBean.remark == 444); - } - - @Test - public void run15() throws Exception { - Bean1 bean1 = new Bean1(); - bean1.intval = "444"; - Bean2 bean2 = new Bean2(); - Copier.load(Bean1.class, Bean2.class, Copier.OPTION_SKIP_NULL_VALUE | Copier.OPTION_ALLOW_TYPE_CAST) - .apply(bean1, bean2); - System.out.println(JsonConvert.root().convertTo(bean2)); - Assertions.assertTrue(bean2.intval == 444); - } - - @Test - public void run16() throws Exception { - Bean3 bean1 = new Bean3(); - bean1.setSeqno(444L); - Bean4 bean2 = new Bean4(); - Copier.load(Bean3.class, Bean4.class, Copier.OPTION_SKIP_NULL_VALUE | Copier.OPTION_ALLOW_TYPE_CAST) - .apply(bean1, bean2); - System.out.println(JsonConvert.root().convertTo(bean2)); - Assertions.assertEquals("444", bean2.getSeqno()); - } - - @Test - public void run17() throws Exception { - Bean4 bean1 = new Bean4(); - bean1.setSeqno("444"); - Bean5 bean2 = new Bean5(); - Copier.load(Bean4.class, Bean5.class, Copier.OPTION_SKIP_NULL_VALUE | Copier.OPTION_ALLOW_TYPE_CAST) - .apply(bean1, bean2); - System.out.println(JsonConvert.root().convertTo(bean2)); - Assertions.assertEquals(444, bean2.getSeqno()); - } - - @Test - public void run18() throws Exception { - Bean4 bean1 = new Bean4(); - bean1.setSeqno("444"); - Bean5 bean2 = new Bean5(); - Copier.load(Bean4.class, Bean5.class, Copier.OPTION_SKIP_NULL_VALUE).apply(bean1, bean2); - System.out.println(JsonConvert.root().convertTo(bean2)); - Assertions.assertEquals(0, bean2.getSeqno()); - } - - @Test - public void run19() throws Exception { - Bean0 bean1 = new Bean0(); - bean1.setCarid(111); - bean1.setUsername("aaa"); - Bean0 bean2 = new Bean0(); - Copier.load(Bean0.class, Bean0.class, Copier.OPTION_SKIP_NULL_VALUE).apply(bean1, bean2); - System.out.println(JsonConvert.root().convertTo(bean2)); - Assertions.assertEquals("aaa", bean2.getUsername()); - } - - @Test - public void run20() throws Exception { - Bean0 bean1 = new Bean0(); - bean1.setCarid(111L); - bean1.setUsername("aaa"); - Bean0 bean2 = new Bean0(); - bean2.setCarid(111L); - bean2.setUsername("bbb"); - Creator.register(Bean0::new); - - System.out.println(Copier.load(Bean0.class, Bean0.class).apply(bean1, new Bean0())); - - Function, Set> funcSet = Copier.funcSet(Bean0.class, Bean0.class); - Set set = funcSet.apply(Arrays.asList(bean1, bean2)); - Assertions.assertEquals(1, set.size()); - - Function, List> funcList = Copier.funcList(Bean0.class, Bean0.class); - List list = funcList.apply(Arrays.asList(bean1, bean2)); - Assertions.assertEquals(2, list.size()); - - System.out.println("--------------------20----------------------"); - } - - @Test - public void run21() throws Exception { - Large21Src src = new Large21Src(); - src.setCurrent(1); - src.setSize(20); - System.out.println(Copier.copy(src, Large21Dest.class, Copier.OPTION_ALLOW_TYPE_CAST)); - System.out.println("--------------------21----------------------"); - } - - public static class Large21Dest extends Large21Page { - - private Integer day; - - public Integer getDay() { - return day; - } - - public void setDay(Integer day) { - this.day = day; - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } - } - - public abstract static class Large21Page { - - private long total; - - private long size; - - private long current; - - private List records; - - public long getTotal() { - return total; - } - - public void setTotal(long total) { - this.total = total; - } - - public long getSize() { - return size; - } - - public Large21Page setSize(long size) { - this.size = size; - return this; - } - - public long getCurrent() { - return current; - } - - public Large21Page setCurrent(long current) { - this.current = current; - return this; - } - - public List getRecords() { - return records; - } - - public void setRecords(List records) { - this.records = records; - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } - } - - public static class Large21Src { - - private Integer current; - - private Integer size; - - private Integer startDay; - - private Integer endDay; - - private List fields; - - public Integer getCurrent() { - return current; - } - - public void setCurrent(Integer current) { - this.current = current; - } - - public Integer getSize() { - return size; - } - - public void setSize(Integer size) { - this.size = size; - } - - public Integer getStartDay() { - return startDay; - } - - public void setStartDay(Integer startDay) { - this.startDay = startDay; - } - - public Integer getEndDay() { - return endDay; - } - - public void setEndDay(Integer endDay) { - this.endDay = endDay; - } - - public List getFields() { - return fields; - } - - public void setFields(List fields) { - this.fields = fields; - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } - } - - public class Bean0 { - - private long carid; - - private int cartype; - - private int userid; - - private String username; - - private String cartitle; - - public Bean0() {} - - public long getCarid() { - return carid; - } - - public Bean0 setCarid(long carid) { - this.carid = carid; - return this; - } - - public int getUserid() { - return userid; - } - - public void setUserid(int userid) { - this.userid = userid; - } - - public String getCartitle() { - return cartitle; - } - - public void setCartitle(String cartitle) { - this.cartitle = cartitle; - } - - public int getCartype() { - return cartype; - } - - public void setCartype(int cartype) { - this.cartype = cartype; - } - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - @Override - public int hashCode() { - int hash = 5; - hash = 59 * hash + (int) (this.carid ^ (this.carid >>> 32)); - return hash; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final Bean0 other = (Bean0) obj; - return this.carid == other.carid; - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } - } - - public static class Bean1 { - - public String intval; - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } - } - - public static class Bean2 { - - public int intval; - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } - } - - public static class Bean3 { - - private Long seqno; - - public Long getSeqno() { - return seqno; - } - - public void setSeqno(Long seqno) { - this.seqno = seqno; - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } - } - - public static class Bean4 { - - private String seqno; - - public String getSeqno() { - return seqno; - } - - public void setSeqno(String seqno) { - this.seqno = seqno; - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } - } - - public static class Bean5 { - - private int seqno; - - public int getSeqno() { - return seqno; - } - - public Bean5 setSeqno(int seqno) { - this.seqno = seqno; - return this; - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } - } -} +/* + * 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.test.util; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; +import org.junit.jupiter.api.*; +import org.redkale.convert.json.JsonConvert; +import org.redkale.util.*; + +/** @author zhangjx */ +public class CopierTest { + + public static void main(String[] args) throws Throwable { + CopierTest test = new CopierTest(); + test.run1(); + test.run2(); + test.run3(); + test.run4(); + test.run5(); + test.run6(); + test.run7(); + test.run8(); + test.run9(); + test.run10(); + test.run11(); + test.run12(); + test.run13(); + test.run14(); + test.run15(); + test.run16(); + test.run17(); + test.run18(); + test.run19(); + test.run20(); + test.run21(); + } + + @Test + public void run1() throws Exception { + TestBean bean = new TestBean(); + bean.setId(222); + bean.time = 55555L; + bean.setName("haha"); + bean.setMap(Utility.ofMap("aa", "bbb")); + Map map = new TreeMap(Copier.copy(bean, Map.class)); + System.out.println(JsonConvert.root().convertTo(map)); + TreeMap rs = Copier.copy(bean, TreeMap.class); + rs.remove("remark"); + rs.remove("seqno"); + Assertions.assertEquals(bean.toString(), JsonConvert.root().convertTo(rs)); + } + + @Test + public void run2() throws Exception { + TestBean bean = new TestBean(); + bean.setId(222); + bean.time = 55555L; + bean.setName("haha"); + bean.setMap(Utility.ofMap("aa", "bbb")); + TreeMap rs = new TreeMap(); + Copier.load(TestInterface.class, Map.class).apply(bean, rs); + System.out.println(JsonConvert.root().convertTo(rs)); + } + + @Test + public void run3() throws Exception { + Map map = new LinkedHashMap(); + map.put("name", "haha"); + map.put("time", "55555"); + map.put("id", "222"); + map.put("map", Utility.ofMap("aa", "bbb")); + TestBean bean = new TestBean(); + TestInterface ti = Copier.load(Map.class, TestInterface.class).apply(map, new TestBean()); + ; + Assertions.assertEquals( + "{\"id\":222,\"map\":{\"aa\":\"bbb\"},\"time\":0}", + JsonConvert.root().convertTo(ti)); + } + + @Test + public void run4() throws Exception { + TestBean bean = new TestBean(); + Map map = new TreeMap(); + map.put("name", "haha"); + map.put("time", "55555"); + map.put("id", "222"); + map.put("map", Utility.ofMap("aa", "bbb")); + Copier.load(Map.class, TestBean.class).apply(map, bean); + System.out.println(JsonConvert.root().convertTo(bean)); + map.put("time", 55555L); + map.put("id", 222); + Assertions.assertEquals(bean.toString(), JsonConvert.root().convertTo(map)); + } + + @Test + public void run5() throws Exception { + Map map = new TreeMap(); + map.put("name", "haha"); + map.put("time", "55555"); + map.put("id", "222"); + map.put("map", Utility.ofMap("aa", "bbb")); + Map rs = new TreeMap(); + Copier.load(Map.class, Map.class).apply(map, rs); + System.out.println("Map: " + JsonConvert.root().convertTo(rs)); + Assertions.assertEquals( + JsonConvert.root().convertTo(map), JsonConvert.root().convertTo(rs)); + } + + @Test + public void run6() throws Exception { + TestBean bean = new TestBean(); + bean.setId(222); + bean.time = 55555L; + bean.setName(null); + bean.setMap(Utility.ofMap("aa", "bbb")); + ConcurrentHashMap rs = Copier.copy(bean, ConcurrentHashMap.class); + System.out.println(JsonConvert.root().convertTo(rs)); + System.out.println("------------------------------------------"); + } + + @Test + public void run7() throws Exception { + TestBean bean = new TestBean(); + Map map = new TreeMap(); + map.put("name", "haha"); + map.put("time", "55555"); + map.put("id", null); + map.put("map", Utility.ofMap("aa", "bbb")); + Copier.load(Map.class, TestBean.class).apply(map, bean); + System.out.println(JsonConvert.root().convertTo(bean)); + System.out.println("------------------------------------------"); + } + + @Test + public void run8() throws Exception { + TestBean bean = new TestBean(); + Map map = new TreeMap(); + map.put("name", ""); + map.put("time", "55555"); + map.put("id", null); + map.put("map", Utility.ofMap("aa", "bbb")); + Copier.load(Map.class, TestBean.class, Copier.OPTION_SKIP_EMPTY_STRING).apply(map, bean); + System.out.println(JsonConvert.root().convertTo(bean)); + Assertions.assertTrue(bean.getName() == null); + } + + @Test + public void run9() throws Exception { + TestBean bean = new TestBean(); + bean.remark = "hehehoho"; + Map map = new TreeMap(); + map.put("name", ""); + map.put("time", "55555"); + map.put("id", null); + map.put("remark", null); + map.put("map", Utility.ofMap("aa", "bbb")); + Copier.load(Map.class, TestBean.class).apply(map, bean); + System.out.println(JsonConvert.root().convertTo(bean)); + Assertions.assertTrue(bean.remark == null); + + bean.remark = "hehehoho"; + Copier.load(Map.class, TestBean.class, Copier.OPTION_SKIP_NULL_VALUE).apply(map, bean); + System.out.println(JsonConvert.root().convertTo(bean)); + Assertions.assertTrue(bean.remark != null); + } + + @Test + public void run10() throws Exception { + TestBean bean = new TestBean(); + bean.remark = "hehehoho"; + TestXBean srcBean = new TestXBean(); + srcBean.setName(""); + srcBean.time = 55555; + srcBean.remark = null; + srcBean.setMap(Utility.ofMap("aa", "bbb")); + Copier.load(TestXBean.class, TestBean.class).apply(srcBean, bean); + System.out.println(JsonConvert.root().convertTo(bean)); + Assertions.assertTrue(bean.remark == null); + + bean.remark = "hehehoho"; + Copier.load(TestXBean.class, TestBean.class, Copier.OPTION_SKIP_NULL_VALUE) + .apply(srcBean, bean); + System.out.println(JsonConvert.root().convertTo(bean)); + Assertions.assertTrue(bean.remark != null); + } + + @Test + public void run11() throws Exception { + TestBean bean = new TestBean(); + TestXBean srcBean = new TestXBean(); + srcBean.setName(""); + srcBean.time = 55555; + srcBean.remark = null; + srcBean.setMap(Utility.ofMap("aa", "bbb")); + Copier.load(TestXBean.class, TestBean.class, Copier.OPTION_SKIP_EMPTY_STRING) + .apply(srcBean, bean); + System.out.println(JsonConvert.root().convertTo(bean)); + Assertions.assertTrue(bean.getName() == null); + } + + @Test + public void run12() throws Exception { + TestBean bean = new TestBean(); + bean.remark = "hehehoho"; + TestXBean srcBean = new TestXBean(); + srcBean.setName(""); + srcBean.time = 55555; + srcBean.remark = null; + srcBean.setMap(Utility.ofMap("aa", "bbb")); + Copier.load(TestXBean.class, TestBean.class).apply(srcBean, bean); + System.out.println(JsonConvert.root().convertTo(bean)); + Assertions.assertTrue(bean.remark == null); + + bean.setName(null); + bean.remark = "hehehoho"; + Copier.load(TestXBean.class, TestBean.class, Copier.OPTION_SKIP_NULL_VALUE | Copier.OPTION_SKIP_EMPTY_STRING) + .apply(srcBean, bean); + System.out.println(JsonConvert.root().convertTo(bean)); + Assertions.assertTrue(bean.getName() == null); + } + + @Test + public void run13() throws Exception { + TestBean bean = new TestBean(); + bean.setSeqno(6666L); + // public String remark; + // private Long seqno; + TestX2Bean destBean = new TestX2Bean(); + // public int remark; + // private String seqno; + + Copier.load(TestBean.class, TestX2Bean.class, Copier.OPTION_ALLOW_TYPE_CAST) + .apply(bean, destBean); + System.out.println(JsonConvert.root().convertTo(destBean)); + Assertions.assertEquals("6666", destBean.getSeqno()); + } + + @Test + public void run14() throws Exception { + TestBean bean = new TestBean(); + bean.remark = "444"; + TestX2Bean destBean = new TestX2Bean(); + Copier.load(TestBean.class, TestX2Bean.class, Copier.OPTION_SKIP_NULL_VALUE | Copier.OPTION_ALLOW_TYPE_CAST) + .apply(bean, destBean); + System.out.println(JsonConvert.root().convertTo(destBean)); + Assertions.assertTrue(destBean.remark == 444); + } + + @Test + public void run15() throws Exception { + Bean1 bean1 = new Bean1(); + bean1.intval = "444"; + Bean2 bean2 = new Bean2(); + Copier.load(Bean1.class, Bean2.class, Copier.OPTION_SKIP_NULL_VALUE | Copier.OPTION_ALLOW_TYPE_CAST) + .apply(bean1, bean2); + System.out.println(JsonConvert.root().convertTo(bean2)); + Assertions.assertTrue(bean2.intval == 444); + } + + @Test + public void run16() throws Exception { + Bean3 bean1 = new Bean3(); + bean1.setSeqno(444L); + Bean4 bean2 = new Bean4(); + Copier.load(Bean3.class, Bean4.class, Copier.OPTION_SKIP_NULL_VALUE | Copier.OPTION_ALLOW_TYPE_CAST) + .apply(bean1, bean2); + System.out.println(JsonConvert.root().convertTo(bean2)); + Assertions.assertEquals("444", bean2.getSeqno()); + } + + @Test + public void run17() throws Exception { + Bean4 bean1 = new Bean4(); + bean1.setSeqno("444"); + Bean5 bean2 = new Bean5(); + Copier.load(Bean4.class, Bean5.class, Copier.OPTION_SKIP_NULL_VALUE | Copier.OPTION_ALLOW_TYPE_CAST) + .apply(bean1, bean2); + System.out.println(JsonConvert.root().convertTo(bean2)); + Assertions.assertEquals(444, bean2.getSeqno()); + } + + @Test + public void run18() throws Exception { + Bean4 bean1 = new Bean4(); + bean1.setSeqno("444"); + Bean5 bean2 = new Bean5(); + Copier.load(Bean4.class, Bean5.class, Copier.OPTION_SKIP_NULL_VALUE).apply(bean1, bean2); + System.out.println(JsonConvert.root().convertTo(bean2)); + Assertions.assertEquals(0, bean2.getSeqno()); + } + + @Test + public void run19() throws Exception { + Bean0 bean1 = new Bean0(); + bean1.setCarid(111); + bean1.setUsername("aaa"); + Bean0 bean2 = new Bean0(); + Copier.load(Bean0.class, Bean0.class, Copier.OPTION_SKIP_NULL_VALUE).apply(bean1, bean2); + System.out.println(JsonConvert.root().convertTo(bean2)); + Assertions.assertEquals("aaa", bean2.getUsername()); + } + + @Test + public void run20() throws Exception { + Bean0 bean1 = new Bean0(); + bean1.setCarid(111L); + bean1.setUsername("aaa"); + Bean0 bean2 = new Bean0(); + bean2.setCarid(111L); + bean2.setUsername("bbb"); + Creator.register(Bean0::new); + + System.out.println(Copier.load(Bean0.class, Bean0.class).apply(bean1, new Bean0())); + + Function, Set> funcSet = Copier.funcSet(Bean0.class, Bean0.class); + Set set = funcSet.apply(Arrays.asList(bean1, bean2)); + Assertions.assertEquals(1, set.size()); + + Function, List> funcList = Copier.funcList(Bean0.class, Bean0.class); + List list = funcList.apply(Arrays.asList(bean1, bean2)); + Assertions.assertEquals(2, list.size()); + + System.out.println("--------------------20----------------------"); + } + + @Test + public void run21() throws Exception { + Large21Src src = new Large21Src(); + src.setCurrent(1); + src.setSize(20); + System.out.println(Copier.copy(src, Large21Dest.class, Copier.OPTION_ALLOW_TYPE_CAST)); + System.out.println("--------------------21----------------------"); + } + + public static class Large21Dest extends Large21Page { + + private Integer day; + + public Integer getDay() { + return day; + } + + public void setDay(Integer day) { + this.day = day; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + } + + public abstract static class Large21Page { + + private long total; + + private long size; + + private long current; + + private List records; + + public long getTotal() { + return total; + } + + public void setTotal(long total) { + this.total = total; + } + + public long getSize() { + return size; + } + + public Large21Page setSize(long size) { + this.size = size; + return this; + } + + public long getCurrent() { + return current; + } + + public Large21Page setCurrent(long current) { + this.current = current; + return this; + } + + public List getRecords() { + return records; + } + + public void setRecords(List records) { + this.records = records; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + } + + public static class Large21Src { + + private Integer current; + + private Integer size; + + private Integer startDay; + + private Integer endDay; + + private List fields; + + public Integer getCurrent() { + return current; + } + + public void setCurrent(Integer current) { + this.current = current; + } + + public Integer getSize() { + return size; + } + + public void setSize(Integer size) { + this.size = size; + } + + public Integer getStartDay() { + return startDay; + } + + public void setStartDay(Integer startDay) { + this.startDay = startDay; + } + + public Integer getEndDay() { + return endDay; + } + + public void setEndDay(Integer endDay) { + this.endDay = endDay; + } + + public List getFields() { + return fields; + } + + public void setFields(List fields) { + this.fields = fields; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + } + + public class Bean0 { + + private long carid; + + private int cartype; + + private int userid; + + private String username; + + private String cartitle; + + public Bean0() {} + + public long getCarid() { + return carid; + } + + public Bean0 setCarid(long carid) { + this.carid = carid; + return this; + } + + public int getUserid() { + return userid; + } + + public void setUserid(int userid) { + this.userid = userid; + } + + public String getCartitle() { + return cartitle; + } + + public void setCartitle(String cartitle) { + this.cartitle = cartitle; + } + + public int getCartype() { + return cartype; + } + + public void setCartype(int cartype) { + this.cartype = cartype; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + @Override + public int hashCode() { + int hash = 5; + hash = 59 * hash + (int) (this.carid ^ (this.carid >>> 32)); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final Bean0 other = (Bean0) obj; + return this.carid == other.carid; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + } + + public static class Bean1 { + + public String intval; + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + } + + public static class Bean2 { + + public int intval; + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + } + + public static class Bean3 { + + private Long seqno; + + public Long getSeqno() { + return seqno; + } + + public void setSeqno(Long seqno) { + this.seqno = seqno; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + } + + public static class Bean4 { + + private String seqno; + + public String getSeqno() { + return seqno; + } + + public void setSeqno(String seqno) { + this.seqno = seqno; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + } + + public static class Bean5 { + + private int seqno; + + public int getSeqno() { + return seqno; + } + + public Bean5 setSeqno(int seqno) { + this.seqno = seqno; + return this; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + } +} diff --git a/src/test/java/org/redkale/test/util/CreatorRecord.java b/src/test/java/org/redkale/test/util/CreatorRecord.java index 39b862280..582b02fd0 100644 --- a/src/test/java/org/redkale/test/util/CreatorRecord.java +++ b/src/test/java/org/redkale/test/util/CreatorRecord.java @@ -1,102 +1,102 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package org.redkale.test.util; - -import java.util.Arrays; -import org.junit.jupiter.api.*; -import org.redkale.annotation.ConstructorParameters; -import org.redkale.convert.json.JsonConvert; -import org.redkale.util.Creator; - -/** @author zhangjx */ -public class CreatorRecord { - - private int id = -1; - - private String name; - - private long lval; - - private boolean tval; - - private byte bval; - - private short sval; - - private char cval; - - private float fval; - - private double dval; - - @ConstructorParameters({"id", "name", "lval", "tval", "bval", "sval", "cval", "fval", "dval"}) - public CreatorRecord( - int id, String name, long lval, boolean tval, byte bval, short sval, char cval, float fval, double dval) { - this.id = id; - this.name = name; - this.lval = lval; - this.tval = tval; - this.bval = bval; - this.sval = sval; - this.cval = cval; - this.fval = fval; - this.dval = dval; - } - - @Test - public void run1() { - Creator creator = Creator.create(CreatorRecord.class); - System.out.println(Arrays.toString(creator.paramTypes())); - CreatorRecord record = - creator.create(new Object[] {null, "ss", null, true, null, (short) 45, null, 4.3f, null}); - String json = record.toString(); - System.out.println(json); - String json2 = JsonConvert.root().convertFrom(CreatorRecord.class, json).toString(); - System.out.println(json2); - Assertions.assertEquals(json, json2); - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } - - public int getId() { - return id; - } - - public String getName() { - return name; - } - - public long getLval() { - return lval; - } - - public boolean isTval() { - return tval; - } - - public byte getBval() { - return bval; - } - - public short getSval() { - return sval; - } - - public char getCval() { - return cval; - } - - public float getFval() { - return fval; - } - - public double getDval() { - return dval; - } -} +/* + * 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.test.util; + +import java.util.Arrays; +import org.junit.jupiter.api.*; +import org.redkale.annotation.ConstructorParameters; +import org.redkale.convert.json.JsonConvert; +import org.redkale.util.Creator; + +/** @author zhangjx */ +public class CreatorRecord { + + private int id = -1; + + private String name; + + private long lval; + + private boolean tval; + + private byte bval; + + private short sval; + + private char cval; + + private float fval; + + private double dval; + + @ConstructorParameters({"id", "name", "lval", "tval", "bval", "sval", "cval", "fval", "dval"}) + public CreatorRecord( + int id, String name, long lval, boolean tval, byte bval, short sval, char cval, float fval, double dval) { + this.id = id; + this.name = name; + this.lval = lval; + this.tval = tval; + this.bval = bval; + this.sval = sval; + this.cval = cval; + this.fval = fval; + this.dval = dval; + } + + @Test + public void run1() { + Creator creator = Creator.create(CreatorRecord.class); + System.out.println(Arrays.toString(creator.paramTypes())); + CreatorRecord record = + creator.create(new Object[] {null, "ss", null, true, null, (short) 45, null, 4.3f, null}); + String json = record.toString(); + System.out.println(json); + String json2 = JsonConvert.root().convertFrom(CreatorRecord.class, json).toString(); + System.out.println(json2); + Assertions.assertEquals(json, json2); + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + + public int getId() { + return id; + } + + public String getName() { + return name; + } + + public long getLval() { + return lval; + } + + public boolean isTval() { + return tval; + } + + public byte getBval() { + return bval; + } + + public short getSval() { + return sval; + } + + public char getCval() { + return cval; + } + + public float getFval() { + return fval; + } + + public double getDval() { + return dval; + } +} diff --git a/src/test/java/org/redkale/test/util/EnvironmentTest.java b/src/test/java/org/redkale/test/util/EnvironmentTest.java index 732e938c8..a716ea16f 100644 --- a/src/test/java/org/redkale/test/util/EnvironmentTest.java +++ b/src/test/java/org/redkale/test/util/EnvironmentTest.java @@ -1,37 +1,37 @@ -/* - * 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.test.util; - -import java.util.Properties; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import org.redkale.util.Environment; - -/** @author zhangjx */ -public class EnvironmentTest { - - public static void main(String[] args) throws Throwable { - EnvironmentTest test = new EnvironmentTest(); - test.run1(); - } - - @Test - public void run1() throws Exception { - Properties properties = new Properties(); - properties.put("age", "18"); - properties.put("haha_18", "test"); - properties.put("bb", "tt"); - - Environment env = new Environment(properties); - String val = env.getPropertyValue("school_#{name}_${haha_${age}}_${bb}_#{dd}"); - System.out.println(val); - Assertions.assertEquals("school_#{name}_test_tt_#{dd}", val); - - val = env.getPropertyValue("${haha_${age}}"); - System.out.println(val); - Assertions.assertEquals("test", val); - } -} +/* + * 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.test.util; + +import java.util.Properties; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.redkale.util.Environment; + +/** @author zhangjx */ +public class EnvironmentTest { + + public static void main(String[] args) throws Throwable { + EnvironmentTest test = new EnvironmentTest(); + test.run1(); + } + + @Test + public void run1() throws Exception { + Properties properties = new Properties(); + properties.put("age", "18"); + properties.put("haha_18", "test"); + properties.put("bb", "tt"); + + Environment env = new Environment(properties); + String val = env.getPropertyValue("school_#{name}_${haha_${age}}_${bb}_#{dd}"); + System.out.println(val); + Assertions.assertEquals("school_#{name}_test_tt_#{dd}", val); + + val = env.getPropertyValue("${haha_${age}}"); + System.out.println(val); + Assertions.assertEquals("test", val); + } +} diff --git a/src/test/java/org/redkale/test/util/InvokerTest.java b/src/test/java/org/redkale/test/util/InvokerTest.java index 1abd1a3e4..1a34bc169 100644 --- a/src/test/java/org/redkale/test/util/InvokerTest.java +++ b/src/test/java/org/redkale/test/util/InvokerTest.java @@ -1,93 +1,93 @@ -/* - * 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.test.util; - -import java.io.IOException; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import org.redkale.util.Invoker; - -/** @author zhangjx */ -public class InvokerTest { - - public static void main(String[] args) throws Throwable { - InvokerTest test = new InvokerTest(); - test.run1(); - test.run2(); - test.run3(); - test.run4(); - test.run5(); - test.run6(); - test.run7(); - } - - @Test - public void run1() { - Invoker invoker = Invoker.create(String.class, "toLowerCase"); - Assertions.assertEquals("aaa", invoker.invoke("AAA")); - } - - @Test - public void run2() { - Invoker invoker = Invoker.create(String.class, "equals", Object.class); - Assertions.assertTrue(invoker.invoke("AAA", "AAA")); - } - - @Test - public void run3() { - Invoker invoker = Invoker.create(java.sql.Date.class, "valueOf", String.class); - String str = new java.sql.Date(System.currentTimeMillis()).toString(); - System.out.println(str); - Assertions.assertEquals(str, invoker.invoke(null, str).toString()); - } - - @Test - public void run4() { - Invoker invoker = Invoker.create(Action.class, "test1"); - Action action = new Action(); - invoker.invoke(action); - } - - @Test - public void run5() { - Invoker invoker = Invoker.create(Action.class, "test2", String.class); - Action action = new Action(); - invoker.invoke(action, "name"); - } - - @Test - public void run6() { - Invoker invoker = Invoker.create(Action.class, "test3", String.class, int.class); - Action action = new Action(); - int rs = invoker.invoke(action, "name", 1); - System.out.println(rs); - Assertions.assertEquals(3, rs); - } - - @Test - public void run7() { - Invoker invoker = Invoker.create(Action.class, "test4", String.class, int.class); - Action action = new Action(); - int rs = invoker.invoke(action, "name", 1); - System.out.println(rs); - Assertions.assertEquals(4, rs); - } - - public static class Action { - - public void test1() {} - - public void test2(String name) throws IOException {} - - public int test3(String name, int id) { - return 3; - } - - public int test4(String name, int id) throws IOException { - return 4; - } - } -} +/* + * 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.test.util; + +import java.io.IOException; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.redkale.util.Invoker; + +/** @author zhangjx */ +public class InvokerTest { + + public static void main(String[] args) throws Throwable { + InvokerTest test = new InvokerTest(); + test.run1(); + test.run2(); + test.run3(); + test.run4(); + test.run5(); + test.run6(); + test.run7(); + } + + @Test + public void run1() { + Invoker invoker = Invoker.create(String.class, "toLowerCase"); + Assertions.assertEquals("aaa", invoker.invoke("AAA")); + } + + @Test + public void run2() { + Invoker invoker = Invoker.create(String.class, "equals", Object.class); + Assertions.assertTrue(invoker.invoke("AAA", "AAA")); + } + + @Test + public void run3() { + Invoker invoker = Invoker.create(java.sql.Date.class, "valueOf", String.class); + String str = new java.sql.Date(System.currentTimeMillis()).toString(); + System.out.println(str); + Assertions.assertEquals(str, invoker.invoke(null, str).toString()); + } + + @Test + public void run4() { + Invoker invoker = Invoker.create(Action.class, "test1"); + Action action = new Action(); + invoker.invoke(action); + } + + @Test + public void run5() { + Invoker invoker = Invoker.create(Action.class, "test2", String.class); + Action action = new Action(); + invoker.invoke(action, "name"); + } + + @Test + public void run6() { + Invoker invoker = Invoker.create(Action.class, "test3", String.class, int.class); + Action action = new Action(); + int rs = invoker.invoke(action, "name", 1); + System.out.println(rs); + Assertions.assertEquals(3, rs); + } + + @Test + public void run7() { + Invoker invoker = Invoker.create(Action.class, "test4", String.class, int.class); + Action action = new Action(); + int rs = invoker.invoke(action, "name", 1); + System.out.println(rs); + Assertions.assertEquals(4, rs); + } + + public static class Action { + + public void test1() {} + + public void test2(String name) throws IOException {} + + public int test3(String name, int id) { + return 3; + } + + public int test4(String name, int id) throws IOException { + return 4; + } + } +} diff --git a/src/test/java/org/redkale/test/util/MultiHashKeyTest.java b/src/test/java/org/redkale/test/util/MultiHashKeyTest.java index 1b42a5268..37ca163d8 100644 --- a/src/test/java/org/redkale/test/util/MultiHashKeyTest.java +++ b/src/test/java/org/redkale/test/util/MultiHashKeyTest.java @@ -1,128 +1,128 @@ -/* - * 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.test.util; - -import java.util.Map; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import org.redkale.util.MultiHashKey; -import org.redkale.util.Utility; - -/** @author zhangjx */ -public class MultiHashKeyTest { - - public static void main(String[] args) throws Throwable { - MultiHashKeyTest test = new MultiHashKeyTest(); - test.run1(); - test.run2(); - test.run3(); - test.run4(); - test.run5(); - test.run6(); - test.run7(); - test.run8(); - test.run9(); - } - - @Test - public void run1() throws Exception { - String[] paramNames = {"name", "id"}; - String key = "#{name}"; - MultiHashKey rs = MultiHashKey.create(paramNames, key); - System.out.println(rs); - Assertions.assertEquals("ParamKey{field: name, index: 0}", rs.toString()); - Assertions.assertEquals("haha", rs.keyFor("haha", 123)); - } - - @Test - public void run2() throws Exception { - String[] paramNames = {"name", "id"}; - String key = "#{id}"; - MultiHashKey rs = MultiHashKey.create(paramNames, key); - System.out.println(rs); - Assertions.assertEquals("ParamKey{field: id, index: 1}", rs.toString()); - Assertions.assertEquals("123", rs.keyFor("haha", 123)); - } - - @Test - public void run3() throws Exception { - String[] paramNames = {"name", "id"}; - String key = "name"; - MultiHashKey rs = MultiHashKey.create(paramNames, key); - System.out.println(rs); - Assertions.assertEquals("StringKey{key: name}", rs.toString()); - Assertions.assertEquals("name", rs.keyFor("haha", 123)); - } - - @Test - public void run4() throws Exception { - String[] paramNames = {"name", "id"}; - String key = "key_#{name}_#{id}_#{name.index}"; - MultiHashKey rs = MultiHashKey.create(paramNames, key); - System.out.println(rs); - Assertions.assertEquals( - "ArrayKey[StringKey{key: key_}, ParamKey{field: name, index: 0}, StringKey{key: _}, " - + "ParamKey{field: id, index: 1}, StringKey{key: _}, " - + "ParamsKey{field: name.index, index: 0}]", - rs.toString()); - Assertions.assertEquals("key_n124_123_124", rs.keyFor(new Name(124), 123)); - } - - @Test - public void run5() throws Exception { - String[] paramNames = {"map", "id"}; - String key = "key_#{map.name}_#{id}_#{map.index}"; - MultiHashKey rs = MultiHashKey.create(paramNames, key); - System.out.println(rs); - Assertions.assertEquals( - "ArrayKey[StringKey{key: key_}, " - + "ParamsKey{field: map.name, index: 0}, StringKey{key: _}, " - + "ParamKey{field: id, index: 1}, StringKey{key: _}, " - + "ParamsKey{field: map.index, index: 0}]", - rs.toString()); - Map map = Utility.ofMap("name", "me", "index", 123); - Assertions.assertEquals("key_me_123_123", rs.keyFor(map, 123)); - } - - @Test - public void run6() throws Exception { - String[] paramNames = {"map", "id"}; - String key = "{key_#{map.name}_#{id}_#{map.index}}"; - MultiHashKey rs = MultiHashKey.create(paramNames, key); - Map map = Utility.ofMap("name", "me", "index", 123); - Assertions.assertEquals("{key_me_123_123}", rs.keyFor(map, 123)); - } - - @Test - public void run7() throws Exception {} - - @Test - public void run8() throws Exception {} - - @Test - public void run9() throws Exception {} - - public static class Name { - - private int index; - - public Name(int index) { - this.index = index; - } - - public int getIndex() { - return index; - } - - public void setIndex(int index) { - this.index = index; - } - - public String toString() { - return "n" + index; - } - } -} +/* + * 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.test.util; + +import java.util.Map; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.redkale.util.MultiHashKey; +import org.redkale.util.Utility; + +/** @author zhangjx */ +public class MultiHashKeyTest { + + public static void main(String[] args) throws Throwable { + MultiHashKeyTest test = new MultiHashKeyTest(); + test.run1(); + test.run2(); + test.run3(); + test.run4(); + test.run5(); + test.run6(); + test.run7(); + test.run8(); + test.run9(); + } + + @Test + public void run1() throws Exception { + String[] paramNames = {"name", "id"}; + String key = "#{name}"; + MultiHashKey rs = MultiHashKey.create(paramNames, key); + System.out.println(rs); + Assertions.assertEquals("ParamKey{field: name, index: 0}", rs.toString()); + Assertions.assertEquals("haha", rs.keyFor("haha", 123)); + } + + @Test + public void run2() throws Exception { + String[] paramNames = {"name", "id"}; + String key = "#{id}"; + MultiHashKey rs = MultiHashKey.create(paramNames, key); + System.out.println(rs); + Assertions.assertEquals("ParamKey{field: id, index: 1}", rs.toString()); + Assertions.assertEquals("123", rs.keyFor("haha", 123)); + } + + @Test + public void run3() throws Exception { + String[] paramNames = {"name", "id"}; + String key = "name"; + MultiHashKey rs = MultiHashKey.create(paramNames, key); + System.out.println(rs); + Assertions.assertEquals("StringKey{key: name}", rs.toString()); + Assertions.assertEquals("name", rs.keyFor("haha", 123)); + } + + @Test + public void run4() throws Exception { + String[] paramNames = {"name", "id"}; + String key = "key_#{name}_#{id}_#{name.index}"; + MultiHashKey rs = MultiHashKey.create(paramNames, key); + System.out.println(rs); + Assertions.assertEquals( + "ArrayKey[StringKey{key: key_}, ParamKey{field: name, index: 0}, StringKey{key: _}, " + + "ParamKey{field: id, index: 1}, StringKey{key: _}, " + + "ParamsKey{field: name.index, index: 0}]", + rs.toString()); + Assertions.assertEquals("key_n124_123_124", rs.keyFor(new Name(124), 123)); + } + + @Test + public void run5() throws Exception { + String[] paramNames = {"map", "id"}; + String key = "key_#{map.name}_#{id}_#{map.index}"; + MultiHashKey rs = MultiHashKey.create(paramNames, key); + System.out.println(rs); + Assertions.assertEquals( + "ArrayKey[StringKey{key: key_}, " + + "ParamsKey{field: map.name, index: 0}, StringKey{key: _}, " + + "ParamKey{field: id, index: 1}, StringKey{key: _}, " + + "ParamsKey{field: map.index, index: 0}]", + rs.toString()); + Map map = Utility.ofMap("name", "me", "index", 123); + Assertions.assertEquals("key_me_123_123", rs.keyFor(map, 123)); + } + + @Test + public void run6() throws Exception { + String[] paramNames = {"map", "id"}; + String key = "{key_#{map.name}_#{id}_#{map.index}}"; + MultiHashKey rs = MultiHashKey.create(paramNames, key); + Map map = Utility.ofMap("name", "me", "index", 123); + Assertions.assertEquals("{key_me_123_123}", rs.keyFor(map, 123)); + } + + @Test + public void run7() throws Exception {} + + @Test + public void run8() throws Exception {} + + @Test + public void run9() throws Exception {} + + public static class Name { + + private int index; + + public Name(int index) { + this.index = index; + } + + public int getIndex() { + return index; + } + + public void setIndex(int index) { + this.index = index; + } + + public String toString() { + return "n" + index; + } + } +} diff --git a/src/test/java/org/redkale/test/util/TestABean.java b/src/test/java/org/redkale/test/util/TestABean.java index 875cb50d5..1b572929f 100644 --- a/src/test/java/org/redkale/test/util/TestABean.java +++ b/src/test/java/org/redkale/test/util/TestABean.java @@ -1,11 +1,11 @@ -/* - * 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.test.util; - -/** @author zhangjx */ -public class TestABean { - public long time; -} +/* + * 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.test.util; + +/** @author zhangjx */ +public class TestABean { + public long time; +} diff --git a/src/test/java/org/redkale/test/util/TestBean.java b/src/test/java/org/redkale/test/util/TestBean.java index 683eb1233..f01b4c6cc 100644 --- a/src/test/java/org/redkale/test/util/TestBean.java +++ b/src/test/java/org/redkale/test/util/TestBean.java @@ -1,60 +1,60 @@ -/* - * 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.test.util; - -import java.util.Map; -import org.redkale.convert.json.JsonConvert; - -/** @author zhangjx */ -public class TestBean extends TestABean implements TestInterface { - - private String name; - - private int id; - - private Map map; - - public String remark; - - private Long seqno; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - public Map getMap() { - return map; - } - - public void setMap(Map map) { - this.map = map; - } - - public Long getSeqno() { - return seqno; - } - - public void setSeqno(Long seqno) { - this.seqno = seqno; - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } -} +/* + * 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.test.util; + +import java.util.Map; +import org.redkale.convert.json.JsonConvert; + +/** @author zhangjx */ +public class TestBean extends TestABean implements TestInterface { + + private String name; + + private int id; + + private Map map; + + public String remark; + + private Long seqno; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public Map getMap() { + return map; + } + + public void setMap(Map map) { + this.map = map; + } + + public Long getSeqno() { + return seqno; + } + + public void setSeqno(Long seqno) { + this.seqno = seqno; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } +} diff --git a/src/test/java/org/redkale/test/util/TestInterface.java b/src/test/java/org/redkale/test/util/TestInterface.java index 39ff5c675..8116f09f0 100644 --- a/src/test/java/org/redkale/test/util/TestInterface.java +++ b/src/test/java/org/redkale/test/util/TestInterface.java @@ -1,20 +1,20 @@ -/* - * 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.test.util; - -import java.util.Map; - -/** @author zhangjx */ -public interface TestInterface { - - public int getId(); - - public Map getMap(); - - public void setId(int id); - - public void setMap(Map map); -} +/* + * 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.test.util; + +import java.util.Map; + +/** @author zhangjx */ +public interface TestInterface { + + public int getId(); + + public Map getMap(); + + public void setId(int id); + + public void setMap(Map map); +} diff --git a/src/test/java/org/redkale/test/util/TestX2Bean.java b/src/test/java/org/redkale/test/util/TestX2Bean.java index 818176abb..f51bc5ae2 100644 --- a/src/test/java/org/redkale/test/util/TestX2Bean.java +++ b/src/test/java/org/redkale/test/util/TestX2Bean.java @@ -1,58 +1,58 @@ -/* - * - */ -package org.redkale.test.util; - -import java.util.Map; -import org.redkale.convert.json.JsonConvert; - -/** @author zhangjx */ -public class TestX2Bean implements TestInterface { - - private String name; - - private int id; - - private Map map; - - public int remark; - - private String seqno; - - public String getSeqno() { - return seqno; - } - - public void setSeqno(String seqno) { - this.seqno = seqno; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - public Map getMap() { - return map; - } - - public void setMap(Map map) { - this.map = map; - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } -} +/* + * + */ +package org.redkale.test.util; + +import java.util.Map; +import org.redkale.convert.json.JsonConvert; + +/** @author zhangjx */ +public class TestX2Bean implements TestInterface { + + private String name; + + private int id; + + private Map map; + + public int remark; + + private String seqno; + + public String getSeqno() { + return seqno; + } + + public void setSeqno(String seqno) { + this.seqno = seqno; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public Map getMap() { + return map; + } + + public void setMap(Map map) { + this.map = map; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } +} diff --git a/src/test/java/org/redkale/test/util/TestXBean.java b/src/test/java/org/redkale/test/util/TestXBean.java index b7a2fa0e0..74f210ff1 100644 --- a/src/test/java/org/redkale/test/util/TestXBean.java +++ b/src/test/java/org/redkale/test/util/TestXBean.java @@ -1,9 +1,9 @@ -/* - * 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.test.util; - -/** @author zhangjx */ -public class TestXBean extends TestBean {} +/* + * 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.test.util; + +/** @author zhangjx */ +public class TestXBean extends TestBean {} diff --git a/src/test/java/org/redkale/test/util/TypeTokenTest.java b/src/test/java/org/redkale/test/util/TypeTokenTest.java index 6dd78ddf6..6d19ad778 100644 --- a/src/test/java/org/redkale/test/util/TypeTokenTest.java +++ b/src/test/java/org/redkale/test/util/TypeTokenTest.java @@ -1,73 +1,73 @@ -/* - * 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.test.util; - -import java.io.File; -import java.lang.reflect.*; -import java.nio.channels.CompletionHandler; -import org.junit.jupiter.api.*; -import org.redkale.util.TypeToken; - -/** @author zhangjx */ -public class TypeTokenTest { - - private boolean main; - - public static void main(String[] args) throws Throwable { - TypeTokenTest test = new TypeTokenTest(); - test.main = true; - test.run(); - test.run2(); - } - - @Test - public void run() throws Exception { - Class serviceType = Service1.class; - Method method = serviceType.getMethod("test", String.class, CompletionHandler.class); - Type handlerType = TypeToken.getGenericType(method.getGenericParameterTypes()[1], serviceType); - Type resultType = null; - if (handlerType instanceof Class) { - resultType = Object.class; - } else if (handlerType instanceof ParameterizedType) { - resultType = TypeToken.getGenericType( - ((ParameterizedType) handlerType).getActualTypeArguments()[0], handlerType); - } - if (!main) { - Assertions.assertEquals(resultType, String.class); - } - System.out.println("resultType = " + resultType); - } - - @Test - public void run2() throws Exception { - Class serviceType = Service2.class; - Method method = serviceType.getMethod("test", String.class, CompletionHandler.class); - Type handlerType = TypeToken.getGenericType(method.getGenericParameterTypes()[1], serviceType); - Type resultType = null; - if (handlerType instanceof Class) { - resultType = Object.class; - } else if (handlerType instanceof ParameterizedType) { - resultType = TypeToken.getGenericType( - ((ParameterizedType) handlerType).getActualTypeArguments()[0], handlerType); - } - if (!main) { - Assertions.assertEquals(resultType, File.class); - } - System.out.println("resultType = " + resultType); - } - - public abstract static class Service1 { - - public abstract void test(String name, CompletionHandler handler); - } - - public abstract static class IService2 { - - public abstract void test(String name, CompletionHandler handler); - } - - public abstract static class Service2 extends IService2 {} -} +/* + * 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.test.util; + +import java.io.File; +import java.lang.reflect.*; +import java.nio.channels.CompletionHandler; +import org.junit.jupiter.api.*; +import org.redkale.util.TypeToken; + +/** @author zhangjx */ +public class TypeTokenTest { + + private boolean main; + + public static void main(String[] args) throws Throwable { + TypeTokenTest test = new TypeTokenTest(); + test.main = true; + test.run(); + test.run2(); + } + + @Test + public void run() throws Exception { + Class serviceType = Service1.class; + Method method = serviceType.getMethod("test", String.class, CompletionHandler.class); + Type handlerType = TypeToken.getGenericType(method.getGenericParameterTypes()[1], serviceType); + Type resultType = null; + if (handlerType instanceof Class) { + resultType = Object.class; + } else if (handlerType instanceof ParameterizedType) { + resultType = TypeToken.getGenericType( + ((ParameterizedType) handlerType).getActualTypeArguments()[0], handlerType); + } + if (!main) { + Assertions.assertEquals(resultType, String.class); + } + System.out.println("resultType = " + resultType); + } + + @Test + public void run2() throws Exception { + Class serviceType = Service2.class; + Method method = serviceType.getMethod("test", String.class, CompletionHandler.class); + Type handlerType = TypeToken.getGenericType(method.getGenericParameterTypes()[1], serviceType); + Type resultType = null; + if (handlerType instanceof Class) { + resultType = Object.class; + } else if (handlerType instanceof ParameterizedType) { + resultType = TypeToken.getGenericType( + ((ParameterizedType) handlerType).getActualTypeArguments()[0], handlerType); + } + if (!main) { + Assertions.assertEquals(resultType, File.class); + } + System.out.println("resultType = " + resultType); + } + + public abstract static class Service1 { + + public abstract void test(String name, CompletionHandler handler); + } + + public abstract static class IService2 { + + public abstract void test(String name, CompletionHandler handler); + } + + public abstract static class Service2 extends IService2 {} +} diff --git a/src/test/java/org/redkale/test/util/UntilTestMain.java b/src/test/java/org/redkale/test/util/UntilTestMain.java index 7ab7e7266..55e0624e9 100644 --- a/src/test/java/org/redkale/test/util/UntilTestMain.java +++ b/src/test/java/org/redkale/test/util/UntilTestMain.java @@ -1,130 +1,130 @@ -/* - * 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.test.util; - -import java.nio.charset.StandardCharsets; -import java.security.Key; -import javax.crypto.Cipher; -import javax.crypto.spec.*; -import org.redkale.util.*; - -/** @author zhangjx */ -public class UntilTestMain { - - public static void main(String[] args) throws Throwable { - copy(args); - attribute(args); - aes(args); - } - - public static void aes(String[] args) throws Throwable { - String mingwen = "我是z前面的"; - String secret = "after z content."; - Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); - Key secureKey = new SecretKeySpec(secret.getBytes(), "AES"); - IvParameterSpec iv = new IvParameterSpec(secret.getBytes(StandardCharsets.UTF_8)); - cipher.init(Cipher.ENCRYPT_MODE, secureKey, iv); - byte[] bs = cipher.doFinal(mingwen.getBytes()); - System.out.println("加密后: " + Utility.binToHexString(bs)); - - System.out.println(new String(Utility.hexToBin("6166746572207a20636f6e74656e742e"))); - String miwen = "2a2c3ff3b51205eb80a02e43e0eb0751"; - secret = "after z content."; - byte[] ms = Utility.hexToBin(miwen); - cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); - secureKey = new SecretKeySpec(secret.substring(0, 16).getBytes(), "AES"); - iv = new IvParameterSpec(secret.substring(0, 16).getBytes(StandardCharsets.UTF_8)); - cipher.init(Cipher.DECRYPT_MODE, secureKey, iv); - bs = cipher.doFinal(ms); - System.out.println("解密后: " + new String(bs)); - System.out.println(Utility.binToHexString(secret.getBytes())); - } - - public static void copy(String[] args) throws Throwable { - final TestBean bean = new TestBean(); - bean.setId(123456); - bean.setName("zhangjx"); - bean.time = 2000; - final TestXBean beanx = new TestXBean(); - Copier action1 = Copier.create(TestBean.class, TestXBean.class); - Copier action2 = new Copier() { - - @Override - public TestXBean apply(TestBean src, TestXBean dest) { - dest.time = src.time; - dest.setId(src.getId()); - dest.setName(src.getName()); - dest.setMap(src.getMap()); - return dest; - } - }; - final int count = 1_000_000; - long s = System.nanoTime(); - for (int i = 0; i < count; i++) { - action2.apply(bean, beanx); - } - long e = System.nanoTime() - s; - System.out.println("静态Reproduce耗时: " + e); - s = System.nanoTime(); - for (int i = 0; i < count; i++) { - action1.apply(bean, beanx); - } - e = System.nanoTime() - s; - System.out.println("动态Reproduce耗时: " + e); - System.out.println(); - } - - public static void attribute(String[] args) throws Throwable { - final TestBean bean = new TestBean(); - bean.setId(123456); - bean.setName("zhangjx"); - Attribute action1 = Attribute.create(TestBean.class.getDeclaredField("name")); - Attribute action2 = new Attribute() { - - @Override - public String field() { - return "name"; - } - - @Override - public String get(TestBean obj) { - return obj.getName(); - } - - @Override - public void set(TestBean obj, String value) { - obj.setName(value); - } - - @Override - public Class type() { - return String.class; - } - - @Override - public Class declaringClass() { - return TestBean.class; - } - }; - final int count = 1_000_000; - long s = System.nanoTime(); - for (int i = 0; i < count; i++) { - action2.set(bean, "zhangjx2"); - } - long e = System.nanoTime() - s; - System.out.println("静态Attribute耗时: " + e); - s = System.nanoTime(); - for (int i = 0; i < count; i++) { - action1.set(bean, "zhangjx2"); - } - e = System.nanoTime() - s; - System.out.println("动态Attribute耗时: " + e); - System.out.println("TestBean.map: " - + Attribute.create(TestBean.class.getDeclaredField("map")).genericType()); - System.out.println(); - System.out.println(); - } -} +/* + * 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.test.util; + +import java.nio.charset.StandardCharsets; +import java.security.Key; +import javax.crypto.Cipher; +import javax.crypto.spec.*; +import org.redkale.util.*; + +/** @author zhangjx */ +public class UntilTestMain { + + public static void main(String[] args) throws Throwable { + copy(args); + attribute(args); + aes(args); + } + + public static void aes(String[] args) throws Throwable { + String mingwen = "我是z前面的"; + String secret = "after z content."; + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); + Key secureKey = new SecretKeySpec(secret.getBytes(), "AES"); + IvParameterSpec iv = new IvParameterSpec(secret.getBytes(StandardCharsets.UTF_8)); + cipher.init(Cipher.ENCRYPT_MODE, secureKey, iv); + byte[] bs = cipher.doFinal(mingwen.getBytes()); + System.out.println("加密后: " + Utility.binToHexString(bs)); + + System.out.println(new String(Utility.hexToBin("6166746572207a20636f6e74656e742e"))); + String miwen = "2a2c3ff3b51205eb80a02e43e0eb0751"; + secret = "after z content."; + byte[] ms = Utility.hexToBin(miwen); + cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); + secureKey = new SecretKeySpec(secret.substring(0, 16).getBytes(), "AES"); + iv = new IvParameterSpec(secret.substring(0, 16).getBytes(StandardCharsets.UTF_8)); + cipher.init(Cipher.DECRYPT_MODE, secureKey, iv); + bs = cipher.doFinal(ms); + System.out.println("解密后: " + new String(bs)); + System.out.println(Utility.binToHexString(secret.getBytes())); + } + + public static void copy(String[] args) throws Throwable { + final TestBean bean = new TestBean(); + bean.setId(123456); + bean.setName("zhangjx"); + bean.time = 2000; + final TestXBean beanx = new TestXBean(); + Copier action1 = Copier.create(TestBean.class, TestXBean.class); + Copier action2 = new Copier() { + + @Override + public TestXBean apply(TestBean src, TestXBean dest) { + dest.time = src.time; + dest.setId(src.getId()); + dest.setName(src.getName()); + dest.setMap(src.getMap()); + return dest; + } + }; + final int count = 1_000_000; + long s = System.nanoTime(); + for (int i = 0; i < count; i++) { + action2.apply(bean, beanx); + } + long e = System.nanoTime() - s; + System.out.println("静态Reproduce耗时: " + e); + s = System.nanoTime(); + for (int i = 0; i < count; i++) { + action1.apply(bean, beanx); + } + e = System.nanoTime() - s; + System.out.println("动态Reproduce耗时: " + e); + System.out.println(); + } + + public static void attribute(String[] args) throws Throwable { + final TestBean bean = new TestBean(); + bean.setId(123456); + bean.setName("zhangjx"); + Attribute action1 = Attribute.create(TestBean.class.getDeclaredField("name")); + Attribute action2 = new Attribute() { + + @Override + public String field() { + return "name"; + } + + @Override + public String get(TestBean obj) { + return obj.getName(); + } + + @Override + public void set(TestBean obj, String value) { + obj.setName(value); + } + + @Override + public Class type() { + return String.class; + } + + @Override + public Class declaringClass() { + return TestBean.class; + } + }; + final int count = 1_000_000; + long s = System.nanoTime(); + for (int i = 0; i < count; i++) { + action2.set(bean, "zhangjx2"); + } + long e = System.nanoTime() - s; + System.out.println("静态Attribute耗时: " + e); + s = System.nanoTime(); + for (int i = 0; i < count; i++) { + action1.set(bean, "zhangjx2"); + } + e = System.nanoTime() - s; + System.out.println("动态Attribute耗时: " + e); + System.out.println("TestBean.map: " + + Attribute.create(TestBean.class.getDeclaredField("map")).genericType()); + System.out.println(); + System.out.println(); + } +} diff --git a/src/test/java/org/redkale/test/websocket/ChatWebSocketServlet.java b/src/test/java/org/redkale/test/websocket/ChatWebSocketServlet.java index 0cdbb66f3..af0983b5e 100644 --- a/src/test/java/org/redkale/test/websocket/ChatWebSocketServlet.java +++ b/src/test/java/org/redkale/test/websocket/ChatWebSocketServlet.java @@ -1,72 +1,72 @@ -/* - * 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.test.websocket; - -import java.util.concurrent.CompletableFuture; -import org.redkale.annotation.Resource; -import org.redkale.net.http.*; -import org.redkale.test.rest.*; -import org.redkale.util.AnyValue; - -/** @author zhangjx */ -@WebServlet("/ws/chat") -public class ChatWebSocketServlet extends WebSocketServlet { - - @Resource - private UserService userService; - - @Override - public void init(HttpContext context, AnyValue conf) { - System.out.println("本实例的WebSocketNode: " + super.webSocketNode); - } - - @Override - public void destroy(HttpContext context, AnyValue conf) { - System.out.println("关闭了ChatWebSocketServlet"); - } - - @Override - protected WebSocket createWebSocket() { - - return new WebSocket() { - - private UserInfo user; - - @Override - public void onMessage( - ChatMessage message, - boolean last) { // text 接收的格式: {"receiveid":200000001, "content":"Hi Redkale!"} - message.sendid = user.getUserid(); // 将当前用户设为消息的发送方 - message.sendtime = System.currentTimeMillis(); // 设置消息发送时间 - // 给接收方发送消息, 即使接收方在其他WebSocket进程节点上有链接,Redkale也会自动发送到其他链接进程节点上。 - super.sendMessage(message, message.receiveid); - } - - @Override - protected CompletableFuture createUserid() { // 创建用户ID - this.user = userService.current(String.valueOf(super.getSessionid())); - return CompletableFuture.completedFuture(this.user == null ? null : this.user.getUserid()); - } - - @Override - public CompletableFuture onOpen(HttpRequest request) { - return CompletableFuture.completedFuture( - request.getSessionid(false)); // 以request中的sessionid字符串作为WebSocket的sessionid - } - }; - } - - public static class ChatMessage { - - public int sendid; // 发送方用户ID - - public int receiveid; // 接收方用户ID - - public String content; // 文本消息内容 - - public long sendtime; // 消息发送时间 - } -} +/* + * 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.test.websocket; + +import java.util.concurrent.CompletableFuture; +import org.redkale.annotation.Resource; +import org.redkale.net.http.*; +import org.redkale.test.rest.*; +import org.redkale.util.AnyValue; + +/** @author zhangjx */ +@WebServlet("/ws/chat") +public class ChatWebSocketServlet extends WebSocketServlet { + + @Resource + private UserService userService; + + @Override + public void init(HttpContext context, AnyValue conf) { + System.out.println("本实例的WebSocketNode: " + super.webSocketNode); + } + + @Override + public void destroy(HttpContext context, AnyValue conf) { + System.out.println("关闭了ChatWebSocketServlet"); + } + + @Override + protected WebSocket createWebSocket() { + + return new WebSocket() { + + private UserInfo user; + + @Override + public void onMessage( + ChatMessage message, + boolean last) { // text 接收的格式: {"receiveid":200000001, "content":"Hi Redkale!"} + message.sendid = user.getUserid(); // 将当前用户设为消息的发送方 + message.sendtime = System.currentTimeMillis(); // 设置消息发送时间 + // 给接收方发送消息, 即使接收方在其他WebSocket进程节点上有链接,Redkale也会自动发送到其他链接进程节点上。 + super.sendMessage(message, message.receiveid); + } + + @Override + protected CompletableFuture createUserid() { // 创建用户ID + this.user = userService.current(String.valueOf(super.getSessionid())); + return CompletableFuture.completedFuture(this.user == null ? null : this.user.getUserid()); + } + + @Override + public CompletableFuture onOpen(HttpRequest request) { + return CompletableFuture.completedFuture( + request.getSessionid(false)); // 以request中的sessionid字符串作为WebSocket的sessionid + } + }; + } + + public static class ChatMessage { + + public int sendid; // 发送方用户ID + + public int receiveid; // 接收方用户ID + + public String content; // 文本消息内容 + + public long sendtime; // 消息发送时间 + } +} diff --git a/src/test/java/org/redkale/test/websocket/Flash843.java b/src/test/java/org/redkale/test/websocket/Flash843.java index 9d4953a94..b78d0a9f3 100644 --- a/src/test/java/org/redkale/test/websocket/Flash843.java +++ b/src/test/java/org/redkale/test/websocket/Flash843.java @@ -1,26 +1,26 @@ -/* - * 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.test.websocket; - -import java.io.ByteArrayOutputStream; -import java.net.Socket; - -/** @author zhangjx */ -public class Flash843 { - - public static void main(String[] args) throws Exception { - Socket socket = new Socket("113.105.88.229", 843); - socket.getOutputStream().write("".getBytes()); - socket.getOutputStream().flush(); - ByteArrayOutputStream out = new ByteArrayOutputStream(); - byte[] bytes = new byte[1024]; - int pos; - while ((pos = socket.getInputStream().read(bytes)) != -1) { - out.write(bytes, 0, pos); - } - System.out.println(out.toString()); - } -} +/* + * 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.test.websocket; + +import java.io.ByteArrayOutputStream; +import java.net.Socket; + +/** @author zhangjx */ +public class Flash843 { + + public static void main(String[] args) throws Exception { + Socket socket = new Socket("113.105.88.229", 843); + socket.getOutputStream().write("".getBytes()); + socket.getOutputStream().flush(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + byte[] bytes = new byte[1024]; + int pos; + while ((pos = socket.getInputStream().read(bytes)) != -1) { + out.write(bytes, 0, pos); + } + System.out.println(out.toString()); + } +} diff --git a/src/test/java/org/redkale/test/websocket/VideoWebSocketServlet.java b/src/test/java/org/redkale/test/websocket/VideoWebSocketServlet.java index f664d6cd0..5c21ba3e0 100644 --- a/src/test/java/org/redkale/test/websocket/VideoWebSocketServlet.java +++ b/src/test/java/org/redkale/test/websocket/VideoWebSocketServlet.java @@ -1,127 +1,127 @@ -/* - * 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.test.websocket; - -import java.io.*; -import java.util.*; -import java.util.concurrent.*; -import org.redkale.net.http.HttpRequest; -import org.redkale.net.http.HttpServer; -import org.redkale.net.http.WebServlet; -import org.redkale.net.http.WebSocket; -import org.redkale.net.http.WebSocketServlet; -import org.redkale.util.AnyValueWriter; -import org.redkale.util.TypeToken; - -/** @author zhangjx */ -@WebServlet({"/ws/listen"}) -public class VideoWebSocketServlet extends WebSocketServlet { - - private final Map sessions = new java.util.concurrent.ConcurrentHashMap<>(); - - private final Map users = new HashMap<>(); - - private static final class Entry { - - public WebSocket socket; - - public String username; - - public Serializable userid; - } - - public VideoWebSocketServlet() { - super(); - users.put("zhangjx", "xxxx"); - } - - @Override - protected WebSocket createWebSocket() { - WebSocket socket = new WebSocket() { - - private final TypeToken> mapToken = new TypeToken>() {}; - - private boolean repeat = false; - - @Override - public CompletableFuture onOpen(final HttpRequest request) { - String uri = request.getRequestPath(); - int pos = uri.indexOf("/listen/"); - uri = uri.substring(pos + "/listen/".length()); - this.repeat = sessions.get(uri) != null; - if (!this.repeat) this.repeat = users.get(uri) == null; - String sessionid = Long.toString(System.nanoTime()); - if (uri.indexOf('\'') >= 0 || uri.indexOf('"') >= 0) return null; - if (!repeat) sessionid = uri; - return CompletableFuture.completedFuture(sessionid); - } - - @Override - public CompletableFuture onConnected() { - if (repeat) { - super.close(); - } else { - Entry entry = new Entry(); - entry.userid = this.getSessionid(); - entry.username = users.get(entry.userid); - sessions.put(this.getSessionid(), entry); - StringBuilder sb = new StringBuilder(); - for (Map.Entry en : sessions.entrySet()) { - if (sb.length() > 0) sb.append(','); - sb.append("{'userid':'") - .append(en.getKey()) - .append("','username':'") - .append(en.getValue().username) - .append("'}"); - } - super.send(("{'type':'user_list','users':[" + sb + "]}").replace('\'', '"')); - String msg = ("{'type':'discover_user','user':{'userid':'" + this.getSessionid() + "','username':'" - + users.get(this.getSessionid()) + "'}}") - .replace('\'', '"'); - super.broadcastMessage(msg); - } - return null; - } - - @Override - public void onMessage(Object text, boolean last) { - // System.out.println("接收到消息: " + text); - super.broadcastMessage(text, last); - } - - @Override - public CompletableFuture onClose(int code, String reason) { - sessions.remove(this.getSessionid()); - String msg = ("{'type':'remove_user','user':{'userid':'" + this.getSessionid() + "','username':'" - + users.get(this.getSessionid()) + "'}}") - .replace('\'', '"'); - return super.broadcastMessage(msg); - } - - @Override - protected CompletableFuture createUserid() { - return CompletableFuture.completedFuture("2"); - } - }; - return socket; - } - - public static void main(String[] args) throws Throwable { - CountDownLatch cdl = new CountDownLatch(1); - AnyValueWriter config = AnyValueWriter.create() - .addValue("threads", System.getProperty("threads")) - .addValue("bufferPoolSize", System.getProperty("bufferPoolSize")) - .addValue("responsePoolSize", System.getProperty("responsePoolSize")) - .addValue("host", System.getProperty("host", "0.0.0.0")) - .addValue("port", System.getProperty("port", "8070")) - .addValue("root", System.getProperty("root", "./root3/")); - HttpServer server = new HttpServer(); - server.addHttpServlet("/pipes", new VideoWebSocketServlet(), "/listen/*"); - server.init(config); - server.start(); - cdl.await(); - } -} +/* + * 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.test.websocket; + +import java.io.*; +import java.util.*; +import java.util.concurrent.*; +import org.redkale.net.http.HttpRequest; +import org.redkale.net.http.HttpServer; +import org.redkale.net.http.WebServlet; +import org.redkale.net.http.WebSocket; +import org.redkale.net.http.WebSocketServlet; +import org.redkale.util.AnyValueWriter; +import org.redkale.util.TypeToken; + +/** @author zhangjx */ +@WebServlet({"/ws/listen"}) +public class VideoWebSocketServlet extends WebSocketServlet { + + private final Map sessions = new java.util.concurrent.ConcurrentHashMap<>(); + + private final Map users = new HashMap<>(); + + private static final class Entry { + + public WebSocket socket; + + public String username; + + public Serializable userid; + } + + public VideoWebSocketServlet() { + super(); + users.put("zhangjx", "xxxx"); + } + + @Override + protected WebSocket createWebSocket() { + WebSocket socket = new WebSocket() { + + private final TypeToken> mapToken = new TypeToken>() {}; + + private boolean repeat = false; + + @Override + public CompletableFuture onOpen(final HttpRequest request) { + String uri = request.getRequestPath(); + int pos = uri.indexOf("/listen/"); + uri = uri.substring(pos + "/listen/".length()); + this.repeat = sessions.get(uri) != null; + if (!this.repeat) this.repeat = users.get(uri) == null; + String sessionid = Long.toString(System.nanoTime()); + if (uri.indexOf('\'') >= 0 || uri.indexOf('"') >= 0) return null; + if (!repeat) sessionid = uri; + return CompletableFuture.completedFuture(sessionid); + } + + @Override + public CompletableFuture onConnected() { + if (repeat) { + super.close(); + } else { + Entry entry = new Entry(); + entry.userid = this.getSessionid(); + entry.username = users.get(entry.userid); + sessions.put(this.getSessionid(), entry); + StringBuilder sb = new StringBuilder(); + for (Map.Entry en : sessions.entrySet()) { + if (sb.length() > 0) sb.append(','); + sb.append("{'userid':'") + .append(en.getKey()) + .append("','username':'") + .append(en.getValue().username) + .append("'}"); + } + super.send(("{'type':'user_list','users':[" + sb + "]}").replace('\'', '"')); + String msg = ("{'type':'discover_user','user':{'userid':'" + this.getSessionid() + "','username':'" + + users.get(this.getSessionid()) + "'}}") + .replace('\'', '"'); + super.broadcastMessage(msg); + } + return null; + } + + @Override + public void onMessage(Object text, boolean last) { + // System.out.println("接收到消息: " + text); + super.broadcastMessage(text, last); + } + + @Override + public CompletableFuture onClose(int code, String reason) { + sessions.remove(this.getSessionid()); + String msg = ("{'type':'remove_user','user':{'userid':'" + this.getSessionid() + "','username':'" + + users.get(this.getSessionid()) + "'}}") + .replace('\'', '"'); + return super.broadcastMessage(msg); + } + + @Override + protected CompletableFuture createUserid() { + return CompletableFuture.completedFuture("2"); + } + }; + return socket; + } + + public static void main(String[] args) throws Throwable { + CountDownLatch cdl = new CountDownLatch(1); + AnyValueWriter config = AnyValueWriter.create() + .addValue("threads", System.getProperty("threads")) + .addValue("bufferPoolSize", System.getProperty("bufferPoolSize")) + .addValue("responsePoolSize", System.getProperty("responsePoolSize")) + .addValue("host", System.getProperty("host", "0.0.0.0")) + .addValue("port", System.getProperty("port", "8070")) + .addValue("root", System.getProperty("root", "./root3/")); + HttpServer server = new HttpServer(); + server.addHttpServlet("/pipes", new VideoWebSocketServlet(), "/listen/*"); + server.init(config); + server.start(); + cdl.await(); + } +} diff --git a/src/test/java/org/redkale/test/ws/ChatMessage.java b/src/test/java/org/redkale/test/ws/ChatMessage.java index 1312ce9e0..9d9378b72 100644 --- a/src/test/java/org/redkale/test/ws/ChatMessage.java +++ b/src/test/java/org/redkale/test/ws/ChatMessage.java @@ -1,24 +1,24 @@ -/* - * 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.test.ws; - -import org.redkale.convert.json.JsonConvert; - -/** @author zhangjx */ -public class ChatMessage { - - public int fromuserid; - - public int touserid; - - public String fromusername; - - public String content; - - public String toString() { - return JsonConvert.root().convertTo(this); - } -} +/* + * 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.test.ws; + +import org.redkale.convert.json.JsonConvert; + +/** @author zhangjx */ +public class ChatMessage { + + public int fromuserid; + + public int touserid; + + public String fromusername; + + public String content; + + public String toString() { + return JsonConvert.root().convertTo(this); + } +} diff --git a/src/test/java/org/redkale/test/ws/ChatService.java b/src/test/java/org/redkale/test/ws/ChatService.java index 3c559bce1..1fa70c70b 100644 --- a/src/test/java/org/redkale/test/ws/ChatService.java +++ b/src/test/java/org/redkale/test/ws/ChatService.java @@ -1,51 +1,51 @@ -/* - * 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.test.ws; - -import java.util.*; -import java.util.concurrent.*; -import java.util.concurrent.atomic.AtomicInteger; -import org.redkale.annotation.Comment; -import org.redkale.annotation.Resource; -import org.redkale.net.http.WebSocketNode; -import org.redkale.service.*; - -/** @author zhangjx */ -public class ChatService implements Service { - - @Comment("key=用户ID,value=房间ID") - private final Map userToRooms = new ConcurrentHashMap<>(); - - @Comment("key=房间ID,value=用户ID列表") - private final Map> roomToUsers = new ConcurrentHashMap<>(); - - protected final AtomicInteger idcreator = new AtomicInteger(10000); - - @Resource(name = "chat") - protected WebSocketNode wsnode; - - @Comment("创建一个用户ID") - public int createUserid() { - return idcreator.incrementAndGet(); - } - - @Comment("用户加入指定房间") - public boolean joinRoom(int userid, int roomid) { - userToRooms.put(userid, roomid); - roomToUsers.computeIfAbsent(roomid, (id) -> new CopyOnWriteArrayList()).add(userid); - System.out.println("加入房间: roomid: " + roomid); - return true; - } - - public void chatMessage(ChatMessage message) { - wsnode.broadcastMessage(message); - } - - @Comment("其他操作") - public void other(int roomid, String name) { - System.out.println("其他操作: roomid: " + roomid + ", name: " + name); - } -} +/* + * 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.test.ws; + +import java.util.*; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicInteger; +import org.redkale.annotation.Comment; +import org.redkale.annotation.Resource; +import org.redkale.net.http.WebSocketNode; +import org.redkale.service.*; + +/** @author zhangjx */ +public class ChatService implements Service { + + @Comment("key=用户ID,value=房间ID") + private final Map userToRooms = new ConcurrentHashMap<>(); + + @Comment("key=房间ID,value=用户ID列表") + private final Map> roomToUsers = new ConcurrentHashMap<>(); + + protected final AtomicInteger idcreator = new AtomicInteger(10000); + + @Resource(name = "chat") + protected WebSocketNode wsnode; + + @Comment("创建一个用户ID") + public int createUserid() { + return idcreator.incrementAndGet(); + } + + @Comment("用户加入指定房间") + public boolean joinRoom(int userid, int roomid) { + userToRooms.put(userid, roomid); + roomToUsers.computeIfAbsent(roomid, (id) -> new CopyOnWriteArrayList()).add(userid); + System.out.println("加入房间: roomid: " + roomid); + return true; + } + + public void chatMessage(ChatMessage message) { + wsnode.broadcastMessage(message); + } + + @Comment("其他操作") + public void other(int roomid, String name) { + System.out.println("其他操作: roomid: " + roomid + ", name: " + name); + } +} diff --git a/src/test/java/org/redkale/test/ws/ChatWebSocket.java b/src/test/java/org/redkale/test/ws/ChatWebSocket.java index 5ddc28bad..4b55e1582 100644 --- a/src/test/java/org/redkale/test/ws/ChatWebSocket.java +++ b/src/test/java/org/redkale/test/ws/ChatWebSocket.java @@ -1,110 +1,110 @@ -/* - * 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.test.ws; - -import java.util.*; -import java.util.concurrent.CompletableFuture; -import org.redkale.annotation.Resource; -import org.redkale.net.http.*; -import org.redkale.service.RetResult; -import org.redkale.test.rest.*; - -/** @author zhangjx */ -// anyuser = true 表示WebSocket.createUserid返回的值不表示用户登录态 -@RestWebSocket(name = "chat", catalog = "ws", comment = "文字聊天", anyuser = true) -public class ChatWebSocket extends WebSocket { - - // @Resource标记的Field只能被修饰为public或protected - @Resource - protected ChatService service; - - @Resource - protected UserService userService; - - protected UserInfo user; - - @Override - protected CompletableFuture onOpen(final HttpRequest request) { - LoginBean bean = request.getJsonParameter(LoginBean.class, "bean"); - RetResult ret = userService.login(bean); - if (ret.isSuccess()) { // 登录成功 - user = ret.getResult(); - // 随机创建一个sessionid - return CompletableFuture.completedFuture(request.getSessionid(true)); - } else { // 登录失败, 返回null - return send("{\"onLoginFailMessage\":" + ret + "}").thenApply(x -> null); - } - } - - @Override - protected CompletableFuture createUserid() { - return CompletableFuture.completedFuture(user.getUserid()); - } - - /** - * 浏览器WebSocket请求: - * - *
-     * websocket.send(JSON.stringify({
-     *      sendmessage:{
-     *          message:{
-     *              content : "这是聊天内容"
-     *          },
-     *          extmap:{
-     *              "a":1,
-     *              "b":"haha"
-     *          }
-     *      }
-     * }));
-     * 
- * - * @param message 参数1 - * @param extmap 参数2 - */ - @RestOnMessage(name = "sendmessage") - public void onChatMessage(ChatMessage message, Map extmap) { - message.fromuserid = getUserid(); - message.fromusername = "用户" + getUserid(); - System.out.println("获取消息: message: " + message + ", map: " + extmap); - service.chatMessage(message); - } - - /** - * 浏览器WebSocket请求: - * - *
-     * websocket.send(JSON.stringify({
-     *      joinroom:{
-     *          roomid: 10212
-     *      }
-     * }));
-     * 
- * - * @param roomid 参数1 - */ - @RestOnMessage(name = "joinroom") - public void onJoinRoom(int roomid) { - service.joinRoom(getUserid(), roomid); - } - - /** - * 浏览器WebSocket请求: - * - *
-     * websocket.send(JSON.stringify({
-     *      roomid: 10212
-     *      name: "haha"
-     * }));
-     * 
- * - * @param roomid 参数1 - * @param name 参数2 - */ - @RestOnMessage(name = "*") // *为特殊值表示参数中不包含方法名 - public void other(int roomid, String name) { - service.other(roomid, name); - } -} +/* + * 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.test.ws; + +import java.util.*; +import java.util.concurrent.CompletableFuture; +import org.redkale.annotation.Resource; +import org.redkale.net.http.*; +import org.redkale.service.RetResult; +import org.redkale.test.rest.*; + +/** @author zhangjx */ +// anyuser = true 表示WebSocket.createUserid返回的值不表示用户登录态 +@RestWebSocket(name = "chat", catalog = "ws", comment = "文字聊天", anyuser = true) +public class ChatWebSocket extends WebSocket { + + // @Resource标记的Field只能被修饰为public或protected + @Resource + protected ChatService service; + + @Resource + protected UserService userService; + + protected UserInfo user; + + @Override + protected CompletableFuture onOpen(final HttpRequest request) { + LoginBean bean = request.getJsonParameter(LoginBean.class, "bean"); + RetResult ret = userService.login(bean); + if (ret.isSuccess()) { // 登录成功 + user = ret.getResult(); + // 随机创建一个sessionid + return CompletableFuture.completedFuture(request.getSessionid(true)); + } else { // 登录失败, 返回null + return send("{\"onLoginFailMessage\":" + ret + "}").thenApply(x -> null); + } + } + + @Override + protected CompletableFuture createUserid() { + return CompletableFuture.completedFuture(user.getUserid()); + } + + /** + * 浏览器WebSocket请求: + * + *
+     * websocket.send(JSON.stringify({
+     *      sendmessage:{
+     *          message:{
+     *              content : "这是聊天内容"
+     *          },
+     *          extmap:{
+     *              "a":1,
+     *              "b":"haha"
+     *          }
+     *      }
+     * }));
+     * 
+ * + * @param message 参数1 + * @param extmap 参数2 + */ + @RestOnMessage(name = "sendmessage") + public void onChatMessage(ChatMessage message, Map extmap) { + message.fromuserid = getUserid(); + message.fromusername = "用户" + getUserid(); + System.out.println("获取消息: message: " + message + ", map: " + extmap); + service.chatMessage(message); + } + + /** + * 浏览器WebSocket请求: + * + *
+     * websocket.send(JSON.stringify({
+     *      joinroom:{
+     *          roomid: 10212
+     *      }
+     * }));
+     * 
+ * + * @param roomid 参数1 + */ + @RestOnMessage(name = "joinroom") + public void onJoinRoom(int roomid) { + service.joinRoom(getUserid(), roomid); + } + + /** + * 浏览器WebSocket请求: + * + *
+     * websocket.send(JSON.stringify({
+     *      roomid: 10212
+     *      name: "haha"
+     * }));
+     * 
+ * + * @param roomid 参数1 + * @param name 参数2 + */ + @RestOnMessage(name = "*") // *为特殊值表示参数中不包含方法名 + public void other(int roomid, String name) { + service.other(roomid, name); + } +} diff --git a/src/test/java/org/redkale/test/wsdync/_DyncChatWebSocketServlet.java b/src/test/java/org/redkale/test/wsdync/_DyncChatWebSocketServlet.java index a9d1785cf..c773fb1c5 100644 --- a/src/test/java/org/redkale/test/wsdync/_DyncChatWebSocketServlet.java +++ b/src/test/java/org/redkale/test/wsdync/_DyncChatWebSocketServlet.java @@ -1,205 +1,205 @@ -/* - * 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.test.wsdync; - -import java.io.Serializable; -import java.lang.annotation.Annotation; -import java.util.*; -import java.util.function.BiConsumer; -import org.redkale.annotation.Resource; -import org.redkale.convert.ConvertDisabled; -import org.redkale.convert.json.JsonConvert; -import org.redkale.net.http.*; -import org.redkale.test.ws.ChatMessage; -import org.redkale.test.ws.ChatService; -import org.redkale.test.ws.ChatWebSocket; - -/** @author zhangjx */ -// @WebServlet("/ws/chat") -public final class _DyncChatWebSocketServlet extends WebSocketServlet { - - @Resource - private ChatService _redkale_resource_0; - - public static Map _redkale_annotations; - - public _DyncChatWebSocketServlet() { - super(); - this.messageRestType = _DyncChatWebSocketMessage.class; - } - - @Override - protected WebSocket createWebSocket() { - return (WebSocket) new _DyncChatWebSocket(_redkale_resource_0); - } - - @Override - protected BiConsumer createRestOnMessageConsumer() { - return new _DynRestOnMessageConsumer(); - } - - public static class _DyncChatWebSocket extends ChatWebSocket { - - public _DyncChatWebSocket(ChatService service) { - super(); - this.service = service; - } - } - - public static class _DyncChatWebSocketMessage implements WebSocketParam, Runnable { - - public _DyncChatWebSocketMessage_sendmessagee_00 sendmessage; - - public _DyncChatWebSocketMessage_joinroom_01 joinroom; - - @ConvertDisabled - public _DyncChatWebSocket _redkale_websocket; - - public int roomid; - - public String name; - - @Override - public String[] getNames() { - return new String[] {"roomid", "name"}; - } - - @Override - public T getValue(String name) { - if ("roomid".equals(name)) return (T) (Integer) roomid; - if ("name".equals(name)) return (T) (String) name; - return null; - } - - @Override - public Annotation[] getAnnotations() { - Annotation[] annotations = _redkale_annotations.get( - "org/redkale/test/wsdync/_DyncChatWebSocketServlet$_DyncChatWebSocketMessage"); - if (annotations == null) return new Annotation[0]; - return Arrays.copyOf(annotations, annotations.length); - } - - public void execute(_DyncChatWebSocket websocket) { - this._redkale_websocket = websocket; - websocket.preOnMessage("*", this, this); - } - - @Override - public void run() { - _redkale_websocket.other(this.roomid, this.name); - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } - } - - public static class _DyncChatWebSocketMessage_sendmessagee_00 implements WebSocketParam, Runnable { - - public ChatMessage message; - - public Map extmap; - - @ConvertDisabled - public _DyncChatWebSocket _redkale_websocket; - - @Override - public String[] getNames() { - return new String[] {"message", "extmap"}; - } - - @Override - public T getValue(String name) { - if ("message".equals(name)) return (T) message; - if ("extmap".equals(name)) return (T) extmap; - return null; - } - - @Override - public Annotation[] getAnnotations() { - Annotation[] annotations = _redkale_annotations.get( - "org/redkale/test/wsdync/_DyncChatWebSocketServlet$_DyncChatWebSocketMessage_sendmessagee_00"); - if (annotations == null) return new Annotation[0]; - return Arrays.copyOf(annotations, annotations.length); - } - - public void execute(_DyncChatWebSocket websocket) { - this._redkale_websocket = websocket; - websocket.preOnMessage("sendmessage", this, this); - } - - @Override - public void run() { - _redkale_websocket.onChatMessage(this.message, this.extmap); - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } - } - - public static class _DyncChatWebSocketMessage_joinroom_01 implements WebSocketParam, Runnable { - - public int roomid; - - @ConvertDisabled - public _DyncChatWebSocket _redkale_websocket; - - @Override - public String[] getNames() { - return new String[] {"roomid"}; - } - - @Override - public T getValue(String name) { - if ("roomid".equals(name)) return (T) (Integer) roomid; - return null; - } - - @Override - public Annotation[] getAnnotations() { - Annotation[] annotations = _redkale_annotations.get( - "org/redkale/test/wsdync/_DyncChatWebSocketServlet$_DyncChatWebSocketMessage_joinroom_01"); - if (annotations == null) return new Annotation[0]; - return Arrays.copyOf(annotations, annotations.length); - } - - public void execute(_DyncChatWebSocket websocket) { - this._redkale_websocket = websocket; - websocket.preOnMessage("joinroom", this, this); - } - - @Override - public void run() { - _redkale_websocket.onJoinRoom(this.roomid); - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } - } - - public static class _DynRestOnMessageConsumer implements BiConsumer { - - @Override - public void accept(WebSocket websocket0, Object message0) { - _DyncChatWebSocket websocket = (_DyncChatWebSocket) websocket0; - _DyncChatWebSocketMessage message = (_DyncChatWebSocketMessage) message0; - if (message.sendmessage != null) { - message.sendmessage.execute(websocket); - return; - } - if (message.joinroom != null) { - message.joinroom.execute(websocket); - return; - } - message.execute(websocket); - } - } -} +/* + * 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.test.wsdync; + +import java.io.Serializable; +import java.lang.annotation.Annotation; +import java.util.*; +import java.util.function.BiConsumer; +import org.redkale.annotation.Resource; +import org.redkale.convert.ConvertDisabled; +import org.redkale.convert.json.JsonConvert; +import org.redkale.net.http.*; +import org.redkale.test.ws.ChatMessage; +import org.redkale.test.ws.ChatService; +import org.redkale.test.ws.ChatWebSocket; + +/** @author zhangjx */ +// @WebServlet("/ws/chat") +public final class _DyncChatWebSocketServlet extends WebSocketServlet { + + @Resource + private ChatService _redkale_resource_0; + + public static Map _redkale_annotations; + + public _DyncChatWebSocketServlet() { + super(); + this.messageRestType = _DyncChatWebSocketMessage.class; + } + + @Override + protected WebSocket createWebSocket() { + return (WebSocket) new _DyncChatWebSocket(_redkale_resource_0); + } + + @Override + protected BiConsumer createRestOnMessageConsumer() { + return new _DynRestOnMessageConsumer(); + } + + public static class _DyncChatWebSocket extends ChatWebSocket { + + public _DyncChatWebSocket(ChatService service) { + super(); + this.service = service; + } + } + + public static class _DyncChatWebSocketMessage implements WebSocketParam, Runnable { + + public _DyncChatWebSocketMessage_sendmessagee_00 sendmessage; + + public _DyncChatWebSocketMessage_joinroom_01 joinroom; + + @ConvertDisabled + public _DyncChatWebSocket _redkale_websocket; + + public int roomid; + + public String name; + + @Override + public String[] getNames() { + return new String[] {"roomid", "name"}; + } + + @Override + public T getValue(String name) { + if ("roomid".equals(name)) return (T) (Integer) roomid; + if ("name".equals(name)) return (T) (String) name; + return null; + } + + @Override + public Annotation[] getAnnotations() { + Annotation[] annotations = _redkale_annotations.get( + "org/redkale/test/wsdync/_DyncChatWebSocketServlet$_DyncChatWebSocketMessage"); + if (annotations == null) return new Annotation[0]; + return Arrays.copyOf(annotations, annotations.length); + } + + public void execute(_DyncChatWebSocket websocket) { + this._redkale_websocket = websocket; + websocket.preOnMessage("*", this, this); + } + + @Override + public void run() { + _redkale_websocket.other(this.roomid, this.name); + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + } + + public static class _DyncChatWebSocketMessage_sendmessagee_00 implements WebSocketParam, Runnable { + + public ChatMessage message; + + public Map extmap; + + @ConvertDisabled + public _DyncChatWebSocket _redkale_websocket; + + @Override + public String[] getNames() { + return new String[] {"message", "extmap"}; + } + + @Override + public T getValue(String name) { + if ("message".equals(name)) return (T) message; + if ("extmap".equals(name)) return (T) extmap; + return null; + } + + @Override + public Annotation[] getAnnotations() { + Annotation[] annotations = _redkale_annotations.get( + "org/redkale/test/wsdync/_DyncChatWebSocketServlet$_DyncChatWebSocketMessage_sendmessagee_00"); + if (annotations == null) return new Annotation[0]; + return Arrays.copyOf(annotations, annotations.length); + } + + public void execute(_DyncChatWebSocket websocket) { + this._redkale_websocket = websocket; + websocket.preOnMessage("sendmessage", this, this); + } + + @Override + public void run() { + _redkale_websocket.onChatMessage(this.message, this.extmap); + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + } + + public static class _DyncChatWebSocketMessage_joinroom_01 implements WebSocketParam, Runnable { + + public int roomid; + + @ConvertDisabled + public _DyncChatWebSocket _redkale_websocket; + + @Override + public String[] getNames() { + return new String[] {"roomid"}; + } + + @Override + public T getValue(String name) { + if ("roomid".equals(name)) return (T) (Integer) roomid; + return null; + } + + @Override + public Annotation[] getAnnotations() { + Annotation[] annotations = _redkale_annotations.get( + "org/redkale/test/wsdync/_DyncChatWebSocketServlet$_DyncChatWebSocketMessage_joinroom_01"); + if (annotations == null) return new Annotation[0]; + return Arrays.copyOf(annotations, annotations.length); + } + + public void execute(_DyncChatWebSocket websocket) { + this._redkale_websocket = websocket; + websocket.preOnMessage("joinroom", this, this); + } + + @Override + public void run() { + _redkale_websocket.onJoinRoom(this.roomid); + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + } + + public static class _DynRestOnMessageConsumer implements BiConsumer { + + @Override + public void accept(WebSocket websocket0, Object message0) { + _DyncChatWebSocket websocket = (_DyncChatWebSocket) websocket0; + _DyncChatWebSocketMessage message = (_DyncChatWebSocketMessage) message0; + if (message.sendmessage != null) { + message.sendmessage.execute(websocket); + return; + } + if (message.joinroom != null) { + message.joinroom.execute(websocket); + return; + } + message.execute(websocket); + } + } +}

详情见: https://redkale.org - * - * @author zhangjx - * @param 结果对象的泛型 - * @param 附件对象的泛型 - * @since 2.8.0 - */ -public interface SncpAsyncHandler extends CompletionHandler { - - public static SncpAsyncHandler createHandler( - Class handlerClazz, CompletionHandler factHandler) { - Objects.requireNonNull(handlerClazz); - Objects.requireNonNull(factHandler); - if (handlerClazz == CompletionHandler.class) { - return new SncpAsyncHandler() { - @Override - public void completed(Object result, Object attachment) { - factHandler.completed(result, attachment); - } - - @Override - public void failed(Throwable exc, Object attachment) { - factHandler.failed(exc, attachment); - } - }; - } - return HandlerInner.creatorMap - .computeIfAbsent(handlerClazz, handlerClass -> { - // ------------------------------------------------------------- - final boolean handlerInterface = handlerClass.isInterface(); - final Class sncpHandlerClass = SncpAsyncHandler.class; - final String handlerClassName = handlerClass.getName().replace('.', '/'); - final String sncpHandlerName = sncpHandlerClass.getName().replace('.', '/'); - final String cpDesc = Type.getDescriptor(org.redkale.annotation.ConstructorParameters.class); - final String realHandlerName = - CompletionHandler.class.getName().replace('.', '/'); - final String realHandlerDesc = Type.getDescriptor(CompletionHandler.class); - final String newDynName = "org/redkaledyn/sncp/handler/_Dyn" + sncpHandlerClass.getSimpleName() - + "__" + handlerClass.getName().replace('.', '/').replace('$', '_'); - try { - Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.')); - Class newHandlerClazz = clz == null - ? Thread.currentThread().getContextClassLoader().loadClass(newDynName.replace('/', '.')) - : clz; - return (Creator) Creator.create(newHandlerClazz); - } catch (Throwable ex) { - // do nothing - } - // ------------------------------------------------------------------------------ - ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); - FieldVisitor fv; - MethodDebugVisitor mv; - AnnotationVisitor av0; - cw.visit( - V11, - ACC_PUBLIC + ACC_FINAL + ACC_SUPER, - newDynName, - null, - handlerInterface ? "java/lang/Object" : handlerClassName, - handlerInterface && handlerClass != sncpHandlerClass - ? new String[] {handlerClassName, sncpHandlerName} - : new String[] {sncpHandlerName}); - - { // handler 属性 - fv = cw.visitField(ACC_PRIVATE, "factHandler", realHandlerDesc, null, null); - fv.visitEnd(); - } - { // 构造方法 - mv = new MethodDebugVisitor( - cw.visitMethod(ACC_PUBLIC, "", "(" + realHandlerDesc + ")V", null, null)); - // mv.setDebug(true); - { - av0 = mv.visitAnnotation(cpDesc, true); - { - AnnotationVisitor av1 = av0.visitArray("value"); - av1.visit(null, "factHandler"); - av1.visitEnd(); - } - av0.visitEnd(); - } - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn( - INVOKESPECIAL, - handlerInterface ? "java/lang/Object" : handlerClassName, - "", - "()V", - false); - mv.visitVarInsn(ALOAD, 0); - mv.visitVarInsn(ALOAD, 1); - mv.visitFieldInsn(PUTFIELD, newDynName, "factHandler", realHandlerDesc); - mv.visitInsn(RETURN); - mv.visitMaxs(2, 2); - mv.visitEnd(); - } - for (Method method : Sncp.loadNotImplMethods(handlerClass)) { // - int mod = method.getModifiers(); - String methodDesc = Type.getMethodDescriptor(method); - if (Modifier.isPublic(mod) - && "completed".equals(method.getName()) - && method.getParameterCount() == 2) { - mv = new MethodDebugVisitor( - cw.visitMethod(ACC_PUBLIC, "completed", methodDesc, null, null)); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, "factHandler", realHandlerDesc); - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(ALOAD, 2); - mv.visitMethodInsn( - INVOKEINTERFACE, - realHandlerName, - "completed", - "(Ljava/lang/Object;Ljava/lang/Object;)V", - true); - mv.visitInsn(RETURN); - mv.visitMaxs(3, 3); - mv.visitEnd(); - // if (!"(Ljava/lang/Object;Ljava/lang/Object;)V".equals(methodDesc)) { - // mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC + ACC_BRIDGE - // + ACC_SYNTHETIC, "completed", "(Ljava/lang/Object;Ljava/lang/Object;)V", null, null)); - // mv.visitVarInsn(ALOAD, 0); - // mv.visitVarInsn(ALOAD, 1); - // mv.visitTypeInsn(CHECKCAST, "java/lang/Object"); - // mv.visitVarInsn(ALOAD, 2); - // mv.visitTypeInsn(CHECKCAST, "java/lang/Object"); - // mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "completed", - // methodDesc, false); - // mv.visitInsn(RETURN); - // mv.visitMaxs(3, 3); - // mv.visitEnd(); - // } - } else if (Modifier.isPublic(mod) - && "failed".equals(method.getName()) - && method.getParameterCount() == 2) { - mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "failed", methodDesc, null, null)); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, "factHandler", realHandlerDesc); - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(ALOAD, 2); - mv.visitMethodInsn( - INVOKEINTERFACE, - realHandlerName, - "failed", - "(Ljava/lang/Throwable;Ljava/lang/Object;)V", - true); - mv.visitInsn(RETURN); - mv.visitMaxs(3, 3); - mv.visitEnd(); - // if (!"(Ljava/lang/Throwable;Ljava/lang/Object;)V".equals(methodDesc)) - // { - // mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC + ACC_BRIDGE - // + ACC_SYNTHETIC, "failed", "(Ljava/lang/Throwable;Ljava/lang/Object;)V", null, null)); - // mv.visitVarInsn(ALOAD, 0); - // mv.visitVarInsn(ALOAD, 1); - // mv.visitVarInsn(ALOAD, 2); - // mv.visitTypeInsn(CHECKCAST, "java/lang/Object"); - // mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "failed", - // methodDesc, false); - // mv.visitInsn(RETURN); - // mv.visitMaxs(3, 3); - // mv.visitEnd(); - // } - } else if (handlerInterface || Modifier.isAbstract(mod)) { - mv = new MethodDebugVisitor(cw.visitMethod( - ACC_PUBLIC, method.getName(), Type.getMethodDescriptor(method), null, null)); - Class returnType = method.getReturnType(); - if (returnType == void.class) { - mv.visitInsn(RETURN); - mv.visitMaxs(0, 1); - } else if (returnType.isPrimitive()) { - mv.visitInsn(ICONST_0); - if (returnType == long.class) { - mv.visitInsn(LRETURN); - mv.visitMaxs(2, 1); - } else if (returnType == float.class) { - mv.visitInsn(FRETURN); - mv.visitMaxs(2, 1); - } else if (returnType == double.class) { - mv.visitInsn(DRETURN); - mv.visitMaxs(2, 1); - } else { - mv.visitInsn(IRETURN); - mv.visitMaxs(1, 1); - } - } else { - mv.visitInsn(ACONST_NULL); - mv.visitInsn(ARETURN); - mv.visitMaxs(1, 1); - } - mv.visitEnd(); - } - } - cw.visitEnd(); - byte[] bytes = cw.toByteArray(); - Class newClazz = - new ClassLoader((handlerClass != CompletionHandler.class ? handlerClass : sncpHandlerClass) - .getClassLoader()) { - public final Class loadClass(String name, byte[] b) { - return defineClass(name, b, 0, b.length); - } - }.loadClass(newDynName.replace('/', '.'), bytes); - RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, newClazz); - return (Creator) Creator.create(newClazz); - }) - .create(factHandler); - } - - static class HandlerInner { - - static final Map> creatorMap = new ConcurrentHashMap<>(); - - private HandlerInner() { - // do nothing - } - } -} +/* + * + */ +package org.redkale.net.sncp; + +import static org.redkale.asm.Opcodes.*; + +import java.lang.reflect.*; +import java.nio.channels.CompletionHandler; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import org.redkale.asm.*; +import org.redkale.asm.Type; +import org.redkale.util.*; + +/** + * 异步回调函数 + * + *