From 7b0ae127a96eb508af5c2b980b20041efff01d56 Mon Sep 17 00:00:00 2001 From: Mercy Ma Date: Mon, 17 Feb 2020 20:15:43 +0800 Subject: [PATCH] 2.7.6 REST Metadata (#5738) * Polish /apache/dubbo#4687 : Remove the duplicated test code in dubbo-config-spring * Polish /apache/dubbo#4674 & /apache/dubbo#4470 * Polish /apache/dubbo#5093 : Revert the previous commit * Polish apache/dubbo#5093 : [Feature] Dubbo Services generate the metadata of REST services * Polish apache/dubbo#5306 : [Migration] Upgrade the @since tags in Javadoc migration cloud native to master * Polish apache/dubbo#5306 : [Migration] Upgrade the @since tags in Javadoc migration cloud native to master * Polish apache/dubbo#5309 : [ISSURE] The beans of Dubbo's Config can't be found on the ReferenceBean's initialization * Polish apache/dubbo#5312 : Resolve the demos' issues of zookeeper and nacos * Polish apache/dubbo#5313 : [Migration] migrate the code in common module from cloud-native branch to master * Polish apache/dubbo#5316 : [Refactor] Replace @EnableDubboConfigBinding Using spring-context-support * Polish apache/dubbo#5317 : [Refactor] Refactor ReferenceAnnotationBeanPostProcessor using Alibaba spring-context-suuport API * Polish apache/dubbo#5321 : Remove BeanFactoryUtils * Polish apache/dubbo#5321 : Remove AnnotatedBeanDefinitionRegistryUtils * Polish apache/dubbo#5321 : Remove AnnotationUtils * Polish apache/dubbo#5321 : Remove ClassUtils * Polish apache/dubbo#5321 : Remove BeanRegistrar * Polish apache/dubbo#5321 : Remove ObjectUtils * Polish apache/dubbo#5321 : Remove PropertySourcesUtils * Polish apache/dubbo#5325 : [Migration] To migrate dubbo-metadata-api from cloud-native branch * Polish apache/dubbo#5326 : [Migration] To migrate dubbo-metadata-processor from cloud-native branch * Polish apache/dubbo#5329 : [Feature] To add the default metadata into ServiceInstance * Polish apache/dubbo#5339 : [Refactor] Refactor the DynamicConfiguration interface * Polish bugfix * Fixes test cases * Merge remote-tracking branch 'upstream/master' into cloud-native-2.7.5 # Conflicts: # dubbo-configcenter/dubbo-configcenter-zookeeper/src/test/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfigurationTest.java # dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/DynamicConfigurationServiceNameMappingTest.java * Merge remote-tracking branch 'upstream/master' into cloud-native-2.7.5 # Conflicts: # dubbo-configcenter/dubbo-configcenter-zookeeper/src/test/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfigurationTest.java # dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/DynamicConfigurationServiceNameMappingTest.java * Polish /apache/dubbo#5721 : [Enhancement] Setting the default IDs for Dubbo's Config Beans * Polish /apache/dubbo#5729 : [Optimization] To remove EnableDubboConfigBinding and EnableDubboConfigBindings * Polish /apache/dubbo#5594 : [Feature] Add the resolver of ServiceRestMetadata based on Java Reflection * Polish /apache/dubbo#5736 : [Feature] Introducing Conversion features * Polish /apache/dubbo#5737 : [Feature] Introducing "dubbo-metadata-processor" module * Polish /apache/dubbo#5594 : Change the Metadata implementation * Polish /apache/dubbo#5594 : Fixed test cases * Polish /apache/dubbo#5594 : Fixed test cases * Polish /apache/dubbo#5594 : Fixed test cases * Polish /apache/dubbo#5594 : Fixed test cases * Polish /apache/dubbo#5594 : Fixed test cases * Polish /apache/dubbo#5594 : Fixed test cases * Polish /apache/dubbo#5594 : Fixed test cases * Polish /apache/dubbo#5594 : Fixed test cases --- dubbo-all/pom.xml | 191 +++++-- .../dubbo/common/convert/Converter.java | 91 ++++ .../dubbo/common/convert/StringConverter.java | 27 + .../convert/StringToBooleanConverter.java | 38 ++ .../convert/StringToCharArrayConverter.java | 39 ++ .../convert/StringToCharacterConverter.java | 44 ++ .../convert/StringToDoubleConverter.java | 39 ++ .../convert/StringToFloatConverter.java | 38 ++ .../convert/StringToIntegerConverter.java | 38 ++ .../common/convert/StringToLongConverter.java | 39 ++ .../convert/StringToOptionalConverter.java | 40 ++ .../convert/StringToShortConverter.java | 39 ++ .../convert/StringToStringConverter.java | 30 ++ .../convert/multiple/MultiValueConverter.java | 64 +++ .../multiple/StringToArrayConverter.java | 60 +++ .../StringToBlockingDequeConverter.java | 33 ++ .../StringToBlockingQueueConverter.java | 34 ++ .../multiple/StringToCollectionConverter.java | 33 ++ .../multiple/StringToDequeConverter.java | 33 ++ .../multiple/StringToIterableConverter.java | 80 +++ .../multiple/StringToListConverter.java | 33 ++ .../multiple/StringToMultiValueConverter.java | 61 +++ .../StringToNavigableSetConverter.java | 34 ++ .../multiple/StringToQueueConverter.java | 34 ++ .../multiple/StringToSetConverter.java | 33 ++ .../multiple/StringToSortedSetConverter.java | 33 ++ .../StringToTransferQueueConverter.java | 33 ++ .../common/extension/ExtensionLoader.java | 11 +- .../dubbo/common/utils/AnnotationUtils.java | 452 +++++++++++++++++ .../common/utils/CharSequenceComparator.java | 37 ++ .../apache/dubbo/common/utils/ClassUtils.java | 226 ++++++++- .../dubbo/common/utils/CollectionUtils.java | 109 +++- .../apache/dubbo/common/utils/HttpUtils.java | 264 ++++++++++ .../dubbo/common/utils/MemberUtils.java | 62 +++ .../dubbo/common/utils/MethodComparator.java | 71 +++ .../dubbo/common/utils/MethodUtils.java | 292 ++++++++++- .../dubbo/common/utils/ReflectUtils.java | 34 ++ .../utils/ServiceAnnotationResolver.java | 119 +++++ .../apache/dubbo/common/utils/TypeUtils.java | 224 +++++++++ .../org.apache.dubbo.common.convert.Converter | 11 + ...ommon.convert.multiple.MultiValueConverter | 12 + .../common/utils/AnnotationUtilsTest.java | 343 +++++++++++++ .../dubbo/common/utils/MemberUtilsTest.java | 42 ++ .../convert/StringToBooleanConverterTest.java | 58 +++ .../StringToCharArrayConverterTest.java | 54 ++ .../StringToCharacterConverterTest.java | 58 +++ .../convert/StringToDoubleConverterTest.java | 58 +++ .../convert/StringToFloatConverterTest.java | 58 +++ .../convert/StringToIntegerConverterTest.java | 58 +++ .../convert/StringToLongConverterTest.java | 58 +++ .../StringToOptionalConverterTest.java | 55 ++ .../convert/StringToShortConverterTest.java | 58 +++ .../convert/StringToStringConverterTest.java | 54 ++ .../multiple/StringToArrayConverterTest.java | 70 +++ .../StringToBlockingDequeConverterTest.java | 122 +++++ .../StringToBlockingQueueConverterTest.java | 125 +++++ .../StringToCollectionConverterTest.java | 119 +++++ .../multiple/StringToDequeConverterTest.java | 120 +++++ .../multiple/StringToListConverterTest.java | 119 +++++ .../StringToNavigableSetConverterTest.java | 119 +++++ .../multiple/StringToQueueConverterTest.java | 119 +++++ .../multiple/StringToSetConverterTest.java | 118 +++++ .../StringToSortedSetConverterTest.java | 119 +++++ .../StringToTransferQueueConverterTest.java | 122 +++++ .../dubbo/generic/GenericServiceTest.java | 3 +- .../dubbo/config/spring/ServiceBean.java | 3 +- dubbo-metadata/dubbo-metadata-api/pom.xml | 14 + .../definition/MethodDefinitionBuilder.java | 78 +++ .../definition/TypeDefinitionBuilder.java | 4 +- .../definition/builder/MapTypeBuilder.java | 37 +- ...ractAnnotatedMethodParameterProcessor.java | 51 ++ .../AbstractServiceRestMetadataResolver.java | 341 +++++++++++++ .../AnnotatedMethodParameterProcessor.java | 66 +++ .../ClassPathServiceRestMetadataReader.java | 82 +++ .../DefaultServiceRestMetadataResolver.java | 59 +++ .../dubbo/metadata/rest/RequestMetadata.java | 226 +++++++++ .../metadata/rest/RestMetadataConstants.java | 112 +++++ .../metadata/rest/RestMethodMetadata.java | 195 ++++++++ .../metadata/rest/ServiceRestMetadata.java | 103 ++++ .../rest/ServiceRestMetadataReader.java | 39 ++ .../rest/ServiceRestMetadataResolver.java | 43 ++ .../jaxrs/DefaultValueParameterProcessor.java | 74 +++ .../jaxrs/FormParamParameterProcessor.java | 34 ++ .../jaxrs/HeaderParamParameterProcessor.java | 49 ++ .../JAXRSServiceRestMetadataResolver.java | 99 ++++ .../jaxrs/MatrixParamParameterProcessor.java | 34 ++ .../ParamAnnotationParameterProcessor.java | 38 ++ .../jaxrs/QueryParamParameterProcessor.java | 34 ++ ...ctRequestAnnotationParameterProcessor.java | 62 +++ .../RequestHeaderParameterProcessor.java | 43 ++ .../RequestParamParameterProcessor.java | 43 ++ .../SpringMvcServiceRestMetadataResolver.java | 128 +++++ ...ata.rest.AnnotatedMethodParameterProcessor | 10 + ....metadata.rest.ServiceRestMetadataResolver | 3 + ...java => ServiceDefinitionBuilderTest.java} | 4 +- .../metadata/rest/DefaultRestService.java | 69 +++ .../dubbo/metadata/rest/RestService.java | 42 ++ .../metadata/rest/SpringRestService.java | 97 ++++ .../metadata/rest/StandardRestService.java | 107 ++++ .../org/apache/dubbo/metadata/rest/User.java | 61 +++ .../JAXRSServiceRestMetadataResolverTest.java | 82 +++ .../dubbo/jax-rs-service-rest-metadata.json | 349 +++++++++++++ .../protobuf/ProtobufTypeBuilderTest.java | 4 +- .../dubbo-metadata-processor/pom.xml | 177 +++++++ .../AbstractServiceAnnotationProcessor.java | 108 ++++ .../processing/ClassPathMetadataStorage.java | 105 ++++ ...DefinitionMetadataAnnotationProcessor.java | 60 +++ .../builder/ArrayTypeDefinitionBuilder.java | 50 ++ .../CollectionTypeDefinitionBuilder.java | 61 +++ .../DeclaredTypeDefinitionBuilder.java | 49 ++ .../builder/EnumTypeDefinitionBuilder.java | 55 ++ .../builder/GeneralTypeDefinitionBuilder.java | 65 +++ .../builder/MapTypeDefinitionBuilder.java | 62 +++ .../builder/MethodDefinitionBuilder.java | 53 ++ .../PrimitiveTypeDefinitionBuilder.java | 48 ++ .../builder/ServiceDefinitionBuilder.java | 56 +++ .../builder/SimpleTypeDefinitionBuilder.java | 49 ++ .../builder/TypeDefinitionBuilder.java | 96 ++++ ...ractAnnotatedMethodParameterProcessor.java | 52 ++ .../AbstractServiceRestMetadataResolver.java | 291 +++++++++++ .../AnnotatedMethodParameterProcessor.java | 64 +++ .../DefaultServiceRestMetadataResolver.java | 186 +++++++ ...erviceRestMetadataAnnotationProcessor.java | 86 ++++ .../rest/ServiceRestMetadataResolver.java | 55 ++ .../rest/ServiceRestMetadataStorage.java | 65 +++ .../jaxrs/DefaultValueParameterProcessor.java | 75 +++ .../jaxrs/FormParamParameterProcessor.java | 34 ++ .../jaxrs/HeaderParamParameterProcessor.java | 51 ++ .../JAXRSServiceRestMetadataResolver.java | 108 ++++ .../jaxrs/MatrixParamParameterProcessor.java | 34 ++ .../ParamAnnotationParameterProcessor.java | 38 ++ .../jaxrs/QueryParamParameterProcessor.java | 34 ++ ...ctRequestAnnotationParameterProcessor.java | 69 +++ .../RequestHeaderParameterProcessor.java | 43 ++ .../RequestParamParameterProcessor.java | 44 ++ .../SpringMvcServiceRestMetadataResolver.java | 165 ++++++ .../processing/util/AnnotationUtils.java | 233 +++++++++ .../util/ExecutableElementComparator.java | 72 +++ .../processing/util/FieldUtils.java | 146 ++++++ .../processing/util/LoggerUtils.java | 45 ++ .../processing/util/MemberUtils.java | 94 ++++ .../processing/util/MethodUtils.java | 156 ++++++ .../util/ServiceAnnotationUtils.java | 121 +++++ .../annotation/processing/util/TypeUtils.java | 400 +++++++++++++++ ...n.processing.builder.TypeDefinitionBuilder | 7 + ...ing.rest.AnnotatedMethodParameterProcessor | 10 + ...rocessing.rest.ServiceRestMetadataResolver | 3 + .../javax.annotation.processing.Processor | 2 + .../AbstractAnnotationProcessingTest.java | 69 +++ .../ArrayTypeDefinitionBuilderTest.java | 121 +++++ .../CollectionTypeDefinitionBuilderTest.java | 105 ++++ .../EnumTypeDefinitionBuilderTest.java | 67 +++ .../GeneralTypeDefinitionBuilderTest.java | 67 +++ .../builder/MapTypeDefinitionBuilderTest.java | 134 +++++ .../PrimitiveTypeDefinitionBuilderTest.java | 130 +++++ .../builder/ServiceDefinitionBuilderTest.java | 64 +++ .../SimpleTypeDefinitionBuilderTest.java | 146 ++++++ .../processing/model/ArrayTypeModel.java | 36 ++ .../processing/model/CollectionTypeModel.java | 42 ++ .../annotation/processing/model/Color.java | 46 ++ .../processing/model/MapTypeModel.java | 41 ++ .../annotation/processing/model/Model.java | 89 ++++ .../processing/model/PrimitiveTypeModel.java | 73 +++ .../processing/model/SimpleTypeModel.java | 161 ++++++ ...AnnotatedMethodParameterProcessorTest.java | 59 +++ .../processing/util/AnnotationUtilsTest.java | 231 +++++++++ .../processing/util/FieldUtilsTest.java | 259 ++++++++++ .../processing/util/LoggerUtilsTest.java | 50 ++ .../processing/util/MemberUtilsTest.java | 113 +++++ .../processing/util/MethodUtilsTest.java | 195 ++++++++ .../util/ServiceAnnotationUtilsTest.java | 136 +++++ .../processing/util/TypeUtilsTest.java | 468 ++++++++++++++++++ .../metadata/rest/DefaultRestService.java | 69 +++ .../dubbo/metadata/rest/RestService.java | 42 ++ .../metadata/rest/SpringRestService.java | 97 ++++ .../metadata/rest/StandardRestService.java | 107 ++++ .../org/apache/dubbo/metadata/rest/User.java | 61 +++ .../apache/dubbo/metadata/tools/Ancestor.java | 35 ++ .../apache/dubbo/metadata/tools/Compiler.java | 116 +++++ .../dubbo/metadata/tools/CompilerTest.java | 37 ++ .../tools/DefaultRestServiceTest.java | 45 ++ .../metadata/tools/DefaultTestService.java | 63 +++ .../metadata/tools/GenericTestService.java | 38 ++ .../apache/dubbo/metadata/tools/Parent.java | 63 +++ .../dubbo/metadata/tools/RestServiceTest.java | 42 ++ .../metadata/tools/SpringRestServiceTest.java | 39 ++ .../tools/StandardRestServiceTest.java | 39 ++ .../dubbo/metadata/tools/TestProcessor.java | 46 ++ .../dubbo/metadata/tools/TestService.java | 54 ++ .../dubbo/metadata/tools/TestServiceImpl.java | 51 ++ dubbo-metadata/pom.xml | 1 + pom.xml | 5 +- 192 files changed, 16107 insertions(+), 85 deletions(-) create mode 100644 dubbo-common/src/main/java/org/apache/dubbo/common/convert/Converter.java create mode 100644 dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringConverter.java create mode 100644 dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringToBooleanConverter.java create mode 100644 dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringToCharArrayConverter.java create mode 100644 dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringToCharacterConverter.java create mode 100644 dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringToDoubleConverter.java create mode 100644 dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringToFloatConverter.java create mode 100644 dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringToIntegerConverter.java create mode 100644 dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringToLongConverter.java create mode 100644 dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringToOptionalConverter.java create mode 100644 dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringToShortConverter.java create mode 100644 dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringToStringConverter.java create mode 100644 dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/MultiValueConverter.java create mode 100644 dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToArrayConverter.java create mode 100644 dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToBlockingDequeConverter.java create mode 100644 dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToBlockingQueueConverter.java create mode 100644 dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToCollectionConverter.java create mode 100644 dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToDequeConverter.java create mode 100644 dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToIterableConverter.java create mode 100644 dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToListConverter.java create mode 100644 dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToMultiValueConverter.java create mode 100644 dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToNavigableSetConverter.java create mode 100644 dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToQueueConverter.java create mode 100644 dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToSetConverter.java create mode 100644 dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToSortedSetConverter.java create mode 100644 dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToTransferQueueConverter.java create mode 100644 dubbo-common/src/main/java/org/apache/dubbo/common/utils/AnnotationUtils.java create mode 100644 dubbo-common/src/main/java/org/apache/dubbo/common/utils/CharSequenceComparator.java create mode 100644 dubbo-common/src/main/java/org/apache/dubbo/common/utils/HttpUtils.java create mode 100644 dubbo-common/src/main/java/org/apache/dubbo/common/utils/MemberUtils.java create mode 100644 dubbo-common/src/main/java/org/apache/dubbo/common/utils/MethodComparator.java create mode 100644 dubbo-common/src/main/java/org/apache/dubbo/common/utils/ServiceAnnotationResolver.java create mode 100644 dubbo-common/src/main/java/org/apache/dubbo/common/utils/TypeUtils.java create mode 100644 dubbo-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.convert.Converter create mode 100644 dubbo-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.convert.multiple.MultiValueConverter create mode 100644 dubbo-common/src/test/java/org/apache/dubbo/common/utils/AnnotationUtilsTest.java create mode 100644 dubbo-common/src/test/java/org/apache/dubbo/common/utils/MemberUtilsTest.java create mode 100644 dubbo-common/src/test/java/org/apache/dubbo/convert/StringToBooleanConverterTest.java create mode 100644 dubbo-common/src/test/java/org/apache/dubbo/convert/StringToCharArrayConverterTest.java create mode 100644 dubbo-common/src/test/java/org/apache/dubbo/convert/StringToCharacterConverterTest.java create mode 100644 dubbo-common/src/test/java/org/apache/dubbo/convert/StringToDoubleConverterTest.java create mode 100644 dubbo-common/src/test/java/org/apache/dubbo/convert/StringToFloatConverterTest.java create mode 100644 dubbo-common/src/test/java/org/apache/dubbo/convert/StringToIntegerConverterTest.java create mode 100644 dubbo-common/src/test/java/org/apache/dubbo/convert/StringToLongConverterTest.java create mode 100644 dubbo-common/src/test/java/org/apache/dubbo/convert/StringToOptionalConverterTest.java create mode 100644 dubbo-common/src/test/java/org/apache/dubbo/convert/StringToShortConverterTest.java create mode 100644 dubbo-common/src/test/java/org/apache/dubbo/convert/StringToStringConverterTest.java create mode 100644 dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToArrayConverterTest.java create mode 100644 dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToBlockingDequeConverterTest.java create mode 100644 dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToBlockingQueueConverterTest.java create mode 100644 dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToCollectionConverterTest.java create mode 100644 dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToDequeConverterTest.java create mode 100644 dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToListConverterTest.java create mode 100644 dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToNavigableSetConverterTest.java create mode 100644 dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToQueueConverterTest.java create mode 100644 dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToSetConverterTest.java create mode 100644 dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToSortedSetConverterTest.java create mode 100644 dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToTransferQueueConverterTest.java create mode 100644 dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/definition/MethodDefinitionBuilder.java create mode 100644 dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/AbstractAnnotatedMethodParameterProcessor.java create mode 100644 dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/AbstractServiceRestMetadataResolver.java create mode 100644 dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/AnnotatedMethodParameterProcessor.java create mode 100644 dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/ClassPathServiceRestMetadataReader.java create mode 100644 dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/DefaultServiceRestMetadataResolver.java create mode 100644 dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/RequestMetadata.java create mode 100644 dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/RestMetadataConstants.java create mode 100644 dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/RestMethodMetadata.java create mode 100644 dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/ServiceRestMetadata.java create mode 100644 dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/ServiceRestMetadataReader.java create mode 100644 dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/ServiceRestMetadataResolver.java create mode 100644 dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/jaxrs/DefaultValueParameterProcessor.java create mode 100644 dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/jaxrs/FormParamParameterProcessor.java create mode 100644 dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/jaxrs/HeaderParamParameterProcessor.java create mode 100644 dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/jaxrs/JAXRSServiceRestMetadataResolver.java create mode 100644 dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/jaxrs/MatrixParamParameterProcessor.java create mode 100644 dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/jaxrs/ParamAnnotationParameterProcessor.java create mode 100644 dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/jaxrs/QueryParamParameterProcessor.java create mode 100644 dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/springmvc/AbstractRequestAnnotationParameterProcessor.java create mode 100644 dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/springmvc/RequestHeaderParameterProcessor.java create mode 100644 dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/springmvc/RequestParamParameterProcessor.java create mode 100644 dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/springmvc/SpringMvcServiceRestMetadataResolver.java create mode 100644 dubbo-metadata/dubbo-metadata-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.rest.AnnotatedMethodParameterProcessor create mode 100644 dubbo-metadata/dubbo-metadata-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.rest.ServiceRestMetadataResolver rename dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/definition/{ServiceDefinitionBuildderTest.java => ServiceDefinitionBuilderTest.java} (97%) create mode 100644 dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/rest/DefaultRestService.java create mode 100644 dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/rest/RestService.java create mode 100644 dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/rest/SpringRestService.java create mode 100644 dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/rest/StandardRestService.java create mode 100644 dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/rest/User.java create mode 100644 dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/rest/resolver/jaxrs/JAXRSServiceRestMetadataResolverTest.java create mode 100644 dubbo-metadata/dubbo-metadata-api/src/test/resources/META-INF/dubbo/jax-rs-service-rest-metadata.json create mode 100644 dubbo-metadata/dubbo-metadata-processor/pom.xml create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/AbstractServiceAnnotationProcessor.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/ClassPathMetadataStorage.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/ServiceDefinitionMetadataAnnotationProcessor.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/ArrayTypeDefinitionBuilder.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/CollectionTypeDefinitionBuilder.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/DeclaredTypeDefinitionBuilder.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/EnumTypeDefinitionBuilder.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/GeneralTypeDefinitionBuilder.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/MapTypeDefinitionBuilder.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/MethodDefinitionBuilder.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/PrimitiveTypeDefinitionBuilder.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/ServiceDefinitionBuilder.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/SimpleTypeDefinitionBuilder.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/TypeDefinitionBuilder.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/AbstractAnnotatedMethodParameterProcessor.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/AbstractServiceRestMetadataResolver.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/AnnotatedMethodParameterProcessor.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/DefaultServiceRestMetadataResolver.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/ServiceRestMetadataAnnotationProcessor.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/ServiceRestMetadataResolver.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/ServiceRestMetadataStorage.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/jaxrs/DefaultValueParameterProcessor.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/jaxrs/FormParamParameterProcessor.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/jaxrs/HeaderParamParameterProcessor.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/jaxrs/JAXRSServiceRestMetadataResolver.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/jaxrs/MatrixParamParameterProcessor.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/jaxrs/ParamAnnotationParameterProcessor.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/jaxrs/QueryParamParameterProcessor.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/springmvc/AbstractRequestAnnotationParameterProcessor.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/springmvc/RequestHeaderParameterProcessor.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/springmvc/RequestParamParameterProcessor.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/springmvc/SpringMvcServiceRestMetadataResolver.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/AnnotationUtils.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/ExecutableElementComparator.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/FieldUtils.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/LoggerUtils.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/MemberUtils.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/MethodUtils.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/ServiceAnnotationUtils.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/TypeUtils.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.annotation.processing.builder.TypeDefinitionBuilder create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.annotation.processing.rest.AnnotatedMethodParameterProcessor create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.annotation.processing.rest.ServiceRestMetadataResolver create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/main/resources/META-INF/services/javax.annotation.processing.Processor create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/AbstractAnnotationProcessingTest.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/ArrayTypeDefinitionBuilderTest.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/CollectionTypeDefinitionBuilderTest.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/EnumTypeDefinitionBuilderTest.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/GeneralTypeDefinitionBuilderTest.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/MapTypeDefinitionBuilderTest.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/PrimitiveTypeDefinitionBuilderTest.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/ServiceDefinitionBuilderTest.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/SimpleTypeDefinitionBuilderTest.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/ArrayTypeModel.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/CollectionTypeModel.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/Color.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/MapTypeModel.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/Model.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/PrimitiveTypeModel.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/SimpleTypeModel.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/rest/AnnotatedMethodParameterProcessorTest.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/AnnotationUtilsTest.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/FieldUtilsTest.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/LoggerUtilsTest.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/MemberUtilsTest.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/MethodUtilsTest.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/ServiceAnnotationUtilsTest.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/TypeUtilsTest.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/rest/DefaultRestService.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/rest/RestService.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/rest/SpringRestService.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/rest/StandardRestService.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/rest/User.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/Ancestor.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/Compiler.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/CompilerTest.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/DefaultRestServiceTest.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/DefaultTestService.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/GenericTestService.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/Parent.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/RestServiceTest.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/SpringRestServiceTest.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/StandardRestServiceTest.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/TestProcessor.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/TestService.java create mode 100644 dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/TestServiceImpl.java diff --git a/dubbo-all/pom.xml b/dubbo-all/pom.xml index 6904795038..325083e80e 100644 --- a/dubbo-all/pom.xml +++ b/dubbo-all/pom.xml @@ -14,7 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. --> - + 4.0.0 org.apache.dubbo @@ -685,172 +686,218 @@ - + META-INF/dubbo/internal/org.apache.dubbo.common.compiler.Compiler - + META-INF/dubbo/internal/org.apache.dubbo.common.config.configcenter.DynamicConfigurationFactory - + META-INF/dubbo/internal/org.apache.dubbo.common.extension.ExtensionFactory - + META-INF/dubbo/internal/org.apache.dubbo.common.infra.InfraAdapter - + META-INF/dubbo/internal/org.apache.dubbo.common.logger.LoggerAdapter - + META-INF/dubbo/internal/org.apache.dubbo.common.status.StatusChecker - + META-INF/dubbo/internal/org.apache.dubbo.common.store.DataStore - + META-INF/dubbo/internal/org.apache.dubbo.common.threadpool.ThreadPool - + META-INF/dubbo/internal/org.apache.dubbo.common.serialize.Serialization - + META-INF/dubbo/internal/org.apache.dubbo.remoting.Dispatcher - + META-INF/dubbo/internal/org.apache.dubbo.remoting.Codec2 - + META-INF/dubbo/internal/org.apache.dubbo.remoting.Transporter - + META-INF/dubbo/internal/org.apache.dubbo.remoting.exchange.Exchanger - + META-INF/dubbo/internal/org.apache.dubbo.remoting.http.HttpBinder - + META-INF/dubbo/internal/org.apache.dubbo.remoting.p2p.Networker - + META-INF/dubbo/internal/org.apache.dubbo.remoting.telnet.TelnetHandler - + META-INF/dubbo/internal/org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter - + META-INF/dubbo/internal/org.apache.dubbo.rpc.Protocol - + META-INF/dubbo/internal/org.apache.dubbo.rpc.Filter - + META-INF/dubbo/internal/org.apache.dubbo.rpc.InvokerListener - + META-INF/dubbo/internal/org.apache.dubbo.rpc.ExporterListener - + META-INF/dubbo/internal/org.apache.dubbo.rpc.ProxyFactory - + META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.Cluster - + META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.LoadBalance - + META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.Merger - + META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.RouterFactory - + META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.ConfiguratorFactory - + META-INF/dubbo/internal/org.apache.dubbo.container.Container - + META-INF/dubbo/internal/org.apache.dubbo.monitor.MonitorFactory - + META-INF/dubbo/internal/org.apache.dubbo.registry.RegistryFactory - + META-INF/dubbo/internal/org.apache.dubbo.validation.Validation - + META-INF/dubbo/internal/org.apache.dubbo.cache.CacheFactory - + META-INF/dubbo/internal/org.apache.dubbo.qos.command.BaseCommand - - META-INF/dubbo/internal/org.apache.dubbo.metadata.report.MetadataReportFactory + + + META-INF/dubbo/internal/org.apache.dubbo.metadata.report.MetadataReportFactory - + META-INF/dubbo/internal/org.apache.dubbo.event.EventDispatcher - + META-INF/dubbo/internal/org.apache.dubbo.metadata.MetadataServiceExporter - + META-INF/dubbo/internal/org.apache.dubbo.metadata.WritableMetadataService - + META-INF/dubbo/internal/org.apache.dubbo.metadata.ServiceNameMapping - - META-INF/dubbo/internal/org.apache.dubbo.registry.client.metadata.proxy.MetadataServiceProxyFactory + + + META-INF/dubbo/internal/org.apache.dubbo.registry.client.metadata.proxy.MetadataServiceProxyFactory - - META-INF/dubbo/internal/org.apache.dubbo.registry.client.ServiceDiscoveryFactory + + + META-INF/dubbo/internal/org.apache.dubbo.registry.client.ServiceDiscoveryFactory - + META-INF/dubbo/internal/org.apache.dubbo.registry.client.ServiceDiscovery - - META-INF/dubbo/internal/org.apache.dubbo.metadata.definition.builder.TypeBuilder + + + META-INF/dubbo/internal/org.apache.dubbo.metadata.definition.builder.TypeBuilder + + + + + + META-INF/dubbo/internal/org.apache.dubbo.common.convert.Converter + + + + + META-INF/dubbo/internal/org.apache.dubbo.common.convert.multiple.MultiValueConverter + + + + + + + META-INF/dubbo/internal/org.apache.dubbo.metadata.rest.AnnotatedMethodParameterProcessor + + + + + META-INF/dubbo/internal/org.apache.dubbo.metadata.rest.ServiceRestMetadataResolver + + + + + + + META-INF/dubbo/internal/org.apache.dubbo.metadata.annotation.processing.builder.TypeDefinitionBuilder + + + + + META-INF/dubbo/internal/org.apache.dubbo.metadata.annotation.processing.rest.AnnotatedMethodParameterProcessor + + + + + META-INF/dubbo/internal/org.apache.dubbo.metadata.annotation.processing.rest.ServiceRestMetadataResolver + + + diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/convert/Converter.java b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/Converter.java new file mode 100644 index 0000000000..5bc2d4d809 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/Converter.java @@ -0,0 +1,91 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.common.convert; + +import org.apache.dubbo.common.extension.ExtensionLoader; +import org.apache.dubbo.common.extension.SPI; +import org.apache.dubbo.common.lang.Prioritized; + +import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader; +import static org.apache.dubbo.common.utils.ClassUtils.isAssignableFrom; +import static org.apache.dubbo.common.utils.TypeUtils.findActualTypeArgument; + +/** + * A class to convert the source-typed value to the target-typed value + * + * @param The source type + * @param The target type + * @since 2.7.6 + */ +@SPI +@FunctionalInterface +public interface Converter extends Prioritized { + + /** + * Accept the source type and target type or not + * + * @param sourceType the source type + * @param targetType the target type + * @return if accepted, return true, or false + */ + default boolean accept(Class sourceType, Class targetType) { + return isAssignableFrom(sourceType, getSourceType()) && isAssignableFrom(targetType, getTargetType()); + } + + /** + * Convert the source-typed value to the target-typed value + * + * @param source the source-typed value + * @return the target-typed value + */ + T convert(S source); + + /** + * Get the source type + * + * @return non-null + */ + default Class getSourceType() { + return findActualTypeArgument(getClass(), Converter.class, 0); + } + + /** + * Get the target type + * + * @return non-null + */ + default Class getTargetType() { + return findActualTypeArgument(getClass(), Converter.class, 1); + } + + /** + * Get the Converter instance from {@link ExtensionLoader} with the specified source and target type + * + * @param sourceType the source type + * @param targetType the target type + * @return + * @see ExtensionLoader#getSupportedExtensionInstances() + */ + static Converter getConverter(Class sourceType, Class targetType) { + return getExtensionLoader(Converter.class) + .getSupportedExtensionInstances() + .stream() + .filter(converter -> converter.accept(sourceType, targetType)) + .findFirst() + .orElse(null); + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringConverter.java b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringConverter.java new file mode 100644 index 0000000000..9232fedc5f --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringConverter.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.common.convert; + +/** + * A class to covert {@link String} to the target-typed value + * + * @see Converter + * @since 2.7.6 + */ +@FunctionalInterface +public interface StringConverter extends Converter { +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringToBooleanConverter.java b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringToBooleanConverter.java new file mode 100644 index 0000000000..98655c70a4 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringToBooleanConverter.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.common.convert; + +import static java.lang.Boolean.valueOf; +import static org.apache.dubbo.common.utils.StringUtils.isNotEmpty; + +/** + * The class to convert {@link String} to {@link Boolean} + * + * @since 2.7.6 + */ +public class StringToBooleanConverter implements StringConverter { + + @Override + public Boolean convert(String source) { + return isNotEmpty(source) ? valueOf(source) : null; + } + + @Override + public int getPriority() { + return NORMAL_PRIORITY + 5; + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringToCharArrayConverter.java b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringToCharArrayConverter.java new file mode 100644 index 0000000000..3e40bf1ed8 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringToCharArrayConverter.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.common.convert; + + +import static org.apache.dubbo.common.utils.StringUtils.isNotEmpty; + +/** + * The class to convert {@link String} to char[] + * + * @since 2.7.6 + */ +public class StringToCharArrayConverter implements StringConverter { + + @Override + public char[] convert(String source) { + return isNotEmpty(source) ? source.toCharArray() : null; + } + + + @Override + public int getPriority() { + return NORMAL_PRIORITY + 7; + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringToCharacterConverter.java b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringToCharacterConverter.java new file mode 100644 index 0000000000..580986f529 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringToCharacterConverter.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.common.convert; + +import static org.apache.dubbo.common.utils.StringUtils.length; + +/** + * The class to convert {@link String} to {@link Character} + * + * @since 2.7.6 + */ +public class StringToCharacterConverter implements StringConverter { + + @Override + public Character convert(String source) { + int length = length(source); + if (length == 0) { + return null; + } + if (length > 1) { + throw new IllegalArgumentException("The source String is more than one character!"); + } + return source.charAt(0); + } + + @Override + public int getPriority() { + return NORMAL_PRIORITY + 8; + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringToDoubleConverter.java b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringToDoubleConverter.java new file mode 100644 index 0000000000..148b2f8b5c --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringToDoubleConverter.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.common.convert; + +import static java.lang.Double.valueOf; +import static org.apache.dubbo.common.utils.StringUtils.isNotEmpty; + +/** + * The class to convert {@link String} to {@link Double} + * + * @since 2.7.6 + */ +public class StringToDoubleConverter implements StringConverter { + + @Override + public Double convert(String source) { + return isNotEmpty(source) ? valueOf(source) : null; + } + + + @Override + public int getPriority() { + return NORMAL_PRIORITY + 3; + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringToFloatConverter.java b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringToFloatConverter.java new file mode 100644 index 0000000000..a3b3b166c9 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringToFloatConverter.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.common.convert; + +import static java.lang.Float.valueOf; +import static org.apache.dubbo.common.utils.StringUtils.isNotEmpty; + +/** + * The class to convert {@link String} to {@link Float} + * + * @since 2.7.6 + */ +public class StringToFloatConverter implements StringConverter { + + @Override + public Float convert(String source) { + return isNotEmpty(source) ? valueOf(source) : null; + } + + @Override + public int getPriority() { + return NORMAL_PRIORITY + 4; + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringToIntegerConverter.java b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringToIntegerConverter.java new file mode 100644 index 0000000000..211f66d2dc --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringToIntegerConverter.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.common.convert; + +import static java.lang.Integer.valueOf; +import static org.apache.dubbo.common.utils.StringUtils.isNotEmpty; + +/** + * The class to convert {@link String} to {@link Integer} + * + * @since 2.7.6 + */ +public class StringToIntegerConverter implements StringConverter { + + @Override + public Integer convert(String source) { + return isNotEmpty(source) ? valueOf(source) : null; + } + + @Override + public int getPriority() { + return NORMAL_PRIORITY; + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringToLongConverter.java b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringToLongConverter.java new file mode 100644 index 0000000000..f9ebdcd687 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringToLongConverter.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.common.convert; + +import static java.lang.Long.valueOf; +import static org.apache.dubbo.common.utils.StringUtils.isNotEmpty; + +/** + * The class to convert {@link String} to {@link Long} + * + * @since 2.7.6 + */ +public class StringToLongConverter implements StringConverter { + + @Override + public Long convert(String source) { + return isNotEmpty(source) ? valueOf(source) : null; + } + + + @Override + public int getPriority() { + return NORMAL_PRIORITY + 1; + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringToOptionalConverter.java b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringToOptionalConverter.java new file mode 100644 index 0000000000..a26fa04b02 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringToOptionalConverter.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.common.convert; + +import java.util.Optional; + +import static java.util.Optional.ofNullable; + +/** + * The class to convert {@link String} to {@link Optional} + * + * @since 2.7.6 + */ +public class StringToOptionalConverter implements StringConverter { + + @Override + public Optional convert(String source) { + return ofNullable(source); + } + + + @Override + public int getPriority() { + return MIN_PRIORITY; + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringToShortConverter.java b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringToShortConverter.java new file mode 100644 index 0000000000..6427b17de4 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringToShortConverter.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.common.convert; + +import static java.lang.Short.valueOf; +import static org.apache.dubbo.common.utils.StringUtils.isNotEmpty; + +/** + * The class to convert {@link String} to {@link Short} + * + * @since 2.7.6 + */ +public class StringToShortConverter implements StringConverter { + + @Override + public Short convert(String source) { + return isNotEmpty(source) ? valueOf(source) : null; + } + + + @Override + public int getPriority() { + return NORMAL_PRIORITY + 2; + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringToStringConverter.java b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringToStringConverter.java new file mode 100644 index 0000000000..d97d523856 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringToStringConverter.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.common.convert; + +/** + * A class to covert {@link String} to {@link String} value, just no-op + * + * @since 2.7.6 + */ +public class StringToStringConverter implements StringConverter { + + @Override + public String convert(String source) { + return source; + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/MultiValueConverter.java b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/MultiValueConverter.java new file mode 100644 index 0000000000..298b4594a9 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/MultiValueConverter.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.common.convert.multiple; + +import org.apache.dubbo.common.extension.SPI; +import org.apache.dubbo.common.lang.Prioritized; + +import java.util.Collection; + +import static org.apache.dubbo.common.utils.TypeUtils.findActualTypeArgument; + +/** + * An interface to convert the source-typed value to multiple value, e.g , Java array, {@link Collection} or + * sub-interfaces + * + * @param The source type + * @since 2.7.6 + */ +@SPI +public interface MultiValueConverter extends Prioritized { + + /** + * Accept the source type and target type or not + * + * @param sourceType the source type + * @param multiValueType the multi-value type + * @return if accepted, return true, or false + */ + boolean accept(Class sourceType, Class multiValueType); + + /** + * Convert the source to be the multiple value + * + * @param source the source-typed value + * @param multiValueType the multi-value type + * @param elementType the element type + * @return + */ + Object convert(S source, Class multiValueType, Class elementType); + + /** + * Get the source type + * + * @return non-null + */ + default Class getSourceType() { + return findActualTypeArgument(getClass(), MultiValueConverter.class, 0); + } + +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToArrayConverter.java b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToArrayConverter.java new file mode 100644 index 0000000000..32490cd4a8 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToArrayConverter.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.common.convert.multiple; + +import org.apache.dubbo.common.convert.Converter; + +import java.lang.reflect.Array; + +import static java.lang.reflect.Array.newInstance; + +/** + * The class to convert {@link String} to array-type object + * + * @since 2.7.6 + */ +public class StringToArrayConverter implements StringToMultiValueConverter { + + public boolean accept(Class type, Class multiValueType) { + if (multiValueType != null && multiValueType.isArray()) { + return true; + } + return false; + } + + @Override + public Object convert(String[] segments, int size, Class targetType, Class elementType) { + + Class componentType = targetType.getComponentType(); + + Converter converter = Converter.getConverter(String.class, componentType); + + Object array = newInstance(componentType, size); + + for (int i = 0; i < size; i++) { + Array.set(array, i, converter.convert(segments[i])); + } + + return array; + } + + + @Override + public int getPriority() { + return MIN_PRIORITY; + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToBlockingDequeConverter.java b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToBlockingDequeConverter.java new file mode 100644 index 0000000000..61e0a7d529 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToBlockingDequeConverter.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.common.convert.multiple; + +import java.util.concurrent.BlockingDeque; +import java.util.concurrent.LinkedBlockingDeque; + +/** + * The class to convert {@link String} to {@link BlockingDeque}-based value + * + * @since 2.7.6 + */ +public class StringToBlockingDequeConverter extends StringToIterableConverter { + + @Override + protected BlockingDeque createMultiValue(int size, Class multiValueType) { + return new LinkedBlockingDeque(size); + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToBlockingQueueConverter.java b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToBlockingQueueConverter.java new file mode 100644 index 0000000000..f099e8475d --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToBlockingQueueConverter.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.common.convert.multiple; + +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingDeque; +import java.util.concurrent.BlockingQueue; + +/** + * The class to convert {@link String} to {@link BlockingDeque}-based value + * + * @since 2.7.6 + */ +public class StringToBlockingQueueConverter extends StringToIterableConverter { + + @Override + protected BlockingQueue createMultiValue(int size, Class multiValueType) { + return new ArrayBlockingQueue(size); + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToCollectionConverter.java b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToCollectionConverter.java new file mode 100644 index 0000000000..478447e445 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToCollectionConverter.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.common.convert.multiple; + +import java.util.ArrayList; +import java.util.Collection; + +/** + * The class to convert {@link String} to {@link Collection}-based value + * + * @since 2.7.6 + */ +public class StringToCollectionConverter extends StringToIterableConverter { + + @Override + protected Collection createMultiValue(int size, Class multiValueType) { + return new ArrayList(size); + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToDequeConverter.java b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToDequeConverter.java new file mode 100644 index 0000000000..19bdc33719 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToDequeConverter.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.common.convert.multiple; + +import java.util.ArrayDeque; +import java.util.Deque; + +/** + * The class to convert {@link String} to {@link Deque}-based value + * + * @since 2.7.6 + */ +public class StringToDequeConverter extends StringToIterableConverter { + + @Override + protected Deque createMultiValue(int size, Class multiValueType) { + return new ArrayDeque(size); + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToIterableConverter.java b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToIterableConverter.java new file mode 100644 index 0000000000..f84b360f25 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToIterableConverter.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.common.convert.multiple; + +import org.apache.dubbo.common.convert.StringConverter; + +import java.util.Collection; +import java.util.Optional; + +import static org.apache.dubbo.common.convert.Converter.getConverter; +import static org.apache.dubbo.common.utils.ClassUtils.getAllInterfaces; +import static org.apache.dubbo.common.utils.ClassUtils.isAssignableFrom; +import static org.apache.dubbo.common.utils.TypeUtils.findActualTypeArgument; + +/** + * The class to convert {@link String} to {@link Iterable}-based value + * + * @since 2.7.6 + */ +public abstract class StringToIterableConverter implements StringToMultiValueConverter { + + public boolean accept(Class type, Class multiValueType) { + return isAssignableFrom(getSupportedType(), multiValueType); + } + + @Override + public final Object convert(String[] segments, int size, Class multiValueType, Class elementType) { + + Optional stringConverter = getStringConverter(elementType); + + return stringConverter.map(converter -> { + + T convertedObject = createMultiValue(size, multiValueType); + + if (convertedObject instanceof Collection) { + Collection collection = (Collection) convertedObject; + for (int i = 0; i < size; i++) { + String segment = segments[i]; + Object element = converter.convert(segment); + collection.add(element); + } + return collection; + } + + return convertedObject; + }).orElse(null); + } + + protected abstract T createMultiValue(int size, Class multiValueType); + + protected Optional getStringConverter(Class elementType) { + StringConverter converter = (StringConverter) getConverter(String.class, elementType); + return Optional.ofNullable(converter); + } + + protected final Class getSupportedType() { + return findActualTypeArgument(getClass(), StringToIterableConverter.class, 0); + } + + @Override + public final int getPriority() { + int level = getAllInterfaces(getSupportedType(), type -> + isAssignableFrom(Iterable.class, type)).size(); + return MIN_PRIORITY - level; + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToListConverter.java b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToListConverter.java new file mode 100644 index 0000000000..111a3a78a0 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToListConverter.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.common.convert.multiple; + +import java.util.ArrayList; +import java.util.List; + +/** + * The class to convert {@link String} to {@link List}-based value + * + * @since 2.7.6 + */ +public class StringToListConverter extends StringToIterableConverter { + + @Override + protected List createMultiValue(int size, Class multiValueType) { + return new ArrayList(size); + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToMultiValueConverter.java b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToMultiValueConverter.java new file mode 100644 index 0000000000..75fefe6a7e --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToMultiValueConverter.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.common.convert.multiple; + +import org.apache.dubbo.common.utils.ArrayUtils; + +import static org.apache.dubbo.common.utils.StringUtils.isEmpty; +import static org.apache.dubbo.common.utils.StringUtils.split; + +/** + * The class to convert {@link String} to multiple value object + * + * @see MultiValueConverter + * @since 2.7.6 + */ +public interface StringToMultiValueConverter extends MultiValueConverter { + + @Override + default Object convert(String source, Class multiValueType, Class elementType) { + + if (isEmpty(source)) { + return null; + } + + // split by the comma + String[] segments = split(source, ','); + + if (ArrayUtils.isEmpty(segments)) { // If empty array, create an array with only one element + segments = new String[]{source}; + } + + int size = segments.length; + + return convert(segments, size, multiValueType, elementType); + } + + /** + * Convert the segments to multiple value object + * + * @param segments the String array of content + * @param size the size of multiple value object + * @param targetType the target type + * @param elementType the element type + * @return multiple value object + */ + Object convert(String[] segments, int size, Class targetType, Class elementType); +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToNavigableSetConverter.java b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToNavigableSetConverter.java new file mode 100644 index 0000000000..ccd692e2e7 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToNavigableSetConverter.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.common.convert.multiple; + +import java.util.NavigableSet; +import java.util.SortedSet; +import java.util.TreeSet; + +/** + * The class to convert {@link String} to {@link SortedSet}-based value + * + * @since 2.7.6 + */ +public class StringToNavigableSetConverter extends StringToIterableConverter { + + @Override + protected NavigableSet createMultiValue(int size, Class multiValueType) { + return new TreeSet(); + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToQueueConverter.java b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToQueueConverter.java new file mode 100644 index 0000000000..3bd7eed7de --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToQueueConverter.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.common.convert.multiple; + +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.Queue; + +/** + * The class to convert {@link String} to {@link Deque}-based value + * + * @since 2.7.6 + */ +public class StringToQueueConverter extends StringToIterableConverter { + + @Override + protected Queue createMultiValue(int size, Class multiValueType) { + return new ArrayDeque(size); + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToSetConverter.java b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToSetConverter.java new file mode 100644 index 0000000000..dfffeadcf6 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToSetConverter.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.common.convert.multiple; + +import java.util.HashSet; +import java.util.Set; + +/** + * The class to convert {@link String} to {@link Set}-based value + * + * @since 2.7.6 + */ +public class StringToSetConverter extends StringToIterableConverter { + + @Override + protected Set createMultiValue(int size, Class multiValueType) { + return new HashSet(size); + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToSortedSetConverter.java b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToSortedSetConverter.java new file mode 100644 index 0000000000..12b48d6ad5 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToSortedSetConverter.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.common.convert.multiple; + +import java.util.SortedSet; +import java.util.TreeSet; + +/** + * The class to convert {@link String} to {@link SortedSet}-based value + * + * @since 2.7.6 + */ +public class StringToSortedSetConverter extends StringToIterableConverter { + + @Override + protected SortedSet createMultiValue(int size, Class multiValueType) { + return new TreeSet(); + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToTransferQueueConverter.java b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToTransferQueueConverter.java new file mode 100644 index 0000000000..32ca09f83c --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToTransferQueueConverter.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.common.convert.multiple; + +import java.util.concurrent.LinkedTransferQueue; +import java.util.concurrent.TransferQueue; + +/** + * The class to convert {@link String} to {@link TransferQueue}-based value + * + * @since 2.7.6 + */ +public class StringToTransferQueueConverter extends StringToIterableConverter { + + @Override + protected TransferQueue createMultiValue(int size, Class multiValueType) { + return new LinkedTransferQueue(); + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionLoader.java b/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionLoader.java index 595b9d03e3..842a43f6ab 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionLoader.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionLoader.java @@ -19,6 +19,7 @@ package org.apache.dubbo.common.extension; import org.apache.dubbo.common.URL; import org.apache.dubbo.common.context.Lifecycle; import org.apache.dubbo.common.extension.support.ActivateComparator; +import org.apache.dubbo.common.lang.Prioritized; import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.utils.ArrayUtils; @@ -40,7 +41,8 @@ import java.util.Arrays; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; -import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; @@ -49,6 +51,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.regex.Pattern; +import static java.util.Collections.sort; import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SPLIT_PATTERN; import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY; import static org.apache.dubbo.common.constants.CommonConstants.REMOVE_VALUE_PREFIX; @@ -442,14 +445,16 @@ public class ExtensionLoader { } public Set getSupportedExtensionInstances() { - Set instances = new HashSet<>(); + List instances = new LinkedList<>(); Set supportedExtensions = getSupportedExtensions(); if (CollectionUtils.isNotEmpty(supportedExtensions)) { for (String name : supportedExtensions) { instances.add(getExtension(name)); } } - return instances; + // sort the Prioritized instances + sort(instances, Prioritized.COMPARATOR); + return new LinkedHashSet<>(instances); } /** diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/AnnotationUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/AnnotationUtils.java new file mode 100644 index 0000000000..600c8aaef9 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/AnnotationUtils.java @@ -0,0 +1,452 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.common.utils; + +import java.lang.annotation.Annotation; +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; +import java.lang.reflect.AnnotatedElement; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.function.Predicate; + +import static java.util.Arrays.asList; +import static java.util.Collections.emptyList; +import static java.util.Collections.unmodifiableList; +import static org.apache.dubbo.common.function.Predicates.and; +import static org.apache.dubbo.common.function.Streams.filterAll; +import static org.apache.dubbo.common.function.Streams.filterFirst; +import static org.apache.dubbo.common.utils.ClassUtils.getAllInheritedTypes; +import static org.apache.dubbo.common.utils.ClassUtils.resolveClass; +import static org.apache.dubbo.common.utils.CollectionUtils.first; +import static org.apache.dubbo.common.utils.MethodUtils.invokeMethod; + +/** + * Commons Annotation Utilities class + * + * @since 2.7.6 + */ +public interface AnnotationUtils { + + /** + * Resolve the annotation type by the annotated element and resolved class name + * + * @param annotatedElement the annotated element + * @param annotationClassName the class name of annotation + * @param the type of annotation + * @return If resolved, return the type of annotation, or null + */ + static Class resolveAnnotationType(AnnotatedElement annotatedElement, + String annotationClassName) { + ClassLoader classLoader = annotatedElement.getClass().getClassLoader(); + Class annotationType = resolveClass(annotationClassName, classLoader); + if (annotationType == null || !Annotation.class.isAssignableFrom(annotationType)) { + return null; + } + return (Class) annotationType; + } + + /** + * Is the specified type a generic {@link Class type} + * + * @param annotatedElement the annotated element + * @return if annotatedElement is the {@link Class}, return true, or false + * @see ElementType#TYPE + */ + static boolean isType(AnnotatedElement annotatedElement) { + return annotatedElement instanceof Class; + } + + /** + * Is the type of specified annotation same to the expected type? + * + * @param annotation the specified {@link Annotation} + * @param annotationType the expected annotation type + * @return if same, return true, or false + */ + static boolean isSameType(Annotation annotation, Class annotationType) { + if (annotation == null || annotationType == null) { + return false; + } + return Objects.equals(annotation.annotationType(), annotationType); + } + + /** + * Build an instance of {@link Predicate} to excluded annotation type + * + * @param excludedAnnotationType excluded annotation type + * @return non-null + */ + static Predicate excludedType(Class excludedAnnotationType) { + return annotation -> !isSameType(annotation, excludedAnnotationType); + } + + /** + * Get the attribute from the specified {@link Annotation annotation} + * + * @param annotation the specified {@link Annotation annotation} + * @param attributeName the attribute name + * @param the type of attribute + * @return the attribute value + * @throws IllegalArgumentException If the attribute name can't be found + */ + static T getAttribute(Annotation annotation, String attributeName) throws IllegalArgumentException { + return annotation == null ? null : invokeMethod(annotation, attributeName); + } + + /** + * Get the "value" attribute from the specified {@link Annotation annotation} + * + * @param annotation the specified {@link Annotation annotation} + * @param the type of attribute + * @return the value of "value" attribute + * @throws IllegalArgumentException If the attribute name can't be found + */ + static T getValue(Annotation annotation) throws IllegalArgumentException { + return getAttribute(annotation, "value"); + } + + /** + * Get the {@link Annotation} from the specified {@link AnnotatedElement the annotated element} and + * {@link Annotation annotation} class name + * + * @param annotatedElement {@link AnnotatedElement} + * @param annotationClassName the class name of annotation + * @param The type of {@link Annotation} + * @return the {@link Annotation} if found + * @throws ClassCastException If the {@link Annotation annotation} type that client requires can't match actual type + */ + static A getAnnotation(AnnotatedElement annotatedElement, String annotationClassName) + throws ClassCastException { + Class annotationType = resolveAnnotationType(annotatedElement, annotationClassName); + if (annotationType == null) { + return null; + } + return (A) annotatedElement.getAnnotation(annotationType); + } + + /** + * Get annotations that are directly present on this element. + * This method ignores inherited annotations. + * + * @param annotatedElement the annotated element + * @param annotationsToFilter the annotations to filter + * @return non-null read-only {@link List} + */ + static List getDeclaredAnnotations(AnnotatedElement annotatedElement, + Predicate... annotationsToFilter) { + if (annotatedElement == null) { + return emptyList(); + } + + return unmodifiableList(filterAll(asList(annotatedElement.getDeclaredAnnotations()), annotationsToFilter)); + } + + /** + * Get all directly declared annotations of the the annotated element, not including + * meta annotations. + * + * @param annotatedElement the annotated element + * @param annotationsToFilter the annotations to filter + * @return non-null read-only {@link List} + */ + static List getAllDeclaredAnnotations(AnnotatedElement annotatedElement, + Predicate... annotationsToFilter) { + if (isType(annotatedElement)) { + return getAllDeclaredAnnotations((Class) annotatedElement, annotationsToFilter); + } else { + return getDeclaredAnnotations(annotatedElement, annotationsToFilter); + } + } + + /** + * Get all directly declared annotations of the specified type and its' all hierarchical types, not including + * meta annotations. + * + * @param type the specified type + * @param annotationsToFilter the annotations to filter + * @return non-null read-only {@link List} + */ + static List getAllDeclaredAnnotations(Class type, Predicate... annotationsToFilter) { + + if (type == null) { + return emptyList(); + } + + List allAnnotations = new LinkedList<>(); + + // All types + Set> allTypes = new LinkedHashSet<>(); + // Add current type + allTypes.add(type); + // Add all inherited types + allTypes.addAll(getAllInheritedTypes(type, t -> !Object.class.equals(t))); + + for (Class t : allTypes) { + allAnnotations.addAll(getDeclaredAnnotations(t, annotationsToFilter)); + } + + return unmodifiableList(allAnnotations); + } + + + /** + * Get the meta-annotated {@link Annotation annotations} directly, excluding {@link Target}, {@link Retention} + * and {@link Documented} + * + * @param annotationType the {@link Annotation annotation} type + * @param metaAnnotationsToFilter the meta annotations to filter + * @return non-null read-only {@link List} + */ + static List getMetaAnnotations(Class annotationType, + Predicate... metaAnnotationsToFilter) { + return getDeclaredAnnotations(annotationType, + // Excludes the Java native annotation types or it causes the stack overflow, e.g, + // @Target annotates itself + excludedType(Target.class), + excludedType(Retention.class), + excludedType(Documented.class), + // Add other predicates + and(metaAnnotationsToFilter) + ); + } + + /** + * Get all meta annotations from the specified {@link Annotation annotation} type + * + * @param annotationType the {@link Annotation annotation} type + * @param annotationsToFilter the annotations to filter + * @return non-null read-only {@link List} + */ + static List getAllMetaAnnotations(Class annotationType, + Predicate... annotationsToFilter) { + + List allMetaAnnotations = new LinkedList<>(); + + List metaAnnotations = getMetaAnnotations(annotationType); + + allMetaAnnotations.addAll(metaAnnotations); + + for (Annotation metaAnnotation : metaAnnotations) { + // Get the nested meta annotations recursively + allMetaAnnotations.addAll(getAllMetaAnnotations(metaAnnotation.annotationType())); + } + + return unmodifiableList(filterAll(allMetaAnnotations, annotationsToFilter)); + } + + /** + * Find the annotation that is annotated on the specified element may be a meta-annotation + * + * @param annotatedElement the annotated element + * @param annotationClassName the class name of annotation + * @param the required type of annotation + * @return If found, return first matched-type {@link Annotation annotation}, or null + */ + static A findAnnotation(AnnotatedElement annotatedElement, String annotationClassName) { + return findAnnotation(annotatedElement, resolveAnnotationType(annotatedElement, annotationClassName)); + } + + /** + * Find the annotation that is annotated on the specified element may be a meta-annotation + * + * @param annotatedElement the annotated element + * @param annotationType the type of annotation + * @param the required type of annotation + * @return If found, return first matched-type {@link Annotation annotation}, or null + */ + static A findAnnotation(AnnotatedElement annotatedElement, Class annotationType) { + return (A) filterFirst(getAllDeclaredAnnotations(annotatedElement), a -> isSameType(a, annotationType)); + } + + /** + * Find the meta annotations from the the {@link Annotation annotation} type by meta annotation type + * + * @param annotationType the {@link Annotation annotation} type + * @param metaAnnotationType the meta annotation type + * @param the type of required annotation + * @return if found, return all matched results, or get an {@link Collections#emptyList() empty list} + */ + static List findMetaAnnotations(Class annotationType, + Class metaAnnotationType) { + return (List) getAllMetaAnnotations(annotationType, a -> isSameType(a, metaAnnotationType)); + } + + /** + * Find the meta annotations from the the the annotated element by meta annotation type + * + * @param annotatedElement the annotated element + * @param metaAnnotationType the meta annotation type + * @param the type of required annotation + * @return if found, return all matched results, or get an {@link Collections#emptyList() empty list} + */ + static List findMetaAnnotations(AnnotatedElement annotatedElement, + Class metaAnnotationType) { + List metaAnnotations = new LinkedList<>(); + + for (Annotation annotation : getAllDeclaredAnnotations(annotatedElement)) { + metaAnnotations.addAll(findMetaAnnotations(annotation.annotationType(), metaAnnotationType)); + } + + return unmodifiableList(metaAnnotations); + } + + /** + * Find the meta annotation from the annotated element by meta annotation type + * + * @param annotatedElement the annotated element + * @param metaAnnotationClassName the class name of meta annotation + * @param the type of required annotation + * @return {@link #findMetaAnnotation(Class, Class)} + */ + static A findMetaAnnotation(AnnotatedElement annotatedElement, + String metaAnnotationClassName) { + return findMetaAnnotation(annotatedElement, resolveAnnotationType(annotatedElement, metaAnnotationClassName)); + } + + /** + * Find the meta annotation from the annotation type by meta annotation type + * + * @param annotationType the {@link Annotation annotation} type + * @param metaAnnotationType the meta annotation type + * @param the type of required annotation + * @return If found, return the {@link CollectionUtils#first(Collection)} matched result, return null. + * If it requires more result, please consider to use {@link #findMetaAnnotations(Class, Class)} + * @see #findMetaAnnotations(Class, Class) + */ + static A findMetaAnnotation(Class annotationType, + Class metaAnnotationType) { + return first(findMetaAnnotations(annotationType, metaAnnotationType)); + } + + /** + * Find the meta annotation from the annotated element by meta annotation type + * + * @param annotatedElement the annotated element + * @param metaAnnotationType the meta annotation type + * @param the type of required annotation + * @return If found, return the {@link CollectionUtils#first(Collection)} matched result, return null. + * If it requires more result, please consider to use {@link #findMetaAnnotations(AnnotatedElement, Class)} + * @see #findMetaAnnotations(AnnotatedElement, Class) + */ + static A findMetaAnnotation(AnnotatedElement annotatedElement, Class metaAnnotationType) { + return first(findMetaAnnotations(annotatedElement, metaAnnotationType)); + } + + /** + * Tests the annotated element is annotated the specified annotations or not + * + * @param type the annotated type + * @param matchAll If true, checking all annotation types are present or not, or match any + * @param annotationTypes the specified annotation types + * @return If the specified annotation types are present, return true, or false + */ + static boolean isAnnotationPresent(Class type, + boolean matchAll, + Class... annotationTypes) { + + int size = annotationTypes == null ? 0 : annotationTypes.length; + + if (size < 1) { + return false; + } + + int presentCount = 0; + + for (int i = 0; i < size; i++) { + Class annotationType = annotationTypes[i]; + if (findAnnotation(type, annotationType) != null || findMetaAnnotation(type, annotationType) != null) { + presentCount++; + } + } + + return matchAll ? presentCount == size : presentCount > 0; + } + + /** + * Tests the annotated element is annotated the specified annotation or not + * + * @param type the annotated type + * @param annotationType the class of annotation + * @return If the specified annotation type is present, return true, or false + */ + static boolean isAnnotationPresent(Class type, Class annotationType) { + return isAnnotationPresent(type, true, annotationType); + } + + /** + * Tests the annotated element is present any specified annotation types + * + * @param annotatedElement the annotated element + * @param annotationClassName the class name of annotation + * @return If any specified annotation types are present, return true + */ + static boolean isAnnotationPresent(AnnotatedElement annotatedElement, String annotationClassName) { + ClassLoader classLoader = annotatedElement.getClass().getClassLoader(); + Class resolvedType = resolveClass(annotationClassName, classLoader); + if (!Annotation.class.isAssignableFrom(resolvedType)) { + return false; + } + return isAnnotationPresent(annotatedElement, (Class) resolvedType); + } + + /** + * Tests the annotated element is present any specified annotation types + * + * @param annotatedElement the annotated element + * @param annotationType the class of annotation + * @return If any specified annotation types are present, return true + */ + static boolean isAnnotationPresent(AnnotatedElement annotatedElement, Class annotationType) { + if (isType(annotatedElement)) { + return isAnnotationPresent((Class) annotatedElement, annotationType); + } else { + return annotatedElement.isAnnotationPresent(annotationType) || + findMetaAnnotation(annotatedElement, annotationType) != null; // to find meta-annotation + } + } + + /** + * Tests the annotated element is annotated all specified annotations or not + * + * @param type the annotated type + * @param annotationTypes the specified annotation types + * @return If the specified annotation types are present, return true, or false + */ + static boolean isAllAnnotationPresent(Class type, Class... annotationTypes) { + return isAnnotationPresent(type, true, annotationTypes); + } + + /** + * Tests the annotated element is present any specified annotation types + * + * @param type the annotated type + * @param annotationTypes the specified annotation types + * @return If any specified annotation types are present, return true + */ + static boolean isAnyAnnotationPresent(Class type, + Class... annotationTypes) { + return isAnnotationPresent(type, false, annotationTypes); + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/CharSequenceComparator.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/CharSequenceComparator.java new file mode 100644 index 0000000000..055ba48e0a --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/CharSequenceComparator.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.common.utils; + +import java.util.Comparator; + +/** + * The {@link Comparator} for {@link CharSequence} + * + * @since 2.7.6 + */ +public class CharSequenceComparator implements Comparator { + + public final static CharSequenceComparator INSTANCE = new CharSequenceComparator(); + + private CharSequenceComparator() { + } + + @Override + public int compare(CharSequence c1, CharSequence c2) { + return c1.toString().compareTo(c2.toString()); + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ClassUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ClassUtils.java index ec5b766f84..a0b6deee07 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ClassUtils.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ClassUtils.java @@ -18,11 +18,26 @@ package org.apache.dubbo.common.utils; import java.lang.reflect.Array; +import java.math.BigDecimal; +import java.math.BigInteger; import java.util.Arrays; +import java.util.Collection; +import java.util.Date; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.Map; +import java.util.Objects; import java.util.Set; +import java.util.function.Predicate; + +import static java.util.Arrays.asList; +import static java.util.Collections.emptySet; +import static java.util.Collections.unmodifiableSet; +import static java.util.stream.Collectors.toList; +import static org.apache.dubbo.common.function.Streams.filterAll; +import static org.apache.dubbo.common.utils.ArrayUtils.isNotEmpty; +import static org.apache.dubbo.common.utils.CollectionUtils.ofSet; public class ClassUtils { /** @@ -44,6 +59,43 @@ public class ClassUtils { */ private static final Map, Class> PRIMITIVE_WRAPPER_TYPE_MAP = new HashMap, Class>(16); + /** + * Simple Types including: + *
    + *
  • {@link Void}
  • + *
  • {@link Boolean}
  • + *
  • {@link Character}
  • + *
  • {@link Byte}
  • + *
  • {@link Integer}
  • + *
  • {@link Float}
  • + *
  • {@link Double}
  • + *
  • {@link String}
  • + *
  • {@link BigDecimal}
  • + *
  • {@link BigInteger}
  • + *
  • {@link Date}
  • + *
  • {@link Object}
  • + *
+ * + * @see javax.management.openmbean.SimpleType + * @since 2.7.6 + */ + public static final Set> SIMPLE_TYPES = ofSet( + Void.class, + Boolean.class, + Character.class, + Byte.class, + Short.class, + Integer.class, + Long.class, + Float.class, + Double.class, + String.class, + BigDecimal.class, + BigInteger.class, + Date.class, + Object.class + ); + private static final char PACKAGE_SEPARATOR_CHAR = '.'; static { @@ -228,18 +280,27 @@ public class ClassUtils { } + /** + * The specified type is primitive type or simple type + * + * @param type the type to test + * @return + * @deprecated as 2.7.6, use {@link Class#isPrimitive()} plus {@link #isSimpleType(Class)} instead + */ public static boolean isPrimitive(Class type) { - return type.isPrimitive() - || type == String.class - || type == Character.class - || type == Boolean.class - || type == Byte.class - || type == Short.class - || type == Integer.class - || type == Long.class - || type == Float.class - || type == Double.class - || type == Object.class; + return type != null && (type.isPrimitive() || isSimpleType(type)); + } + + /** + * The specified type is simple type or not + * + * @param type the type to test + * @return if type is one element of {@link #SIMPLE_TYPES}, return true, or false + * @see #SIMPLE_TYPES + * @since 2.7.6 + */ + public static boolean isSimpleType(Class type) { + return SIMPLE_TYPES.contains(type); } public static Object convertPrimitive(Class type, String value) { @@ -285,4 +346,147 @@ public class ClassUtils { } return true; } + + /** + * Get all super classes from the specified type + * + * @param type the specified type + * @param classFilters the filters for classes + * @return non-null read-only {@link Set} + * @since 2.7.6 + */ + public static Set> getAllSuperClasses(Class type, Predicate>... classFilters) { + + Set> allSuperClasses = new LinkedHashSet<>(); + + Class superClass = type.getSuperclass(); + + if (superClass != null) { + // add current super class + allSuperClasses.add(superClass); + // add ancestor classes + allSuperClasses.addAll(getAllSuperClasses(superClass)); + } + + return unmodifiableSet(filterAll(allSuperClasses, classFilters)); + } + + /** + * Get all interfaces from the specified type + * + * @param type the specified type + * @param interfaceFilters the filters for interfaces + * @return non-null read-only {@link Set} + * @since 2.7.6 + */ + public static Set> getAllInterfaces(Class type, Predicate>... interfaceFilters) { + + if (type == null || type.isPrimitive()) { + return emptySet(); + } + + Set> allInterfaces = new LinkedHashSet<>(); + + Class[] interfaces = type.getInterfaces(); + + if (isNotEmpty(interfaces)) { + // add current interfaces + allInterfaces.addAll(asList(interfaces)); + } + + // add all super interfaces + getAllSuperClasses(type).forEach(superType -> allInterfaces.addAll(getAllInterfaces(superType))); + + // add all super interfaces from all interfaces + allInterfaces.stream() + .map(ClassUtils::getAllInterfaces) + .flatMap(Collection::stream) + .collect(toList()) + .forEach(allInterfaces::add); + + return filterAll(allInterfaces, interfaceFilters); + } + + /** + * Get all inherited types from the specified type + * + * @param type the specified type + * @param typeFilters the filters for types + * @return non-null read-only {@link Set} + * @since 2.7.6 + */ + public static Set> getAllInheritedTypes(Class type, Predicate>... typeFilters) { + // Add all super classes + Set> types = new LinkedHashSet<>(getAllSuperClasses(type, typeFilters)); + // Add all interface classes + types.addAll(getAllInterfaces(type, typeFilters)); + return unmodifiableSet(types); + } + + + /** + * the semantics is same as {@link Class#isAssignableFrom(Class)} + * + * @param superType the super type + * @param targetType the target type + * @return see {@link Class#isAssignableFrom(Class)} + * @since 2.7.6 + */ + public static boolean isAssignableFrom(Class superType, Class targetType) { + // any argument is null + if (superType == null || targetType == null) { + return false; + } + // equals + if (Objects.equals(superType, targetType)) { + return true; + } + // isAssignableFrom + return superType.isAssignableFrom(targetType); + } + + /** + * Test the specified class name is present in the {@link ClassLoader} + * + * @param className the name of {@link Class} + * @param classLoader {@link ClassLoader} + * @return If found, return true + * @since 2.7.6 + */ + public static boolean isPresent(String className, ClassLoader classLoader) { + try { + forName(className, classLoader); + } catch (Throwable ignored) { // Ignored + return false; + } + return true; + } + + /** + * Resolve the {@link Class} by the specified name and {@link ClassLoader} + * + * @param className the name of {@link Class} + * @param classLoader {@link ClassLoader} + * @return If can't be resolved , return null + * @since 2.7.6 + */ + public static Class resolveClass(String className, ClassLoader classLoader) { + Class targetClass = null; + try { + targetClass = forName(className, classLoader); + } catch (Throwable ignored) { // Ignored + } + return targetClass; + } + + /** + * Is generic class or not? + * + * @param type the target type + * @return if the target type is not null or void or Void.class, return true, or false + * @since 2.7.6 + */ + public static boolean isGenericClass(Class type) { + return type != null && !void.class.equals(type) && !Void.class.equals(type); + } } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/CollectionUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/CollectionUtils.java index 9bb3c5ed81..1b73370c0b 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/CollectionUtils.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/CollectionUtils.java @@ -16,6 +16,7 @@ */ package org.apache.dubbo.common.utils; +import java.util.AbstractSet; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -26,7 +27,6 @@ import java.util.List; import java.util.Map; import java.util.Set; -import static java.util.Arrays.asList; import static java.util.Collections.emptySet; import static java.util.Collections.unmodifiableSet; @@ -270,9 +270,112 @@ public class CollectionUtils { * @return read-only {@link Set} */ public static Set ofSet(T... values) { - if (values == null || values.length < 1) { + int size = values == null ? 0 : values.length; + if (size < 1) { return emptySet(); } - return unmodifiableSet(new LinkedHashSet<>(asList(values))); + + float loadFactor = 1f / ((size + 1) * 1.0f); + + if (loadFactor > 0.75f) { + loadFactor = 0.75f; + } + + Set elements = new LinkedHashSet<>(size, loadFactor); + for (int i = 0; i < size; i++) { + elements.add(values[i]); + } + return unmodifiableSet(elements); } + + /** + * Get the size of the specified {@link Collection} + * + * @param collection the specified {@link Collection} + * @return must be positive number + * @since 2.7.6 + */ + public static int size(Collection collection) { + return collection == null ? 0 : collection.size(); + } + + /** + * Compares the specified collection with another, the main implementation references + * {@link AbstractSet} + * + * @param one {@link Collection} + * @param another {@link Collection} + * @return if equals, return true, or false + * @since 2.7.6 + */ + public static boolean equals(Collection one, Collection another) { + + if (one == another) { + return true; + } + + if (isEmpty(one) && isEmpty(another)) { + return true; + } + + if (size(one) != size(another)) { + return false; + } + + try { + return one.containsAll(another); + } catch (ClassCastException unused) { + return false; + } catch (NullPointerException unused) { + return false; + } + } + + /** + * Add the multiple values into {@link Collection the specified collection} + * + * @param collection {@link Collection the specified collection} + * @param values the multiple values + * @param the type of values + * @return the effected count after added + * @since 2.7.6 + */ + public static int addAll(Collection collection, T... values) { + + int size = values == null ? 0 : values.length; + + if (collection == null || size < 1) { + return 0; + } + + int effectedCount = 0; + for (int i = 0; i < size; i++) { + if (collection.add(values[i])) { + effectedCount++; + } + } + + return effectedCount; + } + + /** + * Take the first element from the specified collection + * + * @param values the collection object + * @param the type of element of collection + * @return if found, return the first one, or null + * @since 2.7.6 + */ + public static T first(Collection values) { + if (isEmpty(values)) { + return null; + } + if (values instanceof List) { + List list = (List) values; + return list.get(0); + } else { + return values.iterator().next(); + } + } + } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/HttpUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/HttpUtils.java new file mode 100644 index 0000000000..b944d5a62c --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/HttpUtils.java @@ -0,0 +1,264 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.common.utils; + + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import static java.util.Arrays.asList; +import static java.util.Collections.unmodifiableSet; +import static org.apache.dubbo.common.utils.StringUtils.AND; +import static org.apache.dubbo.common.utils.StringUtils.EQUAL; +import static org.apache.dubbo.common.utils.StringUtils.QUESTION_MASK; +import static org.apache.dubbo.common.utils.StringUtils.SLASH; +import static org.apache.dubbo.common.utils.StringUtils.isEmpty; +import static org.apache.dubbo.common.utils.StringUtils.replace; + +/** + * Http Utilities class + * + * @since 2.7.6 + */ +public abstract class HttpUtils { + + private static final String UTF_8 = "UTF-8"; + + /** + * HTTP GET method. + */ + public static final String GET = "GET"; + /** + * HTTP POST method. + */ + public static final String POST = "POST"; + /** + * HTTP PUT method. + */ + public static final String PUT = "PUT"; + /** + * HTTP DELETE method. + */ + public static final String DELETE = "DELETE"; + /** + * HTTP HEAD method. + */ + public static final String HEAD = "HEAD"; + /** + * HTTP OPTIONS method. + */ + public static final String OPTIONS = "OPTIONS"; + + /** + * The HTTP methods to support + */ + public static final Set HTTP_METHODS = unmodifiableSet(new LinkedHashSet<>(asList( + GET, POST, POST, PUT, DELETE, HEAD, OPTIONS + ))); + + + public static String buildPath(String rootPath, String... subPaths) { + + Set paths = new LinkedHashSet<>(); + paths.add(rootPath); + paths.addAll(asList(subPaths)); + + return normalizePath(paths.stream() + .filter(StringUtils::isNotEmpty) + .collect(Collectors.joining(SLASH))); + } + + /** + * Normalize path: + *
    + *
  1. To remove query string if presents
  2. + *
  3. To remove duplicated slash("/") if exists
  4. + *
+ * + * @param path path to be normalized + * @return a normalized path if required + */ + public static String normalizePath(String path) { + if (isEmpty(path)) { + return SLASH; + } + String normalizedPath = path; + int index = normalizedPath.indexOf(QUESTION_MASK); + if (index > -1) { + normalizedPath = normalizedPath.substring(0, index); + } + return replace(normalizedPath, "//", "/"); + } + +// /** +// * Get Parameters from the specified query string. +// *

+// * +// * @param queryString The query string +// * @return The query parameters +// */ +// public static MultivaluedMap getParameters(String queryString) { +// return getParameters(split(queryString, AND_CHAR)); +// } + +// /** +// * Get Parameters from the specified pairs of name-value. +// *

+// * +// * @param pairs The pairs of name-value +// * @return The query parameters +// */ +// public static MultivaluedMap getParameters(Iterable pairs) { +// MultivaluedMap parameters = new MultivaluedHashMap<>(); +// if (pairs != null) { +// for (String pair : pairs) { +// String[] nameAndValue = split(pair, EQUAL_CHAR); +// String name = decode(nameAndValue[0]); +// String value = nameAndValue.length < 2 ? null : nameAndValue[1]; +// value = decode(value); +// addParam(parameters, name, value); +// } +// } +// return parameters; +// } + +// /** +// * Get Parameters from the specified pairs of name-value. +// *

+// * +// * @param pairs The pairs of name-value +// * @return The query parameters +// */ +// public static MultivaluedMap getParameters(String... pairs) { +// return getParameters(asList(pairs)); +// } + + // /** + // * Parse a read-only {@link MultivaluedMap} of {@link HttpCookie} from {@link + // HttpHeaders} + // * + // * @param httpHeaders {@link HttpHeaders} + // * @return non-null, the key is a cookie name , the value is {@link HttpCookie} + // */ + // public static MultivaluedMap parseCookies(HttpHeaders + // httpHeaders) { + // + // String cookie = httpHeaders.getFirst(COOKIE); + // + // String[] cookieNameAndValues = StringUtils.delimitedListToStringArray(cookie, + // SEMICOLON); + // + // MultivaluedMap cookies = new + // LinkedMultiValueMap<>(cookieNameAndValues.length); + // + // for (String cookeNameAndValue : cookieNameAndValues) { + // String[] nameAndValue = + // delimitedListToStringArray(trimWhitespace(cookeNameAndValue), EQUAL); + // String name = nameAndValue[0]; + // String value = nameAndValue.length < 2 ? null : nameAndValue[1]; + // HttpCookie httpCookie = new HttpCookie(name, value); + // cookies.add(name, httpCookie); + // } + // + // return cookies; + // } + + /** + * To the name and value line sets + * + * @param nameAndValuesMap the map of name and values + * @return non-null + */ + public static Set toNameAndValuesSet( + Map> nameAndValuesMap) { + Set nameAndValues = new LinkedHashSet<>(); + for (Map.Entry> entry : nameAndValuesMap.entrySet()) { + String name = entry.getKey(); + List values = entry.getValue(); + for (String value : values) { + String nameAndValue = name + EQUAL + value; + nameAndValues.add(nameAndValue); + } + } + return nameAndValues; + } + + public static String[] toNameAndValues(Map> nameAndValuesMap) { + return toNameAndValuesSet(nameAndValuesMap).toArray(new String[0]); + } + + /** + * Generate a string of query string from the specified request parameters {@link Map} + * + * @param params the specified request parameters {@link Map} + * @return non-null + */ + public static String toQueryString(Map> params) { + StringBuilder builder = new StringBuilder(); + for (String line : toNameAndValuesSet(params)) { + builder.append(line).append(AND); + } + return builder.toString(); + } + + /** + * Decode value + * + * @param value the value requires to decode + * @return the decoded value + */ + public static String decode(String value) { + if (value == null) { + return value; + } + String decodedValue = value; + try { + decodedValue = URLDecoder.decode(value, UTF_8); + } catch (UnsupportedEncodingException ex) { + } + return decodedValue; + } + + /** + * encode value + * + * @param value the value requires to encode + * @return the encoded value + */ + public static String encode(String value) { + String encodedValue = value; + try { + encodedValue = URLEncoder.encode(value, UTF_8); + } catch (UnsupportedEncodingException ex) { + } + return encodedValue; + } + +// private static void addParam(MultivaluedMap paramsMap, String name, +// String value) { +// String paramValue = trim(value); +// if (isEmpty(paramValue)) { +// paramValue = EMPTY_VALUE; +// } +// paramsMap.add(trim(name), paramValue); +// } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/MemberUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/MemberUtils.java new file mode 100644 index 0000000000..f7aa6ff990 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/MemberUtils.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.common.utils; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +/** + * Java Reflection {@link Member} Utilities class + * + * @since 2.7.6 + */ +public interface MemberUtils { + + /** + * check the specified {@link Member member} is static or not ? + * + * @param member {@link Member} instance, e.g, {@link Constructor}, {@link Method} or {@link Field} + * @return Iff member is static one, return true, or false + */ + static boolean isStatic(Member member) { + return member != null && Modifier.isStatic(member.getModifiers()); + } + + /** + * check the specified {@link Member member} is private or not ? + * + * @param member {@link Member} instance, e.g, {@link Constructor}, {@link Method} or {@link Field} + * @return Iff member is private one, return true, or false + */ + static boolean isPrivate(Member member) { + return member != null && Modifier.isPrivate(member.getModifiers()); + } + + /** + * check the specified {@link Member member} is public or not ? + * + * @param member {@link Member} instance, e.g, {@link Constructor}, {@link Method} or {@link Field} + * @return Iff member is public one, return true, or false + */ + static boolean isPublic(Member member) { + return member != null && Modifier.isPublic(member.getModifiers()); + } + +} \ No newline at end of file diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/MethodComparator.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/MethodComparator.java new file mode 100644 index 0000000000..8270c1da67 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/MethodComparator.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.common.utils; + +import java.lang.reflect.Method; +import java.util.Comparator; + +/** + * The Comparator class for {@link Method}, the comparison rule : + *

    + *
  1. Comparing to two {@link Method#getName() method names} {@link String#compareTo(String) lexicographically}. + * If equals, go to step 2
  2. + *
  3. Comparing to the count of two method parameters. If equals, go to step 3
  4. + *
  5. Comparing to the type names of methods parameter {@link String#compareTo(String) lexicographically}
  6. + *
+ * + * @since 2.7.6 + */ +public class MethodComparator implements Comparator { + + public final static MethodComparator INSTANCE = new MethodComparator(); + + private MethodComparator() { + } + + @Override + public int compare(Method m1, Method m2) { + + if (m1.equals(m2)) { + return 0; + } + + // Step 1 + String n1 = m1.getName(); + String n2 = m2.getName(); + int value = n1.compareTo(n2); + + if (value == 0) { // Step 2 + + Class[] types1 = m1.getParameterTypes(); + Class[] types2 = m2.getParameterTypes(); + + value = types1.length - types2.length; + + if (value == 0) { // Step 3 + for (int i = 0; i < types1.length; i++) { + value = types1[i].getName().compareTo(types2[i].getName()); + if (value != 0) { + break; + } + } + } + } + + return Integer.compare(value, 0); + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/MethodUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/MethodUtils.java index 26b05eff52..27262b48ea 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/MethodUtils.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/MethodUtils.java @@ -16,17 +16,32 @@ */ package org.apache.dubbo.common.utils; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.util.Elements; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.util.LinkedList; +import java.util.List; +import java.util.Objects; +import java.util.function.Predicate; + +import static java.util.Collections.emptyList; +import static java.util.Collections.unmodifiableList; +import static org.apache.dubbo.common.function.Streams.filterAll; +import static org.apache.dubbo.common.utils.ClassUtils.getAllInheritedTypes; +import static org.apache.dubbo.common.utils.MemberUtils.isPrivate; +import static org.apache.dubbo.common.utils.MemberUtils.isStatic; +import static org.apache.dubbo.common.utils.ReflectUtils.EMPTY_CLASS_ARRAY; +import static org.apache.dubbo.common.utils.ReflectUtils.resolveTypes; /** * Miscellaneous method utility methods. * Mainly for internal use within the framework. * - * @author LiZhenNet * @since 2.7.2 */ -public class MethodUtils { +public interface MethodUtils { /** * Return {@code true} if the provided method is a set method. @@ -101,4 +116,277 @@ public class MethodUtils { public static boolean isDeprecated(Method method) { return method.getAnnotation(Deprecated.class) != null; } + + + + /** + * Create an instance of {@link Predicate} for {@link Method} to exclude the specified declared class + * + * @param declaredClass the declared class to exclude + * @return non-null + * @since 2.7.6 + */ + static Predicate excludedDeclaredClass(Class declaredClass) { + return method -> !Objects.equals(declaredClass, method.getDeclaringClass()); + } + + /** + * Get all {@link Method methods} of the declared class + * + * @param declaringClass the declared class + * @param includeInheritedTypes include the inherited types, e,g. super classes or interfaces + * @param publicOnly only public method + * @param methodsToFilter (optional) the methods to be filtered + * @return non-null read-only {@link List} + * @since 2.7.6 + */ + static List getMethods(Class declaringClass, boolean includeInheritedTypes, boolean publicOnly, + Predicate... methodsToFilter) { + + if (declaringClass == null || declaringClass.isPrimitive()) { + return emptyList(); + } + + // All declared classes + List> declaredClasses = new LinkedList<>(); + // Add the top declaring class + declaredClasses.add(declaringClass); + // If the super classes are resolved, all them into declaredClasses + if (includeInheritedTypes) { + declaredClasses.addAll(getAllInheritedTypes(declaringClass)); + } + + // All methods + List allMethods = new LinkedList<>(); + + for (Class classToSearch : declaredClasses) { + Method[] methods = publicOnly ? classToSearch.getMethods() : classToSearch.getDeclaredMethods(); + // Add the declared methods or public methods + for (Method method : methods) { + allMethods.add(method); + } + } + + return unmodifiableList(filterAll(allMethods, methodsToFilter)); + } + + /** + * Get all declared {@link Method methods} of the declared class, excluding the inherited methods + * + * @param declaringClass the declared class + * @param methodsToFilter (optional) the methods to be filtered + * @return non-null read-only {@link List} + * @see #getMethods(Class, boolean, boolean, Predicate[]) + * @since 2.7.6 + */ + static List getDeclaredMethods(Class declaringClass, Predicate... methodsToFilter) { + return getMethods(declaringClass, false, false, methodsToFilter); + } + + /** + * Get all public {@link Method methods} of the declared class, including the inherited methods. + * + * @param declaringClass the declared class + * @param methodsToFilter (optional) the methods to be filtered + * @return non-null read-only {@link List} + * @see #getMethods(Class, boolean, boolean, Predicate[]) + * @since 2.7.6 + */ + static List getMethods(Class declaringClass, Predicate... methodsToFilter) { + return getMethods(declaringClass, false, true, methodsToFilter); + } + + /** + * Get all declared {@link Method methods} of the declared class, including the inherited methods. + * + * @param declaringClass the declared class + * @param methodsToFilter (optional) the methods to be filtered + * @return non-null read-only {@link List} + * @see #getMethods(Class, boolean, boolean, Predicate[]) + * @since 2.7.6 + */ + static List getAllDeclaredMethods(Class declaringClass, Predicate... methodsToFilter) { + return getMethods(declaringClass, true, false, methodsToFilter); + } + + /** + * Get all public {@link Method methods} of the declared class, including the inherited methods. + * + * @param declaringClass the declared class + * @param methodsToFilter (optional) the methods to be filtered + * @return non-null read-only {@link List} + * @see #getMethods(Class, boolean, boolean, Predicate[]) + * @since 2.7.6 + */ + static List getAllMethods(Class declaringClass, Predicate... methodsToFilter) { + return getMethods(declaringClass, true, true, methodsToFilter); + } + +// static List getOverriderMethods(Class implementationClass, Class... superTypes) { + +// + +// } + + /** + * Find the {@link Method} by the the specified type and method name without the parameter types + * + * @param type the target type + * @param methodName the specified method name + * @return if not found, return null + * @since 2.7.6 + */ + static Method findMethod(Class type, String methodName) { + return findMethod(type, methodName, EMPTY_CLASS_ARRAY); + } + + /** + * Find the {@link Method} by the the specified type, method name and parameter types + * + * @param type the target type + * @param methodName the method name + * @param parameterTypes the parameter types + * @return if not found, return null + * @since 2.7.6 + */ + static Method findMethod(Class type, String methodName, Class... parameterTypes) { + Method method = null; + try { + method = type.getDeclaredMethod(methodName, parameterTypes); + } catch (NoSuchMethodException e) { + } + return method; + } + + /** + * Invoke the target object and method + * + * @param object the target object + * @param methodName the method name + * @param methodParameters the method parameters + * @param the return type + * @return the target method's execution result + * @since 2.7.6 + */ + static T invokeMethod(Object object, String methodName, Object... methodParameters) { + Class type = object.getClass(); + Class[] parameterTypes = resolveTypes(methodParameters); + Method method = findMethod(type, methodName, parameterTypes); + T value = null; + + try { + final boolean isAccessible = method.isAccessible(); + + if (!isAccessible) { + method.setAccessible(true); + } + value = (T) method.invoke(object, methodParameters); + method.setAccessible(isAccessible); + } catch (Exception e) { + throw new IllegalArgumentException(e); + } + + return value; + } + + + /** + * Tests whether one method, as a member of a given type, + * overrides another method. + * + * @param overrider the first method, possible overrider + * @param overridden the second method, possibly being overridden + * @return {@code true} if and only if the first method overrides + * the second + * @jls 8.4.8 Inheritance, Overriding, and Hiding + * @jls 9.4.1 Inheritance and Overriding + * @see Elements#overrides(ExecutableElement, ExecutableElement, TypeElement) + */ + static boolean overrides(Method overrider, Method overridden) { + + if (overrider == null || overridden == null) { + return false; + } + + // equality comparison: If two methods are same + if (Objects.equals(overrider, overridden)) { + return false; + } + + // Modifiers comparison: Any method must be non-static method + if (isStatic(overrider) || isStatic(overridden)) { // + return false; + } + + // Modifiers comparison: the accessibility of any method must not be private + if (isPrivate(overrider) || isPrivate(overridden)) { + return false; + } + + // Inheritance comparison: The declaring class of overrider must be inherit from the overridden's + if (!overridden.getDeclaringClass().isAssignableFrom(overrider.getDeclaringClass())) { + return false; + } + + // Method comparison: must not be "default" method + if (overrider.isDefault()) { + return false; + } + + // Method comparison: The method name must be equal + if (!Objects.equals(overrider.getName(), overridden.getName())) { + return false; + } + + // Method comparison: The count of method parameters must be equal + if (!Objects.equals(overrider.getParameterCount(), overridden.getParameterCount())) { + return false; + } + + // Method comparison: Any parameter type of overrider must equal the overridden's + for (int i = 0; i < overrider.getParameterCount(); i++) { + if (!Objects.equals(overridden.getParameterTypes()[i], overrider.getParameterTypes()[i])) { + return false; + } + } + + // Method comparison: The return type of overrider must be inherit from the overridden's + if (!overridden.getReturnType().isAssignableFrom(overrider.getReturnType())) { + return false; + } + + // Throwable comparison: "throws" Throwable list will be ignored, trust the compiler verify + + return true; + } + + /** + * Find the nearest overridden {@link Method method} from the inherited class + * + * @param overrider the overrider {@link Method method} + * @return if found, the overrider method, or null + */ + static Method findNearestOverriddenMethod(Method overrider) { + Class declaringClass = overrider.getDeclaringClass(); + Method overriddenMethod = null; + for (Class inheritedType : getAllInheritedTypes(declaringClass)) { + overriddenMethod = findOverriddenMethod(overrider, inheritedType); + if (overriddenMethod != null) { + break; + } + } + return overriddenMethod; + } + + /** + * Find the overridden {@link Method method} from the declaring class + * + * @param overrider the overrider {@link Method method} + * @param declaringClass the class that is declaring the overridden {@link Method method} + * @return if found, the overrider method, or null + */ + static Method findOverriddenMethod(Method overrider, Class declaringClass) { + List matchedMethods = getAllMethods(declaringClass, method -> overrides(overrider, method)); + return matchedMethods.isEmpty() ? null : matchedMethods.get(0); + } } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ReflectUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ReflectUtils.java index df5764a499..866d4b6cd1 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ReflectUtils.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ReflectUtils.java @@ -55,6 +55,7 @@ import java.util.stream.Stream; import static java.util.Arrays.asList; import static java.util.Collections.unmodifiableSet; +import static org.apache.dubbo.common.utils.ArrayUtils.isEmpty; /** * ReflectUtils @@ -1259,6 +1260,15 @@ public final class ReflectUtils { return unmodifiableSet(hierarchicalTypes); } + /** + * Get the value from the specified bean and its property. + * + * @param bean the bean instance + * @param propertyName the name of property + * @param the type of property value + * @return + * @since 2.7.5 + */ public static T getProperty(Object bean, String propertyName) { Class beanClass = bean.getClass(); BeanInfo beanInfo = null; @@ -1282,4 +1292,28 @@ public final class ReflectUtils { return propertyValue; } + /** + * Resolve the types of the specified values + * + * @param values the values + * @return If can't be resolved, return {@link ReflectUtils#EMPTY_CLASS_ARRAY empty class array} + * @since 2.7.6 + */ + public static Class[] resolveTypes(Object... values) { + + if (isEmpty(values)) { + return EMPTY_CLASS_ARRAY; + } + + int size = values.length; + + Class[] types = new Class[size]; + + for (int i = 0; i < size; i++) { + Object value = values[i]; + types[i] = value == null ? null : value.getClass(); + } + + return types; + } } \ No newline at end of file diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ServiceAnnotationResolver.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ServiceAnnotationResolver.java new file mode 100644 index 0000000000..58e5e7a9b4 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ServiceAnnotationResolver.java @@ -0,0 +1,119 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.common.utils; + +import org.apache.dubbo.config.annotation.Service; + +import java.lang.annotation.Annotation; + +import static java.lang.String.format; +import static org.apache.dubbo.common.utils.AnnotationUtils.getAttribute; +import static org.apache.dubbo.common.utils.ArrayUtils.isNotEmpty; +import static org.apache.dubbo.common.utils.ClassUtils.isGenericClass; +import static org.apache.dubbo.common.utils.ClassUtils.resolveClass; +import static org.apache.dubbo.common.utils.StringUtils.isEmpty; + +/** + * The resolver class for {@link Service @Service} + * + * @see Service + * @see com.alibaba.dubbo.config.annotation.Service + * @since 2.7.6 + */ +public class ServiceAnnotationResolver { + + private final Annotation serviceAnnotation; + + private final Class serviceType; + + public ServiceAnnotationResolver(Class serviceType) throws IllegalArgumentException { + this.serviceType = serviceType; + this.serviceAnnotation = getServiceAnnotation(serviceType); + } + + private Annotation getServiceAnnotation(Class serviceType) { + + Annotation serviceAnnotation = serviceType.getAnnotation(Service.class); + + if (serviceAnnotation == null) { + serviceAnnotation = serviceType.getAnnotation(com.alibaba.dubbo.config.annotation.Service.class); + } + + if (serviceAnnotation == null) { + throw new IllegalArgumentException(format("@%s or @%s can't be found in the service type[%s].", + Service.class.getName(), + com.alibaba.dubbo.config.annotation.Service.class.getName(), + serviceType.getName() + )); + } + + return serviceAnnotation; + } + + /** + * Resolve the class name of interface + * + * @return if not found, return null + */ + public String resolveInterfaceClassName() { + + Class interfaceClass = null; + // first, try to get the value from "interfaceName" attribute + String interfaceName = resolveAttribute("interfaceName"); + + if (isEmpty(interfaceName)) { // If not found, try "interfaceClass" + interfaceClass = resolveAttribute("interfaceClass"); + } else { + interfaceClass = resolveClass(interfaceName, getClass().getClassLoader()); + } + + if (isGenericClass(interfaceClass)) { + interfaceName = interfaceClass.getName(); + } else { + interfaceName = null; + } + + if (isEmpty(interfaceName)) { // If not fund, try to get the first interface from the service type + Class[] interfaces = serviceType.getInterfaces(); + if (isNotEmpty(interfaces)) { + interfaceName = interfaces[0].getName(); + } + } + + return interfaceName; + } + + public String resolveVersion() { + return resolveAttribute("version"); + } + + public String resolveGroup() { + return resolveAttribute("group"); + } + + private T resolveAttribute(String attributeName) { + return getAttribute(serviceAnnotation, attributeName); + } + + public Annotation getServiceAnnotation() { + return serviceAnnotation; + } + + public Class getServiceType() { + return serviceType; + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/TypeUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/TypeUtils.java new file mode 100644 index 0000000000..2e53296311 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/TypeUtils.java @@ -0,0 +1,224 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.common.utils; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.Arrays; +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import static java.util.Arrays.asList; +import static java.util.Collections.emptyList; +import static java.util.Collections.unmodifiableList; +import static java.util.stream.Collectors.toList; +import static java.util.stream.Collectors.toSet; +import static java.util.stream.StreamSupport.stream; +import static org.apache.dubbo.common.function.Predicates.and; +import static org.apache.dubbo.common.function.Streams.filterAll; +import static org.apache.dubbo.common.function.Streams.filterList; +import static org.apache.dubbo.common.utils.ClassUtils.getAllInterfaces; +import static org.apache.dubbo.common.utils.ClassUtils.getAllSuperClasses; +import static org.apache.dubbo.common.utils.ClassUtils.isAssignableFrom; + +/** + * The utilities class for {@link Type} + * + * @since 2.7.6 + */ +public interface TypeUtils { + + Predicate> NON_OBJECT_TYPE_FILTER = t -> !Objects.equals(Object.class, t); + + static boolean isParameterizedType(Type type) { + return type instanceof ParameterizedType; + } + + static Type getRawType(Type type) { + if (isParameterizedType(type)) { + return ((ParameterizedType) type).getRawType(); + } else { + return type; + } + } + + static Class getRawClass(Type type) { + Type rawType = getRawType(type); + if (isClass(rawType)) { + return (Class) rawType; + } + return null; + } + + static boolean isClass(Type type) { + return type instanceof Class; + } + + static Class findActualTypeArgument(Type type, Class interfaceClass, int index) { + return (Class) findActualTypeArguments(type, interfaceClass).get(index); + } + + static List> findActualTypeArguments(Type type, Class interfaceClass) { + + List> actualTypeArguments = new LinkedList<>(); + + getAllGenericTypes(type, t -> isAssignableFrom(interfaceClass, getRawClass(t))) + .forEach(parameterizedType -> { + Class rawClass = getRawClass(parameterizedType); + Type[] typeArguments = parameterizedType.getActualTypeArguments(); + for (int i = 0; i < typeArguments.length; i++) { + Type typeArgument = typeArguments[i]; + if (typeArgument instanceof Class) { + actualTypeArguments.add(i, (Class) typeArgument); + } + } + Class superClass = rawClass.getSuperclass(); + if (superClass != null) { + actualTypeArguments.addAll(findActualTypeArguments(superClass, interfaceClass)); + } + }); + + return unmodifiableList(actualTypeArguments); + } + + /** + * Get the specified types' generic types(including super classes and interfaces) that are assignable from {@link ParameterizedType} interface + * + * @param type the specified type + * @param typeFilters one or more {@link Predicate}s to filter the {@link ParameterizedType} instance + * @return non-null read-only {@link List} + */ + static List getGenericTypes(Type type, Predicate... typeFilters) { + + Class rawClass = getRawClass(type); + + if (rawClass == null) { + return emptyList(); + } + + List genericTypes = new LinkedList<>(); + + genericTypes.add(rawClass.getGenericSuperclass()); + genericTypes.addAll(asList(rawClass.getGenericInterfaces())); + + return unmodifiableList( + filterList(genericTypes, TypeUtils::isParameterizedType) + .stream() + .map(ParameterizedType.class::cast) + .filter(and(typeFilters)) + .collect(toList()) + ); + } + + /** + * Get all generic types(including super classes and interfaces) that are assignable from {@link ParameterizedType} interface + * + * @param type the specified type + * @param typeFilters one or more {@link Predicate}s to filter the {@link ParameterizedType} instance + * @return non-null read-only {@link List} + */ + static List getAllGenericTypes(Type type, Predicate... typeFilters) { + List allGenericTypes = new LinkedList<>(); + // Add generic super classes + allGenericTypes.addAll(getAllGenericSuperClasses(type, typeFilters)); + // Add generic super interfaces + allGenericTypes.addAll(getAllGenericInterfaces(type, typeFilters)); + // wrap unmodifiable object + return unmodifiableList(allGenericTypes); + } + + /** + * Get all generic super classes that are assignable from {@link ParameterizedType} interface + * + * @param type the specified type + * @param typeFilters one or more {@link Predicate}s to filter the {@link ParameterizedType} instance + * @return non-null read-only {@link List} + */ + static List getAllGenericSuperClasses(Type type, Predicate... typeFilters) { + + Class rawClass = getRawClass(type); + + if (rawClass == null || rawClass.isInterface()) { + return emptyList(); + } + + List> allTypes = new LinkedList<>(); + // Add current class + allTypes.add(rawClass); + // Add all super classes + allTypes.addAll(getAllSuperClasses(rawClass, NON_OBJECT_TYPE_FILTER)); + + List allGenericSuperClasses = allTypes + .stream() + .map(Class::getGenericSuperclass) + .filter(TypeUtils::isParameterizedType) + .map(ParameterizedType.class::cast) + .collect(Collectors.toList()); + + return unmodifiableList(filterAll(allGenericSuperClasses, typeFilters)); + } + + /** + * Get all generic interfaces that are assignable from {@link ParameterizedType} interface + * + * @param type the specified type + * @param typeFilters one or more {@link Predicate}s to filter the {@link ParameterizedType} instance + * @return non-null read-only {@link List} + */ + static List getAllGenericInterfaces(Type type, Predicate... typeFilters) { + + Class rawClass = getRawClass(type); + + if (rawClass == null) { + return emptyList(); + } + + List> allTypes = new LinkedList<>(); + // Add current class + allTypes.add(rawClass); + // Add all super classes + allTypes.addAll(getAllSuperClasses(rawClass, NON_OBJECT_TYPE_FILTER)); + // Add all super interfaces + allTypes.addAll(getAllInterfaces(rawClass)); + + List allGenericInterfaces = allTypes + .stream() + .map(Class::getGenericInterfaces) + .map(Arrays::asList) + .flatMap(Collection::stream) + .filter(TypeUtils::isParameterizedType) + .map(ParameterizedType.class::cast) + .collect(toList()); + + return unmodifiableList(filterAll(allGenericInterfaces, typeFilters)); + } + + static String getClassName(Type type) { + return getRawType(type).getTypeName(); + } + + static Set getClassNames(Iterable types) { + return stream(types.spliterator(), false) + .map(TypeUtils::getClassName) + .collect(toSet()); + } +} diff --git a/dubbo-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.convert.Converter b/dubbo-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.convert.Converter new file mode 100644 index 0000000000..f1ad0cc1fa --- /dev/null +++ b/dubbo-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.convert.Converter @@ -0,0 +1,11 @@ +# org.apache.dubbo.common.convert.Converter +string-to-boolean=org.apache.dubbo.common.convert.StringToBooleanConverter +string-to-character=org.apache.dubbo.common.convert.StringToCharacterConverter +string-to-char-array=org.apache.dubbo.common.convert.StringToCharArrayConverter +string-to-double=org.apache.dubbo.common.convert.StringToDoubleConverter +string-to-float=org.apache.dubbo.common.convert.StringToFloatConverter +string-to-integer=org.apache.dubbo.common.convert.StringToIntegerConverter +string-to-long=org.apache.dubbo.common.convert.StringToLongConverter +string-to-optional=org.apache.dubbo.common.convert.StringToOptionalConverter +string-to-short=org.apache.dubbo.common.convert.StringToShortConverter +string-to-string=org.apache.dubbo.common.convert.StringToStringConverter \ No newline at end of file diff --git a/dubbo-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.convert.multiple.MultiValueConverter b/dubbo-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.convert.multiple.MultiValueConverter new file mode 100644 index 0000000000..d7f76928d8 --- /dev/null +++ b/dubbo-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.convert.multiple.MultiValueConverter @@ -0,0 +1,12 @@ +# org.apache.dubbo.common.convert.multiple.MultiValueConverter +string-to-array=org.apache.dubbo.common.convert.multiple.StringToArrayConverter +string-to-blocking-deque=org.apache.dubbo.common.convert.multiple.StringToBlockingDequeConverter +string-to-blocking-queue=org.apache.dubbo.common.convert.multiple.StringToBlockingQueueConverter +string-to-collection=org.apache.dubbo.common.convert.multiple.StringToCollectionConverter +string-to-deque=org.apache.dubbo.common.convert.multiple.StringToDequeConverter +string-to-list=org.apache.dubbo.common.convert.multiple.StringToListConverter +string-to-navigable-set=org.apache.dubbo.common.convert.multiple.StringToNavigableSetConverter +string-to-queue=org.apache.dubbo.common.convert.multiple.StringToQueueConverter +string-to-set=org.apache.dubbo.common.convert.multiple.StringToSetConverter +string-to-sorted-set=org.apache.dubbo.common.convert.multiple.StringToSortedSetConverter +string-to-transfer-queue=org.apache.dubbo.common.convert.multiple.StringToTransferQueueConverter diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/AnnotationUtilsTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/AnnotationUtilsTest.java new file mode 100644 index 0000000000..04017636ad --- /dev/null +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/AnnotationUtilsTest.java @@ -0,0 +1,343 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.common.utils; + +import org.apache.dubbo.common.extension.Adaptive; +import org.apache.dubbo.config.annotation.Service; + +import org.junit.jupiter.api.Test; + +import java.lang.annotation.Annotation; +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.LinkedList; +import java.util.List; + +import static java.util.Arrays.asList; +import static org.apache.dubbo.common.utils.AnnotationUtils.excludedType; +import static org.apache.dubbo.common.utils.AnnotationUtils.findAnnotation; +import static org.apache.dubbo.common.utils.AnnotationUtils.findMetaAnnotation; +import static org.apache.dubbo.common.utils.AnnotationUtils.findMetaAnnotations; +import static org.apache.dubbo.common.utils.AnnotationUtils.getAllDeclaredAnnotations; +import static org.apache.dubbo.common.utils.AnnotationUtils.getAllMetaAnnotations; +import static org.apache.dubbo.common.utils.AnnotationUtils.getAnnotation; +import static org.apache.dubbo.common.utils.AnnotationUtils.getAttribute; +import static org.apache.dubbo.common.utils.AnnotationUtils.getDeclaredAnnotations; +import static org.apache.dubbo.common.utils.AnnotationUtils.getMetaAnnotations; +import static org.apache.dubbo.common.utils.AnnotationUtils.getValue; +import static org.apache.dubbo.common.utils.AnnotationUtils.isAnnotationPresent; +import static org.apache.dubbo.common.utils.AnnotationUtils.isAnyAnnotationPresent; +import static org.apache.dubbo.common.utils.AnnotationUtils.isSameType; +import static org.apache.dubbo.common.utils.AnnotationUtils.isType; +import static org.apache.dubbo.common.utils.MethodUtils.findMethod; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link AnnotationUtils} Test + * + * @since 2.7.6 + */ +public class AnnotationUtilsTest { + + @Test + public void testIsType() throws NoSuchMethodException { + // null checking + assertFalse(isType(null)); + // Method checking + assertFalse(isType(findMethod(A.class, "execute"))); + // Class checking + assertTrue(isType(A.class)); + } + + @Test + public void testIsSameType() { + assertTrue(isSameType(A.class.getAnnotation(Service.class), Service.class)); + assertFalse(isSameType(A.class.getAnnotation(Service.class), Deprecated.class)); + assertFalse(isSameType(A.class.getAnnotation(Service.class), null)); + assertFalse(isSameType(null, Deprecated.class)); + assertFalse(isSameType(null, null)); + } + + @Test + public void testExcludedType() { + assertFalse(excludedType(Service.class).test(A.class.getAnnotation(Service.class))); + assertTrue(excludedType(Service.class).test(A.class.getAnnotation(Deprecated.class))); + } + + @Test + public void testGetAttribute() { + Annotation annotation = A.class.getAnnotation(Service.class); + assertEquals("java.lang.CharSequence", getAttribute(annotation, "interfaceName")); + assertEquals(CharSequence.class, getAttribute(annotation, "interfaceClass")); + assertEquals("", getAttribute(annotation, "version")); + assertEquals("", getAttribute(annotation, "group")); + assertEquals("", getAttribute(annotation, "path")); + assertEquals(true, getAttribute(annotation, "export")); + assertEquals(false, getAttribute(annotation, "deprecated")); + } + + @Test + public void testGetValue() { + Adaptive adaptive = A.class.getAnnotation(Adaptive.class); + String[] value = getValue(adaptive); + assertEquals(asList("a", "b", "c"), asList(value)); + } + + @Test + public void testGetDeclaredAnnotations() { + List annotations = getDeclaredAnnotations(A.class); + assertADeclaredAnnotations(annotations, 0); + + annotations = getDeclaredAnnotations(A.class, a -> isSameType(a, Service.class)); + assertEquals(1, annotations.size()); + Service service = (Service) annotations.get(0); + assertEquals("java.lang.CharSequence", service.interfaceName()); + assertEquals(CharSequence.class, service.interfaceClass()); + } + + @Test + public void testGetAllDeclaredAnnotations() { + List annotations = getAllDeclaredAnnotations(A.class); + assertADeclaredAnnotations(annotations, 0); + + annotations = getAllDeclaredAnnotations(B.class); + assertTrue(isSameType(annotations.get(0), Service5.class)); + assertADeclaredAnnotations(annotations, 1); + + annotations = new LinkedList<>(getAllDeclaredAnnotations(C.class)); + assertTrue(isSameType(annotations.get(0), MyAdaptive.class)); + assertTrue(isSameType(annotations.get(1), Service5.class)); + assertADeclaredAnnotations(annotations, 2); + + annotations = getAllDeclaredAnnotations(findMethod(A.class, "execute")); + MyAdaptive myAdaptive = (MyAdaptive) annotations.get(0); + assertArrayEquals(new String[]{"e"}, myAdaptive.value()); + + annotations = getAllDeclaredAnnotations(findMethod(B.class, "execute")); + Adaptive adaptive = (Adaptive) annotations.get(0); + assertArrayEquals(new String[]{"f"}, adaptive.value()); + } + + @Test + public void testGetMetaAnnotations() { + List metaAnnotations = getMetaAnnotations(Service.class, a -> isSameType(a, Inherited.class)); + assertEquals(1, metaAnnotations.size()); + assertEquals(Inherited.class, metaAnnotations.get(0).annotationType()); + + metaAnnotations = getMetaAnnotations(Service.class); + assertEquals(1, metaAnnotations.size()); + assertEquals(Inherited.class, metaAnnotations.get(0).annotationType()); + } + + @Test + public void testGetAllMetaAnnotations() { + List metaAnnotations = getAllMetaAnnotations(Service5.class); + int offset = 0; + assertEquals(9, metaAnnotations.size()); + assertEquals(Inherited.class, metaAnnotations.get(offset++).annotationType()); + assertEquals(Service4.class, metaAnnotations.get(offset++).annotationType()); + assertEquals(Inherited.class, metaAnnotations.get(offset++).annotationType()); + assertEquals(Service3.class, metaAnnotations.get(offset++).annotationType()); + assertEquals(Inherited.class, metaAnnotations.get(offset++).annotationType()); + assertEquals(Service2.class, metaAnnotations.get(offset++).annotationType()); + assertEquals(Inherited.class, metaAnnotations.get(offset++).annotationType()); + assertEquals(Service.class, metaAnnotations.get(offset++).annotationType()); + assertEquals(Inherited.class, metaAnnotations.get(offset++).annotationType()); + + metaAnnotations = getAllMetaAnnotations(MyAdaptive.class); + offset = 0; + assertEquals(2, metaAnnotations.size()); + assertEquals(Inherited.class, metaAnnotations.get(offset++).annotationType()); + assertEquals(Adaptive.class, metaAnnotations.get(offset++).annotationType()); + } + + + @Test + public void testIsAnnotationPresent() { + assertTrue(isAnnotationPresent(A.class, true, Service.class)); + assertTrue(isAnnotationPresent(A.class, true, Service.class, com.alibaba.dubbo.config.annotation.Service.class)); + assertTrue(isAnnotationPresent(A.class, Service.class)); + assertTrue(isAnnotationPresent(A.class, "org.apache.dubbo.config.annotation.Service")); + assertTrue(AnnotationUtils.isAllAnnotationPresent(A.class, Service.class, Service.class, com.alibaba.dubbo.config.annotation.Service.class)); + assertTrue(isAnnotationPresent(A.class, Deprecated.class)); + } + + @Test + public void testIsAnyAnnotationPresent() { + assertTrue(isAnyAnnotationPresent(A.class, Service.class, com.alibaba.dubbo.config.annotation.Service.class, Deprecated.class)); + assertTrue(isAnyAnnotationPresent(A.class, Service.class, com.alibaba.dubbo.config.annotation.Service.class)); + assertTrue(isAnyAnnotationPresent(A.class, Service.class, Deprecated.class)); + assertTrue(isAnyAnnotationPresent(A.class, com.alibaba.dubbo.config.annotation.Service.class, Deprecated.class)); + assertTrue(isAnyAnnotationPresent(A.class, Service.class)); + assertTrue(isAnyAnnotationPresent(A.class, com.alibaba.dubbo.config.annotation.Service.class)); + assertTrue(isAnyAnnotationPresent(A.class, Deprecated.class)); + } + + @Test + public void testGetAnnotation() { + assertNotNull(getAnnotation(A.class, "org.apache.dubbo.config.annotation.Service")); + assertNotNull(getAnnotation(A.class, "com.alibaba.dubbo.config.annotation.Service")); + assertNotNull(getAnnotation(A.class, "org.apache.dubbo.common.extension.Adaptive")); + assertNull(getAnnotation(A.class, "java.lang.Deprecated")); + assertNull(getAnnotation(A.class, "java.lang.String")); + assertNull(getAnnotation(A.class, "NotExistedClass")); + } + + @Test + public void testFindAnnotation() { + Service service = findAnnotation(A.class, Service.class); + assertEquals("java.lang.CharSequence", service.interfaceName()); + assertEquals(CharSequence.class, service.interfaceClass()); + + service = findAnnotation(B.class, Service.class); + assertEquals(CharSequence.class, service.interfaceClass()); + } + + @Test + public void testFindMetaAnnotations() { + List services = findMetaAnnotations(B.class, Service.class); + assertEquals(1, services.size()); + + Service service = services.get(0); + assertEquals("", service.interfaceName()); + assertEquals(Cloneable.class, service.interfaceClass()); + + services = findMetaAnnotations(Service5.class, Service.class); + assertEquals(1, services.size()); + + service = services.get(0); + assertEquals("", service.interfaceName()); + assertEquals(Cloneable.class, service.interfaceClass()); + } + + @Test + public void testFindMetaAnnotation() { + Service service = findMetaAnnotation(B.class, Service.class); + assertEquals(Cloneable.class, service.interfaceClass()); + + service = findMetaAnnotation(B.class, "org.apache.dubbo.config.annotation.Service"); + assertEquals(Cloneable.class, service.interfaceClass()); + + service = findMetaAnnotation(Service5.class, Service.class); + assertEquals(Cloneable.class, service.interfaceClass()); + } + + @Service(interfaceName = "java.lang.CharSequence", interfaceClass = CharSequence.class) + @com.alibaba.dubbo.config.annotation.Service(interfaceName = "java.lang.CharSequence", interfaceClass = CharSequence.class) + @Adaptive(value = {"a", "b", "c"}) + static class A { + + @MyAdaptive("e") + public void execute() { + + } + + + } + + @Documented + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.TYPE}) + @Inherited + @Service(interfaceClass = Cloneable.class) + @interface Service2 { + + + } + + @Documented + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.TYPE}) + @Inherited + @Service2 + @interface Service3 { + + + } + + @Documented + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.TYPE}) + @Inherited + @Service3 + @interface Service4 { + + + } + + @Documented + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.TYPE}) + @Inherited + @Service4 + @interface Service5 { + + + } + + @Documented + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.TYPE, ElementType.METHOD}) + @Inherited + @Adaptive + @interface MyAdaptive { + + String[] value() default {}; + + } + + @Service5 + static class B extends A { + + @Adaptive("f") + @Override + public void execute() { + + } + + + } + + @MyAdaptive + static class C extends B { + + } + + private void assertADeclaredAnnotations(List annotations, int offset) { + int size = 3 + offset; + assertEquals(size, annotations.size()); + Service service = (Service) annotations.get(offset++); + assertEquals("java.lang.CharSequence", service.interfaceName()); + assertEquals(CharSequence.class, service.interfaceClass()); + + com.alibaba.dubbo.config.annotation.Service s = (com.alibaba.dubbo.config.annotation.Service) annotations.get(offset++); + assertEquals("java.lang.CharSequence", service.interfaceName()); + assertEquals(CharSequence.class, service.interfaceClass()); + + Adaptive adaptive = (Adaptive) annotations.get(offset++); + assertArrayEquals(new String[]{"a", "b", "c"}, adaptive.value()); + } +} diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/MemberUtilsTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/MemberUtilsTest.java new file mode 100644 index 0000000000..051363b981 --- /dev/null +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/MemberUtilsTest.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.common.utils; + +import org.junit.jupiter.api.Test; + +import static org.apache.dubbo.common.utils.MemberUtils.isStatic; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link MemberUtils} Test + * + * @since 2.7.6 + */ +public class MemberUtilsTest { + + @Test + public void testIsStatic() throws NoSuchMethodException { + + assertFalse(isStatic(getClass().getMethod("testIsStatic"))); + assertTrue(isStatic(getClass().getMethod("staticMethod"))); + } + + public static void staticMethod() { + + } +} diff --git a/dubbo-common/src/test/java/org/apache/dubbo/convert/StringToBooleanConverterTest.java b/dubbo-common/src/test/java/org/apache/dubbo/convert/StringToBooleanConverterTest.java new file mode 100644 index 0000000000..3b1d75bb63 --- /dev/null +++ b/dubbo-common/src/test/java/org/apache/dubbo/convert/StringToBooleanConverterTest.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.convert; + +import org.apache.dubbo.common.convert.Converter; +import org.apache.dubbo.common.convert.StringToBooleanConverter; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link StringToBooleanConverter} Test + * + * @since 2.7.6 + */ +public class StringToBooleanConverterTest { + + private StringToBooleanConverter converter; + + @BeforeEach + public void init() { + converter = (StringToBooleanConverter) getExtensionLoader(Converter.class).getExtension("string-to-boolean"); + } + + @Test + public void testAccept() { + assertTrue(converter.accept(String.class, Boolean.class)); + } + + @Test + public void testConvert() { + assertTrue(converter.convert("true")); + assertTrue(converter.convert("true")); + assertTrue(converter.convert("True")); + assertFalse(converter.convert("a")); + assertNull(converter.convert("")); + assertNull(converter.convert(null)); + } +} diff --git a/dubbo-common/src/test/java/org/apache/dubbo/convert/StringToCharArrayConverterTest.java b/dubbo-common/src/test/java/org/apache/dubbo/convert/StringToCharArrayConverterTest.java new file mode 100644 index 0000000000..492a1299e4 --- /dev/null +++ b/dubbo-common/src/test/java/org/apache/dubbo/convert/StringToCharArrayConverterTest.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.convert; + +import org.apache.dubbo.common.convert.Converter; +import org.apache.dubbo.common.convert.StringToCharArrayConverter; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link StringToCharArrayConverter} Test + * + * @since 2.7.6 + */ +public class StringToCharArrayConverterTest { + + private StringToCharArrayConverter converter; + + @BeforeEach + public void init() { + converter = (StringToCharArrayConverter) getExtensionLoader(Converter.class).getExtension("string-to-char-array"); + } + + @Test + public void testAccept() { + assertTrue(converter.accept(String.class, char[].class)); + } + + @Test + public void testConvert() { + assertArrayEquals(new char[]{'1', '2', '3'}, converter.convert("123")); + assertNull(converter.convert(null)); + } +} diff --git a/dubbo-common/src/test/java/org/apache/dubbo/convert/StringToCharacterConverterTest.java b/dubbo-common/src/test/java/org/apache/dubbo/convert/StringToCharacterConverterTest.java new file mode 100644 index 0000000000..c9e88c2421 --- /dev/null +++ b/dubbo-common/src/test/java/org/apache/dubbo/convert/StringToCharacterConverterTest.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.convert; + +import org.apache.dubbo.common.convert.Converter; +import org.apache.dubbo.common.convert.StringToCharacterConverter; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link StringToCharacterConverter} Test + * + * @since 2.7.6 + */ +public class StringToCharacterConverterTest { + + private StringToCharacterConverter converter; + + @BeforeEach + public void init() { + converter = (StringToCharacterConverter) getExtensionLoader(Converter.class).getExtension("string-to-character"); + } + + @Test + public void testAccept() { + assertTrue(converter.accept(String.class, Character.class)); + } + + @Test + public void testConvert() { + assertEquals('t', converter.convert("t")); + assertNull(converter.convert(null)); + assertThrows(IllegalArgumentException.class, () -> { + converter.convert("ttt"); + }); + } +} diff --git a/dubbo-common/src/test/java/org/apache/dubbo/convert/StringToDoubleConverterTest.java b/dubbo-common/src/test/java/org/apache/dubbo/convert/StringToDoubleConverterTest.java new file mode 100644 index 0000000000..668f3e6b80 --- /dev/null +++ b/dubbo-common/src/test/java/org/apache/dubbo/convert/StringToDoubleConverterTest.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.convert; + +import org.apache.dubbo.common.convert.Converter; +import org.apache.dubbo.common.convert.StringToDoubleConverter; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link StringToDoubleConverter} Test + * + * @since 2.7.6 + */ +public class StringToDoubleConverterTest { + + private StringToDoubleConverter converter; + + @BeforeEach + public void init() { + converter = (StringToDoubleConverter) getExtensionLoader(Converter.class).getExtension("string-to-double"); + } + + @Test + public void testAccept() { + assertTrue(converter.accept(String.class, Double.class)); + } + + @Test + public void testConvert() { + assertEquals(Double.valueOf("1.0"), converter.convert("1.0")); + assertNull(converter.convert(null)); + assertThrows(NumberFormatException.class, () -> { + converter.convert("ttt"); + }); + } +} diff --git a/dubbo-common/src/test/java/org/apache/dubbo/convert/StringToFloatConverterTest.java b/dubbo-common/src/test/java/org/apache/dubbo/convert/StringToFloatConverterTest.java new file mode 100644 index 0000000000..aa1749948a --- /dev/null +++ b/dubbo-common/src/test/java/org/apache/dubbo/convert/StringToFloatConverterTest.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.convert; + +import org.apache.dubbo.common.convert.Converter; +import org.apache.dubbo.common.convert.StringToFloatConverter; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link StringToFloatConverter} Test + * + * @since 2.7.6 + */ +public class StringToFloatConverterTest { + + private StringToFloatConverter converter; + + @BeforeEach + public void init() { + converter = (StringToFloatConverter) getExtensionLoader(Converter.class).getExtension("string-to-float"); + } + + @Test + public void testAccept() { + assertTrue(converter.accept(String.class, Float.class)); + } + + @Test + public void testConvert() { + assertEquals(Float.valueOf("1.0"), converter.convert("1.0")); + assertNull(converter.convert(null)); + assertThrows(NumberFormatException.class, () -> { + converter.convert("ttt"); + }); + } +} diff --git a/dubbo-common/src/test/java/org/apache/dubbo/convert/StringToIntegerConverterTest.java b/dubbo-common/src/test/java/org/apache/dubbo/convert/StringToIntegerConverterTest.java new file mode 100644 index 0000000000..9c7d24b601 --- /dev/null +++ b/dubbo-common/src/test/java/org/apache/dubbo/convert/StringToIntegerConverterTest.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.convert; + +import org.apache.dubbo.common.convert.Converter; +import org.apache.dubbo.common.convert.StringToIntegerConverter; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link StringToIntegerConverter} Test + * + * @since 2.7.6 + */ +public class StringToIntegerConverterTest { + + private StringToIntegerConverter converter; + + @BeforeEach + public void init() { + converter = (StringToIntegerConverter) getExtensionLoader(Converter.class).getExtension("string-to-integer"); + } + + @Test + public void testAccept() { + assertTrue(converter.accept(String.class, Integer.class)); + } + + @Test + public void testConvert() { + assertEquals(Integer.valueOf("1"), converter.convert("1")); + assertNull(converter.convert(null)); + assertThrows(NumberFormatException.class, () -> { + converter.convert("ttt"); + }); + } +} diff --git a/dubbo-common/src/test/java/org/apache/dubbo/convert/StringToLongConverterTest.java b/dubbo-common/src/test/java/org/apache/dubbo/convert/StringToLongConverterTest.java new file mode 100644 index 0000000000..e14424a62b --- /dev/null +++ b/dubbo-common/src/test/java/org/apache/dubbo/convert/StringToLongConverterTest.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.convert; + +import org.apache.dubbo.common.convert.Converter; +import org.apache.dubbo.common.convert.StringToLongConverter; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link StringToLongConverter} Test + * + * @since 2.7.6 + */ +public class StringToLongConverterTest { + + private StringToLongConverter converter; + + @BeforeEach + public void init() { + converter = (StringToLongConverter) getExtensionLoader(Converter.class).getExtension("string-to-long"); + } + + @Test + public void testAccept() { + assertTrue(converter.accept(String.class, Long.class)); + } + + @Test + public void testConvert() { + assertEquals(Long.valueOf("1"), converter.convert("1")); + assertNull(converter.convert(null)); + assertThrows(NumberFormatException.class, () -> { + converter.convert("ttt"); + }); + } +} diff --git a/dubbo-common/src/test/java/org/apache/dubbo/convert/StringToOptionalConverterTest.java b/dubbo-common/src/test/java/org/apache/dubbo/convert/StringToOptionalConverterTest.java new file mode 100644 index 0000000000..242ae6053e --- /dev/null +++ b/dubbo-common/src/test/java/org/apache/dubbo/convert/StringToOptionalConverterTest.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.convert; + +import org.apache.dubbo.common.convert.Converter; +import org.apache.dubbo.common.convert.StringToOptionalConverter; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.Optional; + +import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link StringToOptionalConverter} Test + * + * @since 2.7.6 + */ +public class StringToOptionalConverterTest { + + private StringToOptionalConverter converter; + + @BeforeEach + public void init() { + converter = (StringToOptionalConverter) getExtensionLoader(Converter.class).getExtension("string-to-optional"); + } + + @Test + public void testAccept() { + assertTrue(converter.accept(String.class, Optional.class)); + } + + @Test + public void testConvert() { + assertEquals(Optional.of("1"), converter.convert("1")); + assertEquals(Optional.empty(), converter.convert(null)); + } +} diff --git a/dubbo-common/src/test/java/org/apache/dubbo/convert/StringToShortConverterTest.java b/dubbo-common/src/test/java/org/apache/dubbo/convert/StringToShortConverterTest.java new file mode 100644 index 0000000000..3f1d4935a1 --- /dev/null +++ b/dubbo-common/src/test/java/org/apache/dubbo/convert/StringToShortConverterTest.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.convert; + +import org.apache.dubbo.common.convert.Converter; +import org.apache.dubbo.common.convert.StringToShortConverter; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link StringToShortConverter} Test + * + * @since 2.7.6 + */ +public class StringToShortConverterTest { + + private StringToShortConverter converter; + + @BeforeEach + public void init() { + converter = (StringToShortConverter) getExtensionLoader(Converter.class).getExtension("string-to-short"); + } + + @Test + public void testAccept() { + assertTrue(converter.accept(String.class, Short.class)); + } + + @Test + public void testConvert() { + assertEquals(Short.valueOf("1"), converter.convert("1")); + assertNull(converter.convert(null)); + assertThrows(NumberFormatException.class, () -> { + converter.convert("ttt"); + }); + } +} diff --git a/dubbo-common/src/test/java/org/apache/dubbo/convert/StringToStringConverterTest.java b/dubbo-common/src/test/java/org/apache/dubbo/convert/StringToStringConverterTest.java new file mode 100644 index 0000000000..57806c345a --- /dev/null +++ b/dubbo-common/src/test/java/org/apache/dubbo/convert/StringToStringConverterTest.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.convert; + +import org.apache.dubbo.common.convert.Converter; +import org.apache.dubbo.common.convert.StringToStringConverter; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link StringToStringConverter} Test + * + * @since 2.7.6 + */ +public class StringToStringConverterTest { + + private StringToStringConverter converter; + + @BeforeEach + public void init() { + converter = (StringToStringConverter) getExtensionLoader(Converter.class).getExtension("string-to-string"); + } + + @Test + public void testAccept() { + assertTrue(converter.accept(String.class, String.class)); + } + + @Test + public void testConvert() { + assertEquals("1", converter.convert("1")); + assertNull(converter.convert(null)); + } +} diff --git a/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToArrayConverterTest.java b/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToArrayConverterTest.java new file mode 100644 index 0000000000..17813566c7 --- /dev/null +++ b/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToArrayConverterTest.java @@ -0,0 +1,70 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.convert.multiple; + +import org.apache.dubbo.common.convert.multiple.StringToArrayConverter; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static java.util.Objects.deepEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link StringToArrayConverter} Test + * + * @since 2.7.6 + */ +public class StringToArrayConverterTest { + + private StringToArrayConverter converter; + + @BeforeEach + public void init() { + converter = new StringToArrayConverter(); + } + + @Test + public void testAccept() { + assertTrue(converter.accept(String.class, char[].class)); + assertTrue(converter.accept(null, char[].class)); + assertFalse(converter.accept(null, String.class)); + assertFalse(converter.accept(null, String.class)); + assertFalse(converter.accept(null, null)); + } + + @Test + public void testConvert() { + assertTrue(deepEquals(new Integer[]{123}, converter.convert("123", Integer[].class, Integer.class))); + assertTrue(deepEquals(new Integer[]{1, 2, 3}, converter.convert("1,2,3", Integer[].class, null))); + assertNull(converter.convert("", Integer[].class, null)); + assertNull(converter.convert(null, Integer[].class, null)); + } + + @Test + public void testGetSourceType() { + assertEquals(String.class, converter.getSourceType()); + } + + @Test + public void testGetPriority() { + assertEquals(Integer.MAX_VALUE, converter.getPriority()); + } +} diff --git a/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToBlockingDequeConverterTest.java b/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToBlockingDequeConverterTest.java new file mode 100644 index 0000000000..6f9597d706 --- /dev/null +++ b/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToBlockingDequeConverterTest.java @@ -0,0 +1,122 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.convert.multiple; + +import org.apache.dubbo.common.convert.multiple.MultiValueConverter; +import org.apache.dubbo.common.convert.multiple.StringToBlockingDequeConverter; +import org.apache.dubbo.common.utils.CollectionUtils; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.AbstractList; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Deque; +import java.util.LinkedList; +import java.util.List; +import java.util.NavigableSet; +import java.util.Queue; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; +import java.util.concurrent.BlockingDeque; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ConcurrentSkipListSet; +import java.util.concurrent.LinkedBlockingDeque; +import java.util.concurrent.TransferQueue; + +import static java.util.Arrays.asList; +import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link StringToBlockingDequeConverter} Test + * + * @see BlockingDeque + * @since 2.7.6 + */ +public class StringToBlockingDequeConverterTest { + + private MultiValueConverter converter; + + @BeforeEach + public void init() { + converter = getExtensionLoader(MultiValueConverter.class).getExtension("string-to-blocking-deque"); + } + + @Test + public void testAccept() { + + assertFalse(converter.accept(String.class, Collection.class)); + + assertFalse(converter.accept(String.class, List.class)); + assertFalse(converter.accept(String.class, AbstractList.class)); + assertFalse(converter.accept(String.class, ArrayList.class)); + assertFalse(converter.accept(String.class, LinkedList.class)); + + assertFalse(converter.accept(String.class, Set.class)); + assertFalse(converter.accept(String.class, SortedSet.class)); + assertFalse(converter.accept(String.class, NavigableSet.class)); + assertFalse(converter.accept(String.class, TreeSet.class)); + assertFalse(converter.accept(String.class, ConcurrentSkipListSet.class)); + + assertFalse(converter.accept(String.class, Queue.class)); + assertFalse(converter.accept(String.class, BlockingQueue.class)); + assertFalse(converter.accept(String.class, TransferQueue.class)); + assertFalse(converter.accept(String.class, Deque.class)); + assertTrue(converter.accept(String.class, BlockingDeque.class)); + + assertFalse(converter.accept(null, char[].class)); + assertFalse(converter.accept(null, String.class)); + assertFalse(converter.accept(null, String.class)); + assertFalse(converter.accept(null, null)); + } + + @Test + public void testConvert() throws NoSuchFieldException { + + BlockingQueue values = new LinkedBlockingDeque(asList(1, 2, 3)); + + BlockingDeque result = (BlockingDeque) converter.convert("1,2,3", BlockingDeque.class, Integer.class); + + assertTrue(CollectionUtils.equals(values, result)); + + values = new LinkedBlockingDeque(asList(123)); + + result = (BlockingDeque) converter.convert("123", BlockingDeque.class, Integer.class); + + assertTrue(CollectionUtils.equals(values, result)); + + assertNull(converter.convert(null, Collection.class, null)); + assertNull(converter.convert("", Collection.class, null)); + + } + + @Test + public void testGetSourceType() { + assertEquals(String.class, converter.getSourceType()); + } + + @Test + public void testGetPriority() { + assertEquals(Integer.MAX_VALUE - 5, converter.getPriority()); + } +} diff --git a/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToBlockingQueueConverterTest.java b/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToBlockingQueueConverterTest.java new file mode 100644 index 0000000000..4fa7532a03 --- /dev/null +++ b/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToBlockingQueueConverterTest.java @@ -0,0 +1,125 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.convert.multiple; + +import org.apache.dubbo.common.convert.multiple.MultiValueConverter; +import org.apache.dubbo.common.convert.multiple.StringToBlockingQueueConverter; +import org.apache.dubbo.common.utils.CollectionUtils; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.AbstractList; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Deque; +import java.util.LinkedList; +import java.util.List; +import java.util.NavigableSet; +import java.util.Queue; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingDeque; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ConcurrentSkipListSet; +import java.util.concurrent.TransferQueue; + +import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link StringToBlockingQueueConverter} Test + * + * @see BlockingDeque + * @since 2.7.6 + */ +public class StringToBlockingQueueConverterTest { + + private MultiValueConverter converter; + + @BeforeEach + public void init() { + converter = getExtensionLoader(MultiValueConverter.class).getExtension("string-to-blocking-queue"); + } + + @Test + public void testAccept() { + + assertFalse(converter.accept(String.class, Collection.class)); + + assertFalse(converter.accept(String.class, List.class)); + assertFalse(converter.accept(String.class, AbstractList.class)); + assertFalse(converter.accept(String.class, ArrayList.class)); + assertFalse(converter.accept(String.class, LinkedList.class)); + + assertFalse(converter.accept(String.class, Set.class)); + assertFalse(converter.accept(String.class, SortedSet.class)); + assertFalse(converter.accept(String.class, NavigableSet.class)); + assertFalse(converter.accept(String.class, TreeSet.class)); + assertFalse(converter.accept(String.class, ConcurrentSkipListSet.class)); + + assertFalse(converter.accept(String.class, Queue.class)); + assertTrue(converter.accept(String.class, BlockingQueue.class)); + assertTrue(converter.accept(String.class, TransferQueue.class)); + assertFalse(converter.accept(String.class, Deque.class)); + assertTrue(converter.accept(String.class, BlockingDeque.class)); + + assertFalse(converter.accept(null, char[].class)); + assertFalse(converter.accept(null, String.class)); + assertFalse(converter.accept(null, String.class)); + assertFalse(converter.accept(null, null)); + } + + @Test + public void testConvert() { + + BlockingQueue values = new ArrayBlockingQueue(3); + values.offer(1); + values.offer(2); + values.offer(3); + + BlockingQueue result = (BlockingQueue) converter.convert("1,2,3", BlockingDeque.class, Integer.class); + + assertTrue(CollectionUtils.equals(values, result)); + + values.clear(); + values.offer(123); + + result = (BlockingQueue) converter.convert("123", BlockingDeque.class, Integer.class); + + assertTrue(CollectionUtils.equals(values, result)); + + assertNull(converter.convert(null, Collection.class, null)); + assertNull(converter.convert("", Collection.class, null)); + + } + + @Test + public void testGetSourceType() { + assertEquals(String.class, converter.getSourceType()); + } + + @Test + public void testGetPriority() { + assertEquals(Integer.MAX_VALUE - 3, converter.getPriority()); + } +} diff --git a/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToCollectionConverterTest.java b/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToCollectionConverterTest.java new file mode 100644 index 0000000000..f0b06ec19c --- /dev/null +++ b/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToCollectionConverterTest.java @@ -0,0 +1,119 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.convert.multiple; + +import org.apache.dubbo.common.convert.multiple.MultiValueConverter; +import org.apache.dubbo.common.convert.multiple.StringToCollectionConverter; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.AbstractList; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Deque; +import java.util.LinkedList; +import java.util.List; +import java.util.NavigableSet; +import java.util.Queue; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; +import java.util.concurrent.BlockingDeque; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ConcurrentSkipListSet; +import java.util.concurrent.TransferQueue; + +import static java.util.Arrays.asList; +import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link StringToCollectionConverter} Test + * + * @since 2.7.6 + */ +public class StringToCollectionConverterTest { + + private MultiValueConverter converter; + + @BeforeEach + public void init() { + converter = getExtensionLoader(MultiValueConverter.class).getExtension("string-to-collection"); + } + + @Test + public void testAccept() { + + assertTrue(converter.accept(String.class, Collection.class)); + + assertTrue(converter.accept(String.class, List.class)); + assertTrue(converter.accept(String.class, AbstractList.class)); + assertTrue(converter.accept(String.class, ArrayList.class)); + assertTrue(converter.accept(String.class, LinkedList.class)); + + assertTrue(converter.accept(String.class, Set.class)); + assertTrue(converter.accept(String.class, SortedSet.class)); + assertTrue(converter.accept(String.class, NavigableSet.class)); + assertTrue(converter.accept(String.class, TreeSet.class)); + assertTrue(converter.accept(String.class, ConcurrentSkipListSet.class)); + + assertTrue(converter.accept(String.class, Queue.class)); + assertTrue(converter.accept(String.class, BlockingQueue.class)); + assertTrue(converter.accept(String.class, TransferQueue.class)); + assertTrue(converter.accept(String.class, Deque.class)); + assertTrue(converter.accept(String.class, BlockingDeque.class)); + + assertFalse(converter.accept(null, char[].class)); + assertFalse(converter.accept(null, String.class)); + assertFalse(converter.accept(null, String.class)); + assertFalse(converter.accept(null, null)); + } + + @Test + public void testConvert() { + + List values = asList(1L, 2L, 3L); + + Collection result = (Collection) converter.convert("1,2,3", Collection.class, Long.class); + + assertEquals(values, result); + + values = asList(123); + + result = (Collection) converter.convert("123", Collection.class, Integer.class); + + assertEquals(values, result); + + assertNull(converter.convert(null, Collection.class, Integer.class)); + assertNull(converter.convert("", Collection.class, Integer.class)); + + } + + @Test + public void testGetSourceType() { + assertEquals(String.class, converter.getSourceType()); + } + + @Test + public void testGetPriority() { + assertEquals(Integer.MAX_VALUE - 1, converter.getPriority()); + } +} diff --git a/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToDequeConverterTest.java b/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToDequeConverterTest.java new file mode 100644 index 0000000000..e810092092 --- /dev/null +++ b/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToDequeConverterTest.java @@ -0,0 +1,120 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.convert.multiple; + +import org.apache.dubbo.common.convert.multiple.MultiValueConverter; +import org.apache.dubbo.common.convert.multiple.StringToDequeConverter; +import org.apache.dubbo.common.utils.CollectionUtils; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.AbstractList; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Deque; +import java.util.LinkedList; +import java.util.List; +import java.util.NavigableSet; +import java.util.Queue; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; +import java.util.concurrent.BlockingDeque; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ConcurrentSkipListSet; +import java.util.concurrent.TransferQueue; + +import static java.util.Arrays.asList; +import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link StringToDequeConverter} Test + * + * @since 2.7.6 + */ +public class StringToDequeConverterTest { + + private MultiValueConverter converter; + + @BeforeEach + public void init() { + converter = getExtensionLoader(MultiValueConverter.class).getExtension("string-to-deque"); + } + + @Test + public void testAccept() { + + assertFalse(converter.accept(String.class, Collection.class)); + + assertFalse(converter.accept(String.class, List.class)); + assertFalse(converter.accept(String.class, AbstractList.class)); + assertTrue(converter.accept(String.class, LinkedList.class)); + assertFalse(converter.accept(String.class, ArrayList.class)); + + assertFalse(converter.accept(String.class, Queue.class)); + assertFalse(converter.accept(String.class, BlockingQueue.class)); + assertFalse(converter.accept(String.class, TransferQueue.class)); + assertTrue(converter.accept(String.class, Deque.class)); + assertTrue(converter.accept(String.class, BlockingDeque.class)); + + assertFalse(converter.accept(String.class, Set.class)); + assertFalse(converter.accept(String.class, SortedSet.class)); + assertFalse(converter.accept(String.class, NavigableSet.class)); + assertFalse(converter.accept(String.class, TreeSet.class)); + assertFalse(converter.accept(String.class, ConcurrentSkipListSet.class)); + + assertFalse(converter.accept(null, char[].class)); + assertFalse(converter.accept(null, String.class)); + assertFalse(converter.accept(null, String.class)); + assertFalse(converter.accept(null, null)); + } + + @Test + public void testConvert() { + + Deque values = new ArrayDeque(asList(1, 2, 3)); + + Deque result = (Deque) converter.convert("1,2,3", Deque.class, Integer.class); + + assertTrue(CollectionUtils.equals(values, result)); + + values = new ArrayDeque(asList("123")); + + result = (Deque) converter.convert("123", Deque.class, String.class); + + assertTrue(CollectionUtils.equals(values, result)); + + assertNull(converter.convert(null, Collection.class, Integer.class)); + assertNull(converter.convert("", Collection.class, null)); + } + + @Test + public void testGetSourceType() { + assertEquals(String.class, converter.getSourceType()); + } + + @Test + public void testGetPriority() { + assertEquals(Integer.MAX_VALUE - 3, converter.getPriority()); + } +} diff --git a/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToListConverterTest.java b/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToListConverterTest.java new file mode 100644 index 0000000000..af9ee91c48 --- /dev/null +++ b/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToListConverterTest.java @@ -0,0 +1,119 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.convert.multiple; + +import org.apache.dubbo.common.convert.multiple.MultiValueConverter; +import org.apache.dubbo.common.convert.multiple.StringToListConverter; +import org.apache.dubbo.common.utils.CollectionUtils; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.AbstractList; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Deque; +import java.util.LinkedList; +import java.util.List; +import java.util.NavigableSet; +import java.util.Queue; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; +import java.util.concurrent.BlockingDeque; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ConcurrentSkipListSet; +import java.util.concurrent.TransferQueue; + +import static java.util.Arrays.asList; +import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link StringToListConverter} Test + * + * @since 2.7.6 + */ +public class StringToListConverterTest { + + private MultiValueConverter converter; + + @BeforeEach + public void init() { + converter = getExtensionLoader(MultiValueConverter.class).getExtension("string-to-list"); + } + + @Test + public void testAccept() { + + assertFalse(converter.accept(String.class, Collection.class)); + + assertTrue(converter.accept(String.class, List.class)); + assertTrue(converter.accept(String.class, AbstractList.class)); + assertTrue(converter.accept(String.class, LinkedList.class)); + assertTrue(converter.accept(String.class, ArrayList.class)); + + assertFalse(converter.accept(String.class, Set.class)); + assertFalse(converter.accept(String.class, SortedSet.class)); + assertFalse(converter.accept(String.class, NavigableSet.class)); + assertFalse(converter.accept(String.class, TreeSet.class)); + assertFalse(converter.accept(String.class, ConcurrentSkipListSet.class)); + + assertFalse(converter.accept(String.class, Queue.class)); + assertFalse(converter.accept(String.class, BlockingQueue.class)); + assertFalse(converter.accept(String.class, TransferQueue.class)); + assertFalse(converter.accept(String.class, Deque.class)); + assertFalse(converter.accept(String.class, BlockingDeque.class)); + + assertFalse(converter.accept(null, char[].class)); + assertFalse(converter.accept(null, String.class)); + assertFalse(converter.accept(null, String.class)); + assertFalse(converter.accept(null, null)); + } + + @Test + public void testConvert() { + + List values = asList(1, 2, 3); + + List result = (List) converter.convert("1,2,3", List.class, Integer.class); + + assertTrue(CollectionUtils.equals(values, result)); + + values = asList("123"); + + result = (List) converter.convert("123", List.class, String.class); + + assertTrue(CollectionUtils.equals(values, result)); + + assertNull(converter.convert(null, Collection.class, Integer.class)); + assertNull(converter.convert("", Collection.class, null)); + } + + @Test + public void testGetSourceType() { + assertEquals(String.class, converter.getSourceType()); + } + + @Test + public void testGetPriority() { + assertEquals(Integer.MAX_VALUE - 2, converter.getPriority()); + } +} diff --git a/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToNavigableSetConverterTest.java b/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToNavigableSetConverterTest.java new file mode 100644 index 0000000000..face60dbfd --- /dev/null +++ b/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToNavigableSetConverterTest.java @@ -0,0 +1,119 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.convert.multiple; + +import org.apache.dubbo.common.convert.multiple.MultiValueConverter; +import org.apache.dubbo.common.convert.multiple.StringToListConverter; +import org.apache.dubbo.common.utils.CollectionUtils; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.AbstractList; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Deque; +import java.util.LinkedList; +import java.util.List; +import java.util.NavigableSet; +import java.util.Queue; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; +import java.util.concurrent.BlockingDeque; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ConcurrentSkipListSet; +import java.util.concurrent.TransferQueue; + +import static java.util.Arrays.asList; +import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link StringToListConverter} Test + * + * @since 2.7.6 + */ +public class StringToNavigableSetConverterTest { + + private MultiValueConverter converter; + + @BeforeEach + public void init() { + converter = getExtensionLoader(MultiValueConverter.class).getExtension("string-to-navigable-set"); + } + + @Test + public void testAccept() { + + assertFalse(converter.accept(String.class, Collection.class)); + + assertFalse(converter.accept(String.class, List.class)); + assertFalse(converter.accept(String.class, AbstractList.class)); + assertFalse(converter.accept(String.class, LinkedList.class)); + assertFalse(converter.accept(String.class, ArrayList.class)); + + assertFalse(converter.accept(String.class, Set.class)); + assertFalse(converter.accept(String.class, SortedSet.class)); + assertTrue(converter.accept(String.class, NavigableSet.class)); + assertTrue(converter.accept(String.class, TreeSet.class)); + assertTrue(converter.accept(String.class, ConcurrentSkipListSet.class)); + + assertFalse(converter.accept(String.class, Queue.class)); + assertFalse(converter.accept(String.class, BlockingQueue.class)); + assertFalse(converter.accept(String.class, TransferQueue.class)); + assertFalse(converter.accept(String.class, Deque.class)); + assertFalse(converter.accept(String.class, BlockingDeque.class)); + + assertFalse(converter.accept(null, char[].class)); + assertFalse(converter.accept(null, String.class)); + assertFalse(converter.accept(null, String.class)); + assertFalse(converter.accept(null, null)); + } + + @Test + public void testConvert() { + + Set values = new TreeSet(asList(1, 2, 3)); + + NavigableSet result = (NavigableSet) converter.convert("1,2,3", List.class, Integer.class); + + assertTrue(CollectionUtils.equals(values, result)); + + values = new TreeSet(asList("123")); + + result = (NavigableSet) converter.convert("123", NavigableSet.class, String.class); + + assertTrue(CollectionUtils.equals(values, result)); + + assertNull(converter.convert(null, Collection.class, Integer.class)); + assertNull(converter.convert("", Collection.class, null)); + } + + @Test + public void testGetSourceType() { + assertEquals(String.class, converter.getSourceType()); + } + + @Test + public void testGetPriority() { + assertEquals(Integer.MAX_VALUE - 4, converter.getPriority()); + } +} diff --git a/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToQueueConverterTest.java b/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToQueueConverterTest.java new file mode 100644 index 0000000000..539693adfd --- /dev/null +++ b/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToQueueConverterTest.java @@ -0,0 +1,119 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.convert.multiple; + +import org.apache.dubbo.common.convert.multiple.StringToQueueConverter; +import org.apache.dubbo.common.utils.CollectionUtils; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.AbstractList; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Deque; +import java.util.LinkedList; +import java.util.List; +import java.util.NavigableSet; +import java.util.Queue; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; +import java.util.concurrent.BlockingDeque; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ConcurrentSkipListSet; +import java.util.concurrent.TransferQueue; + +import static java.util.Arrays.asList; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link StringToQueueConverter} Test + * + * @since 2.7.6 + */ +public class StringToQueueConverterTest { + + private StringToQueueConverter converter; + + @BeforeEach + public void init() { + converter = new StringToQueueConverter(); + } + + @Test + public void testAccept() { + + assertFalse(converter.accept(String.class, Collection.class)); + + assertFalse(converter.accept(String.class, List.class)); + assertFalse(converter.accept(String.class, AbstractList.class)); + assertTrue(converter.accept(String.class, LinkedList.class)); + assertFalse(converter.accept(String.class, ArrayList.class)); + + assertTrue(converter.accept(String.class, Queue.class)); + assertTrue(converter.accept(String.class, BlockingQueue.class)); + assertTrue(converter.accept(String.class, TransferQueue.class)); + assertTrue(converter.accept(String.class, Deque.class)); + assertTrue(converter.accept(String.class, BlockingDeque.class)); + + assertFalse(converter.accept(String.class, Set.class)); + assertFalse(converter.accept(String.class, SortedSet.class)); + assertFalse(converter.accept(String.class, NavigableSet.class)); + assertFalse(converter.accept(String.class, TreeSet.class)); + assertFalse(converter.accept(String.class, ConcurrentSkipListSet.class)); + + assertFalse(converter.accept(null, char[].class)); + assertFalse(converter.accept(null, String.class)); + assertFalse(converter.accept(null, String.class)); + assertFalse(converter.accept(null, null)); + } + + @Test + public void testConvert() { + + Queue values = new ArrayDeque(asList(1.0, 2.0, 3.0)); + + Queue result = (Queue) converter.convert("1.0,2.0,3.0", Queue.class, Double.class); + + assertTrue(CollectionUtils.equals(values, result)); + + values.clear(); + values.add(123); + + result = (Queue) converter.convert("123", Queue.class, Integer.class); + + assertTrue(CollectionUtils.equals(values, result)); + + assertNull(converter.convert(null, Collection.class, Integer.class)); + assertNull(converter.convert("", Collection.class, null)); + } + + @Test + public void testGetSourceType() { + assertEquals(String.class, converter.getSourceType()); + } + + @Test + public void testGetPriority() { + assertEquals(Integer.MAX_VALUE - 2, converter.getPriority()); + } +} diff --git a/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToSetConverterTest.java b/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToSetConverterTest.java new file mode 100644 index 0000000000..269d709a66 --- /dev/null +++ b/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToSetConverterTest.java @@ -0,0 +1,118 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.convert.multiple; + +import org.apache.dubbo.common.convert.multiple.StringToSetConverter; +import org.apache.dubbo.common.utils.CollectionUtils; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.AbstractList; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Deque; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.NavigableSet; +import java.util.Queue; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; +import java.util.concurrent.BlockingDeque; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ConcurrentSkipListSet; +import java.util.concurrent.TransferQueue; + +import static java.util.Arrays.asList; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link StringToSetConverter} Test + * + * @since 2.7.6 + */ +public class StringToSetConverterTest { + + private StringToSetConverter converter; + + @BeforeEach + public void init() { + converter = new StringToSetConverter(); + } + + @Test + public void testAccept() { + + assertFalse(converter.accept(String.class, Collection.class)); + + assertFalse(converter.accept(String.class, List.class)); + assertFalse(converter.accept(String.class, AbstractList.class)); + assertFalse(converter.accept(String.class, LinkedList.class)); + assertFalse(converter.accept(String.class, ArrayList.class)); + + assertTrue(converter.accept(String.class, Set.class)); + assertTrue(converter.accept(String.class, SortedSet.class)); + assertTrue(converter.accept(String.class, NavigableSet.class)); + assertTrue(converter.accept(String.class, TreeSet.class)); + assertTrue(converter.accept(String.class, ConcurrentSkipListSet.class)); + + assertFalse(converter.accept(String.class, Queue.class)); + assertFalse(converter.accept(String.class, BlockingQueue.class)); + assertFalse(converter.accept(String.class, TransferQueue.class)); + assertFalse(converter.accept(String.class, Deque.class)); + assertFalse(converter.accept(String.class, BlockingDeque.class)); + + assertFalse(converter.accept(null, char[].class)); + assertFalse(converter.accept(null, String.class)); + assertFalse(converter.accept(null, String.class)); + assertFalse(converter.accept(null, null)); + } + + @Test + public void testConvert() { + Set values = new HashSet(asList(1.0, 2.0, 3.0)); + + Set result = (Set) converter.convert("1.0,2.0,3.0", Queue.class, Double.class); + + assertTrue(CollectionUtils.equals(values, result)); + + values.clear(); + values.add(123); + + result = (Set) converter.convert("123", Queue.class, Integer.class); + + assertTrue(CollectionUtils.equals(values, result)); + + assertNull(converter.convert(null, Collection.class, Integer.class)); + assertNull(converter.convert("", Collection.class, null)); + } + + @Test + public void testGetSourceType() { + assertEquals(String.class, converter.getSourceType()); + } + + @Test + public void testGetPriority() { + assertEquals(Integer.MAX_VALUE - 2, converter.getPriority()); + } +} diff --git a/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToSortedSetConverterTest.java b/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToSortedSetConverterTest.java new file mode 100644 index 0000000000..6af8f9de9e --- /dev/null +++ b/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToSortedSetConverterTest.java @@ -0,0 +1,119 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.convert.multiple; + +import org.apache.dubbo.common.convert.multiple.MultiValueConverter; +import org.apache.dubbo.common.convert.multiple.StringToListConverter; +import org.apache.dubbo.common.utils.CollectionUtils; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.AbstractList; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Deque; +import java.util.LinkedList; +import java.util.List; +import java.util.NavigableSet; +import java.util.Queue; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; +import java.util.concurrent.BlockingDeque; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ConcurrentSkipListSet; +import java.util.concurrent.TransferQueue; + +import static java.util.Arrays.asList; +import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link StringToListConverter} Test + * + * @since 2.7.6 + */ +public class StringToSortedSetConverterTest { + + private MultiValueConverter converter; + + @BeforeEach + public void init() { + converter = getExtensionLoader(MultiValueConverter.class).getExtension("string-to-sorted-set"); + } + + @Test + public void testAccept() { + + assertFalse(converter.accept(String.class, Collection.class)); + + assertFalse(converter.accept(String.class, List.class)); + assertFalse(converter.accept(String.class, AbstractList.class)); + assertFalse(converter.accept(String.class, LinkedList.class)); + assertFalse(converter.accept(String.class, ArrayList.class)); + + assertFalse(converter.accept(String.class, Set.class)); + assertTrue(converter.accept(String.class, SortedSet.class)); + assertTrue(converter.accept(String.class, NavigableSet.class)); + assertTrue(converter.accept(String.class, TreeSet.class)); + assertTrue(converter.accept(String.class, ConcurrentSkipListSet.class)); + + assertFalse(converter.accept(String.class, Queue.class)); + assertFalse(converter.accept(String.class, BlockingQueue.class)); + assertFalse(converter.accept(String.class, TransferQueue.class)); + assertFalse(converter.accept(String.class, Deque.class)); + assertFalse(converter.accept(String.class, BlockingDeque.class)); + + assertFalse(converter.accept(null, char[].class)); + assertFalse(converter.accept(null, String.class)); + assertFalse(converter.accept(null, String.class)); + assertFalse(converter.accept(null, null)); + } + + @Test + public void testConvert() { + + Set values = new TreeSet(asList(1, 2, 3)); + + SortedSet result = (SortedSet) converter.convert("1,2,3", List.class, Integer.class); + + assertTrue(CollectionUtils.equals(values, result)); + + values = new TreeSet(asList("123")); + + result = (SortedSet) converter.convert("123", NavigableSet.class, String.class); + + assertTrue(CollectionUtils.equals(values, result)); + + assertNull(converter.convert(null, Collection.class, Integer.class)); + assertNull(converter.convert("", Collection.class, null)); + } + + @Test + public void testGetSourceType() { + assertEquals(String.class, converter.getSourceType()); + } + + @Test + public void testGetPriority() { + assertEquals(Integer.MAX_VALUE - 3, converter.getPriority()); + } +} diff --git a/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToTransferQueueConverterTest.java b/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToTransferQueueConverterTest.java new file mode 100644 index 0000000000..4d8d66b7db --- /dev/null +++ b/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToTransferQueueConverterTest.java @@ -0,0 +1,122 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.convert.multiple; + +import org.apache.dubbo.common.convert.multiple.MultiValueConverter; +import org.apache.dubbo.common.convert.multiple.StringToListConverter; +import org.apache.dubbo.common.utils.CollectionUtils; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.AbstractList; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Deque; +import java.util.LinkedList; +import java.util.List; +import java.util.NavigableSet; +import java.util.Queue; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; +import java.util.concurrent.BlockingDeque; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ConcurrentSkipListSet; +import java.util.concurrent.LinkedTransferQueue; +import java.util.concurrent.TransferQueue; + +import static java.util.Arrays.asList; +import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link StringToListConverter} Test + * + * @since 2.7.6 + */ +public class StringToTransferQueueConverterTest { + + private MultiValueConverter converter; + + @BeforeEach + public void init() { + converter = getExtensionLoader(MultiValueConverter.class).getExtension("string-to-transfer-queue"); + } + + @Test + public void testAccept() { + + assertFalse(converter.accept(String.class, Collection.class)); + + assertFalse(converter.accept(String.class, List.class)); + assertFalse(converter.accept(String.class, AbstractList.class)); + assertFalse(converter.accept(String.class, LinkedList.class)); + assertFalse(converter.accept(String.class, ArrayList.class)); + + assertFalse(converter.accept(String.class, Set.class)); + assertFalse(converter.accept(String.class, SortedSet.class)); + assertFalse(converter.accept(String.class, NavigableSet.class)); + assertFalse(converter.accept(String.class, TreeSet.class)); + assertFalse(converter.accept(String.class, ConcurrentSkipListSet.class)); + + assertFalse(converter.accept(String.class, Queue.class)); + assertFalse(converter.accept(String.class, BlockingQueue.class)); + assertFalse(converter.accept(String.class, Deque.class)); + assertFalse(converter.accept(String.class, BlockingDeque.class)); + assertTrue(converter.accept(String.class, TransferQueue.class)); + + assertFalse(converter.accept(null, char[].class)); + assertFalse(converter.accept(null, String.class)); + assertFalse(converter.accept(null, String.class)); + assertFalse(converter.accept(null, null)); + } + + @Test + public void testConvert() { + + TransferQueue values = new LinkedTransferQueue(asList(1, 2, 3)); + + TransferQueue result = (TransferQueue) converter.convert("1,2,3", List.class, Integer.class); + + assertTrue(CollectionUtils.equals(values, result)); + + values.clear(); + + values.addAll(asList("123")); + + result = (TransferQueue) converter.convert("123", NavigableSet.class, String.class); + + assertTrue(CollectionUtils.equals(values, result)); + + assertNull(converter.convert(null, Collection.class, Integer.class)); + assertNull(converter.convert("", Collection.class, null)); + } + + @Test + public void testGetSourceType() { + assertEquals(String.class, converter.getSourceType()); + } + + @Test + public void testGetPriority() { + assertEquals(Integer.MAX_VALUE - 4, converter.getPriority()); + } +} diff --git a/dubbo-compatible/src/test/java/org/apache/dubbo/generic/GenericServiceTest.java b/dubbo-compatible/src/test/java/org/apache/dubbo/generic/GenericServiceTest.java index 09d62cc067..ec9a08e3de 100644 --- a/dubbo-compatible/src/test/java/org/apache/dubbo/generic/GenericServiceTest.java +++ b/dubbo-compatible/src/test/java/org/apache/dubbo/generic/GenericServiceTest.java @@ -34,7 +34,6 @@ import org.apache.dubbo.service.DemoService; import org.apache.dubbo.service.DemoServiceImpl; import com.alibaba.fastjson.JSON; - import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -184,7 +183,7 @@ public class GenericServiceTest { } } Assertions.assertEquals(topTypeDefinition.getProperties().get("v").getType(), "long"); - Assertions.assertEquals(topTypeDefinition.getProperties().get("maps").getType(), "java.util.Map"); + Assertions.assertEquals(topTypeDefinition.getProperties().get("maps").getType(), "java.util.Map"); Assertions.assertEquals(topTypeDefinition.getProperties().get("innerObject").getType(), "org.apache.dubbo.service.ComplexObject$InnerObject"); Assertions.assertEquals(topTypeDefinition.getProperties().get("intList").getType(), "java.util.List"); Assertions.assertEquals(topTypeDefinition.getProperties().get("strArrays").getType(), "java.lang.String[]"); diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/ServiceBean.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/ServiceBean.java index bc63e4d52a..f826f85d41 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/ServiceBean.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/ServiceBean.java @@ -38,8 +38,7 @@ import org.springframework.context.ApplicationEventPublisherAware; * @export */ public class ServiceBean extends ServiceConfig implements InitializingBean, DisposableBean, - ApplicationContextAware, BeanNameAware, - ApplicationEventPublisherAware { + ApplicationContextAware, BeanNameAware, ApplicationEventPublisherAware { private static final long serialVersionUID = 213195494150089726L; diff --git a/dubbo-metadata/dubbo-metadata-api/pom.xml b/dubbo-metadata/dubbo-metadata-api/pom.xml index 8c9a80c80d..fe6a20c190 100644 --- a/dubbo-metadata/dubbo-metadata-api/pom.xml +++ b/dubbo-metadata/dubbo-metadata-api/pom.xml @@ -64,6 +64,20 @@ test + + + javax.ws.rs + javax.ws.rs-api + test + + + + + org.springframework + spring-web + test + +
\ No newline at end of file diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/definition/MethodDefinitionBuilder.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/definition/MethodDefinitionBuilder.java new file mode 100644 index 0000000000..e7c18e6f6f --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/definition/MethodDefinitionBuilder.java @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.definition; + +import org.apache.dubbo.metadata.definition.model.MethodDefinition; +import org.apache.dubbo.metadata.definition.model.TypeDefinition; + +import java.lang.reflect.Method; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.List; + +/** + * {@link MethodDefinition} Builder based on Java Reflection + * + * @since 2.7.6 + */ +public class MethodDefinitionBuilder { + + private final TypeDefinitionBuilder builder; + + public MethodDefinitionBuilder(TypeDefinitionBuilder builder) { + this.builder = builder; + } + + public MethodDefinitionBuilder() { + this.builder = new TypeDefinitionBuilder(); + } + + /** + * Build the instance of {@link MethodDefinition} + * + * @param method {@link Method} + * @return non-null + */ + public MethodDefinition build(Method method) { + + MethodDefinition md = new MethodDefinition(); + md.setName(method.getName()); + + // Process the parameters + Class[] paramTypes = method.getParameterTypes(); + Type[] genericParamTypes = method.getGenericParameterTypes(); + + int paramSize = paramTypes.length; + String[] parameterTypes = new String[paramSize]; + List parameters = new ArrayList<>(paramSize); + for (int i = 0; i < paramSize; i++) { + TypeDefinition parameter = builder.build(genericParamTypes[i], paramTypes[i]); + parameterTypes[i] = parameter.getType(); + parameters.add(parameter); + } + + md.setParameterTypes(parameterTypes); + md.setParameters(parameters); + + // Process return type. + TypeDefinition td = builder.build(method.getGenericReturnType(), method.getReturnType()); + md.setReturnType(td.getType()); + + return md; + } + +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/definition/TypeDefinitionBuilder.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/definition/TypeDefinitionBuilder.java index b9f68e9903..d1275e749d 100755 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/definition/TypeDefinitionBuilder.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/definition/TypeDefinitionBuilder.java @@ -29,6 +29,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import static org.apache.dubbo.common.utils.ClassUtils.isSimpleType; + /** * 2015/1/27. */ @@ -55,7 +57,7 @@ public class TypeDefinitionBuilder { td = DefaultTypeBuilder.build(clazz, typeCache); td.setTypeBuilderName(DefaultTypeBuilder.class.getName()); } - if (clazz.equals(String.class)) { + if (isSimpleType(clazz)) { // changed since 2.7.6 td.setProperties(null); } return td; diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/definition/builder/MapTypeBuilder.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/definition/builder/MapTypeBuilder.java index a2070829ff..4fd3865359 100755 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/definition/builder/MapTypeBuilder.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/definition/builder/MapTypeBuilder.java @@ -25,6 +25,11 @@ import java.text.MessageFormat; import java.util.Arrays; import java.util.Map; +import static org.apache.dubbo.common.utils.StringUtils.replace; +import static org.apache.dubbo.common.utils.TypeUtils.getRawClass; +import static org.apache.dubbo.common.utils.TypeUtils.isClass; +import static org.apache.dubbo.common.utils.TypeUtils.isParameterizedType; + /** * 2015/1/27. */ @@ -46,23 +51,37 @@ public class MapTypeBuilder implements TypeBuilder { ParameterizedType parameterizedType = (ParameterizedType) type; Type[] actualTypeArgs = parameterizedType.getActualTypeArguments(); - if (actualTypeArgs == null || actualTypeArgs.length != 2) { + int actualTypeArgsLength = actualTypeArgs == null ? 0 : actualTypeArgs.length; + + if (actualTypeArgsLength != 2) { throw new IllegalArgumentException(MessageFormat.format( "[ServiceDefinitionBuilder] Map type [{0}] with unexpected amount of arguments [{1}]." + Arrays.toString(actualTypeArgs), type, actualTypeArgs)); } - for (Type actualType : actualTypeArgs) { - if (actualType instanceof ParameterizedType) { + // Change since 2.7.6 + /** + * Replacing ", " to "," will not change the semantic of + * {@link ParameterizedType#toString()} + * @see sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl + */ + String mapType = replace(type.toString(), ", ", ","); + + TypeDefinition typeDefinition = new TypeDefinition(mapType); + + for (int i = 0; i < actualTypeArgsLength; i++) { + Type actualType = actualTypeArgs[i]; + TypeDefinition item = null; + Class rawType = getRawClass(actualType); + if (isParameterizedType(actualType)) { // Nested collection or map. - Class rawType = (Class) ((ParameterizedType) actualType).getRawType(); - TypeDefinitionBuilder.build(actualType, rawType, typeCache); - } else if (actualType instanceof Class) { - Class actualClass = (Class) actualType; - TypeDefinitionBuilder.build(null, actualClass, typeCache); + item = TypeDefinitionBuilder.build(actualType, rawType, typeCache); + } else if (isClass(actualType)) { + item = TypeDefinitionBuilder.build(null, rawType, typeCache); } + typeDefinition.getItems().add(item); } - return new TypeDefinition(type.toString()); + return typeDefinition; } } diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/AbstractAnnotatedMethodParameterProcessor.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/AbstractAnnotatedMethodParameterProcessor.java new file mode 100644 index 0000000000..a168f0f96b --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/AbstractAnnotatedMethodParameterProcessor.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.rest; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; + +import static org.apache.dubbo.common.utils.AnnotationUtils.getValue; +import static org.apache.dubbo.metadata.rest.AnnotatedMethodParameterProcessor.buildDefaultValue; + +/** + * The abstract {@link AnnotatedMethodParameterProcessor} implementation + * + * @since 2.7.6 + */ +public abstract class AbstractAnnotatedMethodParameterProcessor implements AnnotatedMethodParameterProcessor { + + @Override + public void process(Annotation annotation, Parameter parameter, int parameterIndex, Method method, + Class serviceType, Class serviceInterfaceClass, RestMethodMetadata restMethodMetadata) { + String annotationValue = getAnnotationValue(annotation, parameter, parameterIndex); + String defaultValue = getDefaultValue(annotation, parameter, parameterIndex); + process(annotationValue, defaultValue, annotation, parameter, parameterIndex, method, restMethodMetadata); + } + + protected String getAnnotationValue(Annotation annotation, Parameter parameter, int parameterIndex) { + return getValue(annotation); + } + + protected String getDefaultValue(Annotation annotation, Parameter parameter, int parameterIndex) { + return buildDefaultValue(parameterIndex); + } + + protected abstract void process(String annotationValue, String defaultValue, Annotation annotation, Object parameter, + int parameterIndex, Method method, RestMethodMetadata restMethodMetadata); +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/AbstractServiceRestMetadataResolver.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/AbstractServiceRestMetadataResolver.java new file mode 100644 index 0000000000..ea074214ec --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/AbstractServiceRestMetadataResolver.java @@ -0,0 +1,341 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.rest; + +import org.apache.dubbo.common.utils.MethodComparator; +import org.apache.dubbo.common.utils.ServiceAnnotationResolver; +import org.apache.dubbo.config.annotation.Service; +import org.apache.dubbo.metadata.definition.MethodDefinitionBuilder; +import org.apache.dubbo.metadata.definition.model.MethodDefinition; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Consumer; + +import static java.util.Collections.emptyList; +import static java.util.Collections.sort; +import static java.util.Collections.unmodifiableMap; +import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader; +import static org.apache.dubbo.common.function.ThrowableFunction.execute; +import static org.apache.dubbo.common.utils.AnnotationUtils.isAnyAnnotationPresent; +import static org.apache.dubbo.common.utils.ClassUtils.forName; +import static org.apache.dubbo.common.utils.ClassUtils.getAllInterfaces; +import static org.apache.dubbo.common.utils.MethodUtils.excludedDeclaredClass; +import static org.apache.dubbo.common.utils.MethodUtils.getAllMethods; +import static org.apache.dubbo.common.utils.MethodUtils.overrides; + +/** + * The abstract {@link ServiceRestMetadataResolver} class to provider some template methods assemble the instance of + * {@link ServiceRestMetadata} will extended by the sub-classes. + * + * @since 2.7.6 + */ +public abstract class AbstractServiceRestMetadataResolver implements ServiceRestMetadataResolver { + + private final Map> parameterProcessorsMap; + + public AbstractServiceRestMetadataResolver() { + this.parameterProcessorsMap = loadAnnotatedMethodParameterProcessors(); + } + + @Override + public final boolean supports(Class serviceType) { + return isImplementedInterface(serviceType) && isServiceAnnotationPresent(serviceType) && supports0(serviceType); + } + + protected final boolean isImplementedInterface(Class serviceType) { + return !getAllInterfaces(serviceType).isEmpty(); + } + + protected final boolean isServiceAnnotationPresent(Class serviceType) { + return isAnyAnnotationPresent(serviceType, Service.class, com.alibaba.dubbo.config.annotation.Service.class); + } + + /** + * internal support method + * + * @param serviceType Dubbo Service interface or type + * @return If supports, return true, or false + */ + protected abstract boolean supports0(Class serviceType); + + @Override + public final ServiceRestMetadata resolve(Class serviceType) { + + ServiceRestMetadata serviceRestMetadata = new ServiceRestMetadata(); + + // Process ServiceRestMetadata + processServiceRestMetadata(serviceRestMetadata, serviceType); + + // Process RestMethodMetadata + processAllRestMethodMetadata(serviceRestMetadata, serviceType); + + return serviceRestMetadata; + } + + /** + * Process the service type including the sub-routines: + *
    + *
  • {@link ServiceRestMetadata#setServiceInterface(String)}
  • + *
  • {@link ServiceRestMetadata#setVersion(String)}
  • + *
  • {@link ServiceRestMetadata#setGroup(String)}
  • + *
+ * + * @param serviceRestMetadata {@link ServiceRestMetadata} + * @param serviceType Dubbo Service interface or type + */ + protected void processServiceRestMetadata(ServiceRestMetadata serviceRestMetadata, Class serviceType) { + ServiceAnnotationResolver resolver = new ServiceAnnotationResolver(serviceType); + serviceRestMetadata.setServiceInterface(resolver.resolveInterfaceClassName()); + serviceRestMetadata.setVersion(resolver.resolveVersion()); + serviceRestMetadata.setGroup(resolver.resolveGroup()); + } + + /** + * Process all {@link RestMethodMetadata} + * + * @param serviceRestMetadata {@link ServiceRestMetadata} + * @param serviceType Dubbo Service interface or type + */ + protected void processAllRestMethodMetadata(ServiceRestMetadata serviceRestMetadata, Class serviceType) { + Class serviceInterfaceClass = resolveServiceInterfaceClass(serviceRestMetadata, serviceType); + Map serviceMethodsMap = resolveServiceMethodsMap(serviceType, serviceInterfaceClass); + for (Map.Entry entry : serviceMethodsMap.entrySet()) { + // try the overrider method first + Method serviceMethod = entry.getKey(); + // If failed, it indicates the overrider method does not contain metadata , then try the declared method + if (!processRestMethodMetadata(serviceMethod, serviceType, serviceInterfaceClass, serviceRestMetadata.getMeta()::add)) { + Method declaredServiceMethod = entry.getValue(); + processRestMethodMetadata(declaredServiceMethod, serviceType, serviceInterfaceClass, + serviceRestMetadata.getMeta()::add); + } + } + } + + /** + * Resolve a map of all public services methods from the specified service type and its interface class, whose key is the + * declared method, and the value is the overrider method + * + * @param serviceType the service interface implementation class + * @param serviceInterfaceClass the service interface class + * @return non-null read-only {@link Map} + */ + protected Map resolveServiceMethodsMap(Class serviceType, Class serviceInterfaceClass) { + Map serviceMethodsMap = new LinkedHashMap<>(); + // exclude the public methods declared in java.lang.Object.class + List declaredServiceMethods = new ArrayList<>(getAllMethods(serviceInterfaceClass, excludedDeclaredClass(Object.class))); + List serviceMethods = new ArrayList<>(getAllMethods(serviceType, excludedDeclaredClass(Object.class))); + + // sort methods + sort(declaredServiceMethods, MethodComparator.INSTANCE); + sort(serviceMethods, MethodComparator.INSTANCE); + + for (Method declaredServiceMethod : declaredServiceMethods) { + for (Method serviceMethod : serviceMethods) { + if (overrides(serviceMethod, declaredServiceMethod)) { + serviceMethodsMap.put(serviceMethod, declaredServiceMethod); + continue; + } + } + } + // make them to be read-only + return unmodifiableMap(serviceMethodsMap); + } + + /** + * Resolve the class of Dubbo Service interface + * + * @param serviceRestMetadata {@link ServiceRestMetadata} + * @param serviceType Dubbo Service interface or type + * @return non-null + * @throws RuntimeException If the class is not found, the {@link RuntimeException} wraps the cause will be thrown + */ + protected Class resolveServiceInterfaceClass(ServiceRestMetadata serviceRestMetadata, Class serviceType) { + return execute(serviceType.getClassLoader(), classLoader -> { + String serviceInterface = serviceRestMetadata.getServiceInterface(); + return forName(serviceInterface, classLoader); + }); + } + + /** + * Process the single {@link RestMethodMetadata} by the specified {@link Consumer} if present + * + * @param serviceMethod Dubbo Service method + * @param serviceType Dubbo Service interface or type + * @param serviceInterfaceClass The type of Dubbo Service interface + * @param metadataToProcess {@link RestMethodMetadata} to process if present + * @return if processed successfully, return true, or false + */ + protected boolean processRestMethodMetadata(Method serviceMethod, Class serviceType, + Class serviceInterfaceClass, + Consumer metadataToProcess) { + + if (!isRestCapableMethod(serviceMethod, serviceType, serviceInterfaceClass)) { + return false; + } + + String requestPath = resolveRequestPath(serviceMethod, serviceType, serviceInterfaceClass); // requestPath is required + + if (requestPath == null) { + return false; + } + + String requestMethod = resolveRequestMethod(serviceMethod, serviceType, serviceInterfaceClass); // requestMethod is required + + if (requestMethod == null) { + return false; + } + + RestMethodMetadata metadata = new RestMethodMetadata(); + + MethodDefinition methodDefinition = resolveMethodDefinition(serviceMethod, serviceType, serviceInterfaceClass); + // Set MethodDefinition + metadata.setMethod(methodDefinition); + + // process the annotated method parameters + processAnnotatedMethodParameters(serviceMethod, serviceType, serviceInterfaceClass, metadata); + + // process produces + Set produces = new LinkedHashSet<>(); + processProduces(serviceMethod, serviceType, serviceInterfaceClass, produces); + + // process consumes + Set consumes = new LinkedHashSet<>(); + processConsumes(serviceMethod, serviceType, serviceInterfaceClass, consumes); + + // Initialize RequestMetadata + RequestMetadata request = metadata.getRequest(); + request.setPath(requestPath); + request.setMethod(requestMethod); + request.setProduces(produces); + request.setConsumes(consumes); + + // Post-Process + postResolveRestMethodMetadata(serviceMethod, serviceType, serviceInterfaceClass, metadata); + + // Accept RestMethodMetadata + metadataToProcess.accept(metadata); + + return true; + } + + /** + * Test the service method is capable of REST or not? + * + * @param serviceMethod Dubbo Service method + * @param serviceType Dubbo Service interface or type + * @param serviceInterfaceClass The type of Dubbo Service interface + * @return If capable, return true + */ + protected abstract boolean isRestCapableMethod(Method serviceMethod, Class serviceType, Class + serviceInterfaceClass); + + /** + * Resolve the request method + * + * @param serviceMethod Dubbo Service method + * @param serviceType Dubbo Service interface or type + * @param serviceInterfaceClass The type of Dubbo Service interface + * @return if can't be resolve, return null + */ + protected abstract String resolveRequestMethod(Method serviceMethod, Class serviceType, Class + serviceInterfaceClass); + + /** + * Resolve the request path + * + * @param serviceMethod Dubbo Service method + * @param serviceType Dubbo Service interface or type + * @param serviceInterfaceClass The type of Dubbo Service interface + * @return if can't be resolve, return null + */ + protected abstract String resolveRequestPath(Method serviceMethod, Class serviceType, Class + serviceInterfaceClass); + + /** + * Resolve the {@link MethodDefinition} + * + * @param serviceMethod Dubbo Service method + * @param serviceType Dubbo Service interface or type + * @param serviceInterfaceClass The type of Dubbo Service interface + * @return if can't be resolve, return null + * @see MethodDefinitionBuilder + */ + protected MethodDefinition resolveMethodDefinition(Method serviceMethod, Class serviceType, + Class serviceInterfaceClass) { + MethodDefinitionBuilder builder = new MethodDefinitionBuilder(); + return builder.build(serviceMethod); + } + + private void processAnnotatedMethodParameters(Method serviceMethod, Class serviceType, + Class serviceInterfaceClass, RestMethodMetadata metadata) { + int paramCount = serviceMethod.getParameterCount(); + Parameter[] parameters = serviceMethod.getParameters(); + for (int i = 0; i < paramCount; i++) { + Parameter parameter = parameters[i]; + // Add indexed parameter name + metadata.addIndexToName(i,parameter.getName()); + processAnnotatedMethodParameter(parameter, i, serviceMethod, serviceType, serviceInterfaceClass, metadata); + } + } + + private void processAnnotatedMethodParameter(Parameter parameter, int parameterIndex, Method serviceMethod, + Class serviceType, Class serviceInterfaceClass, + RestMethodMetadata metadata) { + Annotation[] annotations = parameter.getAnnotations(); + for (Annotation annotation : annotations) { + String annotationType = annotation.annotationType().getName(); + parameterProcessorsMap.getOrDefault(annotationType, emptyList()) + .forEach(processor -> { + processor.process(annotation, parameter, parameterIndex, serviceMethod, serviceType, + serviceInterfaceClass, metadata); + }); + } + } + + protected abstract void processProduces(Method serviceMethod, Class serviceType, Class + serviceInterfaceClass, + Set produces); + + protected abstract void processConsumes(Method serviceMethod, Class serviceType, Class + serviceInterfaceClass, + Set consumes); + + protected void postResolveRestMethodMetadata(Method serviceMethod, Class serviceType, + Class serviceInterfaceClass, RestMethodMetadata metadata) { + } + + private static Map> loadAnnotatedMethodParameterProcessors() { + Map> parameterProcessorsMap = new LinkedHashMap<>(); + getExtensionLoader(AnnotatedMethodParameterProcessor.class) + .getSupportedExtensionInstances() + .forEach(processor -> { + List processors = + parameterProcessorsMap.computeIfAbsent(processor.getAnnotationType(), k -> new LinkedList<>()); + processors.add(processor); + }); + return parameterProcessorsMap; + } +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/AnnotatedMethodParameterProcessor.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/AnnotatedMethodParameterProcessor.java new file mode 100644 index 0000000000..bd520179ad --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/AnnotatedMethodParameterProcessor.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.rest; + +import org.apache.dubbo.common.extension.SPI; +import org.apache.dubbo.common.lang.Prioritized; + +import javax.lang.model.element.VariableElement; +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; + +/** + * The interface to process the annotated method parameter + * + * @since 2.7.6 + */ +@SPI +public interface AnnotatedMethodParameterProcessor extends Prioritized { + + /** + * The string presenting the annotation type + * + * @return non-null + */ + String getAnnotationType(); + + /** + * Process the specified method {@link VariableElement parameter} + * + * @param annotation {@link Annotation the target annotation} whose type is {@link #getAnnotationType()} + * @param parameter the method parameter + * @param parameterIndex the index of method parameter + * @param method {@link Method method that parameter belongs to} + * @param serviceType Dubbo Service interface or type + * @param serviceInterfaceClass The type of Dubbo Service interface + * @param restMethodMetadata {@link RestMethodMetadata the metadata is used to update} + */ + void process(Annotation annotation, Parameter parameter, int parameterIndex, Method method, + Class serviceType, Class serviceInterfaceClass, RestMethodMetadata restMethodMetadata); + + /** + * Build the default value + * + * @param parameterIndex the index of parameter + * @return the placeholder + */ + static String buildDefaultValue(int parameterIndex) { + return "{" + parameterIndex + "}"; + } + +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/ClassPathServiceRestMetadataReader.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/ClassPathServiceRestMetadataReader.java new file mode 100644 index 0000000000..bd4d5a0a73 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/ClassPathServiceRestMetadataReader.java @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.rest; + +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonParser; + +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URL; +import java.util.Enumeration; +import java.util.LinkedList; +import java.util.List; + +import static java.util.Collections.unmodifiableList; +import static org.apache.dubbo.common.function.ThrowableAction.execute; +import static org.apache.dubbo.metadata.rest.RestMetadataConstants.METADATA_ENCODING; +import static org.apache.dubbo.metadata.rest.RestMetadataConstants.SERVICE_REST_METADATA_RESOURCE_PATH; + +/** + * Class-Path based {@link ServiceRestMetadataReader} implementation + * + * @see ServiceRestMetadataReader + * @since 2.7.6 + */ +public class ClassPathServiceRestMetadataReader implements ServiceRestMetadataReader { + + private final String serviceRestMetadataJsonResoucePath; + + public ClassPathServiceRestMetadataReader() { + this(SERVICE_REST_METADATA_RESOURCE_PATH); + } + + public ClassPathServiceRestMetadataReader(String serviceRestMetadataJsonResoucePath) { + this.serviceRestMetadataJsonResoucePath = serviceRestMetadataJsonResoucePath; + } + + @Override + public List read() { + + List serviceRestMetadataList = new LinkedList<>(); + + ClassLoader classLoader = getClass().getClassLoader(); + + execute(() -> { + Enumeration resources = classLoader.getResources(serviceRestMetadataJsonResoucePath); + Gson gson = new Gson(); + while (resources.hasMoreElements()) { + URL resource = resources.nextElement(); + InputStream inputStream = resource.openStream(); + JsonParser parser = new JsonParser(); + JsonElement jsonElement = parser.parse(new InputStreamReader(inputStream, METADATA_ENCODING)); + if (jsonElement.isJsonArray()) { + JsonArray jsonArray = jsonElement.getAsJsonArray(); + for (int i = 0; i < jsonArray.size(); i++) { + JsonElement childJsonElement = jsonArray.get(i); + ServiceRestMetadata serviceRestMetadata = gson.fromJson(childJsonElement, ServiceRestMetadata.class); + serviceRestMetadataList.add(serviceRestMetadata); + } + } + } + }); + + return unmodifiableList(serviceRestMetadataList); + } +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/DefaultServiceRestMetadataResolver.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/DefaultServiceRestMetadataResolver.java new file mode 100644 index 0000000000..ce53dd883e --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/DefaultServiceRestMetadataResolver.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.rest; + +import java.lang.reflect.Method; +import java.util.Set; + + +/** + * The default implementation {@link ServiceRestMetadataResolver} + * + * @since 2.7.6 + */ +public class DefaultServiceRestMetadataResolver extends AbstractServiceRestMetadataResolver { + + @Override + protected boolean supports0(Class serviceType) { + return false; + } + + @Override + protected boolean isRestCapableMethod(Method serviceMethod, Class serviceType, Class serviceInterfaceClass) { + return false; + } + + @Override + protected String resolveRequestMethod(Method serviceMethod, Class serviceType, Class serviceInterfaceClass) { + return null; + } + + @Override + protected String resolveRequestPath(Method serviceMethod, Class serviceType, Class serviceInterfaceClass) { + return null; + } + + @Override + protected void processProduces(Method serviceMethod, Class serviceType, Class serviceInterfaceClass, Set produces) { + + } + + @Override + protected void processConsumes(Method serviceMethod, Class serviceType, Class serviceInterfaceClass, Set consumes) { + + } +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/RequestMetadata.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/RequestMetadata.java new file mode 100644 index 0000000000..9381d20673 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/RequestMetadata.java @@ -0,0 +1,226 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.rest; + + +import org.apache.dubbo.common.utils.CollectionUtils; + +import java.io.Serializable; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +import static java.util.Collections.unmodifiableMap; +import static org.apache.dubbo.common.utils.HttpUtils.normalizePath; +import static org.apache.dubbo.common.utils.StringUtils.isBlank; + +/** + * The metadata class for REST request + * + * @since 2.7.6 + */ +public class RequestMetadata implements Serializable { + + private static final long serialVersionUID = -240099840085329958L; + + private String method; + + private String path; + + private Map> params = new LinkedHashMap<>(); + + private Map> headers = new LinkedHashMap<>(); + + private Set consumes = new LinkedHashSet<>(); + + private Set produces = new LinkedHashSet<>(); + + /** + * Default Constructor + */ + public RequestMetadata() { + } + + public String getMethod() { + return method; + } + + public void setMethod(String method) { + this.method = method == null ? null : method.toUpperCase(); + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = normalizePath(path); + } + + public Map> getParams() { + return unmodifiableMap(params); + } + + public void setParams(Map> params) { + params(params); + } + + private static void add(Map> multiValueMap, String key, String value) { + if (isBlank(key)) { + return; + } + List values = get(multiValueMap, key, true); + values.add(value); + } + + private static > void addAll(Map> multiValueMap, + Map source) { + for (Map.Entry entry : source.entrySet()) { + String key = entry.getKey(); + for (String value : entry.getValue()) { + add(multiValueMap, key, value); + } + } + } + + private static String getFirst(Map> multiValueMap, String key) { + List values = get(multiValueMap, key); + return CollectionUtils.isNotEmpty(values) ? values.get(0) : null; + } + + private static List get(Map> multiValueMap, String key) { + return get(multiValueMap, key, false); + } + + private static List get(Map> multiValueMap, String key, boolean createIfAbsent) { + return createIfAbsent ? multiValueMap.computeIfAbsent(key, k -> new LinkedList<>()) : multiValueMap.get(key); + } + + public Map> getHeaders() { + return unmodifiableMap(headers); + } + + public void setHeaders(Map> headers) { + headers(headers); + } + + public Set getConsumes() { + return consumes; + } + + public void setConsumes(Set consumes) { + this.consumes = consumes; + } + + public Set getProduces() { + return produces; + } + + public void setProduces(Set produces) { + this.produces = produces; + } + + public Set getParamNames() { + return params.keySet(); + } + + public Set getHeaderNames() { + return headers.keySet(); + } + +// public List getConsumeMediaTypes() { +// return toMediaTypes(consumes); +// } +// +// public List getProduceMediaTypes() { +// return toMediaTypes(produces); +// } + + public String getParameter(String name) { + return getFirst(params, name); + } + + public String getHeader(String name) { + return getFirst(headers, name); + } + + public RequestMetadata addParam(String name, String value) { + add(params, name, value); + return this; + } + + public RequestMetadata addHeader(String name, String value) { + add(headers, name, value); + return this; + } + + private > RequestMetadata params(Map params) { + addAll(this.params, params); + return this; + } + + private > RequestMetadata headers(Map> headers) { + if (headers != null && !headers.isEmpty()) { + Map> httpHeaders = new LinkedHashMap<>(); + // Add all headers + addAll(headers, httpHeaders); + // Handles "Content-Type" and "Accept" headers if present +// mediaTypes(httpHeaders, HttpHeaders.CONTENT_TYPE, this.consumes); +// mediaTypes(httpHeaders, HttpHeaders.ACCEPT, this.produces); + this.headers.putAll(httpHeaders); + } + return this; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof RequestMetadata)) { + return false; + } + RequestMetadata that = (RequestMetadata) o; + return Objects.equals(method, that.method) + && Objects.equals(path, that.path) + && Objects.equals(consumes, that.consumes) + && Objects.equals(produces, that.produces) && + // Metadata should not compare the values + Objects.equals(getParamNames(), that.getParamNames()) + && Objects.equals(getHeaderNames(), that.getHeaderNames()); + + } + + @Override + public int hashCode() { + // The values of metadata should not use for the hashCode() method + return Objects.hash(method, path, consumes, produces, getParamNames(), + getHeaderNames()); + } + + @Override + public String toString() { + return "RequestMetadata{" + "method='" + method + '\'' + ", path='" + path + '\'' + + ", params=" + params + ", headers=" + headers + ", consumes=" + consumes + + ", produces=" + produces + '}'; + } +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/RestMetadataConstants.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/RestMetadataConstants.java new file mode 100644 index 0000000000..82e6328574 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/RestMetadataConstants.java @@ -0,0 +1,112 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.rest; + +/** + * The REST Metadata Constants definition interface + * + * @since 2.7.6 + */ +public interface RestMetadataConstants { + + /** + * The encoding of metadata + */ + String METADATA_ENCODING = "UTF-8"; + + /** + * {@link ServiceRestMetadata} Resource PATH + */ + String SERVICE_REST_METADATA_RESOURCE_PATH = "META-INF/dubbo/service-rest-metadata.json"; + + /** + * JAX-RS + */ + interface JAX_RS { + + /** + * The annotation class name of @Path + */ + String PATH_ANNOTATION_CLASS_NAME = "javax.ws.rs.Path"; + + /** + * The annotation class name of @HttpMethod + */ + String HTTP_METHOD_ANNOTATION_CLASS_NAME = "javax.ws.rs.HttpMethod"; + + /** + * The annotation class name of @Produces + */ + String PRODUCES_ANNOTATION_CLASS_NAME = "javax.ws.rs.Produces"; + + /** + * The annotation class name of @Consumes + */ + String CONSUMES_ANNOTATION_CLASS_NAME = "javax.ws.rs.Consumes"; + + /** + * The annotation class name of @DefaultValue + */ + String DEFAULT_VALUE_ANNOTATION_CLASS_NAME = "javax.ws.rs.DefaultValue"; + + /** + * The annotation class name of @FormParam + */ + String FORM_PARAM_ANNOTATION_CLASS_NAME = "javax.ws.rs.FormParam"; + + /** + * The annotation class name of @HeaderParam + */ + String HEADER_PARAM_ANNOTATION_CLASS_NAME = "javax.ws.rs.HeaderParam"; + + /** + * The annotation class name of @MatrixParam + */ + String MATRIX_PARAM_ANNOTATION_CLASS_NAME = "javax.ws.rs.MatrixParam"; + + /** + * The annotation class name of @QueryParam + */ + String QUERY_PARAM_ANNOTATION_CLASS_NAME = "javax.ws.rs.QueryParam"; + } + + /** + * Spring MVC + */ + interface SPRING_MVC { + + /** + * The annotation class name of @Controller + */ + String CONTROLLER_ANNOTATION_CLASS_NAME = "org.springframework.stereotype.Controller"; + + /** + * The annotation class name of @RequestMapping + */ + String REQUEST_MAPPING_ANNOTATION_CLASS_NAME = "org.springframework.web.bind.annotation.RequestMapping"; + + /** + * The annotation class name of @RequestHeader + */ + String REQUEST_HEADER_ANNOTATION_CLASS_NAME = "org.springframework.web.bind.annotation.RequestHeader"; + + /** + * The annotation class name of @RequestParam + */ + String REQUEST_PARAM_ANNOTATION_CLASS_NAME = "org.springframework.web.bind.annotation.RequestParam"; + } +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/RestMethodMetadata.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/RestMethodMetadata.java new file mode 100644 index 0000000000..a675eb3da0 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/RestMethodMetadata.java @@ -0,0 +1,195 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.rest; + +import org.apache.dubbo.metadata.definition.model.MethodDefinition; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import static java.util.Collections.emptyList; + +/** + * The metadata class for {@link RequestMetadata HTTP(REST) request} and + * its binding {@link MethodDefinition method definition} + * + * @since 2.7.6 + */ +public class RestMethodMetadata implements Serializable { + + private static final long serialVersionUID = 2935252016200830694L; + + private MethodDefinition method; + + private RequestMetadata request; + + private Integer urlIndex; + + private Integer bodyIndex; + + private Integer headerMapIndex; + + private String bodyType; + + private Map> indexToName; + + private List formParams; + + private Map indexToEncoded; + + public MethodDefinition getMethod() { + if (method == null) { + method = new MethodDefinition(); + } + return method; + } + + public void setMethod(MethodDefinition method) { + this.method = method; + } + + public RequestMetadata getRequest() { + if (request == null) { + request = new RequestMetadata(); + } + return request; + } + + public void setRequest(RequestMetadata request) { + this.request = request; + } + + public Integer getUrlIndex() { + return urlIndex; + } + + public void setUrlIndex(Integer urlIndex) { + this.urlIndex = urlIndex; + } + + public Integer getBodyIndex() { + return bodyIndex; + } + + public void setBodyIndex(Integer bodyIndex) { + this.bodyIndex = bodyIndex; + } + + public Integer getHeaderMapIndex() { + return headerMapIndex; + } + + public void setHeaderMapIndex(Integer headerMapIndex) { + this.headerMapIndex = headerMapIndex; + } + + public String getBodyType() { + return bodyType; + } + + public void setBodyType(String bodyType) { + this.bodyType = bodyType; + } + + public Map> getIndexToName() { + if (indexToName == null) { + indexToName = new HashMap<>(); + } + return indexToName; + } + + public void setIndexToName(Map> indexToName) { + this.indexToName = indexToName; + } + + public void addIndexToName(Integer index, String name) { + if (index == null) { + return; + } + + if (name.startsWith("arg") && name.endsWith(index.toString())) { + // Ignore this value because of the Java byte-code without the metadata of method parameters + return; + } + + Map> indexToName = getIndexToName(); + Collection parameterNames = indexToName.computeIfAbsent(index, i -> new ArrayList<>(1)); + parameterNames.add(name); + } + + public boolean hasIndexedName(Integer index, String name) { + Map> indexToName = getIndexToName(); + return indexToName.getOrDefault(index, emptyList()).contains(name); + } + + public List getFormParams() { + return formParams; + } + + public void setFormParams(List formParams) { + this.formParams = formParams; + } + + public Map getIndexToEncoded() { + return indexToEncoded; + } + + public void setIndexToEncoded(Map indexToEncoded) { + this.indexToEncoded = indexToEncoded; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof RestMethodMetadata)) return false; + RestMethodMetadata that = (RestMethodMetadata) o; + return Objects.equals(getMethod(), that.getMethod()) && + Objects.equals(getRequest(), that.getRequest()) && + Objects.equals(getUrlIndex(), that.getUrlIndex()) && + Objects.equals(getBodyIndex(), that.getBodyIndex()) && + Objects.equals(getHeaderMapIndex(), that.getHeaderMapIndex()) && + Objects.equals(getBodyType(), that.getBodyType()) && + Objects.equals(getFormParams(), that.getFormParams()) && + Objects.equals(getIndexToEncoded(), that.getIndexToEncoded()); + } + + @Override + public int hashCode() { + return Objects.hash(getMethod(), getRequest(), getUrlIndex(), getBodyIndex(), getHeaderMapIndex(), getBodyType(), getFormParams(), getIndexToEncoded()); + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("RestMethodMetadata{"); + sb.append("method=").append(method); + sb.append(", request=").append(request); + sb.append(", urlIndex=").append(urlIndex); + sb.append(", bodyIndex=").append(bodyIndex); + sb.append(", headerMapIndex=").append(headerMapIndex); + sb.append(", bodyType='").append(bodyType).append('\''); + sb.append(", indexToName=").append(indexToName); + sb.append(", formParams=").append(formParams); + sb.append(", indexToEncoded=").append(indexToEncoded); + sb.append('}'); + return sb.toString(); + } +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/ServiceRestMetadata.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/ServiceRestMetadata.java new file mode 100644 index 0000000000..876b8a354a --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/ServiceRestMetadata.java @@ -0,0 +1,103 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.rest; + +import java.io.Serializable; +import java.util.LinkedHashSet; +import java.util.Objects; +import java.util.Set; + +/** + * The metadata class for {@link RequestMetadata HTTP(REST) request} and + * its binding Dubbo service metadata + * + * @since 2.7.6 + */ +public class ServiceRestMetadata implements Serializable { + + private static final long serialVersionUID = -4549723140727443569L; + + private String serviceInterface; + + private String version; + + private String group; + + private Set meta; + + public String getServiceInterface() { + return serviceInterface; + } + + public void setServiceInterface(String serviceInterface) { + this.serviceInterface = serviceInterface; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getGroup() { + return group; + } + + public void setGroup(String group) { + this.group = group; + } + + public Set getMeta() { + if (meta == null) { + meta = new LinkedHashSet<>(); + } + return meta; + } + + public void setMeta(Set meta) { + this.meta = meta; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof ServiceRestMetadata)) return false; + ServiceRestMetadata that = (ServiceRestMetadata) o; + return Objects.equals(getServiceInterface(), that.getServiceInterface()) && + Objects.equals(getVersion(), that.getVersion()) && + Objects.equals(getGroup(), that.getGroup()) && + Objects.equals(getMeta(), that.getMeta()); + } + + @Override + public int hashCode() { + return Objects.hash(getServiceInterface(), getVersion(), getGroup(), getMeta()); + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("ServiceRestMetadata{"); + sb.append("serviceInterface='").append(serviceInterface).append('\''); + sb.append(", version='").append(version).append('\''); + sb.append(", group='").append(group).append('\''); + sb.append(", meta=").append(meta); + sb.append('}'); + return sb.toString(); + } +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/ServiceRestMetadataReader.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/ServiceRestMetadataReader.java new file mode 100644 index 0000000000..de5207a9dd --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/ServiceRestMetadataReader.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.rest; + + +import org.apache.dubbo.common.extension.SPI; + +import java.util.List; + +/** + * An interface to read {@link ServiceRestMetadata} + * + * @see ServiceRestMetadata + * @since 2.7.6 + */ +@SPI +public interface ServiceRestMetadataReader { + + /** + * Read the instances of {@link ServiceRestMetadata} + * + * @return non-null + */ + List read(); +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/ServiceRestMetadataResolver.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/ServiceRestMetadataResolver.java new file mode 100644 index 0000000000..0c1ece882a --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/ServiceRestMetadataResolver.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.rest; + +/** + * The interface to resolve the {@link ServiceRestMetadata REST metadata} from the specified + * Dubbo Service interface or type. + * + * @since 2.7.6 + */ +public interface ServiceRestMetadataResolver { + + /** + * Support to resolve {@link ServiceRestMetadata REST metadata} or not + * + * @param serviceType Dubbo Service interface or type + * @return If supports, return true, or false + */ + boolean supports(Class serviceType); + + /** + * Resolve the {@link ServiceRestMetadata REST metadata} from the specified + * Dubbo Service interface or type + * + * @param serviceType Dubbo Service interface or type + * @return + */ + ServiceRestMetadata resolve(Class serviceType); +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/jaxrs/DefaultValueParameterProcessor.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/jaxrs/DefaultValueParameterProcessor.java new file mode 100644 index 0000000000..a9e7c0ebbf --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/jaxrs/DefaultValueParameterProcessor.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.rest.jaxrs; + +import org.apache.dubbo.metadata.rest.AbstractAnnotatedMethodParameterProcessor; +import org.apache.dubbo.metadata.rest.AnnotatedMethodParameterProcessor; +import org.apache.dubbo.metadata.rest.RequestMetadata; +import org.apache.dubbo.metadata.rest.RestMethodMetadata; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.util.List; +import java.util.Map; + +import static org.apache.dubbo.metadata.rest.RestMetadataConstants.JAX_RS.DEFAULT_VALUE_ANNOTATION_CLASS_NAME; + + +/** + * The {@link AnnotatedMethodParameterProcessor} implementation for JAX-RS's @DefaultValue + * * + * + * @since 2.7.6 + */ +public class DefaultValueParameterProcessor extends AbstractAnnotatedMethodParameterProcessor { + + @Override + public String getAnnotationType() { + return DEFAULT_VALUE_ANNOTATION_CLASS_NAME; + } + + @Override + protected void process(String annotationValue, String defaultValue, Annotation annotation, Object parameter, + int parameterIndex, Method method, RestMethodMetadata restMethodMetadata) { + RequestMetadata requestMetadata = restMethodMetadata.getRequest(); + + // process the request parameters + setDefaultValue(requestMetadata.getParams(), defaultValue, annotationValue); + // process the request headers + setDefaultValue(requestMetadata.getHeaders(), defaultValue, annotationValue); + } + + private void setDefaultValue(Map> source, String placeholderValue, String defaultValue) { + OUTTER: + for (Map.Entry> entry : source.entrySet()) { + List values = entry.getValue(); + int size = values.size(); + for (int i = 0; i < size; i++) { + String value = values.get(i); + if (placeholderValue.equals(value)) { + values.set(i, defaultValue); + break OUTTER; + } + } + } + } + + public int getPriority() { + return MIN_PRIORITY; + } +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/jaxrs/FormParamParameterProcessor.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/jaxrs/FormParamParameterProcessor.java new file mode 100644 index 0000000000..d102e397b7 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/jaxrs/FormParamParameterProcessor.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.rest.jaxrs; + +import org.apache.dubbo.metadata.rest.AnnotatedMethodParameterProcessor; + +import static org.apache.dubbo.metadata.rest.RestMetadataConstants.JAX_RS.FORM_PARAM_ANNOTATION_CLASS_NAME; + +/** + * The {@link AnnotatedMethodParameterProcessor} implementation for JAX-RS's @FormParam + * + * @since 2.7.6 + */ +public class FormParamParameterProcessor extends ParamAnnotationParameterProcessor { + + @Override + public String getAnnotationType() { + return FORM_PARAM_ANNOTATION_CLASS_NAME; + } +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/jaxrs/HeaderParamParameterProcessor.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/jaxrs/HeaderParamParameterProcessor.java new file mode 100644 index 0000000000..16d21bfd3b --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/jaxrs/HeaderParamParameterProcessor.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.rest.jaxrs; + +import org.apache.dubbo.metadata.rest.AbstractAnnotatedMethodParameterProcessor; +import org.apache.dubbo.metadata.rest.AnnotatedMethodParameterProcessor; +import org.apache.dubbo.metadata.rest.RequestMetadata; +import org.apache.dubbo.metadata.rest.RestMethodMetadata; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; + +import static org.apache.dubbo.metadata.rest.AnnotatedMethodParameterProcessor.buildDefaultValue; +import static org.apache.dubbo.metadata.rest.RestMetadataConstants.JAX_RS.HEADER_PARAM_ANNOTATION_CLASS_NAME; + +/** + * The {@link AnnotatedMethodParameterProcessor} implementation for JAX-RS's @HeaderParam + * + * @since 2.7.6 + */ +public class HeaderParamParameterProcessor extends AbstractAnnotatedMethodParameterProcessor { + + @Override + public String getAnnotationType() { + return HEADER_PARAM_ANNOTATION_CLASS_NAME; + } + + @Override + protected void process(String headerName, String defaultValue, Annotation annotation, Object parameter, + int parameterIndex, Method method, RestMethodMetadata restMethodMetadata) { + RequestMetadata requestMetadata = restMethodMetadata.getRequest(); + // Add the placeholder as header value + requestMetadata.addHeader(headerName, buildDefaultValue(parameterIndex)); + } +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/jaxrs/JAXRSServiceRestMetadataResolver.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/jaxrs/JAXRSServiceRestMetadataResolver.java new file mode 100644 index 0000000000..ca4a77fc7e --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/jaxrs/JAXRSServiceRestMetadataResolver.java @@ -0,0 +1,99 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.rest.jaxrs; + +import org.apache.dubbo.metadata.rest.AbstractServiceRestMetadataResolver; +import org.apache.dubbo.metadata.rest.ServiceRestMetadataResolver; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.util.Set; +import java.util.stream.Stream; + +import static org.apache.dubbo.common.utils.AnnotationUtils.findAnnotation; +import static org.apache.dubbo.common.utils.AnnotationUtils.findMetaAnnotation; +import static org.apache.dubbo.common.utils.AnnotationUtils.getValue; +import static org.apache.dubbo.common.utils.AnnotationUtils.isAnnotationPresent; +import static org.apache.dubbo.common.utils.HttpUtils.buildPath; +import static org.apache.dubbo.metadata.rest.RestMetadataConstants.JAX_RS.CONSUMES_ANNOTATION_CLASS_NAME; +import static org.apache.dubbo.metadata.rest.RestMetadataConstants.JAX_RS.HTTP_METHOD_ANNOTATION_CLASS_NAME; +import static org.apache.dubbo.metadata.rest.RestMetadataConstants.JAX_RS.PATH_ANNOTATION_CLASS_NAME; +import static org.apache.dubbo.metadata.rest.RestMetadataConstants.JAX_RS.PRODUCES_ANNOTATION_CLASS_NAME; + +/** + * JAX-RS {@link ServiceRestMetadataResolver} implementation + * + * @since 2.7.6 + */ +public class JAXRSServiceRestMetadataResolver extends AbstractServiceRestMetadataResolver { + + @Override + protected boolean supports0(Class serviceType) { + return isAnnotationPresent(serviceType, PATH_ANNOTATION_CLASS_NAME); + } + + @Override + protected boolean isRestCapableMethod(Method serviceMethod, Class serviceType, Class serviceInterfaceClass) { + return isAnnotationPresent(serviceMethod, HTTP_METHOD_ANNOTATION_CLASS_NAME); + } + + @Override + protected String resolveRequestMethod(Method serviceMethod, Class serviceType, Class serviceInterfaceClass) { + Annotation httpMethod = findMetaAnnotation(serviceMethod, HTTP_METHOD_ANNOTATION_CLASS_NAME); + return getValue(httpMethod); + } + + @Override + protected String resolveRequestPath(Method serviceMethod, Class serviceType, Class serviceInterfaceClass) { + String requestBasePath = resolveRequestPathFromType(serviceType, serviceInterfaceClass); + String requestRelativePath = resolveRequestPathFromMethod(serviceMethod); + return buildPath(requestBasePath, requestRelativePath); + } + + private String resolveRequestPathFromType(Class serviceType, Class serviceInterfaceClass) { + Annotation path = findAnnotation(serviceType, PATH_ANNOTATION_CLASS_NAME); + if (path == null) { + path = findAnnotation(serviceInterfaceClass, PATH_ANNOTATION_CLASS_NAME); + } + return getValue(path); + } + + private String resolveRequestPathFromMethod(Method serviceMethod) { + Annotation path = findAnnotation(serviceMethod, PATH_ANNOTATION_CLASS_NAME); + return getValue(path); + } + + @Override + protected void processProduces(Method serviceMethod, Class serviceType, Class serviceInterfaceClass, + Set produces) { + addAnnotationValues(serviceMethod, PRODUCES_ANNOTATION_CLASS_NAME, produces); + } + + @Override + protected void processConsumes(Method serviceMethod, Class serviceType, Class serviceInterfaceClass, + Set consumes) { + addAnnotationValues(serviceMethod, CONSUMES_ANNOTATION_CLASS_NAME, consumes); + } + + private void addAnnotationValues(Method serviceMethod, String annotationAttributeName, Set result) { + Annotation annotation = findAnnotation(serviceMethod, annotationAttributeName); + String[] value = getValue(annotation); + if (value != null) { + Stream.of(value).forEach(result::add); + } + } +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/jaxrs/MatrixParamParameterProcessor.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/jaxrs/MatrixParamParameterProcessor.java new file mode 100644 index 0000000000..894f33db2a --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/jaxrs/MatrixParamParameterProcessor.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.rest.jaxrs; + +import org.apache.dubbo.metadata.rest.AnnotatedMethodParameterProcessor; + +import static org.apache.dubbo.metadata.rest.RestMetadataConstants.JAX_RS.MATRIX_PARAM_ANNOTATION_CLASS_NAME; + +/** + * The {@link AnnotatedMethodParameterProcessor} implementation for JAX-RS's @MatrixParam + * + * @since 2.7.6 + */ +public class MatrixParamParameterProcessor extends ParamAnnotationParameterProcessor { + + @Override + public String getAnnotationType() { + return MATRIX_PARAM_ANNOTATION_CLASS_NAME; + } +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/jaxrs/ParamAnnotationParameterProcessor.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/jaxrs/ParamAnnotationParameterProcessor.java new file mode 100644 index 0000000000..b6be293e16 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/jaxrs/ParamAnnotationParameterProcessor.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.rest.jaxrs; + +import org.apache.dubbo.metadata.rest.AbstractAnnotatedMethodParameterProcessor; +import org.apache.dubbo.metadata.rest.AnnotatedMethodParameterProcessor; +import org.apache.dubbo.metadata.rest.RequestMetadata; +import org.apache.dubbo.metadata.rest.RestMethodMetadata; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; + +/** + * The abstract {@link AnnotatedMethodParameterProcessor} implementation for JAX-RS's @*Param + */ +public abstract class ParamAnnotationParameterProcessor extends AbstractAnnotatedMethodParameterProcessor { + + @Override + protected void process(String name, String defaultValue, Annotation annotation, Object parameter, + int parameterIndex, Method method, RestMethodMetadata restMethodMetadata) { + RequestMetadata requestMetadata = restMethodMetadata.getRequest(); + requestMetadata.addParam(name, defaultValue); + } +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/jaxrs/QueryParamParameterProcessor.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/jaxrs/QueryParamParameterProcessor.java new file mode 100644 index 0000000000..bfe539c9cc --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/jaxrs/QueryParamParameterProcessor.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.rest.jaxrs; + +import org.apache.dubbo.metadata.rest.AnnotatedMethodParameterProcessor; + +import static org.apache.dubbo.metadata.rest.RestMetadataConstants.JAX_RS.QUERY_PARAM_ANNOTATION_CLASS_NAME; + +/** + * The {@link AnnotatedMethodParameterProcessor} implementation for JAX-RS's @QueryParam + * + * @since 2.7.6 + */ +public class QueryParamParameterProcessor extends ParamAnnotationParameterProcessor { + + @Override + public String getAnnotationType() { + return QUERY_PARAM_ANNOTATION_CLASS_NAME; + } +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/springmvc/AbstractRequestAnnotationParameterProcessor.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/springmvc/AbstractRequestAnnotationParameterProcessor.java new file mode 100644 index 0000000000..28407c267a --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/springmvc/AbstractRequestAnnotationParameterProcessor.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.rest.springmvc; + +import org.apache.dubbo.metadata.rest.AbstractAnnotatedMethodParameterProcessor; +import org.apache.dubbo.metadata.rest.AnnotatedMethodParameterProcessor; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Parameter; + +import static org.apache.dubbo.common.utils.AnnotationUtils.getAttribute; + +/** + * The abstract {@link AnnotatedMethodParameterProcessor} implementation for Spring Web MVC's @Request* + */ +public abstract class AbstractRequestAnnotationParameterProcessor extends AbstractAnnotatedMethodParameterProcessor { + + @Override + protected String getAnnotationValue(Annotation annotation, Parameter parameter, int parameterIndex) { + // try to get "value" attribute first + String name = super.getAnnotationValue(annotation, parameter, parameterIndex); + + // try to get "name" attribute if required + if (isEmpty(name)) { + name = getAttribute(annotation, "name"); + } + + // finally , try to the name of parameter + if (isEmpty(name)) { + name = parameter.getName(); + } + + return name; + } + + @Override + protected String getDefaultValue(Annotation annotation, Parameter parameter, int parameterIndex) { + String defaultValue = getAttribute(annotation, "defaultValue"); + if (isEmpty(defaultValue)) { + defaultValue = super.getDefaultValue(annotation, parameter, parameterIndex); + } + return defaultValue; + } + + protected boolean isEmpty(String str) { + return str == null || str.isEmpty(); + } +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/springmvc/RequestHeaderParameterProcessor.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/springmvc/RequestHeaderParameterProcessor.java new file mode 100644 index 0000000000..8d16898462 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/springmvc/RequestHeaderParameterProcessor.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.rest.springmvc; + +import org.apache.dubbo.metadata.rest.AnnotatedMethodParameterProcessor; +import org.apache.dubbo.metadata.rest.RestMethodMetadata; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; + +import static org.apache.dubbo.metadata.rest.RestMetadataConstants.SPRING_MVC.REQUEST_HEADER_ANNOTATION_CLASS_NAME; + +/** + * The {@link AnnotatedMethodParameterProcessor} implementation for Spring Web MVC's @RequestHeader + */ +public class RequestHeaderParameterProcessor extends AbstractRequestAnnotationParameterProcessor { + + @Override + public String getAnnotationType() { + return REQUEST_HEADER_ANNOTATION_CLASS_NAME; + } + + @Override + protected void process(String name, String defaultValue, Annotation annotation, Object parameter, + int parameterIndex, Method method, RestMethodMetadata restMethodMetadata) { + restMethodMetadata.getRequest().addHeader(name, defaultValue); + } + +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/springmvc/RequestParamParameterProcessor.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/springmvc/RequestParamParameterProcessor.java new file mode 100644 index 0000000000..5ae4727f3b --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/springmvc/RequestParamParameterProcessor.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.rest.springmvc; + +import org.apache.dubbo.metadata.rest.AnnotatedMethodParameterProcessor; +import org.apache.dubbo.metadata.rest.RestMethodMetadata; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; + +import static org.apache.dubbo.metadata.rest.RestMetadataConstants.SPRING_MVC.REQUEST_PARAM_ANNOTATION_CLASS_NAME; + +/** + * The {@link AnnotatedMethodParameterProcessor} implementation for Spring Web MVC's @RequestParam + */ +public class RequestParamParameterProcessor extends AbstractRequestAnnotationParameterProcessor { + + @Override + public String getAnnotationType() { + return REQUEST_PARAM_ANNOTATION_CLASS_NAME; + } + + @Override + protected void process(String name, String defaultValue, Annotation annotation, Object parameter, int parameterIndex, + Method method, RestMethodMetadata restMethodMetadata) { + restMethodMetadata.getRequest().addParam(name, defaultValue); + + } +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/springmvc/SpringMvcServiceRestMetadataResolver.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/springmvc/SpringMvcServiceRestMetadataResolver.java new file mode 100644 index 0000000000..2fde671e01 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/springmvc/SpringMvcServiceRestMetadataResolver.java @@ -0,0 +1,128 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.rest.springmvc; + +import org.apache.dubbo.metadata.rest.AbstractServiceRestMetadataResolver; +import org.apache.dubbo.metadata.rest.ServiceRestMetadataResolver; + +import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Array; +import java.lang.reflect.Method; +import java.util.Set; + +import static java.lang.String.valueOf; +import static java.lang.reflect.Array.getLength; +import static java.util.stream.Stream.of; +import static org.apache.dubbo.common.utils.AnnotationUtils.findAnnotation; +import static org.apache.dubbo.common.utils.AnnotationUtils.findMetaAnnotation; +import static org.apache.dubbo.common.utils.AnnotationUtils.getAttribute; +import static org.apache.dubbo.common.utils.AnnotationUtils.isAnnotationPresent; +import static org.apache.dubbo.common.utils.ArrayUtils.isEmpty; +import static org.apache.dubbo.common.utils.ArrayUtils.isNotEmpty; +import static org.apache.dubbo.common.utils.HttpUtils.buildPath; +import static org.apache.dubbo.metadata.rest.RestMetadataConstants.SPRING_MVC.CONTROLLER_ANNOTATION_CLASS_NAME; +import static org.apache.dubbo.metadata.rest.RestMetadataConstants.SPRING_MVC.REQUEST_MAPPING_ANNOTATION_CLASS_NAME; + +/** + * {@link ServiceRestMetadataResolver} + * + * @since 2.7.6 + */ +public class SpringMvcServiceRestMetadataResolver extends AbstractServiceRestMetadataResolver { + + private static final int FIRST_ELEMENT_INDEX = 0; + + @Override + protected boolean supports0(Class serviceType) { + return isAnnotationPresent(serviceType, CONTROLLER_ANNOTATION_CLASS_NAME); + } + + @Override + protected boolean isRestCapableMethod(Method serviceMethod, Class serviceType, Class serviceInterfaceClass) { + return isAnnotationPresent(serviceType, REQUEST_MAPPING_ANNOTATION_CLASS_NAME); + } + + @Override + protected String resolveRequestMethod(Method serviceMethod, Class serviceType, Class serviceInterfaceClass) { + String requestBasePath = resolveRequestPath(serviceType); + String requestRelativePath = resolveRequestPath(serviceMethod); + return buildPath(requestBasePath, requestRelativePath); + } + + @Override + protected String resolveRequestPath(Method serviceMethod, Class serviceType, Class serviceInterfaceClass) { + Annotation requestMapping = getRequestMapping(serviceMethod); + + // httpMethod is an array of RequestMethod + Object httpMethod = getAttribute(requestMapping, "method"); + + if (httpMethod == null || getLength(httpMethod) < 1) { + return null; + } + + // TODO Is is required to support more request methods? + return valueOf(Array.get(httpMethod, FIRST_ELEMENT_INDEX)); + } + + @Override + protected void processProduces(Method serviceMethod, Class serviceType, Class serviceInterfaceClass, Set produces) { + addMediaTypes(serviceMethod, "produces", produces); + } + + @Override + protected void processConsumes(Method serviceMethod, Class serviceType, Class serviceInterfaceClass, Set consumes) { + addMediaTypes(serviceMethod, "consumes", consumes); + } + + private String resolveRequestPath(AnnotatedElement annotatedElement) { + Annotation mappingAnnotation = getRequestMapping(annotatedElement); + // try "value" first + String[] value = getAttribute(mappingAnnotation, "value"); + + if (isEmpty(value)) { // try "path" later + value = getAttribute(mappingAnnotation, "path"); + } + + if (isEmpty(value)) { + return ""; + } + // TODO Is is required to support more request paths? + return value[FIRST_ELEMENT_INDEX]; + } + + private void addMediaTypes(Method serviceMethod, String annotationAttributeName, Set mediaTypesSet) { + + Annotation mappingAnnotation = getRequestMapping(serviceMethod); + + String[] mediaTypes = getAttribute(mappingAnnotation, annotationAttributeName); + + if (isNotEmpty(mediaTypes)) { + of(mediaTypes).forEach(mediaTypesSet::add); + } + } + + private Annotation getRequestMapping(AnnotatedElement annotatedElement) { + // try "@RequestMapping" first + Annotation requestMapping = findAnnotation(annotatedElement, REQUEST_MAPPING_ANNOTATION_CLASS_NAME); + // try the annotation meta-annotated later + if (requestMapping == null) { + requestMapping = findMetaAnnotation(annotatedElement, REQUEST_MAPPING_ANNOTATION_CLASS_NAME); + } + return requestMapping; + } +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.rest.AnnotatedMethodParameterProcessor b/dubbo-metadata/dubbo-metadata-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.rest.AnnotatedMethodParameterProcessor new file mode 100644 index 0000000000..bcb620cdbe --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.rest.AnnotatedMethodParameterProcessor @@ -0,0 +1,10 @@ +# JAX-RS's implementations +jax-rs.query-param = org.apache.dubbo.metadata.rest.jaxrs.QueryParamParameterProcessor +jax-rs.form-param = org.apache.dubbo.metadata.rest.jaxrs.FormParamParameterProcessor +jax-rs.matrix-param = org.apache.dubbo.metadata.rest.jaxrs.MatrixParamParameterProcessor +jax-rs.header-param = org.apache.dubbo.metadata.rest.jaxrs.HeaderParamParameterProcessor +jax-rs.default-value-param = org.apache.dubbo.metadata.rest.jaxrs.DefaultValueParameterProcessor + +# Spring Web MVC's implementations +spring-webmvc.request-param = org.apache.dubbo.metadata.rest.springmvc.RequestParamParameterProcessor +spring-webmvc.request-header = org.apache.dubbo.metadata.rest.springmvc.RequestHeaderParameterProcessor \ No newline at end of file diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.rest.ServiceRestMetadataResolver b/dubbo-metadata/dubbo-metadata-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.rest.ServiceRestMetadataResolver new file mode 100644 index 0000000000..5b0873bf69 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.rest.ServiceRestMetadataResolver @@ -0,0 +1,3 @@ +default = +jax-rs = org.apache.dubbo.metadata.rest.jaxrs.JAXRSServiceRestMetadataResolver +spring-webmvc = org.apache.dubbo.metadata.rest.springmvc.SpringMvcServiceRestMetadataResolver \ No newline at end of file diff --git a/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/definition/ServiceDefinitionBuildderTest.java b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/definition/ServiceDefinitionBuilderTest.java similarity index 97% rename from dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/definition/ServiceDefinitionBuildderTest.java rename to dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/definition/ServiceDefinitionBuilderTest.java index 89c81a5ae5..3762f3a8ea 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/definition/ServiceDefinitionBuildderTest.java +++ b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/definition/ServiceDefinitionBuilderTest.java @@ -31,7 +31,7 @@ import java.util.List; /** * 2018/11/6 */ -public class ServiceDefinitionBuildderTest { +public class ServiceDefinitionBuilderTest { @Test public void testBuilderComplextObject() { @@ -77,7 +77,7 @@ public class ServiceDefinitionBuildderTest { } } Assertions.assertEquals(topTypeDefinition.getProperties().get("v").getType(), "long"); - Assertions.assertEquals(topTypeDefinition.getProperties().get("maps").getType(), "java.util.Map"); + Assertions.assertEquals(topTypeDefinition.getProperties().get("maps").getType(), "java.util.Map"); Assertions.assertEquals(topTypeDefinition.getProperties().get("innerObject").getType(), ComplexObject.InnerObject.class.getName()); Assertions.assertEquals(topTypeDefinition.getProperties().get("intList").getType(), "java.util.List"); Assertions.assertEquals(topTypeDefinition.getProperties().get("strArrays").getType(), "java.lang.String[]"); diff --git a/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/rest/DefaultRestService.java b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/rest/DefaultRestService.java new file mode 100644 index 0000000000..210952a86b --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/rest/DefaultRestService.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.rest; + +import org.apache.dubbo.config.annotation.Service; + +import java.util.Map; + +/** + * The default implementation of {@link RestService} + * + * @since 2.7.6 + */ +@Service(version = "1.0.0") +public class DefaultRestService implements RestService { + + @Override + public String param(String param) { + return null; + } + + @Override + public String params(int a, String b) { + return null; + } + + @Override + public String headers(String header, String header2, Integer param) { + return null; + } + + @Override + public String pathVariables(String path1, String path2, String param) { + return null; + } + + @Override + public String form(String form) { + return null; + } + + @Override + public User requestBodyMap(Map data, String param) { + return null; + } + + @Override + public Map requestBodyUser(User user) { + return null; + } + + public User user(User user) { + return user; + } +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/rest/RestService.java b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/rest/RestService.java new file mode 100644 index 0000000000..65d67ab475 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/rest/RestService.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.rest; + + +import java.util.Map; + +/** + * An interface for REST service + * + * @since 2.7.6 + */ +public interface RestService { + + String param(String param); + + String params(int a, String b); + + String headers(String header, String header2, Integer param); + + String pathVariables(String path1, String path2, String param); + + String form(String form); + + User requestBodyMap(Map data, String param); + + Map requestBodyUser(User user); +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/rest/SpringRestService.java b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/rest/SpringRestService.java new file mode 100644 index 0000000000..ead518641d --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/rest/SpringRestService.java @@ -0,0 +1,97 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.rest; + +import org.apache.dubbo.config.annotation.Service; + +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.HashMap; +import java.util.Map; + +/** + * Spring MVC {@link RestService} + * + * @since 2.7.6 + */ +@Service(version = "2.0.0") +@RestController +public class SpringRestService implements RestService { + + @Override + @GetMapping(value = "/param") + public String param(@RequestParam(defaultValue = "value-param") String param) { + return param; + } + + @Override + @PostMapping("/params") + public String params(@RequestParam(defaultValue = "value-a") int a, @RequestParam(defaultValue = "value-b") String b) { + return a + b; + } + + @Override + @GetMapping("/headers") + public String headers(@RequestHeader(name = "h", defaultValue = "value-h") String header, + @RequestHeader(name = "h2", defaultValue = "value-h2") String header2, + @RequestParam(value = "v", defaultValue = "1") Integer param) { + String result = header + " , " + header2 + " , " + param; + return result; + } + + @Override + @GetMapping("/path-variables/{p1}/{p2}") + public String pathVariables(@PathVariable("p1") String path1, + @PathVariable("p2") String path2, @RequestParam("v") String param) { + String result = path1 + " , " + path2 + " , " + param; + return result; + } + + @Override + @PostMapping("/form") + public String form(@RequestParam("f") String form) { + return String.valueOf(form); + } + + @Override + @PostMapping(value = "/request/body/map", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + public User requestBodyMap(@RequestBody Map data, + @RequestParam("param") String param) { + User user = new User(); + user.setId(((Integer) data.get("id")).longValue()); + user.setName((String) data.get("name")); + user.setAge((Integer) data.get("age")); + return user; + } + + @PostMapping(value = "/request/body/user", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE) + @Override + public Map requestBodyUser(@RequestBody User user) { + Map map = new HashMap<>(); + map.put("id", user.getId()); + map.put("name", user.getName()); + map.put("age", user.getAge()); + return map; + } +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/rest/StandardRestService.java b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/rest/StandardRestService.java new file mode 100644 index 0000000000..f5d94b7c1e --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/rest/StandardRestService.java @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.rest; + +import org.apache.dubbo.config.annotation.Service; + +import javax.ws.rs.Consumes; +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import java.util.HashMap; +import java.util.Map; + + +/** + * JAX-RS {@link RestService} + */ +@Service(version = "3.0.0", protocol = {"dubbo", "rest"}, group = "standard") +@Path("/") +public class StandardRestService implements RestService { + + @Override + @Path("param") + @GET + public String param(@QueryParam("param") String param) { + return param; + } + + @Override + @Path("params") + @POST + public String params(@QueryParam("a") int a, @QueryParam("b") String b) { + return a + b; + } + + @Override + @Path("headers") + @GET + public String headers(@HeaderParam("h") String header, + @HeaderParam("h2") String header2, @QueryParam("v") Integer param) { + String result = header + " , " + header2 + " , " + param; + return result; + } + + @Override + @Path("path-variables/{p1}/{p2}") + @GET + public String pathVariables(@PathParam("p1") String path1, + @PathParam("p2") String path2, @QueryParam("v") String param) { + String result = path1 + " , " + path2 + " , " + param; + return result; + } + + // @CookieParam does not support : https://github.com/OpenFeign/feign/issues/913 + // @CookieValue also does not support + + @Override + @Path("form") + @POST + public String form(@FormParam("f") String form) { + return String.valueOf(form); + } + + @Override + @Path("request/body/map") + @POST + @Produces("application/json;charset=UTF-8") + public User requestBodyMap(Map data, + @QueryParam("param") String param) { + User user = new User(); + user.setId(((Integer) data.get("id")).longValue()); + user.setName((String) data.get("name")); + user.setAge((Integer) data.get("age")); + return user; + } + + @Path("request/body/user") + @POST + @Override + @Consumes("application/json;charset=UTF-8") + public Map requestBodyUser(User user) { + Map map = new HashMap<>(); + map.put("id", user.getId()); + map.put("name", user.getName()); + map.put("age", user.getAge()); + return map; + } +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/rest/User.java b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/rest/User.java new file mode 100644 index 0000000000..2ad6a514cf --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/rest/User.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.rest; + +import java.io.Serializable; + +/** + * User Entity + * + * @since 2.7.6 + */ +public class User implements Serializable { + + private Long id; + + private String name; + + private Integer age; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getAge() { + return age; + } + + public void setAge(Integer age) { + this.age = age; + } + + @Override + public String toString() { + return "User{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + '}'; + } +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/rest/resolver/jaxrs/JAXRSServiceRestMetadataResolverTest.java b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/rest/resolver/jaxrs/JAXRSServiceRestMetadataResolverTest.java new file mode 100644 index 0000000000..d959007aba --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/rest/resolver/jaxrs/JAXRSServiceRestMetadataResolverTest.java @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.rest.resolver.jaxrs; + +import org.apache.dubbo.metadata.rest.ClassPathServiceRestMetadataReader; +import org.apache.dubbo.metadata.rest.DefaultRestService; +import org.apache.dubbo.metadata.rest.RestMethodMetadata; +import org.apache.dubbo.metadata.rest.RestService; +import org.apache.dubbo.metadata.rest.ServiceRestMetadata; +import org.apache.dubbo.metadata.rest.SpringRestService; +import org.apache.dubbo.metadata.rest.StandardRestService; +import org.apache.dubbo.metadata.rest.jaxrs.JAXRSServiceRestMetadataResolver; + +import org.junit.jupiter.api.Test; + +import java.util.LinkedList; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link JAXRSServiceRestMetadataResolver} Test + * + * @since 2.7.6 + */ +public class JAXRSServiceRestMetadataResolverTest { + + private JAXRSServiceRestMetadataResolver instance = new JAXRSServiceRestMetadataResolver(); + + @Test + public void testSupports() { + // JAX-RS RestService class + assertTrue(instance.supports(StandardRestService.class)); + // Spring MVC RestService class + assertFalse(instance.supports(SpringRestService.class)); + // Default RestService class + assertFalse(instance.supports(DefaultRestService.class)); + // No annotated RestService class + assertFalse(instance.supports(RestService.class)); + // null + assertFalse(instance.supports(null)); + } + + @Test + public void testResolve() { + // Generated by "dubbo-metadata-processor" + ClassPathServiceRestMetadataReader reader = new ClassPathServiceRestMetadataReader("META-INF/dubbo/jax-rs-service-rest-metadata.json"); + List serviceRestMetadataList = reader.read(); + + ServiceRestMetadata expectedServiceRestMetadata = serviceRestMetadataList.get(0); + ServiceRestMetadata serviceRestMetadata = instance.resolve(StandardRestService.class); + + + List meta1 = new LinkedList<>(expectedServiceRestMetadata.getMeta()); + List meta2 = new LinkedList<>(serviceRestMetadata.getMeta()); + + for (int i = 0; i < meta1.size(); i++) { + RestMethodMetadata restMethodMetadata = meta1.get(i); + RestMethodMetadata restMethodMetadata2 = meta2.get(i); + assertEquals(restMethodMetadata, restMethodMetadata2); + } + + assertEquals(expectedServiceRestMetadata, serviceRestMetadata); + + } +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/test/resources/META-INF/dubbo/jax-rs-service-rest-metadata.json b/dubbo-metadata/dubbo-metadata-api/src/test/resources/META-INF/dubbo/jax-rs-service-rest-metadata.json new file mode 100644 index 0000000000..38303690f1 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/test/resources/META-INF/dubbo/jax-rs-service-rest-metadata.json @@ -0,0 +1,349 @@ +[ + { + "serviceInterface": "org.apache.dubbo.metadata.rest.RestService", + "version": "3.0.0", + "group": "standard", + "meta": [ + { + "method": { + "name": "form", + "parameterTypes": [ + "java.lang.String" + ], + "returnType": "java.lang.String", + "parameters": [ + { + "type": "java.lang.String", + "items": [], + "enum": [], + "properties": {} + } + ] + }, + "request": { + "method": "POST", + "path": "/form", + "params": { + "f": [ + "{0}" + ] + }, + "headers": {}, + "consumes": [], + "produces": [] + }, + "indexToName": { + "0": [ + "form" + ] + } + }, + { + "method": { + "name": "headers", + "parameterTypes": [ + "java.lang.String", + "java.lang.String", + "java.lang.Integer" + ], + "returnType": "java.lang.String", + "parameters": [ + { + "type": "java.lang.String", + "items": [], + "enum": [], + "properties": {} + }, + { + "type": "java.lang.String", + "items": [], + "enum": [], + "properties": {} + }, + { + "type": "java.lang.Integer", + "items": [], + "enum": [], + "properties": {} + } + ] + }, + "request": { + "method": "GET", + "path": "/headers", + "params": { + "v": [ + "{2}" + ] + }, + "headers": { + "h": [ + "{0}" + ], + "h2": [ + "{1}" + ] + }, + "consumes": [], + "produces": [] + }, + "indexToName": { + "0": [ + "header" + ], + "1": [ + "header2" + ], + "2": [ + "param" + ] + } + }, + { + "method": { + "name": "param", + "parameterTypes": [ + "java.lang.String" + ], + "returnType": "java.lang.String", + "parameters": [ + { + "type": "java.lang.String", + "items": [], + "enum": [], + "properties": {} + } + ] + }, + "request": { + "method": "GET", + "path": "/param", + "params": { + "param": [ + "{0}" + ] + }, + "headers": {}, + "consumes": [], + "produces": [] + }, + "indexToName": { + "0": [ + "param" + ] + } + }, + { + "method": { + "name": "params", + "parameterTypes": [ + "int", + "java.lang.String" + ], + "returnType": "java.lang.String", + "parameters": [ + { + "type": "int", + "items": [], + "enum": [], + "properties": {} + }, + { + "type": "java.lang.String", + "items": [], + "enum": [], + "properties": {} + } + ] + }, + "request": { + "method": "POST", + "path": "/params", + "params": { + "a": [ + "{0}" + ], + "b": [ + "{1}" + ] + }, + "headers": {}, + "consumes": [], + "produces": [] + }, + "indexToName": { + "0": [ + "a" + ], + "1": [ + "b" + ] + } + }, + { + "method": { + "name": "pathVariables", + "parameterTypes": [ + "java.lang.String", + "java.lang.String", + "java.lang.String" + ], + "returnType": "java.lang.String", + "parameters": [ + { + "type": "java.lang.String", + "items": [], + "enum": [], + "properties": {} + }, + { + "type": "java.lang.String", + "items": [], + "enum": [], + "properties": {} + }, + { + "type": "java.lang.String", + "items": [], + "enum": [], + "properties": {} + } + ] + }, + "request": { + "method": "GET", + "path": "/path-variables/{p1}/{p2}", + "params": { + "v": [ + "{2}" + ] + }, + "headers": {}, + "consumes": [], + "produces": [] + }, + "indexToName": { + "0": [ + "path1" + ], + "1": [ + "path2" + ], + "2": [ + "param" + ] + } + }, + { + "method": { + "name": "requestBodyMap", + "parameterTypes": [ + "java.util.Map\u003cjava.lang.String,java.lang.Object\u003e", + "java.lang.String" + ], + "returnType": "org.apache.dubbo.metadata.rest.User", + "parameters": [ + { + "type": "java.util.Map\u003cjava.lang.String,java.lang.Object\u003e", + "items": [ + { + "type": "java.lang.String", + "items": [], + "enum": [], + "properties": {} + }, + { + "type": "java.lang.Object", + "items": [], + "enum": [], + "properties": {} + } + ], + "enum": [], + "properties": {} + }, + { + "type": "java.lang.String", + "items": [], + "enum": [], + "properties": {} + } + ] + }, + "request": { + "method": "POST", + "path": "/request/body/map", + "params": { + "param": [ + "{1}" + ] + }, + "headers": {}, + "consumes": [], + "produces": [ + "application/json;charset\u003dUTF-8" + ] + }, + "indexToName": { + "0": [ + "data" + ], + "1": [ + "param" + ] + } + }, + { + "method": { + "name": "requestBodyUser", + "parameterTypes": [ + "org.apache.dubbo.metadata.rest.User" + ], + "returnType": "java.util.Map\u003cjava.lang.String,java.lang.Object\u003e", + "parameters": [ + { + "type": "org.apache.dubbo.metadata.rest.User", + "items": [], + "enum": [], + "properties": { + "name": { + "type": "java.lang.String", + "items": [], + "enum": [], + "properties": {} + }, + "id": { + "type": "java.lang.Long", + "items": [], + "enum": [], + "properties": {} + }, + "age": { + "type": "java.lang.Integer", + "items": [], + "enum": [], + "properties": {} + } + } + } + ] + }, + "request": { + "method": "POST", + "path": "/request/body/user", + "params": {}, + "headers": {}, + "consumes": [ + "application/json;charset\u003dUTF-8" + ], + "produces": [] + }, + "indexToName": { + "0": [ + "user" + ] + } + } + ] + } +] \ No newline at end of file diff --git a/dubbo-metadata/dubbo-metadata-definition-protobuf/src/test/java/org/apache/dubbo/metadata/definition/protobuf/ProtobufTypeBuilderTest.java b/dubbo-metadata/dubbo-metadata-definition-protobuf/src/test/java/org/apache/dubbo/metadata/definition/protobuf/ProtobufTypeBuilderTest.java index 5557e26f9a..e9c8a17ab4 100644 --- a/dubbo-metadata/dubbo-metadata-definition-protobuf/src/test/java/org/apache/dubbo/metadata/definition/protobuf/ProtobufTypeBuilderTest.java +++ b/dubbo-metadata/dubbo-metadata-definition-protobuf/src/test/java/org/apache/dubbo/metadata/definition/protobuf/ProtobufTypeBuilderTest.java @@ -66,8 +66,8 @@ public class ProtobufTypeBuilderTest { assertThat(propertiesMap.containsKey("phone"), is(true)); assertThat(propertiesMap.get("phone").getType(), equalTo("java.util.List")); assertThat(propertiesMap.containsKey("doubleMap"), is(true)); - assertThat(propertiesMap.get("doubleMap").getType(), equalTo("java.util.Map")); + assertThat(propertiesMap.get("doubleMap").getType(), equalTo("java.util.Map")); assertThat(propertiesMap.get("bytesList").getType(), equalTo("java.util.List")); - assertThat(propertiesMap.get("bytesMap").getType(), equalTo("java.util.Map")); + assertThat(propertiesMap.get("bytesMap").getType(), equalTo("java.util.Map")); } } diff --git a/dubbo-metadata/dubbo-metadata-processor/pom.xml b/dubbo-metadata/dubbo-metadata-processor/pom.xml new file mode 100644 index 0000000000..965c036e75 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/pom.xml @@ -0,0 +1,177 @@ + + + + + org.apache.dubbo + dubbo-metadata + ${revision} + ../pom.xml + + 4.0.0 + + dubbo-metadata-processor + jar + dubbo-metadata-processor + The metadata processor module of Dubbo project + + + + org.apache.dubbo + dubbo-metadata-api + ${project.parent.version} + + + org.apache.dubbo + dubbo-rpc-api + + + org.apache.dubbo + dubbo-cluster + + + com.google.code.gson + gson + + + + + + org.apache.dubbo + dubbo-common + ${project.parent.version} + + + javax.annotation + javax.annotation-api + + + + org.slf4j + slf4j-api + + + + commons-logging + commons-logging + + + log4j + log4j + + + + org.apache.logging.log4j + log4j-api + + + + org.apache.logging.log4j + log4j-core + + + org.javassist + javassist + + + com.alibaba + hessian-lite + + + com.alibaba + fastjson + + + com.esotericsoftware + kryo + + + de.javakaffee + kryo-serializers + + + de.ruedigermoeller + fst + + + commons-io + commons-io + + + + + + + com.google.code.gson + gson + + + + + org.apache.dubbo + dubbo-config-api + ${project.parent.version} + test + + + org.apache.dubbo + dubbo-registry-api + + + org.apache.dubbo + dubbo-metadata-api + + + org.apache.dubbo + dubbo-monitor-api + + + org.apache.dubbo + dubbo-remoting-api + + + org.apache.dubbo + dubbo-rpc-injvm + + + org.apache.dubbo + dubbo-filter-validation + + + org.apache.dubbo + dubbo-filter-cache + + + + + + + javax.ws.rs + javax.ws.rs-api + test + + + + + org.springframework + spring-web + test + + + \ No newline at end of file diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/AbstractServiceAnnotationProcessor.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/AbstractServiceAnnotationProcessor.java new file mode 100644 index 0000000000..7ef7794046 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/AbstractServiceAnnotationProcessor.java @@ -0,0 +1,108 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing; + +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.ProcessingEnvironment; +import javax.annotation.processing.Processor; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.PackageElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.util.Elements; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static javax.lang.model.util.ElementFilter.methodsIn; +import static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.SUPPORTED_ANNOTATION_TYPES; + +/** + * Abstract {@link Processor} for the classes that were annotated by Dubbo's @Service + * + * @since 2.7.6 + */ +public abstract class AbstractServiceAnnotationProcessor extends AbstractProcessor { + + protected Elements elements; + + private List objectMembers; + + public synchronized void init(ProcessingEnvironment processingEnv) { + super.init(processingEnv); + this.elements = processingEnv.getElementUtils(); + this.objectMembers = elements.getAllMembers(elements.getTypeElement(Object.class.getName())); + } + + protected List getActualMembers(TypeElement type) { + List members = new LinkedList<>(elements.getAllMembers(type)); + members.removeAll(objectMembers); + return members; + } + + protected List getActualMethods(TypeElement type) { + return methodsIn(getActualMembers(type)); + } + + protected Map getActualMethodsMap(TypeElement type) { + Map methodsMap = new HashMap<>(); + getActualMethods(type).forEach(method -> { + methodsMap.put(method.toString(), method); + }); + return methodsMap; + } + + public static String getMethodSignature(ExecutableElement method) { + if (!ElementKind.METHOD.equals(method.getKind())) { + throw new IllegalArgumentException("The argument must be Method Kind"); + } + + StringBuilder methodSignatureBuilder = new StringBuilder(); + + method.getModifiers().forEach(member -> { + methodSignatureBuilder.append(member).append(" "); + }); + + methodSignatureBuilder.append(method.getReturnType()) + .append(" ") + .append(method.toString()); + + return methodSignatureBuilder.toString(); + } + + protected TypeElement getTypeElement(CharSequence className) { + return elements.getTypeElement(className); + } + + protected PackageElement getPackageElement(Element type) { + return this.elements.getPackageOf(type); + } + + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latest(); + } + + @Override + public final Set getSupportedAnnotationTypes() { + return SUPPORTED_ANNOTATION_TYPES; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/ClassPathMetadataStorage.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/ClassPathMetadataStorage.java new file mode 100644 index 0000000000..9e1032c590 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/ClassPathMetadataStorage.java @@ -0,0 +1,105 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing; + + +import javax.annotation.processing.Filer; +import javax.annotation.processing.ProcessingEnvironment; +import javax.tools.FileObject; +import java.io.File; +import java.io.IOException; +import java.io.Reader; +import java.io.Writer; +import java.util.Optional; +import java.util.function.Function; +import java.util.function.Supplier; + +import static java.util.Optional.empty; +import static java.util.Optional.ofNullable; +import static javax.tools.StandardLocation.CLASS_OUTPUT; +import static org.apache.dubbo.metadata.annotation.processing.util.LoggerUtils.info; +import static org.apache.dubbo.metadata.annotation.processing.util.LoggerUtils.warn; + +/** + * A storage class for metadata under class path + */ +public class ClassPathMetadataStorage { + + private final Filer filer; + + public ClassPathMetadataStorage(ProcessingEnvironment processingEnv) { + this.filer = processingEnv.getFiler(); + } + + public void write(Supplier contentSupplier, String resourceName) { + try (Writer writer = getWriter(resourceName)) { + writer.write(contentSupplier.get()); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public Optional read(String resourceName, Function consumer) { + if (exists(resourceName)) { + try (Reader reader = getReader(resourceName)) { + return ofNullable(consumer.apply(reader)); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + return empty(); + } + + private boolean exists(String resourceName) { + + return getResource(resourceName) + .map(FileObject::toUri) + .map(File::new) + .map(File::exists) + .orElse(false); + } + + private Reader getReader(String resourceName) { + return getResource(resourceName).map(fileObject -> { + try { + return fileObject.openReader(false); + } catch (IOException e) { + } + return null; + }).orElse(null); + } + + private FileObject createResource(String resourceName) throws IOException { + return filer.createResource(CLASS_OUTPUT, "", resourceName); + } + + private Optional getResource(String resourceName) { + try { + FileObject fileObject = filer.getResource(CLASS_OUTPUT, "", resourceName); + return ofNullable(fileObject); + } catch (IOException e) { + warn(e.getMessage()); + } + return empty(); + } + + private Writer getWriter(String resourceName) throws IOException { + FileObject fileObject = createResource(resourceName); + info("The resource[path : %s , deleted : %s] will be written", fileObject.toUri().getPath(), fileObject.delete()); + return fileObject.openWriter(); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/ServiceDefinitionMetadataAnnotationProcessor.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/ServiceDefinitionMetadataAnnotationProcessor.java new file mode 100644 index 0000000000..e5d736a416 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/ServiceDefinitionMetadataAnnotationProcessor.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing; + +import org.apache.dubbo.metadata.definition.model.ServiceDefinition; + +import com.google.gson.Gson; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.annotation.processing.Processor; +import javax.annotation.processing.RoundEnvironment; +import javax.lang.model.element.TypeElement; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +import static javax.lang.model.util.ElementFilter.typesIn; +import static org.apache.dubbo.metadata.annotation.processing.builder.ServiceDefinitionBuilder.build; + +/** + * The {@link Processor} class to generate the metadata of {@link ServiceDefinition} whose classes are annotated by Dubbo's @Service + * + * @see Processor + * @since 2.7.6 + */ +public class ServiceDefinitionMetadataAnnotationProcessor extends AbstractServiceAnnotationProcessor { + + private List serviceDefinitions = new LinkedList<>(); + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + + typesIn(roundEnv.getRootElements()).forEach(serviceType -> process(processingEnv, serviceType, annotations)); + + if (roundEnv.processingOver()) { + ClassPathMetadataStorage writer = new ClassPathMetadataStorage(processingEnv); + writer.write(() -> new Gson().toJson(serviceDefinitions), "META-INF/dubbo/service-definitions.json"); + } + + return false; + } + + private void process(ProcessingEnvironment processingEnv, TypeElement serviceType, Set annotations) { + serviceDefinitions.add(build(processingEnv, serviceType)); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/ArrayTypeDefinitionBuilder.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/ArrayTypeDefinitionBuilder.java new file mode 100644 index 0000000000..a53f334c5b --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/ArrayTypeDefinitionBuilder.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.builder; + +import org.apache.dubbo.metadata.definition.model.TypeDefinition; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.type.ArrayType; +import javax.lang.model.type.TypeMirror; +import java.lang.reflect.Array; + +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isArrayType; + +/** + * {@link TypeDefinitionBuilder} for Java {@link Array} + * + * @since 2.7.6 + */ +public class ArrayTypeDefinitionBuilder implements TypeDefinitionBuilder { + + @Override + public boolean accept(ProcessingEnvironment processingEnv, TypeMirror type) { + return isArrayType(type); + } + + @Override + public void build(ProcessingEnvironment processingEnv, ArrayType type, TypeDefinition typeDefinition) { + TypeMirror componentType = type.getComponentType(); + typeDefinition.getItems().add(TypeDefinitionBuilder.build(processingEnv, componentType)); + } + + @Override + public int getPriority() { + return MIN_PRIORITY - 4; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/CollectionTypeDefinitionBuilder.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/CollectionTypeDefinitionBuilder.java new file mode 100644 index 0000000000..0141ff1103 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/CollectionTypeDefinitionBuilder.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.builder; + +import org.apache.dubbo.metadata.definition.model.TypeDefinition; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.Elements; +import javax.lang.model.util.Types; +import java.util.Collection; +import java.util.Objects; + +/** + * {@link TypeDefinitionBuilder} for Java {@link Collection} + * + * @since 2.7.6 + */ +public class CollectionTypeDefinitionBuilder implements DeclaredTypeDefinitionBuilder { + + @Override + public boolean accept(ProcessingEnvironment processingEnv, DeclaredType type) { + Elements elements = processingEnv.getElementUtils(); + TypeElement collectionTypeElement = elements.getTypeElement(Collection.class.getTypeName()); + TypeMirror collectionType = collectionTypeElement.asType(); + Types types = processingEnv.getTypeUtils(); + TypeMirror erasedType = types.erasure(type); + return types.isAssignable(erasedType, collectionType); + } + + @Override + public void build(ProcessingEnvironment processingEnv, DeclaredType type, TypeDefinition typeDefinition) { + // Generic Type arguments + type.getTypeArguments() + .stream() + .map(typeArgument -> TypeDefinitionBuilder.build(processingEnv, typeArgument)) // build the TypeDefinition from typeArgument + .filter(Objects::nonNull) + .forEach(typeDefinition.getItems()::add); // Add into the declared TypeDefinition + } + + @Override + public int getPriority() { + return MIN_PRIORITY - 5; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/DeclaredTypeDefinitionBuilder.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/DeclaredTypeDefinitionBuilder.java new file mode 100644 index 0000000000..a4d01067a5 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/DeclaredTypeDefinitionBuilder.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.builder; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeMirror; + +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.ofDeclaredType; + +/** + * An interface of {@link TypeDefinitionBuilder} for {@link DeclaredType} + * + * @since 2.7.6 + */ +public interface DeclaredTypeDefinitionBuilder extends TypeDefinitionBuilder { + + @Override + default boolean accept(ProcessingEnvironment processingEnv, TypeMirror type) { + DeclaredType declaredType = ofDeclaredType(type); + if (declaredType == null) { + return false; + } + return accept(processingEnv, declaredType); + } + + /** + * Test the specified {@link DeclaredType type} is accepted or not + * + * @param processingEnv {@link ProcessingEnvironment} + * @param type {@link DeclaredType type} + * @return true if accepted + */ + boolean accept(ProcessingEnvironment processingEnv, DeclaredType type); +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/EnumTypeDefinitionBuilder.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/EnumTypeDefinitionBuilder.java new file mode 100644 index 0000000000..20c38899d5 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/EnumTypeDefinitionBuilder.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.builder; + +import org.apache.dubbo.metadata.annotation.processing.util.FieldUtils; +import org.apache.dubbo.metadata.definition.model.TypeDefinition; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.Element; +import javax.lang.model.element.Name; +import javax.lang.model.type.DeclaredType; + +import static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.getDeclaredFields; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isEnumType; + +/** + * {@link TypeDefinitionBuilder} for Java {@link Enum} + * + * @since 2.7.6 + */ +public class EnumTypeDefinitionBuilder implements DeclaredTypeDefinitionBuilder { + + @Override + public boolean accept(ProcessingEnvironment processingEnv, DeclaredType type) { + return isEnumType(type); + } + + @Override + public void build(ProcessingEnvironment processingEnv, DeclaredType type, TypeDefinition typeDefinition) { + getDeclaredFields(type, FieldUtils::isEnumMemberField) + .stream() + .map(Element::getSimpleName) + .map(Name::toString) + .forEach(typeDefinition.getEnums()::add); + } + + @Override + public int getPriority() { + return MIN_PRIORITY - 2; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/GeneralTypeDefinitionBuilder.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/GeneralTypeDefinitionBuilder.java new file mode 100644 index 0000000000..c1601112b4 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/GeneralTypeDefinitionBuilder.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.builder; + +import org.apache.dubbo.metadata.definition.model.TypeDefinition; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.DeclaredType; + +import static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.getNonStaticFields; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.getType; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isClassType; + +/** + * {@link TypeDefinitionBuilder} for General Object + * + * @since 2.7.6 + */ +public class GeneralTypeDefinitionBuilder implements DeclaredTypeDefinitionBuilder { + + @Override + public boolean accept(ProcessingEnvironment processingEnv, DeclaredType type) { + return isClassType(type); + } + + @Override + public void build(ProcessingEnvironment processingEnv, DeclaredType type, TypeDefinition typeDefinition) { + + String typeName = type.toString(); + + TypeElement typeElement = getType(processingEnv, typeName); + + buildProperties(processingEnv, typeElement, typeDefinition); + } + + protected void buildProperties(ProcessingEnvironment processingEnv, TypeElement type, TypeDefinition definition) { + getNonStaticFields(type).forEach(field -> { + String fieldName = field.getSimpleName().toString(); + TypeDefinition propertyType = TypeDefinitionBuilder.build(processingEnv, field); + if (propertyType != null) { + definition.getProperties().put(fieldName, propertyType); + } + }); + } + + @Override + public int getPriority() { + return MIN_PRIORITY; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/MapTypeDefinitionBuilder.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/MapTypeDefinitionBuilder.java new file mode 100644 index 0000000000..d05e4bbfc4 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/MapTypeDefinitionBuilder.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.builder; + +import org.apache.dubbo.metadata.definition.model.TypeDefinition; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.Elements; +import javax.lang.model.util.Types; +import java.util.Map; +import java.util.Objects; + +/** + * {@link TypeDefinitionBuilder} for Java {@link Map} + * + * @since 2.7.6 + */ +public class MapTypeDefinitionBuilder implements DeclaredTypeDefinitionBuilder { + + @Override + public boolean accept(ProcessingEnvironment processingEnv, DeclaredType type) { + Elements elements = processingEnv.getElementUtils(); + TypeElement mapTypeElement = elements.getTypeElement(Map.class.getTypeName()); + TypeMirror mapType = mapTypeElement.asType(); + Types types = processingEnv.getTypeUtils(); + TypeMirror erasedType = types.erasure(type); + return types.isAssignable(erasedType, mapType); + } + + @Override + public void build(ProcessingEnvironment processingEnv, DeclaredType type, TypeDefinition typeDefinition) { + // Generic Type arguments + type.getTypeArguments() + .stream() + .map(typeArgument -> TypeDefinitionBuilder.build(processingEnv, typeArgument)) // build the TypeDefinition from typeArgument + .filter(Objects::nonNull) + .forEach(typeDefinition.getItems()::add); // Add into the declared TypeDefinition + + } + + @Override + public int getPriority() { + return MIN_PRIORITY - 6; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/MethodDefinitionBuilder.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/MethodDefinitionBuilder.java new file mode 100644 index 0000000000..b5790950aa --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/MethodDefinitionBuilder.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.builder; + +import org.apache.dubbo.metadata.definition.model.MethodDefinition; +import org.apache.dubbo.metadata.definition.model.TypeDefinition; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.ExecutableElement; +import java.util.List; +import java.util.stream.Collectors; + +import static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.getMethodName; +import static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.getMethodParameterTypes; +import static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.getReturnType; + +/** + * A Builder class for {@link MethodDefinition} + * + * @see MethodDefinition + * @since 2.7.6 + */ +public interface MethodDefinitionBuilder { + + static MethodDefinition build(ProcessingEnvironment processingEnv, ExecutableElement method) { + MethodDefinition methodDefinition = new MethodDefinition(); + methodDefinition.setName(getMethodName(method)); + methodDefinition.setReturnType(getReturnType(method)); + methodDefinition.setParameterTypes(getMethodParameterTypes(method)); + methodDefinition.setParameters(getMethodParameters(processingEnv, method)); + return methodDefinition; + } + + static List getMethodParameters(ProcessingEnvironment processingEnv, ExecutableElement method) { + return method.getParameters().stream() + .map(element -> TypeDefinitionBuilder.build(processingEnv, element)) + .collect(Collectors.toList()); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/PrimitiveTypeDefinitionBuilder.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/PrimitiveTypeDefinitionBuilder.java new file mode 100644 index 0000000000..3c7b603eb8 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/PrimitiveTypeDefinitionBuilder.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.builder; + +import org.apache.dubbo.metadata.definition.model.TypeDefinition; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.type.PrimitiveType; +import javax.lang.model.type.TypeMirror; + +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isPrimitiveType; + +/** + * {@link TypeDefinitionBuilder} for Java {@link PrimitiveType primitve type} + * + * @since 2.7.6 + */ +public class PrimitiveTypeDefinitionBuilder implements TypeDefinitionBuilder { + + @Override + public boolean accept(ProcessingEnvironment processingEnv, TypeMirror type) { + return isPrimitiveType(type); + } + + @Override + public void build(ProcessingEnvironment processingEnv, PrimitiveType type, TypeDefinition typeDefinition) { + // DO NOTHING + } + + @Override + public int getPriority() { + return MIN_PRIORITY - 3; + } +} \ No newline at end of file diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/ServiceDefinitionBuilder.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/ServiceDefinitionBuilder.java new file mode 100644 index 0000000000..a5616e6310 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/ServiceDefinitionBuilder.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.builder; + +import org.apache.dubbo.metadata.definition.model.ServiceDefinition; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.TypeElement; + +import static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.getPublicNonStaticMethods; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.getHierarchicalTypes; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.getResourceName; + +/** + * A Builder for {@link ServiceDefinition} + * + * @see ServiceDefinition + * @since 2.7.6 + */ +public interface ServiceDefinitionBuilder { + + static ServiceDefinition build(ProcessingEnvironment processingEnv, TypeElement type) { + ServiceDefinition serviceDefinition = new ServiceDefinition(); + serviceDefinition.setCanonicalName(type.toString()); + serviceDefinition.setCodeSource(getResourceName(type.toString())); + + // Get all super types and interface excluding the specified type + // and then the result will be added into ServiceDefinition#getTypes() + getHierarchicalTypes(type.asType(), Object.class) + .stream() + .map(t -> TypeDefinitionBuilder.build(processingEnv, t)) + .forEach(serviceDefinition.getTypes()::add); + + // Get all declared methods that will be added into ServiceDefinition#getMethods() + getPublicNonStaticMethods(type, Object.class) + .stream() + .map(method -> MethodDefinitionBuilder.build(processingEnv, method)) + .forEach(serviceDefinition.getMethods()::add); + + return serviceDefinition; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/SimpleTypeDefinitionBuilder.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/SimpleTypeDefinitionBuilder.java new file mode 100644 index 0000000000..620988fb66 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/SimpleTypeDefinitionBuilder.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.builder; + +import org.apache.dubbo.metadata.annotation.processing.util.TypeUtils; +import org.apache.dubbo.metadata.definition.model.TypeDefinition; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.type.DeclaredType; + +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isSimpleType; + + +/** + * {@link TypeDefinitionBuilder} for {@link TypeUtils#SIMPLE_TYPES Java Simple Type} + * + * @since 2.7.6 + */ +public class SimpleTypeDefinitionBuilder implements DeclaredTypeDefinitionBuilder { + + @Override + public boolean accept(ProcessingEnvironment processingEnv, DeclaredType type) { + return isSimpleType(type); + } + + @Override + public void build(ProcessingEnvironment processingEnv, DeclaredType type, TypeDefinition typeDefinition) { + // DO NOTHING + } + + @Override + public int getPriority() { + return MIN_PRIORITY - 1; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/TypeDefinitionBuilder.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/TypeDefinitionBuilder.java new file mode 100644 index 0000000000..e65bc1d2ab --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/TypeDefinitionBuilder.java @@ -0,0 +1,96 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.builder; + +import org.apache.dubbo.common.extension.SPI; +import org.apache.dubbo.common.lang.Prioritized; +import org.apache.dubbo.metadata.definition.model.TypeDefinition; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.Element; +import javax.lang.model.type.TypeMirror; + +import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader; + +/** + * A class builds the instance of {@link TypeDefinition} + * + * @since 2.7.6 + */ +@SPI +public interface TypeDefinitionBuilder extends Prioritized { + + /** + * Test the specified {@link TypeMirror type} is accepted or not + * + * @param processingEnv {@link ProcessingEnvironment} + * @param type {@link TypeMirror type} + * @return true if accepted + */ + boolean accept(ProcessingEnvironment processingEnv, TypeMirror type); + + /** + * Build the instance of {@link TypeDefinition} + * + * @param processingEnv {@link ProcessingEnvironment} + * @param type {@link T type} + * @param typeDefinition {@link TypeDefinition} to be built + * @return an instance of {@link TypeDefinition} + */ + void build(ProcessingEnvironment processingEnv, T type, TypeDefinition typeDefinition); + + /** + * Build the instance of {@link TypeDefinition} from the specified {@link Element element} + * + * @param processingEnv {@link ProcessingEnvironment} + * @param element {@link Element source element} + * @return non-null + */ + static TypeDefinition build(ProcessingEnvironment processingEnv, Element element) { + TypeDefinition typeDefinition = build(processingEnv, element.asType()); + // Comment this code for the compatibility + // typeDefinition.set$ref(element.toString()); + return typeDefinition; + } + + /** + * Build the instance of {@link TypeDefinition} from the specified {@link TypeMirror type} + * + * @param processingEnv {@link ProcessingEnvironment} + * @param type {@link TypeMirror type} + * @return non-null + */ + static TypeDefinition build(ProcessingEnvironment processingEnv, TypeMirror type) { + String typeName = type.toString(); + TypeDefinition typeDefinition = new TypeDefinition(typeName); + + // Build by all instances of TypeDefinitionBuilder that were loaded By Java SPI + + getExtensionLoader(TypeDefinitionBuilder.class) + .getSupportedExtensionInstances() + .stream() +// load(TypeDefinitionBuilder.class, TypeDefinitionBuilder.class.getClassLoader()) + .filter(builder -> builder.accept(processingEnv, type)) + .findFirst() + .ifPresent(builder -> { + builder.build(processingEnv, type, typeDefinition); + // typeDefinition.setTypeBuilderName(builder.getClass().getName()); + }); + + return typeDefinition; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/AbstractAnnotatedMethodParameterProcessor.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/AbstractAnnotatedMethodParameterProcessor.java new file mode 100644 index 0000000000..df79c4fbdb --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/AbstractAnnotatedMethodParameterProcessor.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.rest; + +import org.apache.dubbo.metadata.rest.RestMethodMetadata; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.VariableElement; + +import static org.apache.dubbo.metadata.annotation.processing.rest.AnnotatedMethodParameterProcessor.buildDefaultValue; +import static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.getValue; + +/** + * The abstract {@link AnnotatedMethodParameterProcessor} implementation + * + * @since 2.7.6 + */ +public abstract class AbstractAnnotatedMethodParameterProcessor implements AnnotatedMethodParameterProcessor { + + @Override + public final void process(AnnotationMirror annotation, VariableElement parameter, int parameterIndex, ExecutableElement method, RestMethodMetadata restMethodMetadata) { + String annotationValue = getAnnotationValue(annotation, parameter, parameterIndex); + String defaultValue = getDefaultValue(annotation, parameter, parameterIndex); + process(annotationValue, defaultValue, annotation, parameter, parameterIndex, method, restMethodMetadata); + } + + protected abstract void process(String annotationValue, String defaultValue, AnnotationMirror annotation, VariableElement parameter, int parameterIndex, + ExecutableElement method, RestMethodMetadata restMethodMetadata); + + protected String getAnnotationValue(AnnotationMirror annotation, VariableElement parameter, int parameterIndex) { + return getValue(annotation); + } + + protected String getDefaultValue(AnnotationMirror annotation, VariableElement parameter, int parameterIndex) { + return buildDefaultValue(parameterIndex); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/AbstractServiceRestMetadataResolver.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/AbstractServiceRestMetadataResolver.java new file mode 100644 index 0000000000..d2e400af52 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/AbstractServiceRestMetadataResolver.java @@ -0,0 +1,291 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.rest; + +import org.apache.dubbo.metadata.annotation.processing.util.ExecutableElementComparator; +import org.apache.dubbo.metadata.definition.model.MethodDefinition; +import org.apache.dubbo.metadata.rest.RequestMetadata; +import org.apache.dubbo.metadata.rest.RestMethodMetadata; +import org.apache.dubbo.metadata.rest.ServiceRestMetadata; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.util.Elements; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +import static java.lang.ThreadLocal.withInitial; +import static java.util.Collections.emptyList; +import static java.util.Collections.sort; +import static java.util.Optional.empty; +import static java.util.Optional.of; +import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader; +import static org.apache.dubbo.metadata.annotation.processing.builder.MethodDefinitionBuilder.build; +import static org.apache.dubbo.metadata.annotation.processing.util.LoggerUtils.info; +import static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.getOverrideMethod; +import static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.getPublicNonStaticMethods; +import static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.getAnnotation; +import static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.getGroup; +import static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.getVersion; +import static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.resolveServiceInterfaceName; + +/** + * Abstract {@link ServiceRestMetadataResolver} implementation + * + * @since 2.7.6 + */ +public abstract class AbstractServiceRestMetadataResolver implements ServiceRestMetadataResolver { + + private final static ThreadLocal> threadLocalCache = withInitial(HashMap::new); + + private final static Map> parameterProcessorsMap = loadAnnotatedMethodParameterProcessors(); + + private final String processorName = getClass().getSimpleName(); + + @Override + public final ServiceRestMetadata resolve(ProcessingEnvironment processingEnv, + TypeElement serviceType, + Set annotations) { + + info("%s is processing the service type[%s] with annotations[%s]", processorName, serviceType, + annotations.stream().map(t -> "@" + t.toString()).collect(Collectors.joining(","))); + + ServiceRestMetadata serviceRestMetadata = new ServiceRestMetadata(); + + Elements elements = processingEnv.getElementUtils(); + + try { + AnnotationMirror serviceAnnotation = getAnnotation(serviceType); + String serviceInterfaceName = resolveServiceInterfaceName(serviceType, serviceAnnotation); + serviceRestMetadata.setServiceInterface(serviceInterfaceName); + serviceRestMetadata.setGroup(getGroup(serviceAnnotation)); + serviceRestMetadata.setVersion(getVersion(serviceAnnotation)); + + TypeElement serviceInterfaceType = elements.getTypeElement(serviceInterfaceName); + + List serviceMethods = new LinkedList<>(getPublicNonStaticMethods(serviceInterfaceType, Object.class)); + + // Sorts + sort(serviceMethods, ExecutableElementComparator.INSTANCE); + + serviceMethods.forEach(serviceMethod -> { + resolveRestMethodMetadata(processingEnv, serviceType, serviceInterfaceType, serviceMethod) + .ifPresent(serviceRestMetadata.getMeta()::add); + }); + + } finally { + clearCache(); + } + + info("The %s's process result : %s", processorName, serviceRestMetadata); + + return serviceRestMetadata; + } + + protected Optional resolveRestMethodMetadata(ProcessingEnvironment processingEnv, + TypeElement serviceType, + TypeElement serviceInterfaceType, + ExecutableElement serviceMethod) { + + ExecutableElement restCapableMethod = findRestCapableMethod(processingEnv, serviceType, serviceInterfaceType, serviceMethod); + + if (restCapableMethod == null) { // if can't be found + return empty(); + } + + String requestPath = resolveRequestPath(processingEnv, serviceType, restCapableMethod); // requestPath is required + + if (requestPath == null) { + return empty(); + } + + String requestMethod = resolveRequestMethod(processingEnv, serviceType, restCapableMethod); // requestMethod is required + + if (requestMethod == null) { + return empty(); + } + + RestMethodMetadata metadata = new RestMethodMetadata(); + + MethodDefinition methodDefinition = resolveMethodDefinition(processingEnv, serviceType, restCapableMethod); + // Set MethodDefinition + metadata.setMethod(methodDefinition); + + // process the annotated method parameters + processAnnotatedMethodParameters(restCapableMethod, serviceType, metadata); + + // process produces + Set produces = new LinkedHashSet<>(); + processProduces(processingEnv, serviceType, restCapableMethod, produces); + + // process consumes + Set consumes = new LinkedHashSet<>(); + processConsumes(processingEnv, serviceType, restCapableMethod, consumes); + + // Initialize RequestMetadata + RequestMetadata request = metadata.getRequest(); + request.setPath(requestPath); + request.setMethod(requestMethod); + request.setProduces(produces); + request.setConsumes(consumes); + + // Post-Process + postProcessRestMethodMetadata(processingEnv, serviceType, serviceMethod, metadata); + + return of(metadata); + } + + /** + * Find the method with the capable for REST from the specified service method and its override method + * + * @param processingEnv {@link ProcessingEnvironment} + * @param serviceType + * @param serviceInterfaceType + * @param serviceMethod + * @return null if can't be found + */ + private ExecutableElement findRestCapableMethod(ProcessingEnvironment processingEnv, + TypeElement serviceType, + TypeElement serviceInterfaceType, + ExecutableElement serviceMethod) { + // try to judge the override first + ExecutableElement overrideMethod = getOverrideMethod(processingEnv, serviceType, serviceMethod); + if (supports(processingEnv, serviceType, serviceInterfaceType, overrideMethod)) { + return overrideMethod; + } + // or, try to judge the declared method + return supports(processingEnv, serviceType, serviceInterfaceType, serviceMethod) ? serviceMethod : null; + } + + /** + * Does the specified method support REST or not ? + * + * @param processingEnv {@link ProcessingEnvironment} + * @param method the method may be declared on the interface or class + * @return if supports, return true, or false + */ + protected abstract boolean supports(ProcessingEnvironment processingEnv, + TypeElement serviceType, + TypeElement serviceInterfaceType, + ExecutableElement method); + + + /** + * Post-Process for {@link RestMethodMetadata}, sub-type could override this method for further works + * + * @param processingEnv {@link ProcessingEnvironment} + * @param serviceType The type that @Service annotated + * @param method The public method of serviceType + * @param metadata {@link RestMethodMetadata} maybe updated + */ + protected void postProcessRestMethodMetadata(ProcessingEnvironment processingEnv, TypeElement serviceType, + ExecutableElement method, RestMethodMetadata metadata) { + } + + protected abstract String resolveRequestPath(ProcessingEnvironment processingEnv, TypeElement serviceType, + ExecutableElement method); + + protected abstract String resolveRequestMethod(ProcessingEnvironment processingEnv, TypeElement serviceType, + ExecutableElement method); + + protected MethodDefinition resolveMethodDefinition(ProcessingEnvironment processingEnv, TypeElement serviceType, + ExecutableElement method) { + return build(processingEnv, method); + } + + protected void processAnnotatedMethodParameters(ExecutableElement method, TypeElement type, + RestMethodMetadata metadata) { + List methodParameters = method.getParameters(); + int size = methodParameters.size(); + for (int i = 0; i < size; i++) { + VariableElement parameter = methodParameters.get(i); + // Add indexed parameter name + metadata.addIndexToName(i, parameter.getSimpleName().toString()); + processAnnotatedMethodParameter(parameter, i, method, type, metadata); + } + } + + protected void processAnnotatedMethodParameter(VariableElement parameter, int parameterIndex, + ExecutableElement method, TypeElement serviceType, + RestMethodMetadata metadata) { + + parameter.getAnnotationMirrors().forEach(annotation -> { + String annotationType = annotation.getAnnotationType().toString(); + parameterProcessorsMap.getOrDefault(annotationType, emptyList()) + .forEach(parameterProcessor -> { + parameterProcessor.process(annotation, parameter, parameterIndex, method, metadata); + }); + }); + } + + protected abstract void processProduces(ProcessingEnvironment processingEnv, TypeElement serviceType, + ExecutableElement method, Set produces); + + protected abstract void processConsumes(ProcessingEnvironment processingEnv, TypeElement serviceType, + ExecutableElement method, Set consumes); + + protected static final void put(String name, Object value) { + Map cache = getCache(); + cache.put(name, value); + } + + protected static final T get(String name) throws ClassCastException { + Map cache = getCache(); + return (T) cache.get(name); + } + + protected static final V computeIfAbsent(String name, Function mappingFunction) { + return (V) getCache().computeIfAbsent(name, mappingFunction); + } + + private static Map> loadAnnotatedMethodParameterProcessors() { + Map> parameterProcessorsMap = new LinkedHashMap<>(); + +// load(AnnotatedMethodParameterProcessor.class, AnnotatedMethodParameterProcessor.class.getClassLoader()) + + getExtensionLoader(AnnotatedMethodParameterProcessor.class) + .getSupportedExtensionInstances() + .forEach(processor -> { + List processors = + parameterProcessorsMap.computeIfAbsent(processor.getAnnotationType(), k -> new LinkedList<>()); + processors.add(processor); + }); + + return parameterProcessorsMap; + } + + private static Map getCache() { + return threadLocalCache.get(); + } + + private static void clearCache() { + Map cache = getCache(); + cache.clear(); + threadLocalCache.remove(); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/AnnotatedMethodParameterProcessor.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/AnnotatedMethodParameterProcessor.java new file mode 100644 index 0000000000..85f0f8a87d --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/AnnotatedMethodParameterProcessor.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.rest; + +import org.apache.dubbo.common.extension.SPI; +import org.apache.dubbo.common.lang.Prioritized; +import org.apache.dubbo.metadata.rest.RestMethodMetadata; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.VariableElement; + +/** + * The interface to process the parameter of method that was annotated + * + * @since 2.7.6 + */ +@SPI +public interface AnnotatedMethodParameterProcessor extends Prioritized { + + /** + * The string presenting the annotation type + * + * @return non-null + */ + String getAnnotationType(); + + /** + * Process the specified method {@link VariableElement parameter} + * + * @param annotation {@link AnnotationMirror the target annotation} whose type is {@link #getAnnotationType()} + * @param parameter {@link VariableElement method parameter} + * @param parameterIndex the index of parameter in the method + * @param method {@link ExecutableElement method that parameter belongs to} + * @param restMethodMetadata {@link RestMethodMetadata the metadata is used to update} + */ + void process(AnnotationMirror annotation, VariableElement parameter, int parameterIndex, ExecutableElement method, + RestMethodMetadata restMethodMetadata); + + + /** + * Build the default value + * + * @param parameterIndex the index of parameter + * @return the placeholder + */ + static String buildDefaultValue(int parameterIndex) { + return "{" + parameterIndex + "}"; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/DefaultServiceRestMetadataResolver.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/DefaultServiceRestMetadataResolver.java new file mode 100644 index 0000000000..6e50f0be96 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/DefaultServiceRestMetadataResolver.java @@ -0,0 +1,186 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.rest; + +import org.apache.dubbo.common.convert.Converter; +import org.apache.dubbo.metadata.annotation.processing.rest.jaxrs.JAXRSServiceRestMetadataResolver; +import org.apache.dubbo.metadata.annotation.processing.rest.springmvc.SpringMvcServiceRestMetadataResolver; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.TypeMirror; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +import static java.lang.String.valueOf; +import static java.util.Arrays.asList; +import static org.apache.dubbo.common.convert.Converter.getConverter; +import static org.apache.dubbo.common.utils.ClassUtils.forName; +import static org.apache.dubbo.common.utils.StringUtils.SLASH_CHAR; +import static org.apache.dubbo.metadata.annotation.processing.util.LoggerUtils.warn; +import static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.getAnnotation; +import static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.resolveServiceInterfaceName; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.findInterface; + +/** + * The default implementation of {@link ServiceRestMetadataResolver} + * + * @since 2.7.6 + */ +public class DefaultServiceRestMetadataResolver extends AbstractServiceRestMetadataResolver { + + private static final char PACKAGE_SEPARATOR = '.'; + + private static final char PATH_SEPARATOR = SLASH_CHAR; + + private static final String HTTP_REQUEST_METHOD = "POST"; + + private static final List MEDIA_TYPES = asList( + "application/json;", + "application/*+json", + "application/xml;charset=UTF-8", + "text/xml;charset=UTF-8", + "application/*+xml;charset=UTF-8" + ); + + private final Set hasComplexParameterTypeMethods = new LinkedHashSet<>(); + + @Override + public boolean supports(ProcessingEnvironment processingEnvironment, TypeElement serviceType) { + return !JAXRSServiceRestMetadataResolver.supports(serviceType) && + !SpringMvcServiceRestMetadataResolver.supports(serviceType); + } + + @Override + protected boolean supports(ProcessingEnvironment processingEnv, TypeElement serviceType, + TypeElement serviceInterfaceType, ExecutableElement method) { + // TODO add some criterion + return true; + } + + @Override + protected String resolveRequestPath(ProcessingEnvironment processingEnv, TypeElement serviceType, + ExecutableElement method) { + + AnnotationMirror serviceAnnotation = getAnnotation(serviceType); + + String serviceInterfaceName = resolveServiceInterfaceName(serviceType, serviceAnnotation); + + TypeMirror serviceInterface = findInterface(serviceType.asType(), serviceInterfaceName); + + StringBuilder requestPathBuilder = new StringBuilder(); + // the name of service type as the root path + String rootPath = buildRootPath(serviceInterface); + // the method name as the sub path + String subPath = buildSubPath(method); + + requestPathBuilder.append(rootPath).append(subPath); + // the methods' parameters as the the path variables + List parameters = method.getParameters(); + + for (int i = 0; i < parameters.size(); i++) { + VariableElement parameter = parameters.get(i); + TypeMirror parameterType = parameter.asType(); + if (isComplexType(parameterType)) { + if (addComplexParameterType(method)) { + continue; + } else { + // The count of complex types must be only one, or return immediately + warn("The method[%s] contains more than one complex parameter type, " + + "thus it will not be chosen as the REST service", method.toString()); + } + } + String parameterName = parameter.getSimpleName().toString(); + // If "-parameters" option is enabled, take the parameter name as the path variable name, + // or use the index of parameter + String pathVariableName = isEnabledParametersCompilerOption(parameterName) ? parameterName : valueOf(i); + requestPathBuilder.append(PATH_SEPARATOR).append("{").append(pathVariableName).append("}"); + } + + return requestPathBuilder.toString(); + } + + private String buildRootPath(TypeMirror serviceInterface) { + return PATH_SEPARATOR + serviceInterface.toString().replace(PACKAGE_SEPARATOR, PATH_SEPARATOR); + } + + private String buildSubPath(ExecutableElement method) { + return PATH_SEPARATOR + method.getSimpleName().toString(); + } + + private boolean isEnabledParametersCompilerOption(String parameterName) { + return !parameterName.startsWith("arg"); + } + + private boolean isComplexType(TypeMirror parameterType) { + return !supportsPathVariableType(parameterType); + } + + /** + * Supports the type of parameter or not, based by {@link Converter}'s conversion feature + * + * @param parameterType the type of parameter + * @return if supports, this method will return true, or false + */ + private boolean supportsPathVariableType(TypeMirror parameterType) { + String className = parameterType.toString(); + ClassLoader classLoader = getClass().getClassLoader(); + boolean supported; + try { + Class targetType = forName(className, classLoader); + supported = getConverter(String.class, targetType) != null; + } catch (ClassNotFoundException e) { + supported = false; + } + return supported; + } + + @Override + protected String resolveRequestMethod(ProcessingEnvironment processingEnv, TypeElement serviceType, + ExecutableElement method) { + return HTTP_REQUEST_METHOD; + } + + @Override + protected void processProduces(ProcessingEnvironment processingEnv, TypeElement serviceType, + ExecutableElement method, Set produces) { + TypeMirror returnType = method.getReturnType(); + if (isComplexType(returnType)) { + produces.addAll(MEDIA_TYPES); + } + } + + @Override + protected void processConsumes(ProcessingEnvironment processingEnv, TypeElement serviceType, + ExecutableElement method, Set consumes) { + if (hasComplexParameterType(method)) { + consumes.addAll(MEDIA_TYPES); + } + } + + private boolean addComplexParameterType(ExecutableElement method) { + return hasComplexParameterTypeMethods.add(method); + } + + private boolean hasComplexParameterType(ExecutableElement method) { + return hasComplexParameterTypeMethods.remove(method); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/ServiceRestMetadataAnnotationProcessor.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/ServiceRestMetadataAnnotationProcessor.java new file mode 100644 index 0000000000..739c813dfb --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/ServiceRestMetadataAnnotationProcessor.java @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.rest; + +import org.apache.dubbo.metadata.annotation.processing.AbstractServiceAnnotationProcessor; +import org.apache.dubbo.metadata.rest.ServiceRestMetadata; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.annotation.processing.Processor; +import javax.annotation.processing.RoundEnvironment; +import javax.lang.model.element.TypeElement; +import java.io.IOException; +import java.util.LinkedHashSet; +import java.util.Set; + +import static javax.lang.model.util.ElementFilter.typesIn; +import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader; +import static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.isServiceAnnotationPresent; + +/** + * The {@link Processor} class to generate the metadata of REST from the classes that are annotated by Dubbo's + * + * @Service + * @see Processor + * @since 2.7.6 + */ +public class ServiceRestMetadataAnnotationProcessor extends AbstractServiceAnnotationProcessor { + + private Set metadataProcessors; + + private ServiceRestMetadataStorage serviceRestMetadataWriter; + + private Set serviceRestMetadata = new LinkedHashSet<>(); + + @Override + public synchronized void init(ProcessingEnvironment processingEnv) { + super.init(processingEnv); + this.metadataProcessors = getExtensionLoader(ServiceRestMetadataResolver.class).getSupportedExtensionInstances(); + this.serviceRestMetadataWriter = new ServiceRestMetadataStorage(processingEnv); + } + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + + typesIn(roundEnv.getRootElements()).forEach(serviceType -> process(processingEnv, serviceType, annotations)); + + if (roundEnv.processingOver()) { + try { + serviceRestMetadataWriter.append(serviceRestMetadata); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + return false; + } + + private void process(ProcessingEnvironment processingEnv, TypeElement serviceType, + Set annotations) { + metadataProcessors + .stream() + .filter(processor -> supports(processor, processingEnv, serviceType)) + .map(processor -> processor.resolve(processingEnv, serviceType, annotations)) + .forEach(serviceRestMetadata::add); + } + + private boolean supports(ServiceRestMetadataResolver processor, ProcessingEnvironment processingEnv, + TypeElement serviceType) { + // @Service must be present in service type + return isServiceAnnotationPresent(serviceType) && processor.supports(processingEnv, serviceType); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/ServiceRestMetadataResolver.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/ServiceRestMetadataResolver.java new file mode 100644 index 0000000000..9e431f1f16 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/ServiceRestMetadataResolver.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.rest; + +import org.apache.dubbo.common.extension.SPI; +import org.apache.dubbo.common.lang.Prioritized; +import org.apache.dubbo.metadata.rest.ServiceRestMetadata; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.TypeElement; +import java.util.Set; + +/** + * The class to resolve {@link ServiceRestMetadata} based on Annotation Processor Tool + * + * @since 2.7.6 + */ +@SPI("default") +public interface ServiceRestMetadataResolver extends Prioritized { + + /** + * Supports or not to the specified service type + * + * @param processingEnvironment {@link ProcessingEnvironment} + * @param serviceType Dubbo service type or interface + * @return if supports, return true, or false + */ + boolean supports(ProcessingEnvironment processingEnvironment, TypeElement serviceType); + + /** + * Resolve the {@link ServiceRestMetadata} from given service type + * + * @param processingEnvironment {@link ProcessingEnvironment} + * @param serviceType Dubbo service type or interface + * @param annotations + * @return non-null + */ + ServiceRestMetadata resolve(ProcessingEnvironment processingEnvironment, + TypeElement serviceType, + Set annotations); +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/ServiceRestMetadataStorage.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/ServiceRestMetadataStorage.java new file mode 100644 index 0000000000..c3809944fc --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/ServiceRestMetadataStorage.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.rest; + +import org.apache.dubbo.metadata.annotation.processing.ClassPathMetadataStorage; +import org.apache.dubbo.metadata.rest.ServiceRestMetadata; + +import com.google.gson.Gson; + +import javax.annotation.processing.ProcessingEnvironment; +import java.io.IOException; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +import static com.google.gson.reflect.TypeToken.getParameterized; +import static org.apache.dubbo.metadata.rest.RestMetadataConstants.SERVICE_REST_METADATA_RESOURCE_PATH; + +/** + * The storage for {@link ServiceRestMetadata} + */ +public class ServiceRestMetadataStorage { + + private final ClassPathMetadataStorage storage; + + public ServiceRestMetadataStorage(ProcessingEnvironment processingEnv) { + this.storage = new ClassPathMetadataStorage(processingEnv); + } + + public void append(Set serviceRestMetadata) throws IOException { + Set allServiceRestMetadata = new LinkedHashSet<>(); + storage.read(SERVICE_REST_METADATA_RESOURCE_PATH, reader -> { + Gson gson = new Gson(); + return (List) gson.fromJson(reader, getParameterized(List.class, ServiceRestMetadata.class).getType()); + }).ifPresent(existedMetadata -> { + // Add all existed ServiceRestMetadata + allServiceRestMetadata.addAll(existedMetadata); + }); + // Add all new ServiceRestMetadata + allServiceRestMetadata.addAll(serviceRestMetadata); + write(serviceRestMetadata); + } + + public void write(Set serviceRestMetadata) throws IOException { + if (serviceRestMetadata.isEmpty()) { + return; + } + storage.write(() -> new Gson().toJson(serviceRestMetadata), SERVICE_REST_METADATA_RESOURCE_PATH); + } + +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/jaxrs/DefaultValueParameterProcessor.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/jaxrs/DefaultValueParameterProcessor.java new file mode 100644 index 0000000000..856823570a --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/jaxrs/DefaultValueParameterProcessor.java @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.rest.jaxrs; + +import org.apache.dubbo.metadata.annotation.processing.rest.AbstractAnnotatedMethodParameterProcessor; +import org.apache.dubbo.metadata.annotation.processing.rest.AnnotatedMethodParameterProcessor; +import org.apache.dubbo.metadata.rest.RequestMetadata; +import org.apache.dubbo.metadata.rest.RestMethodMetadata; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.VariableElement; +import java.util.List; +import java.util.Map; + +import static org.apache.dubbo.metadata.rest.RestMetadataConstants.JAX_RS.DEFAULT_VALUE_ANNOTATION_CLASS_NAME; + + +/** + * The {@link AnnotatedMethodParameterProcessor} implementation for JAX-RS's @DefaultValue + * * + * + * @since 2.7.6 + */ +public class DefaultValueParameterProcessor extends AbstractAnnotatedMethodParameterProcessor { + + @Override + public String getAnnotationType() { + return DEFAULT_VALUE_ANNOTATION_CLASS_NAME; + } + + @Override + protected void process(String annotationValue, String defaultValue, AnnotationMirror annotation, VariableElement parameter, int parameterIndex, ExecutableElement method, RestMethodMetadata restMethodMetadata) { + RequestMetadata requestMetadata = restMethodMetadata.getRequest(); + + // process the request parameters + setDefaultValue(requestMetadata.getParams(), defaultValue, annotationValue); + // process the request headers + setDefaultValue(requestMetadata.getHeaders(), defaultValue, annotationValue); + + } + + private void setDefaultValue(Map> source, String placeholderValue, String defaultValue) { + OUTTER: + for (Map.Entry> entry : source.entrySet()) { + List values = entry.getValue(); + int size = values.size(); + for (int i = 0; i < size; i++) { + String value = values.get(i); + if (placeholderValue.equals(value)) { + values.set(i, defaultValue); + break OUTTER; + } + } + } + } + + public int getPriority() { + return MIN_PRIORITY; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/jaxrs/FormParamParameterProcessor.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/jaxrs/FormParamParameterProcessor.java new file mode 100644 index 0000000000..01e57db7a0 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/jaxrs/FormParamParameterProcessor.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.rest.jaxrs; + +import org.apache.dubbo.metadata.annotation.processing.rest.AnnotatedMethodParameterProcessor; + +import static org.apache.dubbo.metadata.rest.RestMetadataConstants.JAX_RS.FORM_PARAM_ANNOTATION_CLASS_NAME; + +/** + * The {@link AnnotatedMethodParameterProcessor} implementation for JAX-RS's @FormParam + * + * @since 2.7.6 + */ +public class FormParamParameterProcessor extends ParamAnnotationParameterProcessor { + + @Override + public String getAnnotationType() { + return FORM_PARAM_ANNOTATION_CLASS_NAME; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/jaxrs/HeaderParamParameterProcessor.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/jaxrs/HeaderParamParameterProcessor.java new file mode 100644 index 0000000000..f4ccddf2d6 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/jaxrs/HeaderParamParameterProcessor.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.rest.jaxrs; + +import org.apache.dubbo.metadata.annotation.processing.rest.AbstractAnnotatedMethodParameterProcessor; +import org.apache.dubbo.metadata.annotation.processing.rest.AnnotatedMethodParameterProcessor; +import org.apache.dubbo.metadata.rest.RequestMetadata; +import org.apache.dubbo.metadata.rest.RestMethodMetadata; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.VariableElement; + +import static org.apache.dubbo.metadata.annotation.processing.rest.AnnotatedMethodParameterProcessor.buildDefaultValue; +import static org.apache.dubbo.metadata.rest.RestMetadataConstants.JAX_RS.HEADER_PARAM_ANNOTATION_CLASS_NAME; + +/** + * The {@link AnnotatedMethodParameterProcessor} implementation for JAX-RS's @HeaderParam + * + * @since 2.7.6 + */ +public class HeaderParamParameterProcessor extends AbstractAnnotatedMethodParameterProcessor { + + @Override + public String getAnnotationType() { + return HEADER_PARAM_ANNOTATION_CLASS_NAME; + } + + @Override + protected void process(String headerName, String defaultValue, AnnotationMirror annotation, + VariableElement parameter, int parameterIndex, + ExecutableElement method, RestMethodMetadata restMethodMetadata) { + RequestMetadata requestMetadata = restMethodMetadata.getRequest(); + // Add the placeholder as header value + requestMetadata.addHeader(headerName, buildDefaultValue(parameterIndex)); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/jaxrs/JAXRSServiceRestMetadataResolver.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/jaxrs/JAXRSServiceRestMetadataResolver.java new file mode 100644 index 0000000000..dd30acc962 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/jaxrs/JAXRSServiceRestMetadataResolver.java @@ -0,0 +1,108 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.rest.jaxrs; + +import org.apache.dubbo.metadata.annotation.processing.rest.AbstractServiceRestMetadataResolver; +import org.apache.dubbo.metadata.annotation.processing.rest.ServiceRestMetadataResolver; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.AnnotatedConstruct; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import java.util.Set; +import java.util.stream.Stream; + +import static org.apache.dubbo.common.utils.HttpUtils.buildPath; +import static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.findAnnotation; +import static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.findMetaAnnotation; +import static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.getAnnotation; +import static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.getValue; +import static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.isAnnotationPresent; +import static org.apache.dubbo.metadata.rest.RestMetadataConstants.JAX_RS.CONSUMES_ANNOTATION_CLASS_NAME; +import static org.apache.dubbo.metadata.rest.RestMetadataConstants.JAX_RS.HTTP_METHOD_ANNOTATION_CLASS_NAME; +import static org.apache.dubbo.metadata.rest.RestMetadataConstants.JAX_RS.PATH_ANNOTATION_CLASS_NAME; +import static org.apache.dubbo.metadata.rest.RestMetadataConstants.JAX_RS.PRODUCES_ANNOTATION_CLASS_NAME; + +/** + * {@link ServiceRestMetadataResolver} implementation for JAX-RS 2 and 1 + * + * @since 2.7.6 + */ +public class JAXRSServiceRestMetadataResolver extends AbstractServiceRestMetadataResolver { + + @Override + public boolean supports(ProcessingEnvironment processingEnvironment, TypeElement serviceType) { + return supports(serviceType); + } + + public static boolean supports(TypeElement serviceType) { + return isAnnotationPresent(serviceType, PATH_ANNOTATION_CLASS_NAME); + } + + @Override + protected boolean supports(ProcessingEnvironment processingEnv, TypeElement serviceType, + TypeElement serviceInterfaceType, ExecutableElement method) { + return isAnnotationPresent(method, PATH_ANNOTATION_CLASS_NAME) || + isAnnotationPresent(method, HTTP_METHOD_ANNOTATION_CLASS_NAME); + } + + @Override + protected String resolveRequestPath(ProcessingEnvironment processingEnv, TypeElement serviceType, ExecutableElement method) { + String pathFromType = getPathValue(processingEnv, serviceType); + String pathFromMethod = getPathValue(method); + return buildPath(pathFromType, pathFromMethod); + } + + @Override + protected String resolveRequestMethod(ProcessingEnvironment processingEnv, TypeElement serviceType, ExecutableElement method) { + AnnotationMirror annotation = findMetaAnnotation(method, HTTP_METHOD_ANNOTATION_CLASS_NAME); + return getValue(annotation); + } + + @Override + protected void processProduces(ProcessingEnvironment processingEnv, TypeElement serviceType, + ExecutableElement method, Set produces) { + addAnnotationValues(method, PRODUCES_ANNOTATION_CLASS_NAME, produces); + } + + @Override + protected void processConsumes(ProcessingEnvironment processingEnv, TypeElement serviceType, + ExecutableElement method, Set consumes) { + addAnnotationValues(method, CONSUMES_ANNOTATION_CLASS_NAME, consumes); + } + + + private void addAnnotationValues(Element element, String annotationAttributeName, Set result) { + AnnotationMirror annotation = findAnnotation(element, annotationAttributeName); + String[] value = getValue(annotation); + if (value != null) { + Stream.of(value).forEach(result::add); + } + } + + private String getPathValue(ProcessingEnvironment processingEnv, TypeElement serviceType) { + AnnotationMirror annotation = findAnnotation(serviceType, PATH_ANNOTATION_CLASS_NAME); + return getValue(annotation); + } + + private String getPathValue(AnnotatedConstruct annotatedConstruct) { + AnnotationMirror annotation = getAnnotation(annotatedConstruct, PATH_ANNOTATION_CLASS_NAME); + return getValue(annotation); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/jaxrs/MatrixParamParameterProcessor.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/jaxrs/MatrixParamParameterProcessor.java new file mode 100644 index 0000000000..cf1d96d9aa --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/jaxrs/MatrixParamParameterProcessor.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.rest.jaxrs; + +import org.apache.dubbo.metadata.annotation.processing.rest.AnnotatedMethodParameterProcessor; + +import static org.apache.dubbo.metadata.rest.RestMetadataConstants.JAX_RS.MATRIX_PARAM_ANNOTATION_CLASS_NAME; + +/** + * The {@link AnnotatedMethodParameterProcessor} implementation for JAX-RS's @MatrixParam + * + * @since 2.7.6 + */ +public class MatrixParamParameterProcessor extends ParamAnnotationParameterProcessor { + + @Override + public String getAnnotationType() { + return MATRIX_PARAM_ANNOTATION_CLASS_NAME; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/jaxrs/ParamAnnotationParameterProcessor.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/jaxrs/ParamAnnotationParameterProcessor.java new file mode 100644 index 0000000000..d615cdcb33 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/jaxrs/ParamAnnotationParameterProcessor.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.rest.jaxrs; + +import org.apache.dubbo.metadata.annotation.processing.rest.AbstractAnnotatedMethodParameterProcessor; +import org.apache.dubbo.metadata.annotation.processing.rest.AnnotatedMethodParameterProcessor; +import org.apache.dubbo.metadata.rest.RequestMetadata; +import org.apache.dubbo.metadata.rest.RestMethodMetadata; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.VariableElement; + +/** + * The abstract {@link AnnotatedMethodParameterProcessor} implementation for JAX-RS's @*Param + */ +public abstract class ParamAnnotationParameterProcessor extends AbstractAnnotatedMethodParameterProcessor { + + protected void process(String name, String defaultValue, AnnotationMirror annotation, VariableElement parameter, int parameterIndex, + ExecutableElement method, RestMethodMetadata restMethodMetadata) { + RequestMetadata requestMetadata = restMethodMetadata.getRequest(); + requestMetadata.addParam(name, defaultValue); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/jaxrs/QueryParamParameterProcessor.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/jaxrs/QueryParamParameterProcessor.java new file mode 100644 index 0000000000..71ba378f9f --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/jaxrs/QueryParamParameterProcessor.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.rest.jaxrs; + +import org.apache.dubbo.metadata.annotation.processing.rest.AnnotatedMethodParameterProcessor; + +import static org.apache.dubbo.metadata.rest.RestMetadataConstants.JAX_RS.QUERY_PARAM_ANNOTATION_CLASS_NAME; + +/** + * The {@link AnnotatedMethodParameterProcessor} implementation for JAX-RS's @QueryParam + * + * @since 2.7.6 + */ +public class QueryParamParameterProcessor extends ParamAnnotationParameterProcessor { + + @Override + public String getAnnotationType() { + return QUERY_PARAM_ANNOTATION_CLASS_NAME; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/springmvc/AbstractRequestAnnotationParameterProcessor.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/springmvc/AbstractRequestAnnotationParameterProcessor.java new file mode 100644 index 0000000000..1fa5285ef2 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/springmvc/AbstractRequestAnnotationParameterProcessor.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.rest.springmvc; + +import org.apache.dubbo.metadata.annotation.processing.rest.AbstractAnnotatedMethodParameterProcessor; +import org.apache.dubbo.metadata.annotation.processing.rest.AnnotatedMethodParameterProcessor; +import org.apache.dubbo.metadata.rest.RestMethodMetadata; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.VariableElement; + +import static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.getAttribute; + +/** + * The abstract {@link AnnotatedMethodParameterProcessor} implementation for Spring Web MVC's @Request* + */ +public abstract class AbstractRequestAnnotationParameterProcessor extends AbstractAnnotatedMethodParameterProcessor { + + + protected abstract void process(String name, String defaultValue, AnnotationMirror annotation, + VariableElement parameter, int parameterIndex, + ExecutableElement method, + RestMethodMetadata restMethodMetadata); + + @Override + protected String getAnnotationValue(AnnotationMirror annotation, VariableElement parameter, int parameterIndex) { + // try to get "value" attribute first + String name = super.getAnnotationValue(annotation, parameter, parameterIndex); + + // try to get "name" attribute if required + if (isEmpty(name)) { + name = getAttribute(annotation, "name"); + } + + // finally , try to the name of parameter + if (isEmpty(name)) { + name = parameter.getSimpleName().toString(); + } + + return name; + } + + protected String getDefaultValue(AnnotationMirror annotation, VariableElement parameter, int parameterIndex) { + String defaultValue = getAttribute(annotation, "defaultValue"); + if (isEmpty(defaultValue)) { + defaultValue = super.getDefaultValue(annotation, parameter, parameterIndex); + } + return defaultValue; + } + + protected boolean isEmpty(String str) { + return str == null || str.isEmpty(); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/springmvc/RequestHeaderParameterProcessor.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/springmvc/RequestHeaderParameterProcessor.java new file mode 100644 index 0000000000..c28b88083e --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/springmvc/RequestHeaderParameterProcessor.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.rest.springmvc; + +import org.apache.dubbo.metadata.annotation.processing.rest.AnnotatedMethodParameterProcessor; +import org.apache.dubbo.metadata.rest.RestMethodMetadata; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.VariableElement; + +import static org.apache.dubbo.metadata.rest.RestMetadataConstants.SPRING_MVC.REQUEST_HEADER_ANNOTATION_CLASS_NAME; + +/** + * The {@link AnnotatedMethodParameterProcessor} implementation for Spring Web MVC's @RequestHeader + */ +public class RequestHeaderParameterProcessor extends AbstractRequestAnnotationParameterProcessor { + + @Override + public String getAnnotationType() { + return REQUEST_HEADER_ANNOTATION_CLASS_NAME; + } + + @Override + protected void process(String name, String defaultValue, AnnotationMirror annotation, VariableElement parameter, int parameterIndex, ExecutableElement method, RestMethodMetadata restMethodMetadata) { + restMethodMetadata.getRequest().addHeader(name, defaultValue); + } + +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/springmvc/RequestParamParameterProcessor.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/springmvc/RequestParamParameterProcessor.java new file mode 100644 index 0000000000..e589c0d7db --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/springmvc/RequestParamParameterProcessor.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.rest.springmvc; + +import org.apache.dubbo.metadata.annotation.processing.rest.AnnotatedMethodParameterProcessor; +import org.apache.dubbo.metadata.rest.RestMethodMetadata; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.VariableElement; + +import static org.apache.dubbo.metadata.rest.RestMetadataConstants.SPRING_MVC.REQUEST_PARAM_ANNOTATION_CLASS_NAME; + +/** + * The {@link AnnotatedMethodParameterProcessor} implementation for Spring Web MVC's @RequestParam + */ +public class RequestParamParameterProcessor extends AbstractRequestAnnotationParameterProcessor { + + @Override + public String getAnnotationType() { + return REQUEST_PARAM_ANNOTATION_CLASS_NAME; + } + + @Override + protected void process(String name, String defaultValue, AnnotationMirror annotation, + VariableElement parameter, int parameterIndex, + ExecutableElement method, RestMethodMetadata restMethodMetadata) { + restMethodMetadata.getRequest().addParam(name, defaultValue); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/springmvc/SpringMvcServiceRestMetadataResolver.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/springmvc/SpringMvcServiceRestMetadataResolver.java new file mode 100644 index 0000000000..2a9eeb0cf0 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/springmvc/SpringMvcServiceRestMetadataResolver.java @@ -0,0 +1,165 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.rest.springmvc; + +import org.apache.dubbo.metadata.annotation.processing.rest.AbstractServiceRestMetadataResolver; +import org.apache.dubbo.metadata.annotation.processing.rest.ServiceRestMetadataResolver; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.DeclaredType; +import java.lang.reflect.Array; +import java.util.Set; + +import static java.lang.String.valueOf; +import static java.lang.reflect.Array.getLength; +import static java.util.stream.Stream.of; +import static org.apache.dubbo.common.function.Streams.filterFirst; +import static org.apache.dubbo.common.utils.ArrayUtils.isEmpty; +import static org.apache.dubbo.common.utils.ArrayUtils.isNotEmpty; +import static org.apache.dubbo.common.utils.HttpUtils.buildPath; +import static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.findAnnotation; +import static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.findMetaAnnotation; +import static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.getAllAnnotations; +import static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.getAttribute; +import static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.isAnnotationPresent; +import static org.apache.dubbo.metadata.rest.RestMetadataConstants.SPRING_MVC.CONTROLLER_ANNOTATION_CLASS_NAME; +import static org.apache.dubbo.metadata.rest.RestMetadataConstants.SPRING_MVC.REQUEST_MAPPING_ANNOTATION_CLASS_NAME; + +/** + * {@link ServiceRestMetadataResolver} + * + * @since 2.7.6 + */ +public class SpringMvcServiceRestMetadataResolver extends AbstractServiceRestMetadataResolver { + + private static final int FIRST_ELEMENT_INDEX = 0; + + @Override + public boolean supports(ProcessingEnvironment processingEnvironment, TypeElement serviceType) { + return supports(serviceType); + } + + @Override + protected boolean supports(ProcessingEnvironment processingEnv, TypeElement serviceType, + TypeElement serviceInterfaceType, ExecutableElement method) { + return isAnnotationPresent(method, REQUEST_MAPPING_ANNOTATION_CLASS_NAME); + } + + public static boolean supports(TypeElement serviceType) { + return isAnnotationPresent(serviceType, CONTROLLER_ANNOTATION_CLASS_NAME); + } + + @Override + protected String resolveRequestPath(ProcessingEnvironment processingEnv, TypeElement serviceType, + ExecutableElement method) { + + String requestPathFromType = getRequestPath(serviceType); + + String requestPathFromMethod = getRequestPath(method); + + return buildPath(requestPathFromType, requestPathFromMethod); + } + + + @Override + protected String resolveRequestMethod(ProcessingEnvironment processingEnv, TypeElement serviceType, + ExecutableElement method) { + + AnnotationMirror requestMapping = getRequestMapping(method); + + // httpMethod is an array of RequestMethod + Object httpMethod = getAttribute(requestMapping, "method"); + + if (httpMethod == null || getLength(httpMethod) < 1) { + return null; + } + + // TODO Is is required to support more request methods? + return valueOf(Array.get(httpMethod, FIRST_ELEMENT_INDEX)); + } + + private AnnotationMirror getRequestMapping(Element element) { + // try "@RequestMapping" first + AnnotationMirror requestMapping = findAnnotation(element, REQUEST_MAPPING_ANNOTATION_CLASS_NAME); + // try the annotation meta-annotated later + if (requestMapping == null) { + requestMapping = findMetaAnnotation(element, REQUEST_MAPPING_ANNOTATION_CLASS_NAME); + } + return requestMapping; + } + + @Override + protected void processProduces(ProcessingEnvironment processingEnv, TypeElement serviceType, + ExecutableElement method, Set produces) { + addMediaTypes(method, "produces", produces); + } + + @Override + protected void processConsumes(ProcessingEnvironment processingEnv, TypeElement serviceType, + ExecutableElement method, Set consumes) { + addMediaTypes(method, "consumes", consumes); + } + + private void addMediaTypes(ExecutableElement method, String annotationAttributeName, Set mediaTypesSet) { + + AnnotationMirror mappingAnnotation = getMappingAnnotation(method); + + String[] mediaTypes = getAttribute(mappingAnnotation, annotationAttributeName); + + if (isNotEmpty(mediaTypes)) { + of(mediaTypes).forEach(mediaTypesSet::add); + } + } + + private AnnotationMirror getMappingAnnotation(Element element) { + return computeIfAbsent(valueOf(element), key -> + filterFirst(getAllAnnotations(element), annotation -> { + DeclaredType annotationType = annotation.getAnnotationType(); + // try "@RequestMapping" first + if (REQUEST_MAPPING_ANNOTATION_CLASS_NAME.equals(annotationType.toString())) { + return true; + } + // try meta annotation + return isAnnotationPresent(annotationType.asElement(), REQUEST_MAPPING_ANNOTATION_CLASS_NAME); + }) + ); + } + + private String getRequestPath(Element element) { + AnnotationMirror mappingAnnotation = getMappingAnnotation(element); + return getRequestPath(mappingAnnotation); + } + + private String getRequestPath(AnnotationMirror mappingAnnotation) { + // try "value" first + String[] value = getAttribute(mappingAnnotation, "value"); + + if (isEmpty(value)) { // try "path" later + value = getAttribute(mappingAnnotation, "path"); + } + + if (isEmpty(value)) { + return ""; + } + // TODO Is is required to support more request paths? + return value[FIRST_ELEMENT_INDEX]; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/AnnotationUtils.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/AnnotationUtils.java new file mode 100644 index 0000000000..176043be90 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/AnnotationUtils.java @@ -0,0 +1,233 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.util; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.AnnotatedConstruct; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.AnnotationValue; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.type.ArrayType; +import javax.lang.model.type.TypeMirror; +import java.lang.annotation.Annotation; +import java.lang.reflect.Array; +import java.lang.reflect.Type; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import static java.lang.Enum.valueOf; +import static java.util.Collections.emptyList; +import static org.apache.dubbo.common.function.Predicates.EMPTY_ARRAY; +import static org.apache.dubbo.common.function.Streams.filterAll; +import static org.apache.dubbo.common.function.Streams.filterFirst; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.getHierarchicalTypes; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.getType; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isSameType; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isTypeElement; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.ofTypeElement; + +/** + * The utilities class for annotation in the package "javax.lang.model.*" + * + * @since 2.7.6 + */ +public interface AnnotationUtils { + + static AnnotationMirror getAnnotation(AnnotatedConstruct annotatedConstruct, + Class annotationClass) { + return annotationClass == null ? + null : + getAnnotation(annotatedConstruct, annotationClass.getTypeName()); + } + + static AnnotationMirror getAnnotation(AnnotatedConstruct annotatedConstruct, CharSequence annotationClassName) { + List annotations = getAnnotations(annotatedConstruct, annotationClassName); + return annotations.isEmpty() ? null : annotations.get(0); + } + + static List getAnnotations(AnnotatedConstruct annotatedConstruct, Class annotationClass) { + return annotationClass == null ? + emptyList() : + getAnnotations(annotatedConstruct, annotationClass.getTypeName()); + } + + static List getAnnotations(AnnotatedConstruct annotatedConstruct, + CharSequence annotationClassName) { + return getAnnotations(annotatedConstruct, + annotation -> isSameType(annotation.getAnnotationType(), annotationClassName)); + } + + static List getAnnotations(AnnotatedConstruct annotatedConstruct) { + return getAnnotations(annotatedConstruct, EMPTY_ARRAY); + } + + static List getAnnotations(AnnotatedConstruct annotatedConstruct, + Predicate... annotationFilters) { + + AnnotatedConstruct actualAnnotatedConstruct = annotatedConstruct; + + if (annotatedConstruct instanceof TypeMirror) { + actualAnnotatedConstruct = ofTypeElement((TypeMirror) actualAnnotatedConstruct); + } + + return actualAnnotatedConstruct == null ? + emptyList() : + filterAll((List) actualAnnotatedConstruct.getAnnotationMirrors(), annotationFilters); + } + + static List getAllAnnotations(TypeMirror type) { + return getAllAnnotations(ofTypeElement(type)); + } + + static List getAllAnnotations(Element element) { + return getAllAnnotations(element, EMPTY_ARRAY); + } + + static List getAllAnnotations(TypeMirror type, Class annotationClass) { + return getAllAnnotations(ofTypeElement(type), annotationClass); + } + + static List getAllAnnotations(Element element, Class annotationClass) { + return element == null || annotationClass == null ? + emptyList() : + getAllAnnotations(element, annotationClass.getTypeName()); + } + + static List getAllAnnotations(TypeMirror type, CharSequence annotationClassName) { + return getAllAnnotations(ofTypeElement(type), annotationClassName); + } + + static List getAllAnnotations(Element element, CharSequence annotationClassName) { + return getAllAnnotations(element, annotation -> isSameType(annotation.getAnnotationType(), annotationClassName)); + } + + static List getAllAnnotations(TypeMirror type, Predicate... annotationFilters) { + return getAllAnnotations(ofTypeElement(type), annotationFilters); + } + + static List getAllAnnotations(Element element, Predicate... annotationFilters) { + + List allAnnotations = isTypeElement(element) ? + getHierarchicalTypes(ofTypeElement(element)) + .stream() + .map(AnnotationUtils::getAnnotations) + .flatMap(Collection::stream) + .collect(Collectors.toList()) : + element == null ? emptyList() : (List) element.getAnnotationMirrors(); + + return filterAll(allAnnotations, annotationFilters); + } + + static List getAllAnnotations(ProcessingEnvironment processingEnv, Type annotatedType) { + return getAllAnnotations(processingEnv, annotatedType, EMPTY_ARRAY); + } + + static List getAllAnnotations(ProcessingEnvironment processingEnv, Type annotatedType, + Predicate... annotationFilters) { + return annotatedType == null ? + emptyList() : + getAllAnnotations(processingEnv, annotatedType.getTypeName(), annotationFilters); + } + + static List getAllAnnotations(ProcessingEnvironment processingEnv, CharSequence annotatedTypeName, + Predicate... annotationFilters) { + return getAllAnnotations(getType(processingEnv, annotatedTypeName), annotationFilters); + } + + static AnnotationMirror findAnnotation(TypeMirror type, Class annotationClass) { + return annotationClass == null ? null : findAnnotation(type, annotationClass.getTypeName()); + } + + static AnnotationMirror findAnnotation(TypeMirror type, CharSequence annotationClassName) { + return findAnnotation(ofTypeElement(type), annotationClassName); + } + + static AnnotationMirror findAnnotation(Element element, Class annotationClass) { + return annotationClass == null ? null : findAnnotation(element, annotationClass.getTypeName()); + } + + static AnnotationMirror findAnnotation(Element element, CharSequence annotationClassName) { + return filterFirst(getAllAnnotations(element, annotation -> isSameType(annotation.getAnnotationType(), annotationClassName))); + } + + static AnnotationMirror findMetaAnnotation(Element annotatedConstruct, CharSequence metaAnnotationClassName) { + return annotatedConstruct == null ? + null : + getAnnotations(annotatedConstruct) + .stream() + .map(annotation -> findAnnotation(annotation.getAnnotationType(), metaAnnotationClassName)) + .filter(Objects::nonNull) + .findFirst() + .orElse(null); + } + + static boolean isAnnotationPresent(Element element, CharSequence annotationClassName) { + return findAnnotation(element, annotationClassName) != null || + findMetaAnnotation(element, annotationClassName) != null; + } + + static T getAttribute(AnnotationMirror annotation, String attributeName) { + return annotation == null ? null : getAttribute(annotation.getElementValues(), attributeName); + } + + static T getAttribute(Map attributesMap, + String attributeName) { + T annotationValue = null; + for (Map.Entry entry : attributesMap.entrySet()) { + ExecutableElement attributeMethod = entry.getKey(); + if (Objects.equals(attributeName, attributeMethod.getSimpleName().toString())) { + TypeMirror attributeType = attributeMethod.getReturnType(); + AnnotationValue value = entry.getValue(); + if (attributeType instanceof ArrayType) { // array-typed attribute values + ArrayType arrayType = (ArrayType) attributeType; + String componentType = arrayType.getComponentType().toString(); + ClassLoader classLoader = AnnotationUtils.class.getClassLoader(); + List values = (List) value.getValue(); + int size = values.size(); + try { + Class componentClass = classLoader.loadClass(componentType); + boolean isEnum = componentClass.isEnum(); + Object array = Array.newInstance(componentClass, values.size()); + for (int i = 0; i < size; i++) { + Object element = values.get(i).getValue(); + if (isEnum) { + element = valueOf(componentClass, element.toString()); + } + Array.set(array, i, element); + } + annotationValue = (T) array; + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + } else { + annotationValue = (T) value.getValue(); + } + break; + } + } + return annotationValue; + } + + static T getValue(AnnotationMirror annotation) { + return (T) getAttribute(annotation, "value"); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/ExecutableElementComparator.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/ExecutableElementComparator.java new file mode 100644 index 0000000000..31603faabe --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/ExecutableElementComparator.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.util; + +import org.apache.dubbo.common.utils.CharSequenceComparator; + +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.VariableElement; +import java.util.Comparator; +import java.util.List; + +/** + * The Comparator class for {@link ExecutableElement}, the comparison rule : + *
    + *
  1. Comparing to two {@link ExecutableElement#getSimpleName() element names} {@link String#compareTo(String) lexicographically}. + * If equals, go to step 2
  2. + *
  3. Comparing to the count of two parameters. If equals, go to step 3
  4. + *
  5. Comparing to the type names of parameters {@link String#compareTo(String) lexicographically}
  6. + *
+ * + * @since 2.7.6 + */ +public class ExecutableElementComparator implements Comparator { + + public final static ExecutableElementComparator INSTANCE = new ExecutableElementComparator(); + + private ExecutableElementComparator() { + } + + @Override + public int compare(ExecutableElement e1, ExecutableElement e2) { + + if (e1.equals(e2)) { + return 0; + } + + // Step 1 + int value = CharSequenceComparator.INSTANCE.compare(e1.getSimpleName(), e2.getSimpleName()); + + if (value == 0) { // Step 2 + + List ps1 = e1.getParameters(); + List ps2 = e1.getParameters(); + + value = ps1.size() - ps2.size(); + + if (value == 0) { // Step 3 + for (int i = 0; i < ps1.size(); i++) { + value = CharSequenceComparator.INSTANCE.compare(ps1.get(i).getSimpleName(), ps2.get(i).getSimpleName()); + if (value != 0) { + break; + } + } + } + } + return Integer.compare(value, 0); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/FieldUtils.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/FieldUtils.java new file mode 100644 index 0000000000..b0b2b3ef0b --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/FieldUtils.java @@ -0,0 +1,146 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.util; + +import javax.lang.model.element.Element; +import javax.lang.model.element.Modifier; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.TypeMirror; +import java.util.Collection; +import java.util.List; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import static java.util.Collections.emptyList; +import static javax.lang.model.element.ElementKind.ENUM_CONSTANT; +import static javax.lang.model.element.ElementKind.FIELD; +import static javax.lang.model.element.Modifier.STATIC; +import static javax.lang.model.util.ElementFilter.fieldsIn; +import static org.apache.dubbo.common.function.Predicates.EMPTY_ARRAY; +import static org.apache.dubbo.common.function.Streams.filterAll; +import static org.apache.dubbo.common.function.Streams.filterFirst; +import static org.apache.dubbo.metadata.annotation.processing.util.MemberUtils.getDeclaredMembers; +import static org.apache.dubbo.metadata.annotation.processing.util.MemberUtils.hasModifiers; +import static org.apache.dubbo.metadata.annotation.processing.util.MemberUtils.matches; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.getHierarchicalTypes; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isEnumType; + +/** + * The utilities class for the field in the package "javax.lang.model." + * + * @since 2.7.6 + */ +public interface FieldUtils { + + static List getDeclaredFields(Element element, Predicate... fieldFilters) { + return element == null ? emptyList() : getDeclaredFields(element.asType(), fieldFilters); + } + + static List getDeclaredFields(Element element) { + return getDeclaredFields(element, EMPTY_ARRAY); + } + + static List getDeclaredFields(TypeMirror type, Predicate... fieldFilters) { + return filterAll(fieldsIn(getDeclaredMembers(type)), fieldFilters); + } + + static List getDeclaredFields(TypeMirror type) { + return getDeclaredFields(type, EMPTY_ARRAY); + } + + static List getAllDeclaredFields(Element element, Predicate... fieldFilters) { + return element == null ? emptyList() : getAllDeclaredFields(element.asType(), fieldFilters); + } + + static List getAllDeclaredFields(Element element) { + return getAllDeclaredFields(element, EMPTY_ARRAY); + } + + static List getAllDeclaredFields(TypeMirror type, Predicate... fieldFilters) { + return getHierarchicalTypes(type) + .stream() + .map(t -> getDeclaredFields(t, fieldFilters)) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + } + + static List getAllDeclaredFields(TypeMirror type) { + return getAllDeclaredFields(type, EMPTY_ARRAY); + } + + static VariableElement getDeclaredField(Element element, String fieldName) { + return element == null ? null : getDeclaredField(element.asType(), fieldName); + } + + static VariableElement getDeclaredField(TypeMirror type, String fieldName) { + return filterFirst(getDeclaredFields(type, field -> fieldName.equals(field.getSimpleName().toString()))); + } + + static VariableElement findField(Element element, String fieldName) { + return element == null ? null : findField(element.asType(), fieldName); + } + + static VariableElement findField(TypeMirror type, String fieldName) { + return filterFirst(getAllDeclaredFields(type, field -> equals(field, fieldName))); + } + + /** + * is Enum's member field or not + * + * @param field {@link VariableElement} must be public static final fields + * @return if field is public static final, return true, or false + */ + static boolean isEnumMemberField(VariableElement field) { + if (field == null || !isEnumType(field.getEnclosingElement())) { + return false; + } + return ENUM_CONSTANT.equals(field.getKind()); + } + + static boolean isNonStaticField(VariableElement field) { + return isField(field) && !hasModifiers(field, STATIC); + } + + static boolean isField(VariableElement field) { + return matches(field, FIELD) || isEnumMemberField(field); + } + + static boolean isField(VariableElement field, Modifier... modifiers) { + return isField(field) && hasModifiers(field, modifiers); + } + + static List getNonStaticFields(TypeMirror type) { + return getDeclaredFields(type, FieldUtils::isNonStaticField); + } + + static List getNonStaticFields(Element element) { + return element == null ? emptyList() : getNonStaticFields(element.asType()); + } + + static List getAllNonStaticFields(TypeMirror type) { + return getAllDeclaredFields(type, FieldUtils::isNonStaticField); + } + + static List getAllNonStaticFields(Element element) { + return element == null ? emptyList() : getAllNonStaticFields(element.asType()); + } + + static boolean equals(VariableElement field, CharSequence fieldName) { + return field != null && fieldName != null && field.getSimpleName().toString().equals(fieldName.toString()); + } + +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/LoggerUtils.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/LoggerUtils.java new file mode 100644 index 0000000000..416590ff35 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/LoggerUtils.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.util; + + +import org.apache.dubbo.common.logger.Logger; +import org.apache.dubbo.common.logger.LoggerFactory; + +import static java.lang.String.format; + +/** + * Logger Utils + * + * @since 2.7.6 + */ +public interface LoggerUtils { + + Logger LOGGER = LoggerFactory.getLogger("dubbo-metadata-processor"); + + static void info(String format, Object... args) { + if (LOGGER.isInfoEnabled()) { + LOGGER.info(format(format, args)); + } + } + + static void warn(String format, Object... args) { + if (LOGGER.isWarnEnabled()) { + LOGGER.warn(format(format, args)); + } + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/MemberUtils.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/MemberUtils.java new file mode 100644 index 0000000000..800b4ba1fd --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/MemberUtils.java @@ -0,0 +1,94 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.util; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.Modifier; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.TypeMirror; +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +import static java.util.Collections.emptyList; +import static javax.lang.model.element.Modifier.PUBLIC; +import static javax.lang.model.element.Modifier.STATIC; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.getHierarchicalTypes; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.ofTypeElement; + +/** + * The utilities class for the members in the package "javax.lang.model.", such as "field", "method", "constructor" + * + * @since 2.7.6 + */ +public interface MemberUtils { + + static boolean matches(Element member, ElementKind kind) { + return member == null || kind == null ? false : kind.equals(member.getKind()); + } + + static boolean isPublicNonStatic(Element member) { + return hasModifiers(member, PUBLIC) && !hasModifiers(member, STATIC); + } + + static boolean hasModifiers(Element member, Modifier... modifiers) { + if (member == null || modifiers == null) { + return false; + } + Set actualModifiers = member.getModifiers(); + for (Modifier modifier : modifiers) { + if (!actualModifiers.contains(modifier)) { + return false; + } + } + return true; + } + + static List getDeclaredMembers(TypeMirror type) { + TypeElement element = ofTypeElement(type); + return element == null ? emptyList() : element.getEnclosedElements(); + } + + static List getAllDeclaredMembers(TypeMirror type) { + return getHierarchicalTypes(type) + .stream() + .map(MemberUtils::getDeclaredMembers) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + } + + static boolean matchParameterTypes(List parameters, CharSequence... parameterTypes) { + + int size = parameters.size(); + + if (size != parameterTypes.length) { + return false; + } + + for (int i = 0; i < size; i++) { + VariableElement parameter = parameters.get(i); + if (!Objects.equals(parameter.asType().toString(), parameterTypes[i])) { + return false; + } + } + return true; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/MethodUtils.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/MethodUtils.java new file mode 100644 index 0000000000..0bd2ae900e --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/MethodUtils.java @@ -0,0 +1,156 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.util; + + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.Elements; +import java.lang.reflect.Type; +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import static java.util.Arrays.asList; +import static java.util.Collections.emptyList; +import static javax.lang.model.element.ElementKind.METHOD; +import static javax.lang.model.util.ElementFilter.methodsIn; +import static org.apache.dubbo.common.function.Predicates.EMPTY_ARRAY; +import static org.apache.dubbo.common.function.Streams.filter; +import static org.apache.dubbo.common.function.Streams.filterAll; +import static org.apache.dubbo.common.function.Streams.filterFirst; +import static org.apache.dubbo.metadata.annotation.processing.util.MemberUtils.getDeclaredMembers; +import static org.apache.dubbo.metadata.annotation.processing.util.MemberUtils.isPublicNonStatic; +import static org.apache.dubbo.metadata.annotation.processing.util.MemberUtils.matchParameterTypes; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.getHierarchicalTypes; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.ofDeclaredType; + +/** + * The utilities class for method in the package "javax.lang.model." + * + * @since 2.7.6 + */ +public interface MethodUtils { + + static List getDeclaredMethods(TypeElement type, Predicate... methodFilters) { + return type == null ? emptyList() : getDeclaredMethods(type.asType(), methodFilters); + } + + static List getDeclaredMethods(TypeMirror type, Predicate... methodFilters) { + return filterAll(methodsIn(getDeclaredMembers(type)), methodFilters); + } + + static List getAllDeclaredMethods(TypeElement type, Predicate... methodFilters) { + return type == null ? emptyList() : getAllDeclaredMethods(type.asType(), methodFilters); + } + + static List getAllDeclaredMethods(TypeElement type) { + return getAllDeclaredMethods(type, EMPTY_ARRAY); + } + + static List getAllDeclaredMethods(TypeMirror type, Predicate... methodFilters) { + return getHierarchicalTypes(type) + .stream() + .map(t -> getDeclaredMethods(t, methodFilters)) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + } + + static List getAllDeclaredMethods(TypeMirror type) { + return getAllDeclaredMethods(type, EMPTY_ARRAY); + } + + static List getAllDeclaredMethods(TypeElement type, Type... excludedTypes) { + return type == null ? emptyList() : getAllDeclaredMethods(type.asType(), excludedTypes); + } + + static List getAllDeclaredMethods(TypeMirror type, Type... excludedTypes) { + return getHierarchicalTypes(type, excludedTypes) + .stream() + .map(t -> getDeclaredMethods(t)) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + } + + static List getPublicNonStaticMethods(TypeElement type, Type... excludedTypes) { + return getPublicNonStaticMethods(ofDeclaredType(type), excludedTypes); + } + + static List getPublicNonStaticMethods(TypeMirror type, Type... excludedTypes) { + return filter(getAllDeclaredMethods(type, excludedTypes), MethodUtils::isPublicNonStaticMethod); + } + + static boolean isMethod(ExecutableElement method) { + return method != null && METHOD.equals(method.getKind()); + } + + static boolean isPublicNonStaticMethod(ExecutableElement method) { + return isMethod(method) && isPublicNonStatic(method); + } + + static ExecutableElement findMethod(TypeElement type, String methodName, Type oneParameterType, Type... otherParameterTypes) { + return type == null ? null : findMethod(type.asType(), methodName, oneParameterType, otherParameterTypes); + } + + static ExecutableElement findMethod(TypeMirror type, String methodName, Type oneParameterType, Type... otherParameterTypes) { + List parameterTypes = new LinkedList<>(); + parameterTypes.add(oneParameterType); + parameterTypes.addAll(asList(otherParameterTypes)); + return findMethod(type, methodName, parameterTypes.stream().map(Type::getTypeName).toArray(String[]::new)); + } + + static ExecutableElement findMethod(TypeElement type, String methodName, CharSequence... parameterTypes) { + return type == null ? null : findMethod(type.asType(), methodName, parameterTypes); + } + + static ExecutableElement findMethod(TypeMirror type, String methodName, CharSequence... parameterTypes) { + return filterFirst(getAllDeclaredMethods(type), + method -> methodName.equals(method.getSimpleName().toString()), + method -> matchParameterTypes(method.getParameters(), parameterTypes) + ); + } + + static ExecutableElement getOverrideMethod(ProcessingEnvironment processingEnv, TypeElement type, + ExecutableElement declaringMethod) { + Elements elements = processingEnv.getElementUtils(); + return filterFirst(getAllDeclaredMethods(type), method -> elements.overrides(method, declaringMethod, type)); + } + + + static String getMethodName(ExecutableElement method) { + return method == null ? null : method.getSimpleName().toString(); + } + + static String getReturnType(ExecutableElement method) { + return method == null ? null : TypeUtils.toString(method.getReturnType()); + } + + static String[] getMethodParameterTypes(ExecutableElement method) { + return method == null ? + new String[0] : + method.getParameters() + .stream() + .map(VariableElement::asType) + .map(TypeUtils::toString) + .toArray(String[]::new); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/ServiceAnnotationUtils.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/ServiceAnnotationUtils.java new file mode 100644 index 0000000000..b4aaffdd71 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/ServiceAnnotationUtils.java @@ -0,0 +1,121 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.util; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.TypeElement; +import java.util.HashSet; +import java.util.Set; + +import static java.lang.String.valueOf; +import static java.util.Arrays.asList; +import static java.util.Collections.unmodifiableSet; +import static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.getAttribute; +import static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.isAnnotationPresent; + +/** + * The utilities class for @Service annotation + * + * @since 2.7.6 + */ +public interface ServiceAnnotationUtils { + + /** + * The class name of @Service + */ + String SERVICE_ANNOTATION_TYPE = "org.apache.dubbo.config.annotation.Service"; + + /** + * The class name of the legacy @Service + */ + @Deprecated + String LEGACY_SERVICE_ANNOTATION_TYPE = "com.alibaba.dubbo.config.annotation.Service"; + + /** + * the attribute name of @Service.interfaceClass() + */ + String INTERFACE_CLASS_ATTRIBUTE_NAME = "interfaceClass"; + + /** + * the attribute name of @Service.interfaceName() + */ + String INTERFACE_NAME_ATTRIBUTE_NAME = "interfaceName"; + + /** + * the attribute name of @Service.group() + */ + String GROUP_ATTRIBUTE_NAME = "group"; + + /** + * the attribute name of @Service.version() + */ + String VERSION_ATTRIBUTE_NAME = "version"; + + Set SUPPORTED_ANNOTATION_TYPES = unmodifiableSet(new HashSet(asList(SERVICE_ANNOTATION_TYPE, LEGACY_SERVICE_ANNOTATION_TYPE))); + + static boolean isServiceAnnotationPresent(TypeElement annotatedType) { + return isAnnotationPresent(annotatedType, SERVICE_ANNOTATION_TYPE) || + isAnnotationPresent(annotatedType, LEGACY_SERVICE_ANNOTATION_TYPE); + } + + static AnnotationMirror getAnnotation(TypeElement annotatedClass) { + return getAnnotation(annotatedClass.getAnnotationMirrors()); + } + + static AnnotationMirror getAnnotation(Iterable annotationMirrors) { + AnnotationMirror matchedAnnotationMirror = null; + for (AnnotationMirror annotationMirror : annotationMirrors) { + String annotationType = annotationMirror.getAnnotationType().toString(); + if (SERVICE_ANNOTATION_TYPE.equals(annotationType)) { + matchedAnnotationMirror = annotationMirror; + break; + } else if (LEGACY_SERVICE_ANNOTATION_TYPE.equals(annotationType)) { + matchedAnnotationMirror = annotationMirror; + } + } + + if (matchedAnnotationMirror == null) { + throw new IllegalArgumentException("The annotated element must be implemented the interface " + + SERVICE_ANNOTATION_TYPE + " or " + LEGACY_SERVICE_ANNOTATION_TYPE); + } + + return matchedAnnotationMirror; + } + + static String resolveServiceInterfaceName(TypeElement annotatedClass, AnnotationMirror serviceAnnotation) { + Object interfaceClass = getAttribute(serviceAnnotation, INTERFACE_CLASS_ATTRIBUTE_NAME); + + if (interfaceClass == null) { // try to find the "interfaceName" attribute + interfaceClass = getAttribute(serviceAnnotation, INTERFACE_NAME_ATTRIBUTE_NAME); + } + + if (interfaceClass == null) { + // last, get the interface class from first one + interfaceClass = ((TypeElement) annotatedClass).getInterfaces().get(0); + } + + return valueOf(interfaceClass); + } + + static String getGroup(AnnotationMirror serviceAnnotation) { + return getAttribute(serviceAnnotation, GROUP_ATTRIBUTE_NAME); + } + + static String getVersion(AnnotationMirror serviceAnnotation) { + return getAttribute(serviceAnnotation, VERSION_ATTRIBUTE_NAME); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/TypeUtils.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/TypeUtils.java new file mode 100644 index 0000000000..457f6bc2f5 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/TypeUtils.java @@ -0,0 +1,400 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.util; + +import org.apache.dubbo.common.utils.ClassUtils; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.TypeParameterElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.Elements; +import javax.tools.FileObject; +import javax.tools.StandardLocation; +import java.io.IOException; +import java.lang.reflect.Type; +import java.net.URL; +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.function.Predicate; + +import static java.lang.String.valueOf; +import static java.util.Arrays.asList; +import static java.util.Collections.emptyList; +import static java.util.Collections.emptySet; +import static java.util.stream.Collectors.toSet; +import static java.util.stream.Stream.of; +import static java.util.stream.StreamSupport.stream; +import static javax.lang.model.element.ElementKind.ANNOTATION_TYPE; +import static javax.lang.model.element.ElementKind.CLASS; +import static javax.lang.model.element.ElementKind.ENUM; +import static javax.lang.model.element.ElementKind.INTERFACE; +import static org.apache.dubbo.common.function.Predicates.EMPTY_ARRAY; +import static org.apache.dubbo.common.function.Streams.filterAll; +import static org.apache.dubbo.common.function.Streams.filterFirst; +import static org.apache.dubbo.common.utils.MethodUtils.invokeMethod; + +/** + * The utilities class for type in the package "javax.lang.model.*" + * + * @since 2.7.6 + */ +public interface TypeUtils { + + List SIMPLE_TYPES = asList( + ClassUtils.SIMPLE_TYPES + .stream() + .map(Class::getName) + .toArray(String[]::new) + ); + + static boolean isSimpleType(Element element) { + return element != null && isSimpleType(element.asType()); + } + + static boolean isSimpleType(TypeMirror type) { + return type != null && SIMPLE_TYPES.contains(type.toString()); + } + + static boolean isSameType(TypeMirror type, CharSequence typeName) { + if (type == null || typeName == null) { + return false; + } + return Objects.equals(valueOf(type), valueOf(typeName)); + } + + static boolean isSameType(TypeMirror typeMirror, Type type) { + return type != null && isSameType(typeMirror, type.getTypeName()); + } + + static boolean isArrayType(TypeMirror type) { + return type != null && TypeKind.ARRAY.equals(type.getKind()); + } + + static boolean isArrayType(Element element) { + return element != null && isArrayType(element.asType()); + } + + static boolean isEnumType(TypeMirror type) { + DeclaredType declaredType = ofDeclaredType(type); + return declaredType != null && ENUM.equals(declaredType.asElement().getKind()); + } + + static boolean isEnumType(Element element) { + return element != null && isEnumType(element.asType()); + } + + static boolean isClassType(TypeMirror type) { + DeclaredType declaredType = ofDeclaredType(type); + return declaredType != null && isClassType(declaredType.asElement()); + } + + static boolean isClassType(Element element) { + return element != null && CLASS.equals(element.getKind()); + } + + static boolean isPrimitiveType(TypeMirror type) { + return type != null && type.getKind().isPrimitive(); + } + + static boolean isPrimitiveType(Element element) { + return element != null && isPrimitiveType(element.asType()); + } + + static boolean isInterfaceType(TypeMirror type) { + DeclaredType declaredType = ofDeclaredType(type); + return declaredType != null && isInterfaceType(declaredType.asElement()); + } + + static boolean isInterfaceType(Element element) { + return element != null && INTERFACE.equals(element.getKind()); + } + + static boolean isAnnotationType(TypeMirror type) { + DeclaredType declaredType = ofDeclaredType(type); + return declaredType != null && isAnnotationType(declaredType.asElement()); + } + + static boolean isAnnotationType(Element element) { + return element != null && ANNOTATION_TYPE.equals(element.getKind()); + } + + static Set getHierarchicalTypes(TypeElement type) { + return getHierarchicalTypes(type, true, true, true); + } + + static Set getHierarchicalTypes(TypeMirror type) { + return getHierarchicalTypes(type, EMPTY_ARRAY); + } + + static Set getHierarchicalTypes(TypeMirror type, Predicate... typeFilters) { + return filterAll(ofDeclaredTypes(getHierarchicalTypes(ofTypeElement(type))), typeFilters); + } + + static Set getHierarchicalTypes(TypeMirror type, Type... excludedTypes) { + return getHierarchicalTypes(type, of(excludedTypes).map(Type::getTypeName).toArray(String[]::new)); + } + + static Set getHierarchicalTypes(TypeMirror type, CharSequence... excludedTypeNames) { + Set typeNames = of(excludedTypeNames).map(CharSequence::toString).collect(toSet()); + return getHierarchicalTypes(type, t -> !typeNames.contains(t.toString())); + } + + static Set getHierarchicalTypes(TypeElement type, + boolean includeSelf, + boolean includeSuperTypes, + boolean includeSuperInterfaces, + Predicate... typeFilters) { + + if (type == null) { + return emptySet(); + } + + Set hierarchicalTypes = new LinkedHashSet<>(); + + if (includeSelf) { + hierarchicalTypes.add(type); + } + + if (includeSuperTypes) { + hierarchicalTypes.addAll(getAllSuperTypes(type)); + } + + if (includeSuperInterfaces) { + hierarchicalTypes.addAll(getAllInterfaces(type)); + } + + return filterAll(hierarchicalTypes, typeFilters); + } + + static Set getHierarchicalTypes(TypeMirror type, + boolean includeSelf, + boolean includeSuperTypes, + boolean includeSuperInterfaces) { + return ofDeclaredTypes(getHierarchicalTypes(ofTypeElement(type), + includeSelf, + includeSuperTypes, + includeSuperInterfaces)); + } + + static List getInterfaces(TypeElement type, Predicate... interfaceFilters) { + return type == null ? emptyList() : filterAll((List) ofTypeElement(type).getInterfaces(), interfaceFilters); + } + + static List getInterfaces(TypeMirror type, Predicate... interfaceFilters) { + return getInterfaces(ofTypeElement(type), interfaceFilters); + } + + static Set getAllInterfaces(TypeElement type, Predicate... interfaceFilters) { + return type == null ? emptySet() : filterAll(ofTypeElements(getAllInterfaces(type.asType())), interfaceFilters); + } + + static Set getAllInterfaces(TypeMirror type, Predicate... interfaceFilters) { + if (type == null) { + return emptySet(); + } + Set allInterfaces = new LinkedHashSet<>(); + getInterfaces(type).forEach(i -> { + // Add current type's interfaces + allInterfaces.add(i); + // Add + allInterfaces.addAll(getAllInterfaces(i)); + }); + // Add all super types' interfaces + getAllSuperTypes(type).forEach(superType -> allInterfaces.addAll(getAllInterfaces(superType))); + return filterAll(allInterfaces, interfaceFilters); + } + + static TypeMirror findInterface(TypeMirror type, CharSequence interfaceClassName) { + return filterFirst(getAllInterfaces(type), t -> isSameType(t, interfaceClassName)); + } + + static TypeElement getType(ProcessingEnvironment processingEnv, Type type) { + return type == null ? null : getType(processingEnv, type.getTypeName()); + } + + static TypeElement getType(ProcessingEnvironment processingEnv, TypeMirror type) { + return type == null ? null : getType(processingEnv, type.toString()); + } + + static TypeElement getType(ProcessingEnvironment processingEnv, CharSequence typeName) { + if (processingEnv == null || typeName == null) { + return null; + } + Elements elements = processingEnv.getElementUtils(); + return elements.getTypeElement(typeName); + } + + static TypeElement getSuperType(TypeElement type) { + return type == null ? null : ofTypeElement(type.getSuperclass()); + } + + static DeclaredType getSuperType(TypeMirror type) { + TypeElement superType = getSuperType(ofTypeElement(type)); + return superType == null ? null : ofDeclaredType(superType.asType()); + } + + static Set getAllSuperTypes(TypeElement type) { + return getAllSuperTypes(type, EMPTY_ARRAY); + } + + static Set getAllSuperTypes(TypeElement type, Predicate... typeFilters) { + if (type == null) { + return emptySet(); + } + + Set allSuperTypes = new LinkedHashSet<>(); + TypeElement superType = getSuperType(type); + if (superType != null) { + // add super type + allSuperTypes.add(superType); + // add ancestors' types + allSuperTypes.addAll(getAllSuperTypes(superType)); + } + return filterAll(allSuperTypes, typeFilters); + } + + static Set getAllSuperTypes(TypeMirror type) { + return getAllSuperTypes(type, EMPTY_ARRAY); + } + + static Set getAllSuperTypes(TypeMirror type, Predicate... typeFilters) { + return filterAll(ofDeclaredTypes(getAllSuperTypes(ofTypeElement(type))), typeFilters); + } + + static boolean isDeclaredType(Element element) { + return element != null && isDeclaredType(element.asType()); + } + + static boolean isDeclaredType(TypeMirror type) { + return type instanceof DeclaredType; + } + + static DeclaredType ofDeclaredType(Element element) { + return element == null ? null : ofDeclaredType(element.asType()); + } + + static DeclaredType ofDeclaredType(TypeMirror type) { + return isDeclaredType(type) ? (DeclaredType) type : null; + } + + static boolean isTypeElement(Element element) { + return element instanceof TypeElement; + } + + static boolean isTypeElement(TypeMirror type) { + DeclaredType declaredType = ofDeclaredType(type); + return declaredType != null && isTypeElement(declaredType.asElement()); + } + + static TypeElement ofTypeElement(Element element) { + return isTypeElement(element) ? (TypeElement) element : null; + } + + static TypeElement ofTypeElement(TypeMirror type) { + DeclaredType declaredType = ofDeclaredType(type); + if (declaredType != null) { + return ofTypeElement(declaredType.asElement()); + } + return null; + } + + static Set ofDeclaredTypes(Iterable elements) { + return elements == null ? + emptySet() : + stream(elements.spliterator(), false) + .map(TypeUtils::ofTypeElement) + .filter(Objects::nonNull) + .map(Element::asType) + .map(TypeUtils::ofDeclaredType) + .filter(Objects::nonNull) + .collect(LinkedHashSet::new, Set::add, Set::addAll); + } + + static Set ofTypeElements(Iterable types) { + return types == null ? + emptySet() : + stream(types.spliterator(), false) + .map(TypeUtils::ofTypeElement) + .filter(Objects::nonNull) + .collect(LinkedHashSet::new, Set::add, Set::addAll); + } + + static List listDeclaredTypes(Iterable elements) { + return new ArrayList<>(ofDeclaredTypes(elements)); + } + + static List listTypeElements(Iterable types) { + return new ArrayList<>(ofTypeElements(types)); + } + + static URL getResource(ProcessingEnvironment processingEnv, Element type) { + return getResource(processingEnv, ofDeclaredType(type)); + } + + static URL getResource(ProcessingEnvironment processingEnv, TypeMirror type) { + return type == null ? null : getResource(processingEnv, type.toString()); + } + + static URL getResource(ProcessingEnvironment processingEnv, CharSequence type) { + String relativeName = getResourceName(type); + URL resource = null; + try { + if (relativeName != null) { + FileObject fileObject = processingEnv.getFiler().getResource(StandardLocation.CLASS_OUTPUT, "", relativeName); + resource = fileObject.toUri().toURL(); + // try to open it + resource.getContent(); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + + return resource; + } + + static String getResourceName(CharSequence type) { + return type == null ? null : type.toString().replace('.', '/').concat(".class"); + } + + static String toString(TypeMirror type) { + TypeElement element = ofTypeElement(type); + if (element != null) { + List typeParameterElements = element.getTypeParameters(); + if (!typeParameterElements.isEmpty()) { + List typeMirrors = invokeMethod(type, "getTypeArguments"); + StringBuilder typeBuilder = new StringBuilder(element.toString()); + typeBuilder.append("<"); + for (int i = 0; i < typeMirrors.size(); i++) { + if (i > 0) { + typeBuilder.append(", "); + } + typeBuilder.append(typeMirrors.get(i).toString()); + } + typeBuilder.append(">"); + return typeBuilder.toString(); + } + } + return type.toString(); + } +} \ No newline at end of file diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.annotation.processing.builder.TypeDefinitionBuilder b/dubbo-metadata/dubbo-metadata-processor/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.annotation.processing.builder.TypeDefinitionBuilder new file mode 100644 index 0000000000..b934a6ea77 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.annotation.processing.builder.TypeDefinitionBuilder @@ -0,0 +1,7 @@ +array-type = org.apache.dubbo.metadata.annotation.processing.builder.ArrayTypeDefinitionBuilder +collection-type = org.apache.dubbo.metadata.annotation.processing.builder.CollectionTypeDefinitionBuilder +enum-type = org.apache.dubbo.metadata.annotation.processing.builder.EnumTypeDefinitionBuilder +general-type = org.apache.dubbo.metadata.annotation.processing.builder.GeneralTypeDefinitionBuilder +map-type = org.apache.dubbo.metadata.annotation.processing.builder.MapTypeDefinitionBuilder +primitive-type = org.apache.dubbo.metadata.annotation.processing.builder.PrimitiveTypeDefinitionBuilder +simple-type = org.apache.dubbo.metadata.annotation.processing.builder.SimpleTypeDefinitionBuilder \ No newline at end of file diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.annotation.processing.rest.AnnotatedMethodParameterProcessor b/dubbo-metadata/dubbo-metadata-processor/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.annotation.processing.rest.AnnotatedMethodParameterProcessor new file mode 100644 index 0000000000..985daed606 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.annotation.processing.rest.AnnotatedMethodParameterProcessor @@ -0,0 +1,10 @@ +# JAX-RS's implementations +jax-rs.query-param = org.apache.dubbo.metadata.annotation.processing.rest.jaxrs.QueryParamParameterProcessor +jax-rs.form-param = org.apache.dubbo.metadata.annotation.processing.rest.jaxrs.FormParamParameterProcessor +jax-rs.matrix-param = org.apache.dubbo.metadata.annotation.processing.rest.jaxrs.MatrixParamParameterProcessor +jax-rs.header-param = org.apache.dubbo.metadata.annotation.processing.rest.jaxrs.HeaderParamParameterProcessor +jax-rs.default-value-param = org.apache.dubbo.metadata.annotation.processing.rest.jaxrs.DefaultValueParameterProcessor + +# Spring Web MVC's implementations +spring-webmvc.request-param = org.apache.dubbo.metadata.annotation.processing.rest.springmvc.RequestParamParameterProcessor +spring-webmvc.request-header = org.apache.dubbo.metadata.annotation.processing.rest.springmvc.RequestHeaderParameterProcessor \ No newline at end of file diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.annotation.processing.rest.ServiceRestMetadataResolver b/dubbo-metadata/dubbo-metadata-processor/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.annotation.processing.rest.ServiceRestMetadataResolver new file mode 100644 index 0000000000..9737e7d6f2 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.annotation.processing.rest.ServiceRestMetadataResolver @@ -0,0 +1,3 @@ +default = org.apache.dubbo.metadata.annotation.processing.rest.DefaultServiceRestMetadataResolver +jax-rs = org.apache.dubbo.metadata.annotation.processing.rest.jaxrs.JAXRSServiceRestMetadataResolver +spring-webmvc = org.apache.dubbo.metadata.annotation.processing.rest.springmvc.SpringMvcServiceRestMetadataResolver \ No newline at end of file diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/resources/META-INF/services/javax.annotation.processing.Processor b/dubbo-metadata/dubbo-metadata-processor/src/main/resources/META-INF/services/javax.annotation.processing.Processor new file mode 100644 index 0000000000..6c5909c26f --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/resources/META-INF/services/javax.annotation.processing.Processor @@ -0,0 +1,2 @@ +org.apache.dubbo.metadata.annotation.processing.ServiceDefinitionMetadataAnnotationProcessor +org.apache.dubbo.metadata.annotation.processing.rest.ServiceRestMetadataAnnotationProcessor diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/AbstractAnnotationProcessingTest.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/AbstractAnnotationProcessingTest.java new file mode 100644 index 0000000000..1a8f9dd5db --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/AbstractAnnotationProcessingTest.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing; + +import org.apache.dubbo.metadata.annotation.processing.util.TypeUtils; +import org.apache.dubbo.metadata.tools.Compiler; +import org.apache.dubbo.metadata.tools.TestProcessor; + +import org.junit.jupiter.api.BeforeEach; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.TypeElement; +import javax.lang.model.util.Elements; +import javax.lang.model.util.Types; +import java.io.IOException; +import java.lang.annotation.Annotation; +import java.util.LinkedHashSet; +import java.util.Set; + +/** + * Abstract {@link Annotation} Processing Test case + * + * @since 2.7.6 + */ +public abstract class AbstractAnnotationProcessingTest { + + protected ProcessingEnvironment processingEnv; + + protected Elements elements; + + protected Types types; + + @BeforeEach + public final void init() throws IOException { + Set> classesToBeCompiled = new LinkedHashSet<>(); + classesToBeCompiled.add(getClass()); + addCompiledClasses(classesToBeCompiled); + TestProcessor testProcessor = new TestProcessor(); + Compiler compiler = new Compiler(); + compiler.processors(testProcessor); + compiler.compile(classesToBeCompiled.toArray(new Class[0])); + processingEnv = testProcessor.getProcessingEnvironment(); + elements = processingEnv.getElementUtils(); + types = processingEnv.getTypeUtils(); + beforeEach(); + } + + protected abstract void addCompiledClasses(Set> classesToBeCompiled); + + protected abstract void beforeEach(); + + protected TypeElement getType(Class type) { + return TypeUtils.getType(processingEnv, type); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/ArrayTypeDefinitionBuilderTest.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/ArrayTypeDefinitionBuilderTest.java new file mode 100644 index 0000000000..3290a8a8c5 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/ArrayTypeDefinitionBuilderTest.java @@ -0,0 +1,121 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.builder; + +import org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest; +import org.apache.dubbo.metadata.annotation.processing.model.ArrayTypeModel; +import org.apache.dubbo.metadata.definition.model.TypeDefinition; + +import org.junit.jupiter.api.Test; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import java.util.Set; +import java.util.function.BiConsumer; +import java.util.stream.Stream; + +import static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.findField; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link ArrayTypeDefinitionBuilder} Test + * + * @since 2.7.6 + */ +public class ArrayTypeDefinitionBuilderTest extends AbstractAnnotationProcessingTest { + + private ArrayTypeDefinitionBuilder builder; + + private TypeElement testType; + + private VariableElement integersField; + + private VariableElement stringsField; + + private VariableElement primitiveTypeModelsField; + + private VariableElement modelsField; + + private VariableElement colorsField; + + @Override + protected void addCompiledClasses(Set> classesToBeCompiled) { + classesToBeCompiled.add(ArrayTypeModel.class); + } + + @Override + protected void beforeEach() { + builder = new ArrayTypeDefinitionBuilder(); + testType = getType(ArrayTypeModel.class); + integersField = findField(testType, "integers"); + stringsField = findField(testType, "strings"); + primitiveTypeModelsField = findField(testType, "primitiveTypeModels"); + modelsField = findField(testType, "models"); + colorsField = findField(testType, "colors"); + } + + @Test + public void testAccept() { + assertTrue(builder.accept(processingEnv, integersField.asType())); + assertTrue(builder.accept(processingEnv, stringsField.asType())); + assertTrue(builder.accept(processingEnv, primitiveTypeModelsField.asType())); + assertTrue(builder.accept(processingEnv, modelsField.asType())); + assertTrue(builder.accept(processingEnv, colorsField.asType())); + } + + @Test + public void testBuild() { + + buildAndAssertTypeDefinition(processingEnv, integersField, "int[]", "int", builder); + + buildAndAssertTypeDefinition(processingEnv, stringsField, "java.lang.String[]", "java.lang.String", builder); + + buildAndAssertTypeDefinition(processingEnv, primitiveTypeModelsField, + "org.apache.dubbo.metadata.annotation.processing.model.PrimitiveTypeModel[]", + "org.apache.dubbo.metadata.annotation.processing.model.PrimitiveTypeModel", builder); + + buildAndAssertTypeDefinition(processingEnv, modelsField, + "org.apache.dubbo.metadata.annotation.processing.model.Model[]", + "org.apache.dubbo.metadata.annotation.processing.model.Model", builder, (def, subDef) -> { + TypeElement subType = elements.getTypeElement(subDef.getType()); + assertEquals(ElementKind.CLASS, subType.getKind()); + }); + + buildAndAssertTypeDefinition(processingEnv, colorsField, + "org.apache.dubbo.metadata.annotation.processing.model.Color[]", + "org.apache.dubbo.metadata.annotation.processing.model.Color", builder, (def, subDef) -> { + TypeElement subType = elements.getTypeElement(subDef.getType()); + assertEquals(ElementKind.ENUM, subType.getKind()); + }); + + } + + static void buildAndAssertTypeDefinition(ProcessingEnvironment processingEnv, VariableElement field, + String expectedType, String compositeType, TypeDefinitionBuilder builder, + BiConsumer... assertions) { + TypeDefinition typeDefinition = TypeDefinitionBuilder.build(processingEnv, field); + TypeDefinition subTypeDefinition = typeDefinition.getItems().get(0); + assertEquals(expectedType, typeDefinition.getType()); +// assertEquals(field.getSimpleName().toString(), typeDefinition.get$ref()); + assertEquals(compositeType, subTypeDefinition.getType()); +// assertEquals(builder.getClass().getName(), typeDefinition.getTypeBuilderName()); + Stream.of(assertions).forEach(assertion -> assertion.accept(typeDefinition, subTypeDefinition)); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/CollectionTypeDefinitionBuilderTest.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/CollectionTypeDefinitionBuilderTest.java new file mode 100644 index 0000000000..bd6e7a4e04 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/CollectionTypeDefinitionBuilderTest.java @@ -0,0 +1,105 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.builder; + +import org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest; +import org.apache.dubbo.metadata.annotation.processing.model.CollectionTypeModel; + +import org.junit.jupiter.api.Test; + +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import java.util.Set; + +import static org.apache.dubbo.metadata.annotation.processing.builder.ArrayTypeDefinitionBuilderTest.buildAndAssertTypeDefinition; +import static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.findField; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link CollectionTypeDefinitionBuilder} Test + * + * @since 2.7.6 + */ +public class CollectionTypeDefinitionBuilderTest extends AbstractAnnotationProcessingTest { + + private CollectionTypeDefinitionBuilder builder; + + private VariableElement stringsField; + + private VariableElement colorsField; + + private VariableElement primitiveTypeModelsField; + + private VariableElement modelsField; + + private VariableElement modelArraysField; + + @Override + protected void addCompiledClasses(Set> classesToBeCompiled) { + classesToBeCompiled.add(CollectionTypeModel.class); + } + + @Override + protected void beforeEach() { + builder = new CollectionTypeDefinitionBuilder(); + TypeElement testType = getType(CollectionTypeModel.class); + stringsField = findField( testType, "strings"); + colorsField = findField( testType, "colors"); + primitiveTypeModelsField = findField( testType, "primitiveTypeModels"); + modelsField = findField( testType, "models"); + modelArraysField = findField( testType, "modelArrays"); + + assertEquals("strings", stringsField.getSimpleName().toString()); + assertEquals("colors", colorsField.getSimpleName().toString()); + assertEquals("primitiveTypeModels", primitiveTypeModelsField.getSimpleName().toString()); + assertEquals("models", modelsField.getSimpleName().toString()); + assertEquals("modelArrays", modelArraysField.getSimpleName().toString()); + } + + @Test + public void testAccept() { + assertTrue(builder.accept(processingEnv, stringsField.asType())); + assertTrue(builder.accept(processingEnv, colorsField.asType())); + assertTrue(builder.accept(processingEnv, primitiveTypeModelsField.asType())); + assertTrue(builder.accept(processingEnv, modelsField.asType())); + assertTrue(builder.accept(processingEnv, modelArraysField.asType())); + } + + @Test + public void testBuild() { + + buildAndAssertTypeDefinition(processingEnv, stringsField, "java.util.Collection", "java.lang.String", builder); + + buildAndAssertTypeDefinition(processingEnv, colorsField, "java.util.List", + "org.apache.dubbo.metadata.annotation.processing.model.Color", builder); + + buildAndAssertTypeDefinition(processingEnv, primitiveTypeModelsField, + "java.util.Queue", + "org.apache.dubbo.metadata.annotation.processing.model.PrimitiveTypeModel", builder); + + buildAndAssertTypeDefinition(processingEnv, modelsField, + "java.util.Deque", + "org.apache.dubbo.metadata.annotation.processing.model.Model", builder); + + buildAndAssertTypeDefinition(processingEnv, modelArraysField, + "java.util.Set", + "org.apache.dubbo.metadata.annotation.processing.model.Model[]", builder); + + + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/EnumTypeDefinitionBuilderTest.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/EnumTypeDefinitionBuilderTest.java new file mode 100644 index 0000000000..1157584a60 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/EnumTypeDefinitionBuilderTest.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.builder; + +import org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest; +import org.apache.dubbo.metadata.annotation.processing.model.Color; +import org.apache.dubbo.metadata.definition.model.TypeDefinition; + +import org.junit.jupiter.api.Test; + +import javax.lang.model.element.TypeElement; +import java.util.Set; + +import static java.util.Arrays.asList; +import static org.apache.dubbo.metadata.annotation.processing.builder.TypeDefinitionBuilder.build; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link EnumTypeDefinitionBuilder} Test + * + * @since 2.7.6 + */ +public class EnumTypeDefinitionBuilderTest extends AbstractAnnotationProcessingTest { + + private EnumTypeDefinitionBuilder builder; + + @Override + protected void addCompiledClasses(Set> classesToBeCompiled) { + classesToBeCompiled.add(Color.class); + } + + @Override + protected void beforeEach() { + builder = new EnumTypeDefinitionBuilder(); + } + + @Test + public void testAccept() { + TypeElement typeElement = getType(Color.class); + assertTrue(builder.accept(processingEnv, typeElement.asType())); + } + + @Test + public void testBuild() { + TypeElement typeElement = getType(Color.class); + TypeDefinition typeDefinition = build(processingEnv, typeElement); + assertEquals(Color.class.getName(), typeDefinition.getType()); + assertEquals(asList("RED", "YELLOW", "BLUE"), typeDefinition.getEnums()); +// assertEquals(typeDefinition.getTypeBuilderName(), builder.getClass().getName()); + } + +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/GeneralTypeDefinitionBuilderTest.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/GeneralTypeDefinitionBuilderTest.java new file mode 100644 index 0000000000..33e27d3176 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/GeneralTypeDefinitionBuilderTest.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.builder; + +import org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest; +import org.apache.dubbo.metadata.annotation.processing.model.ArrayTypeModel; +import org.apache.dubbo.metadata.annotation.processing.model.CollectionTypeModel; +import org.apache.dubbo.metadata.annotation.processing.model.Color; +import org.apache.dubbo.metadata.annotation.processing.model.Model; +import org.apache.dubbo.metadata.annotation.processing.model.PrimitiveTypeModel; +import org.apache.dubbo.metadata.annotation.processing.model.SimpleTypeModel; + +import org.junit.jupiter.api.Test; + +import java.util.Set; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link GeneralTypeDefinitionBuilder} Test + * + * @since 2.7.6 + */ +public class GeneralTypeDefinitionBuilderTest extends AbstractAnnotationProcessingTest { + + private GeneralTypeDefinitionBuilder builder; + + @Override + protected void addCompiledClasses(Set> classesToBeCompiled) { + classesToBeCompiled.add(Model.class); + } + + @Override + protected void beforeEach() { + builder = new GeneralTypeDefinitionBuilder(); + } + + @Test + public void testAccept() { + assertTrue(builder.accept(processingEnv, getType(Model.class).asType())); + assertTrue(builder.accept(processingEnv, getType(PrimitiveTypeModel.class).asType())); + assertTrue(builder.accept(processingEnv, getType(SimpleTypeModel.class).asType())); + assertTrue(builder.accept(processingEnv, getType(ArrayTypeModel.class).asType())); + assertTrue(builder.accept(processingEnv, getType(CollectionTypeModel.class).asType())); + assertFalse(builder.accept(processingEnv, getType(Color.class).asType())); + } + + @Test + public void testBuild() { + + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/MapTypeDefinitionBuilderTest.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/MapTypeDefinitionBuilderTest.java new file mode 100644 index 0000000000..f7b32b5016 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/MapTypeDefinitionBuilderTest.java @@ -0,0 +1,134 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.builder; + +import org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest; +import org.apache.dubbo.metadata.annotation.processing.model.MapTypeModel; +import org.apache.dubbo.metadata.definition.model.TypeDefinition; + +import org.junit.jupiter.api.Test; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import java.util.Set; +import java.util.function.BiConsumer; +import java.util.stream.Stream; + +import static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.findField; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link MapTypeDefinitionBuilder} Test + * + * @since 2.7.6 + */ +public class MapTypeDefinitionBuilderTest extends AbstractAnnotationProcessingTest { + + private MapTypeDefinitionBuilder builder; + + private VariableElement stringsField; + + private VariableElement colorsField; + + private VariableElement primitiveTypeModelsField; + + private VariableElement modelsField; + + private VariableElement modelArraysField; + + @Override + protected void addCompiledClasses(Set> classesToBeCompiled) { + classesToBeCompiled.add(MapTypeModel.class); + } + + @Override + protected void beforeEach() { + builder = new MapTypeDefinitionBuilder(); + TypeElement testType = getType(MapTypeModel.class); + stringsField = findField( testType, "strings"); + colorsField = findField( testType, "colors"); + primitiveTypeModelsField = findField( testType, "primitiveTypeModels"); + modelsField = findField( testType, "models"); + modelArraysField = findField( testType, "modelArrays"); + + assertEquals("strings", stringsField.getSimpleName().toString()); + assertEquals("colors", colorsField.getSimpleName().toString()); + assertEquals("primitiveTypeModels", primitiveTypeModelsField.getSimpleName().toString()); + assertEquals("models", modelsField.getSimpleName().toString()); + assertEquals("modelArrays", modelArraysField.getSimpleName().toString()); + } + + @Test + public void testAccept() { + assertTrue(builder.accept(processingEnv, stringsField.asType())); + assertTrue(builder.accept(processingEnv, colorsField.asType())); + assertTrue(builder.accept(processingEnv, primitiveTypeModelsField.asType())); + assertTrue(builder.accept(processingEnv, modelsField.asType())); + assertTrue(builder.accept(processingEnv, modelArraysField.asType())); + } + + @Test + public void testBuild() { + + buildAndAssertTypeDefinition(processingEnv, stringsField, + "java.util.Map", + "java.lang.String", + "java.lang.String", + builder); + + buildAndAssertTypeDefinition(processingEnv, colorsField, + "java.util.SortedMap", + "java.lang.String", + "org.apache.dubbo.metadata.annotation.processing.model.Color", + builder); + + buildAndAssertTypeDefinition(processingEnv, primitiveTypeModelsField, + "java.util.NavigableMap", + "org.apache.dubbo.metadata.annotation.processing.model.Color", + "org.apache.dubbo.metadata.annotation.processing.model.PrimitiveTypeModel", + builder); + + buildAndAssertTypeDefinition(processingEnv, modelsField, + "java.util.HashMap", + "java.lang.String", + "org.apache.dubbo.metadata.annotation.processing.model.Model", + builder); + + buildAndAssertTypeDefinition(processingEnv, modelArraysField, + "java.util.TreeMap", + "org.apache.dubbo.metadata.annotation.processing.model.PrimitiveTypeModel", + "org.apache.dubbo.metadata.annotation.processing.model.Model[]", + builder); + } + + static void buildAndAssertTypeDefinition(ProcessingEnvironment processingEnv, VariableElement field, + String expectedType, String keyType, String valueType, + TypeDefinitionBuilder builder, + BiConsumer... assertions) { + TypeDefinition typeDefinition = TypeDefinitionBuilder.build(processingEnv, field); + TypeDefinition keyTypeDefinition = typeDefinition.getItems().get(0); + TypeDefinition valueTypeDefinition = typeDefinition.getItems().get(1); + assertEquals(expectedType, typeDefinition.getType()); +// assertEquals(field.getSimpleName().toString(), typeDefinition.get$ref()); + assertEquals(keyType, keyTypeDefinition.getType()); + assertEquals(valueType, valueTypeDefinition.getType()); +// assertEquals(builder.getClass().getName(), typeDefinition.getTypeBuilderName()); + Stream.of(assertions).forEach(assertion -> assertion.accept(typeDefinition, keyTypeDefinition)); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/PrimitiveTypeDefinitionBuilderTest.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/PrimitiveTypeDefinitionBuilderTest.java new file mode 100644 index 0000000000..adc25126cc --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/PrimitiveTypeDefinitionBuilderTest.java @@ -0,0 +1,130 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.builder; + +import org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest; +import org.apache.dubbo.metadata.annotation.processing.model.PrimitiveTypeModel; +import org.apache.dubbo.metadata.definition.model.TypeDefinition; + +import org.junit.jupiter.api.Test; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import java.util.Set; + +import static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.findField; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link PrimitiveTypeDefinitionBuilder} Test + * + * @since 2.7.6 + */ +public class PrimitiveTypeDefinitionBuilderTest extends AbstractAnnotationProcessingTest { + + private PrimitiveTypeDefinitionBuilder builder; + + private VariableElement zField; + + private VariableElement bField; + + private VariableElement cField; + + private VariableElement sField; + + private VariableElement iField; + + private VariableElement lField; + + private VariableElement fField; + + private VariableElement dField; + + @Override + protected void addCompiledClasses(Set> classesToBeCompiled) { + classesToBeCompiled.add(PrimitiveTypeModel.class); + } + + @Override + protected void beforeEach() { + + builder = new PrimitiveTypeDefinitionBuilder(); + + TypeElement testType = getType(PrimitiveTypeModel.class); + + zField = findField( testType, "z"); + bField = findField( testType, "b"); + cField = findField( testType, "c"); + sField = findField( testType, "s"); + iField = findField( testType, "i"); + lField = findField( testType, "l"); + fField = findField( testType, "f"); + dField = findField( testType, "d"); + + assertEquals("boolean", zField.asType().toString()); + assertEquals("byte", bField.asType().toString()); + assertEquals("char", cField.asType().toString()); + assertEquals("short", sField.asType().toString()); + assertEquals("int", iField.asType().toString()); + assertEquals("long", lField.asType().toString()); + assertEquals("float", fField.asType().toString()); + assertEquals("double", dField.asType().toString()); + } + + @Test + public void testAccept() { + assertTrue(builder.accept(processingEnv, zField.asType())); + assertTrue(builder.accept(processingEnv, bField.asType())); + assertTrue(builder.accept(processingEnv, cField.asType())); + assertTrue(builder.accept(processingEnv, sField.asType())); + assertTrue(builder.accept(processingEnv, iField.asType())); + assertTrue(builder.accept(processingEnv, lField.asType())); + assertTrue(builder.accept(processingEnv, fField.asType())); + assertTrue(builder.accept(processingEnv, dField.asType())); + } + + @Test + public void testBuild() { + buildAndAssertTypeDefinition(processingEnv, zField, builder); + buildAndAssertTypeDefinition(processingEnv, bField, builder); + buildAndAssertTypeDefinition(processingEnv, cField, builder); + buildAndAssertTypeDefinition(processingEnv, sField, builder); + buildAndAssertTypeDefinition(processingEnv, iField, builder); + buildAndAssertTypeDefinition(processingEnv, lField, builder); + buildAndAssertTypeDefinition(processingEnv, zField, builder); + buildAndAssertTypeDefinition(processingEnv, fField, builder); + buildAndAssertTypeDefinition(processingEnv, dField, builder); + } + + static void buildAndAssertTypeDefinition(ProcessingEnvironment processingEnv, VariableElement field, TypeDefinitionBuilder builder) { + TypeDefinition typeDefinition = TypeDefinitionBuilder.build(processingEnv, field); + assertBasicTypeDefinition(typeDefinition, field.asType().toString(), builder); +// assertEquals(field.getSimpleName().toString(), typeDefinition.get$ref()); + } + + static void assertBasicTypeDefinition(TypeDefinition typeDefinition, String type, TypeDefinitionBuilder builder) { + assertEquals(type, typeDefinition.getType()); +// assertEquals(builder.getClass().getName(), typeDefinition.getTypeBuilderName()); + assertTrue(typeDefinition.getProperties().isEmpty()); + assertTrue(typeDefinition.getItems().isEmpty()); + assertTrue(typeDefinition.getEnums().isEmpty()); + assertNull(typeDefinition.getId()); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/ServiceDefinitionBuilderTest.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/ServiceDefinitionBuilderTest.java new file mode 100644 index 0000000000..7f21cef54d --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/ServiceDefinitionBuilderTest.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.builder; + +import org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest; +import org.apache.dubbo.metadata.definition.model.ServiceDefinition; +import org.apache.dubbo.metadata.tools.TestServiceImpl; + +import org.junit.jupiter.api.Test; + +import java.util.Set; + +import static org.apache.dubbo.metadata.annotation.processing.builder.ServiceDefinitionBuilder.build; +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * {@link ServiceDefinitionBuilder} Test + * + * @since 2.7.6 + */ +public class ServiceDefinitionBuilderTest extends AbstractAnnotationProcessingTest { + + + @Override + protected void addCompiledClasses(Set> classesToBeCompiled) { + classesToBeCompiled.add(TestServiceImpl.class); + } + + @Override + protected void beforeEach() { + } + + @Test + public void testBuild() { + ServiceDefinition serviceDefinition = build(processingEnv, getType(TestServiceImpl.class)); + assertEquals(TestServiceImpl.class.getTypeName(), serviceDefinition.getCanonicalName()); + assertEquals("org/apache/dubbo/metadata/tools/TestServiceImpl.class", serviceDefinition.getCodeSource()); + // types + int i = 0; + assertEquals("org.apache.dubbo.metadata.tools.TestServiceImpl", serviceDefinition.getTypes().get(i++).getType()); + assertEquals("org.apache.dubbo.metadata.tools.GenericTestService", serviceDefinition.getTypes().get(i++).getType()); + assertEquals("org.apache.dubbo.metadata.tools.DefaultTestService", serviceDefinition.getTypes().get(i++).getType()); + assertEquals("org.apache.dubbo.metadata.tools.TestService", serviceDefinition.getTypes().get(i++).getType()); + assertEquals("java.lang.AutoCloseable", serviceDefinition.getTypes().get(i++).getType()); + assertEquals("java.io.Serializable", serviceDefinition.getTypes().get(i++).getType()); + assertEquals("java.util.EventListener", serviceDefinition.getTypes().get(i++).getType()); + // methods + assertEquals(14, serviceDefinition.getMethods().size()); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/SimpleTypeDefinitionBuilderTest.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/SimpleTypeDefinitionBuilderTest.java new file mode 100644 index 0000000000..97edf89655 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/SimpleTypeDefinitionBuilderTest.java @@ -0,0 +1,146 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.builder; + +import org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest; +import org.apache.dubbo.metadata.annotation.processing.model.SimpleTypeModel; + +import org.junit.jupiter.api.Test; + +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import java.util.Set; + +import static org.apache.dubbo.metadata.annotation.processing.builder.PrimitiveTypeDefinitionBuilderTest.buildAndAssertTypeDefinition; +import static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.findField; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link SimpleTypeDefinitionBuilder} Test + * + * @since 2.7.6 + */ +public class SimpleTypeDefinitionBuilderTest extends AbstractAnnotationProcessingTest { + + private SimpleTypeDefinitionBuilder builder; + + private VariableElement vField; + + private VariableElement zField; + + private VariableElement cField; + + private VariableElement bField; + + private VariableElement sField; + + private VariableElement iField; + + private VariableElement lField; + + private VariableElement fField; + + private VariableElement dField; + + private VariableElement strField; + + private VariableElement bdField; + + private VariableElement biField; + + private VariableElement dtField; + + private VariableElement invalidField; + + + @Override + protected void addCompiledClasses(Set> classesToBeCompiled) { + classesToBeCompiled.add(SimpleTypeModel.class); + } + + @Override + protected void beforeEach() { + builder = new SimpleTypeDefinitionBuilder(); + TypeElement testType = getType(SimpleTypeModel.class); + vField = findField(testType, "v"); + zField = findField(testType, "z"); + cField = findField(testType, "c"); + bField = findField(testType, "b"); + sField = findField(testType, "s"); + iField = findField(testType, "i"); + lField = findField(testType, "l"); + fField = findField(testType, "f"); + dField = findField(testType, "d"); + strField = findField(testType, "str"); + bdField = findField(testType, "bd"); + biField = findField(testType, "bi"); + dtField = findField(testType, "dt"); + invalidField = findField(testType, "invalid"); + + assertEquals("java.lang.Void", vField.asType().toString()); + assertEquals("java.lang.Boolean", zField.asType().toString()); + assertEquals("java.lang.Character", cField.asType().toString()); + assertEquals("java.lang.Byte", bField.asType().toString()); + assertEquals("java.lang.Short", sField.asType().toString()); + assertEquals("java.lang.Integer", iField.asType().toString()); + assertEquals("java.lang.Long", lField.asType().toString()); + assertEquals("java.lang.Float", fField.asType().toString()); + assertEquals("java.lang.Double", dField.asType().toString()); + assertEquals("java.lang.String", strField.asType().toString()); + assertEquals("java.math.BigDecimal", bdField.asType().toString()); + assertEquals("java.math.BigInteger", biField.asType().toString()); + assertEquals("java.util.Date", dtField.asType().toString()); + assertEquals("int", invalidField.asType().toString()); + } + + @Test + public void testAccept() { + assertTrue(builder.accept(processingEnv, vField.asType())); + assertTrue(builder.accept(processingEnv, zField.asType())); + assertTrue(builder.accept(processingEnv, cField.asType())); + assertTrue(builder.accept(processingEnv, bField.asType())); + assertTrue(builder.accept(processingEnv, sField.asType())); + assertTrue(builder.accept(processingEnv, iField.asType())); + assertTrue(builder.accept(processingEnv, lField.asType())); + assertTrue(builder.accept(processingEnv, fField.asType())); + assertTrue(builder.accept(processingEnv, dField.asType())); + assertTrue(builder.accept(processingEnv, strField.asType())); + assertTrue(builder.accept(processingEnv, bdField.asType())); + assertTrue(builder.accept(processingEnv, biField.asType())); + assertTrue(builder.accept(processingEnv, dtField.asType())); + // false condition + assertFalse(builder.accept(processingEnv, invalidField.asType())); + } + + @Test + public void testBuild() { + buildAndAssertTypeDefinition(processingEnv, vField, builder); + buildAndAssertTypeDefinition(processingEnv, zField, builder); + buildAndAssertTypeDefinition(processingEnv, cField, builder); + buildAndAssertTypeDefinition(processingEnv, sField, builder); + buildAndAssertTypeDefinition(processingEnv, iField, builder); + buildAndAssertTypeDefinition(processingEnv, lField, builder); + buildAndAssertTypeDefinition(processingEnv, fField, builder); + buildAndAssertTypeDefinition(processingEnv, dField, builder); + buildAndAssertTypeDefinition(processingEnv, strField, builder); + buildAndAssertTypeDefinition(processingEnv, bdField, builder); + buildAndAssertTypeDefinition(processingEnv, biField, builder); + buildAndAssertTypeDefinition(processingEnv, dtField, builder); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/ArrayTypeModel.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/ArrayTypeModel.java new file mode 100644 index 0000000000..28bf4f3111 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/ArrayTypeModel.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.model; + +/** + * Array Type Model + * + * @since 2.7.6 + */ +public class ArrayTypeModel { + + private int[] integers; // Primitive type array + + private String[] strings; // Simple type array + + private PrimitiveTypeModel[] primitiveTypeModels; // Complex type array + + private Model[] models; // Hierarchical Complex type array + + private Color[] colors; // Enum type array + +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/CollectionTypeModel.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/CollectionTypeModel.java new file mode 100644 index 0000000000..e90f1c8926 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/CollectionTypeModel.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.model; + +import java.util.Collection; +import java.util.Deque; +import java.util.List; +import java.util.Queue; +import java.util.Set; + +/** + * {@link Collection} Type Model + * + * @since 2.7.6 + */ +public class CollectionTypeModel { + + private Collection strings; // The composite element is simple type + + private List colors; // The composite element is Enum type + + private Queue primitiveTypeModels; // The composite element is POJO type + + private Deque models; // The composite element is hierarchical POJO type + + private Set modelArrays; // The composite element is hierarchical POJO type + +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/Color.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/Color.java new file mode 100644 index 0000000000..9fab9df62d --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/Color.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.model; + +/** + * Color enumeration + * + * @since 2.7.6 + */ +public enum Color { + + RED(1), + YELLOW(2), + BLUE(3); + + private final int value; + + Color(int value) { + this.value = value; + } + + @Override + public String toString() { + return "Color{" + + "value=" + value + + "} " + super.toString(); + } + + public int getValue() { + return value; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/MapTypeModel.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/MapTypeModel.java new file mode 100644 index 0000000000..087aa932ed --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/MapTypeModel.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.model; + +import java.util.HashMap; +import java.util.Map; +import java.util.NavigableMap; +import java.util.SortedMap; +import java.util.TreeMap; + +/** + * {@link Map} Type model + * + * @since 2.7.6 + */ +public class MapTypeModel { + + private Map strings; // The composite element is simple type + + private SortedMap colors; // The composite element is Enum type + + private NavigableMap primitiveTypeModels; // The composite element is POJO type + + private HashMap models; // The composite element is hierarchical POJO type + + private TreeMap modelArrays; // The composite element is hierarchical POJO type +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/Model.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/Model.java new file mode 100644 index 0000000000..e3c72a5e32 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/Model.java @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.model; + +import org.apache.dubbo.metadata.tools.Parent; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.concurrent.TimeUnit; + +/** + * Model Object + */ +public class Model extends Parent { + + private float f; + + private double d; + + private TimeUnit tu; + + private String str; + + private BigInteger bi; + + private BigDecimal bd; + + public float getF() { + return f; + } + + public void setF(float f) { + this.f = f; + } + + public double getD() { + return d; + } + + public void setD(double d) { + this.d = d; + } + + public TimeUnit getTu() { + return tu; + } + + public void setTu(TimeUnit tu) { + this.tu = tu; + } + + public String getStr() { + return str; + } + + public void setStr(String str) { + this.str = str; + } + + public BigInteger getBi() { + return bi; + } + + public void setBi(BigInteger bi) { + this.bi = bi; + } + + public BigDecimal getBd() { + return bd; + } + + public void setBd(BigDecimal bd) { + this.bd = bd; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/PrimitiveTypeModel.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/PrimitiveTypeModel.java new file mode 100644 index 0000000000..c013a7403b --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/PrimitiveTypeModel.java @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.model; + +/** + * Primitive Type model + * + * @since 2.7.6 + */ +public class PrimitiveTypeModel { + + private boolean z; + + private byte b; + + private char c; + + private short s; + + private int i; + + private long l; + + private float f; + + private double d; + + public boolean isZ() { + return z; + } + + public byte getB() { + return b; + } + + public char getC() { + return c; + } + + public short getS() { + return s; + } + + public int getI() { + return i; + } + + public long getL() { + return l; + } + + public float getF() { + return f; + } + + public double getD() { + return d; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/SimpleTypeModel.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/SimpleTypeModel.java new file mode 100644 index 0000000000..4b3523a2a5 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/SimpleTypeModel.java @@ -0,0 +1,161 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License; Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing; software + * distributed under the License is distributed on an "AS IS" BASIS; + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND; either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.model; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.Date; + +/** + * Simple Type model + * + * @since 2.7.6 + */ +public class SimpleTypeModel { + + private Void v; + + private Boolean z; + + private Character c; + + private Byte b; + + private Short s; + + private Integer i; + + private Long l; + + private Float f; + + private Double d; + + private String str; + + private BigDecimal bd; + + private BigInteger bi; + + private Date dt; + + private int invalid; + + public Void getV() { + return v; + } + + public void setV(Void v) { + this.v = v; + } + + public Boolean getZ() { + return z; + } + + public void setZ(Boolean z) { + this.z = z; + } + + public Character getC() { + return c; + } + + public void setC(Character c) { + this.c = c; + } + + public Byte getB() { + return b; + } + + public void setB(Byte b) { + this.b = b; + } + + public Short getS() { + return s; + } + + public void setS(Short s) { + this.s = s; + } + + public Integer getI() { + return i; + } + + public void setI(Integer i) { + this.i = i; + } + + public Long getL() { + return l; + } + + public void setL(Long l) { + this.l = l; + } + + public Float getF() { + return f; + } + + public void setF(Float f) { + this.f = f; + } + + public Double getD() { + return d; + } + + public void setD(Double d) { + this.d = d; + } + + public String getStr() { + return str; + } + + public void setStr(String str) { + this.str = str; + } + + public BigDecimal getBd() { + return bd; + } + + public void setBd(BigDecimal bd) { + this.bd = bd; + } + + public BigInteger getBi() { + return bi; + } + + public void setBi(BigInteger bi) { + this.bi = bi; + } + + public Date getDt() { + return dt; + } + + public void setDt(Date dt) { + this.dt = dt; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/rest/AnnotatedMethodParameterProcessorTest.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/rest/AnnotatedMethodParameterProcessorTest.java new file mode 100644 index 0000000000..825906b2f6 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/rest/AnnotatedMethodParameterProcessorTest.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.rest; + +import org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest; +import org.apache.dubbo.metadata.rest.RestMethodMetadata; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +/** + * The abstract class for {@link AnnotatedMethodParameterProcessor}'s test cases + * + * @since 2.7.6 + */ +public abstract class AnnotatedMethodParameterProcessorTest extends AbstractAnnotationProcessingTest { + + protected AnnotatedMethodParameterProcessor processor; + + protected RestMethodMetadata restMethodMetadata; + + protected abstract AnnotatedMethodParameterProcessor createTestInstance(); + + @BeforeEach + public final void prepare() { + this.processor = createTestInstance(); + this.restMethodMetadata = createRestMethodMetadata(); + } + + protected RestMethodMetadata createRestMethodMetadata() { + return new RestMethodMetadata(); + } + + protected abstract String getExpectedAnnotationType(); + + @Test + public void testGetAnnotationType() { + String expectedAnnotationType = getExpectedAnnotationType(); + assertNull(processor.getAnnotationType()); + assertEquals(expectedAnnotationType, processor.getAnnotationType()); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/AnnotationUtilsTest.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/AnnotationUtilsTest.java new file mode 100644 index 0000000000..cbc3dc12d9 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/AnnotationUtilsTest.java @@ -0,0 +1,231 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.util; + +import org.apache.dubbo.config.annotation.Service; +import org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest; +import org.apache.dubbo.metadata.rest.SpringRestService; +import org.apache.dubbo.metadata.tools.TestService; +import org.apache.dubbo.metadata.tools.TestServiceImpl; + +import org.junit.jupiter.api.Test; +import org.springframework.web.bind.annotation.GetMapping; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.TypeMirror; +import javax.ws.rs.Path; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.findAnnotation; +import static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.findMetaAnnotation; +import static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.getAllAnnotations; +import static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.getAnnotation; +import static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.getAnnotations; +import static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.getAttribute; +import static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.getValue; +import static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.isAnnotationPresent; +import static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.findMethod; +import static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.getAllDeclaredMethods; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * The {@link AnnotationUtils} Test + * + * @since 2.7.6 + */ +public class AnnotationUtilsTest extends AbstractAnnotationProcessingTest { + + private TypeElement testType; + + @Override + protected void addCompiledClasses(Set> classesToBeCompiled) { + } + + @Override + protected void beforeEach() { + testType = getType(TestServiceImpl.class); + } + + @Test + public void testGetAnnotation() { + AnnotationMirror serviceAnnotation = getAnnotation(testType, Service.class); + assertEquals("3.0.0", getAttribute(serviceAnnotation, "version")); + assertEquals("test", getAttribute(serviceAnnotation, "group")); + assertEquals("org.apache.dubbo.metadata.tools.TestService", getAttribute(serviceAnnotation, "interfaceName")); + + assertNull(getAnnotation(testType, (Class) null)); + assertNull(getAnnotation(testType, (String) null)); + + assertNull(getAnnotation(testType.asType(), (Class) null)); + assertNull(getAnnotation(testType.asType(), (String) null)); + + assertNull(getAnnotation((Element) null, (Class) null)); + assertNull(getAnnotation((Element) null, (String) null)); + + assertNull(getAnnotation((TypeElement) null, (Class) null)); + assertNull(getAnnotation((TypeElement) null, (String) null)); + } + + @Test + public void testGetAnnotations() { + List annotations = getAnnotations(testType); + Iterator iterator = annotations.iterator(); + + assertEquals(2, annotations.size()); + assertEquals("com.alibaba.dubbo.config.annotation.Service", iterator.next().getAnnotationType().toString()); + assertEquals("org.apache.dubbo.config.annotation.Service", iterator.next().getAnnotationType().toString()); + + annotations = getAnnotations(testType, Service.class); + iterator = annotations.iterator(); + assertEquals(1, annotations.size()); + assertEquals("org.apache.dubbo.config.annotation.Service", iterator.next().getAnnotationType().toString()); + + annotations = getAnnotations(testType.asType(), Service.class); + iterator = annotations.iterator(); + assertEquals(1, annotations.size()); + assertEquals("org.apache.dubbo.config.annotation.Service", iterator.next().getAnnotationType().toString()); + + annotations = getAnnotations(testType.asType(), Service.class.getTypeName()); + iterator = annotations.iterator(); + assertEquals(1, annotations.size()); + assertEquals("org.apache.dubbo.config.annotation.Service", iterator.next().getAnnotationType().toString()); + + annotations = getAnnotations(testType, Override.class); + assertEquals(0, annotations.size()); + + annotations = getAnnotations(testType, com.alibaba.dubbo.config.annotation.Service.class); + assertEquals(1, annotations.size()); + + assertTrue(getAnnotations(null, (Class) null).isEmpty()); + assertTrue(getAnnotations(null, (String) null).isEmpty()); + assertTrue(getAnnotations(testType, (Class) null).isEmpty()); + assertTrue(getAnnotations(testType, (String) null).isEmpty()); + + assertTrue(getAnnotations(null, Service.class).isEmpty()); + assertTrue(getAnnotations(null, Service.class.getTypeName()).isEmpty()); + } + + @Test + public void testGetAllAnnotations() { + + List annotations = getAllAnnotations(testType); + assertEquals(5, annotations.size()); + + annotations = getAllAnnotations(testType.asType(), annotation -> true); + assertEquals(5, annotations.size()); + + annotations = getAllAnnotations(processingEnv, TestServiceImpl.class); + assertEquals(5, annotations.size()); + + annotations = getAllAnnotations(testType.asType(), Service.class); + assertEquals(2, annotations.size()); + + annotations = getAllAnnotations(testType, Override.class); + assertEquals(0, annotations.size()); + + annotations = getAllAnnotations(testType.asType(), com.alibaba.dubbo.config.annotation.Service.class); + assertEquals(2, annotations.size()); + + assertTrue(getAllAnnotations((Element) null, (Class) null).isEmpty()); + assertTrue(getAllAnnotations((TypeMirror) null, (String) null).isEmpty()); + assertTrue(getAllAnnotations((ProcessingEnvironment) null, (Class) null).isEmpty()); + assertTrue(getAllAnnotations((ProcessingEnvironment) null, (String) null).isEmpty()); + + assertTrue(getAllAnnotations((Element) null).isEmpty()); + assertTrue(getAllAnnotations((TypeMirror) null).isEmpty()); + assertTrue(getAllAnnotations(processingEnv, (Class) null).isEmpty()); + assertTrue(getAllAnnotations(processingEnv, (String) null).isEmpty()); + + + assertTrue(getAllAnnotations(testType, (Class) null).isEmpty()); + assertTrue(getAllAnnotations(testType.asType(), (Class) null).isEmpty()); + + assertTrue(getAllAnnotations(testType, (String) null).isEmpty()); + assertTrue(getAllAnnotations(testType.asType(), (String) null).isEmpty()); + + assertTrue(getAllAnnotations((Element) null, Service.class).isEmpty()); + assertTrue(getAllAnnotations((TypeMirror) null, Service.class.getTypeName()).isEmpty()); + } + + + @Test + public void testFindAnnotation() { + + assertEquals("org.apache.dubbo.config.annotation.Service", findAnnotation(testType, Service.class).getAnnotationType().toString()); + assertEquals("com.alibaba.dubbo.config.annotation.Service", findAnnotation(testType, com.alibaba.dubbo.config.annotation.Service.class).getAnnotationType().toString()); + assertEquals("javax.ws.rs.Path", findAnnotation(testType, Path.class).getAnnotationType().toString()); + assertEquals("javax.ws.rs.Path", findAnnotation(testType.asType(), Path.class).getAnnotationType().toString()); + assertEquals("javax.ws.rs.Path", findAnnotation(testType.asType(), Path.class.getTypeName()).getAnnotationType().toString()); + assertNull(findAnnotation(testType, Override.class)); + + assertNull(findAnnotation((Element) null, (Class) null)); + assertNull(findAnnotation((Element) null, (String) null)); + assertNull(findAnnotation((TypeMirror) null, (Class) null)); + assertNull(findAnnotation((TypeMirror) null, (String) null)); + + assertNull(findAnnotation(testType, (Class) null)); + assertNull(findAnnotation(testType, (String) null)); + assertNull(findAnnotation(testType.asType(), (Class) null)); + assertNull(findAnnotation(testType.asType(), (String) null)); + } + + @Test + public void testFindMetaAnnotation() { + getAllDeclaredMethods(getType(TestService.class)).forEach(method -> { + assertEquals("javax.ws.rs.HttpMethod", findMetaAnnotation(method, "javax.ws.rs.HttpMethod").getAnnotationType().toString()); + }); + } + + @Test + public void testGetAttribute() { + assertEquals("org.apache.dubbo.metadata.tools.TestService", getAttribute(findAnnotation(testType, Service.class), "interfaceName")); + assertEquals("org.apache.dubbo.metadata.tools.TestService", getAttribute(findAnnotation(testType, Service.class).getElementValues(), "interfaceName")); + assertEquals("/echo", getAttribute(findAnnotation(testType, Path.class), "value")); + + assertNull(getAttribute(findAnnotation(testType, Path.class), null)); + assertNull(getAttribute(findAnnotation(testType, (Class) null), null)); + + ExecutableElement method = findMethod(getType(SpringRestService.class), "param", String.class); + + AnnotationMirror annotation = findAnnotation(method, GetMapping.class); + + assertArrayEquals(new String[]{"/param"}, (String[]) getAttribute(annotation, "value")); + assertNull(getAttribute(annotation, "path")); + } + + @Test + public void testGetValue() { + AnnotationMirror pathAnnotation = getAnnotation(getType(TestService.class), Path.class); + assertEquals("/echo", getValue(pathAnnotation)); + } + + @Test + public void testIsAnnotationPresent() { + assertTrue(isAnnotationPresent(testType, "org.apache.dubbo.config.annotation.Service")); + assertTrue(isAnnotationPresent(testType, "com.alibaba.dubbo.config.annotation.Service")); + assertTrue(isAnnotationPresent(testType, "javax.ws.rs.Path")); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/FieldUtilsTest.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/FieldUtilsTest.java new file mode 100644 index 0000000000..3afc647843 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/FieldUtilsTest.java @@ -0,0 +1,259 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.util; + +import org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest; +import org.apache.dubbo.metadata.annotation.processing.model.Color; +import org.apache.dubbo.metadata.annotation.processing.model.Model; +import org.apache.dubbo.metadata.tools.TestServiceImpl; + +import org.junit.jupiter.api.Test; + +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.TypeMirror; +import java.lang.reflect.Type; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.List; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import static javax.lang.model.element.Modifier.FINAL; +import static javax.lang.model.element.Modifier.PRIVATE; +import static javax.lang.model.element.Modifier.PUBLIC; +import static javax.lang.model.element.Modifier.STATIC; +import static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.findField; +import static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.getAllDeclaredFields; +import static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.getAllNonStaticFields; +import static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.getDeclaredField; +import static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.getDeclaredFields; +import static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.getNonStaticFields; +import static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.isEnumMemberField; +import static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.isField; +import static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.isNonStaticField; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link FieldUtils} Test + * + * @since 2.7.6 + */ +public class FieldUtilsTest extends AbstractAnnotationProcessingTest { + + private TypeElement testType; + + @Override + protected void addCompiledClasses(Set> classesToBeCompiled) { + } + + @Override + protected void beforeEach() { + testType = getType(TestServiceImpl.class); + } + + @Test + public void testGetDeclaredFields() { + TypeElement type = getType(Model.class); + List fields = getDeclaredFields(type); + assertModelFields(fields); + + fields = getDeclaredFields(type.asType()); + assertModelFields(fields); + + assertTrue(getDeclaredFields((Element) null).isEmpty()); + assertTrue(getDeclaredFields((TypeMirror) null).isEmpty()); + + fields = getDeclaredFields(type, f -> "f".equals(f.getSimpleName().toString())); + assertEquals(1, fields.size()); + assertEquals("f", fields.get(0).getSimpleName().toString()); + } + + @Test + public void testGetAllDeclaredFields() { + TypeElement type = getType(Model.class); + + List fields = getAllDeclaredFields(type); + + assertModelAllFields(fields); + + assertTrue(getAllDeclaredFields((Element) null).isEmpty()); + assertTrue(getAllDeclaredFields((TypeMirror) null).isEmpty()); + + fields = getAllDeclaredFields(type, f -> "f".equals(f.getSimpleName().toString())); + assertEquals(1, fields.size()); + assertEquals("f", fields.get(0).getSimpleName().toString()); + } + + @Test + public void testGetDeclaredField() { + TypeElement type = getType(Model.class); + testGetDeclaredField(type, "f", float.class); + testGetDeclaredField(type, "d", double.class); + testGetDeclaredField(type, "tu", TimeUnit.class); + testGetDeclaredField(type, "str", String.class); + testGetDeclaredField(type, "bi", BigInteger.class); + testGetDeclaredField(type, "bd", BigDecimal.class); + + assertNull(getDeclaredField(type, "b")); + assertNull(getDeclaredField(type, "s")); + assertNull(getDeclaredField(type, "i")); + assertNull(getDeclaredField(type, "l")); + assertNull(getDeclaredField(type, "z")); + + assertNull(getDeclaredField((Element) null, "z")); + assertNull(getDeclaredField((TypeMirror) null, "z")); + } + + @Test + public void testFindField() { + TypeElement type = getType(Model.class); + testFindField(type, "f", float.class); + testFindField(type, "d", double.class); + testFindField(type, "tu", TimeUnit.class); + testFindField(type, "str", String.class); + testFindField(type, "bi", BigInteger.class); + testFindField(type, "bd", BigDecimal.class); + testFindField(type, "b", byte.class); + testFindField(type, "s", short.class); + testFindField(type, "i", int.class); + testFindField(type, "l", long.class); + testFindField(type, "z", boolean.class); + + assertNull(findField((Element) null, "f")); + assertNull(findField((Element) null, null)); + + assertNull(findField((TypeMirror) null, "f")); + assertNull(findField((TypeMirror) null, null)); + + assertNull(findField(type, null)); + assertNull(findField(type.asType(), null)); + } + + @Test + public void testIsEnumField() { + TypeElement type = getType(Color.class); + VariableElement field = findField(type, "RED"); + assertTrue(isEnumMemberField(field)); + + field = findField(type, "YELLOW"); + assertTrue(isEnumMemberField(field)); + + field = findField(type, "BLUE"); + assertTrue(isEnumMemberField(field)); + + type = getType(Model.class); + field = findField(type, "f"); + assertFalse(isEnumMemberField(field)); + + assertFalse(isEnumMemberField(null)); + } + + @Test + public void testIsNonStaticField() { + TypeElement type = getType(Model.class); + assertTrue(isNonStaticField(findField(type, "f"))); + + type = getType(Color.class); + assertFalse(isNonStaticField(findField(type, "BLUE"))); + } + + @Test + public void testIsField() { + TypeElement type = getType(Model.class); + assertTrue(isField(findField(type, "f"))); + assertTrue(isField(findField(type, "f"), PRIVATE)); + + type = getType(Color.class); + assertTrue(isField(findField(type, "BLUE"), PUBLIC, STATIC, FINAL)); + + + assertFalse(isField(null)); + assertFalse(isField(null, PUBLIC, STATIC, FINAL)); + } + + @Test + public void testGetNonStaticFields() { + TypeElement type = getType(Model.class); + + List fields = getNonStaticFields(type); + assertModelFields(fields); + + fields = getNonStaticFields(type.asType()); + assertModelFields(fields); + + assertTrue(getAllNonStaticFields((Element) null).isEmpty()); + assertTrue(getAllNonStaticFields((TypeMirror) null).isEmpty()); + } + + @Test + public void testGetAllNonStaticFields() { + TypeElement type = getType(Model.class); + + List fields = getAllNonStaticFields(type); + assertModelAllFields(fields); + + fields = getAllNonStaticFields(type.asType()); + assertModelAllFields(fields); + + assertTrue(getAllNonStaticFields((Element) null).isEmpty()); + assertTrue(getAllNonStaticFields((TypeMirror) null).isEmpty()); + } + + private void assertModelFields(List fields) { + assertEquals(6, fields.size()); + assertEquals("d", fields.get(1).getSimpleName().toString()); + assertEquals("tu", fields.get(2).getSimpleName().toString()); + assertEquals("str", fields.get(3).getSimpleName().toString()); + assertEquals("bi", fields.get(4).getSimpleName().toString()); + assertEquals("bd", fields.get(5).getSimpleName().toString()); + } + + private void assertModelAllFields(List fields) { + assertEquals(11, fields.size()); + assertEquals("f", fields.get(0).getSimpleName().toString()); + assertEquals("d", fields.get(1).getSimpleName().toString()); + assertEquals("tu", fields.get(2).getSimpleName().toString()); + assertEquals("str", fields.get(3).getSimpleName().toString()); + assertEquals("bi", fields.get(4).getSimpleName().toString()); + assertEquals("bd", fields.get(5).getSimpleName().toString()); + assertEquals("b", fields.get(6).getSimpleName().toString()); + assertEquals("s", fields.get(7).getSimpleName().toString()); + assertEquals("i", fields.get(8).getSimpleName().toString()); + assertEquals("l", fields.get(9).getSimpleName().toString()); + assertEquals("z", fields.get(10).getSimpleName().toString()); + } + + private void testGetDeclaredField(TypeElement type, String fieldName, Type fieldType) { + VariableElement field = getDeclaredField(type, fieldName); + assertField(field, fieldName, fieldType); + } + + private void testFindField(TypeElement type, String fieldName, Type fieldType) { + VariableElement field = findField(type, fieldName); + assertField(field, fieldName, fieldType); + } + + private void assertField(VariableElement field, String fieldName, Type fieldType) { + assertEquals(fieldName, field.getSimpleName().toString()); + assertEquals(fieldType.getTypeName(), field.asType().toString()); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/LoggerUtilsTest.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/LoggerUtilsTest.java new file mode 100644 index 0000000000..4a06b216b1 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/LoggerUtilsTest.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.util; + +import org.junit.jupiter.api.Test; + +import static org.apache.dubbo.metadata.annotation.processing.util.LoggerUtils.info; +import static org.apache.dubbo.metadata.annotation.processing.util.LoggerUtils.warn; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +/** + * {@link LoggerUtils} Test + * + * @since 2.7.6 + */ +public class LoggerUtilsTest { + + @Test + public void testLogger() { + assertNotNull(LoggerUtils.LOGGER); + } + + @Test + public void testInfo() { + info("Hello,World"); + info("Hello,%s", "World"); + info("%s,%s", "Hello", "World"); + } + + @Test + public void testWarn() { + warn("Hello,World"); + warn("Hello,%s", "World"); + warn("%s,%s", "Hello", "World"); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/MemberUtilsTest.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/MemberUtilsTest.java new file mode 100644 index 0000000000..e119f00377 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/MemberUtilsTest.java @@ -0,0 +1,113 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.util; + +import org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest; +import org.apache.dubbo.metadata.annotation.processing.model.Model; +import org.apache.dubbo.metadata.tools.TestServiceImpl; + +import org.junit.jupiter.api.Test; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import java.util.List; +import java.util.Set; + +import static javax.lang.model.element.Modifier.PRIVATE; +import static javax.lang.model.util.ElementFilter.fieldsIn; +import static javax.lang.model.util.ElementFilter.methodsIn; +import static org.apache.dubbo.metadata.annotation.processing.util.MemberUtils.getAllDeclaredMembers; +import static org.apache.dubbo.metadata.annotation.processing.util.MemberUtils.getDeclaredMembers; +import static org.apache.dubbo.metadata.annotation.processing.util.MemberUtils.hasModifiers; +import static org.apache.dubbo.metadata.annotation.processing.util.MemberUtils.isPublicNonStatic; +import static org.apache.dubbo.metadata.annotation.processing.util.MemberUtils.matchParameterTypes; +import static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.findMethod; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link MemberUtils} Test + * + * @since 2.7.6 + */ +public class MemberUtilsTest extends AbstractAnnotationProcessingTest { + + private TypeElement testType; + + @Override + protected void addCompiledClasses(Set> classesToBeCompiled) { + } + + @Override + protected void beforeEach() { + testType = getType(TestServiceImpl.class); + } + + @Test + public void testIsPublicNonStatic() { + assertFalse(isPublicNonStatic(null)); + methodsIn(getDeclaredMembers(testType.asType())).forEach(method -> assertTrue(isPublicNonStatic(method))); + } + + @Test + public void testHasModifiers() { + assertFalse(hasModifiers(null)); + List members = getAllDeclaredMembers(testType.asType()); + List fields = fieldsIn(members); + assertTrue(hasModifiers(fields.get(0), PRIVATE)); + } + + @Test + public void testDeclaredMembers() { + TypeElement type = getType(Model.class); + List members = getDeclaredMembers(type.asType()); + List fields = fieldsIn(members); + assertEquals(19, members.size()); + assertEquals(6, fields.size()); + assertEquals("f", fields.get(0).getSimpleName().toString()); + assertEquals("d", fields.get(1).getSimpleName().toString()); + assertEquals("tu", fields.get(2).getSimpleName().toString()); + assertEquals("str", fields.get(3).getSimpleName().toString()); + assertEquals("bi", fields.get(4).getSimpleName().toString()); + assertEquals("bd", fields.get(5).getSimpleName().toString()); + + members = getAllDeclaredMembers(type.asType()); + fields = fieldsIn(members); + assertEquals(11, fields.size()); + assertEquals("f", fields.get(0).getSimpleName().toString()); + assertEquals("d", fields.get(1).getSimpleName().toString()); + assertEquals("tu", fields.get(2).getSimpleName().toString()); + assertEquals("str", fields.get(3).getSimpleName().toString()); + assertEquals("bi", fields.get(4).getSimpleName().toString()); + assertEquals("bd", fields.get(5).getSimpleName().toString()); + assertEquals("b", fields.get(6).getSimpleName().toString()); + assertEquals("s", fields.get(7).getSimpleName().toString()); + assertEquals("i", fields.get(8).getSimpleName().toString()); + assertEquals("l", fields.get(9).getSimpleName().toString()); + assertEquals("z", fields.get(10).getSimpleName().toString()); + } + + @Test + public void testMatchParameterTypes() { + ExecutableElement method = findMethod(testType, "echo", "java.lang.String"); + assertTrue(matchParameterTypes(method.getParameters(), "java.lang.String")); + assertFalse(matchParameterTypes(method.getParameters(), "java.lang.Object")); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/MethodUtilsTest.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/MethodUtilsTest.java new file mode 100644 index 0000000000..2e9c07c5da --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/MethodUtilsTest.java @@ -0,0 +1,195 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.util; + +import org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest; +import org.apache.dubbo.metadata.annotation.processing.model.Model; +import org.apache.dubbo.metadata.tools.TestService; +import org.apache.dubbo.metadata.tools.TestServiceImpl; + +import org.junit.jupiter.api.Test; + +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.TypeMirror; +import java.util.List; +import java.util.Set; + +import static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.findMethod; +import static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.getAllDeclaredMethods; +import static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.getDeclaredMethods; +import static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.getMethodName; +import static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.getMethodParameterTypes; +import static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.getOverrideMethod; +import static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.getPublicNonStaticMethods; +import static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.getReturnType; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link MethodUtils} Test + * + * @since 2.7.6 + */ +public class MethodUtilsTest extends AbstractAnnotationProcessingTest { + + private TypeElement testType; + + @Override + protected void addCompiledClasses(Set> classesToBeCompiled) { + } + + @Override + protected void beforeEach() { + testType = getType(TestServiceImpl.class); + } + + @Test + public void testDeclaredMethods() { + TypeElement type = getType(Model.class); + List methods = getDeclaredMethods(type); + assertEquals(12, methods.size()); + + methods = getAllDeclaredMethods(type); + assertEquals(34, methods.size()); + + assertTrue(getAllDeclaredMethods((TypeElement) null).isEmpty()); + assertTrue(getAllDeclaredMethods((TypeMirror) null).isEmpty()); + } + + private List doGetAllDeclaredMethods() { + return getAllDeclaredMethods(testType, Object.class); + } + + @Test + public void testGetAllDeclaredMethods() { + List methods = doGetAllDeclaredMethods(); + assertEquals(14, methods.size()); + } + + @Test + public void testGetPublicNonStaticMethods() { + List methods = getPublicNonStaticMethods(testType, Object.class); + assertEquals(14, methods.size()); + + methods = getPublicNonStaticMethods(testType.asType(), Object.class); + assertEquals(14, methods.size()); + } + + @Test + public void testIsMethod() { + List methods = getPublicNonStaticMethods(testType, Object.class); + assertEquals(14, methods.stream().map(MethodUtils::isMethod).count()); + } + + @Test + public void testIsPublicNonStaticMethod() { + List methods = getPublicNonStaticMethods(testType, Object.class); + assertEquals(14, methods.stream().map(MethodUtils::isPublicNonStaticMethod).count()); + } + + @Test + public void testFindMethod() { + TypeElement type = getType(Model.class); + // Test methods from java.lang.Object + // Object#toString() + String methodName = "toString"; + ExecutableElement method = findMethod(type.asType(), methodName); + assertEquals(method.getSimpleName().toString(), methodName); + + // Object#hashCode() + methodName = "hashCode"; + method = findMethod(type.asType(), methodName); + assertEquals(method.getSimpleName().toString(), methodName); + + // Object#getClass() + methodName = "getClass"; + method = findMethod(type.asType(), methodName); + assertEquals(method.getSimpleName().toString(), methodName); + + // Object#finalize() + methodName = "finalize"; + method = findMethod(type.asType(), methodName); + assertEquals(method.getSimpleName().toString(), methodName); + + // Object#clone() + methodName = "clone"; + method = findMethod(type.asType(), methodName); + assertEquals(method.getSimpleName().toString(), methodName); + + // Object#notify() + methodName = "notify"; + method = findMethod(type.asType(), methodName); + assertEquals(method.getSimpleName().toString(), methodName); + + // Object#notifyAll() + methodName = "notifyAll"; + method = findMethod(type.asType(), methodName); + assertEquals(method.getSimpleName().toString(), methodName); + + // Object#wait(long) + methodName = "wait"; + method = findMethod(type.asType(), methodName, long.class); + assertEquals(method.getSimpleName().toString(), methodName); + + // Object#wait(long,int) + methodName = "wait"; + method = findMethod(type.asType(), methodName, long.class, int.class); + assertEquals(method.getSimpleName().toString(), methodName); + + // Object#equals(Object) + methodName = "equals"; + method = findMethod(type.asType(), methodName, Object.class); + assertEquals(method.getSimpleName().toString(), methodName); + } + + @Test + public void testGetOverrideMethod() { + List methods = doGetAllDeclaredMethods(); + + ExecutableElement overrideMethod = getOverrideMethod(processingEnv, testType, methods.get(0)); + assertNull(overrideMethod); + + ExecutableElement declaringMethod = findMethod(getType(TestService.class), "echo", "java.lang.String"); + + overrideMethod = getOverrideMethod(processingEnv, testType, declaringMethod); + assertEquals(methods.get(0), overrideMethod); + } + + @Test + public void testGetMethodName() { + ExecutableElement method = findMethod(testType, "echo", "java.lang.String"); + assertEquals("echo", getMethodName(method)); + assertNull(getMethodName(null)); + } + + @Test + public void testReturnType() { + ExecutableElement method = findMethod(testType, "echo", "java.lang.String"); + assertEquals("java.lang.String", getReturnType(method)); + assertNull(getReturnType(null)); + } + + @Test + public void testMatchParameterTypes() { + ExecutableElement method = findMethod(testType, "echo", "java.lang.String"); + assertArrayEquals(new String[]{"java.lang.String"}, getMethodParameterTypes(method)); + assertTrue(getMethodParameterTypes(null).length == 0); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/ServiceAnnotationUtilsTest.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/ServiceAnnotationUtilsTest.java new file mode 100644 index 0000000000..9d18ddf681 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/ServiceAnnotationUtilsTest.java @@ -0,0 +1,136 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.util; + +import org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest; +import org.apache.dubbo.metadata.tools.DefaultTestService; +import org.apache.dubbo.metadata.tools.GenericTestService; +import org.apache.dubbo.metadata.tools.TestService; +import org.apache.dubbo.metadata.tools.TestServiceImpl; + +import org.junit.jupiter.api.Test; + +import javax.lang.model.element.TypeElement; +import java.util.HashSet; +import java.util.Set; + +import static java.util.Arrays.asList; +import static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.GROUP_ATTRIBUTE_NAME; +import static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.INTERFACE_CLASS_ATTRIBUTE_NAME; +import static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.INTERFACE_NAME_ATTRIBUTE_NAME; +import static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.LEGACY_SERVICE_ANNOTATION_TYPE; +import static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.SERVICE_ANNOTATION_TYPE; +import static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.SUPPORTED_ANNOTATION_TYPES; +import static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.VERSION_ATTRIBUTE_NAME; +import static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.getAnnotation; +import static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.getGroup; +import static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.getVersion; +import static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.isServiceAnnotationPresent; +import static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.resolveServiceInterfaceName; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link ServiceAnnotationUtils} Test + * + * @since 2.7.6 + */ +public class ServiceAnnotationUtilsTest extends AbstractAnnotationProcessingTest { + + @Override + protected void addCompiledClasses(Set> classesToBeCompiled) { + + } + + @Override + protected void beforeEach() { + + } + + @Test + public void testConstants() { + assertEquals("org.apache.dubbo.config.annotation.Service", SERVICE_ANNOTATION_TYPE); + assertEquals("com.alibaba.dubbo.config.annotation.Service", LEGACY_SERVICE_ANNOTATION_TYPE); + assertEquals("interfaceClass", INTERFACE_CLASS_ATTRIBUTE_NAME); + assertEquals("interfaceName", INTERFACE_NAME_ATTRIBUTE_NAME); + assertEquals("group", GROUP_ATTRIBUTE_NAME); + assertEquals("version", VERSION_ATTRIBUTE_NAME); + assertEquals(new HashSet(asList("org.apache.dubbo.config.annotation.Service", "com.alibaba.dubbo.config.annotation.Service")), SUPPORTED_ANNOTATION_TYPES); + } + + @Test + public void testIsServiceAnnotationPresent() { + + assertTrue(isServiceAnnotationPresent(getType(TestServiceImpl.class))); + assertTrue(isServiceAnnotationPresent(getType(GenericTestService.class))); + assertTrue(isServiceAnnotationPresent(getType(DefaultTestService.class))); + + assertFalse(isServiceAnnotationPresent(getType(TestService.class))); + } + + @Test + public void testGetAnnotation() { + TypeElement type = getType(TestServiceImpl.class); + assertEquals("org.apache.dubbo.config.annotation.Service", getAnnotation(type).getAnnotationType().toString()); + + type = getType(GenericTestService.class); + assertEquals("com.alibaba.dubbo.config.annotation.Service", getAnnotation(type).getAnnotationType().toString()); + + type = getType(DefaultTestService.class); + assertEquals("org.apache.dubbo.config.annotation.Service", getAnnotation(type).getAnnotationType().toString()); + + assertThrows(IllegalArgumentException.class, () -> getAnnotation(getType(TestService.class))); + } + + @Test + public void testResolveServiceInterfaceName() { + TypeElement type = getType(TestServiceImpl.class); + assertEquals("org.apache.dubbo.metadata.tools.TestService", resolveServiceInterfaceName(type, getAnnotation(type))); + + type = getType(GenericTestService.class); + assertEquals("org.apache.dubbo.metadata.tools.TestService", resolveServiceInterfaceName(type, getAnnotation(type))); + + type = getType(DefaultTestService.class); + assertEquals("org.apache.dubbo.metadata.tools.TestService", resolveServiceInterfaceName(type, getAnnotation(type))); + } + + @Test + public void testGetVersion() { + TypeElement type = getType(TestServiceImpl.class); + assertEquals("3.0.0", getVersion(getAnnotation(type))); + + type = getType(GenericTestService.class); + assertEquals("2.0.0", getVersion(getAnnotation(type))); + + type = getType(DefaultTestService.class); + assertEquals("1.0.0", getVersion(getAnnotation(type))); + } + + @Test + public void testGetGroup() { + TypeElement type = getType(TestServiceImpl.class); + assertEquals("test",getGroup(getAnnotation(type))); + + type = getType(GenericTestService.class); + assertEquals("generic", getGroup(getAnnotation(type))); + + type = getType(DefaultTestService.class); + assertEquals("default", getGroup(getAnnotation(type))); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/TypeUtilsTest.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/TypeUtilsTest.java new file mode 100644 index 0000000000..55d866ebaa --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/TypeUtilsTest.java @@ -0,0 +1,468 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.util; + +import org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest; +import org.apache.dubbo.metadata.annotation.processing.model.ArrayTypeModel; +import org.apache.dubbo.metadata.annotation.processing.model.Color; +import org.apache.dubbo.metadata.annotation.processing.model.Model; +import org.apache.dubbo.metadata.annotation.processing.model.PrimitiveTypeModel; +import org.apache.dubbo.metadata.tools.DefaultTestService; +import org.apache.dubbo.metadata.tools.GenericTestService; +import org.apache.dubbo.metadata.tools.TestServiceImpl; + +import org.junit.jupiter.api.Test; + +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; +import java.io.File; +import java.lang.reflect.Type; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.Date; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import static java.util.Arrays.asList; +import static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.findField; +import static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.getDeclaredFields; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.getAllInterfaces; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.getAllSuperTypes; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.getHierarchicalTypes; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.getInterfaces; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.getResource; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.getResourceName; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.getSuperType; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isAnnotationType; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isArrayType; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isClassType; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isDeclaredType; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isEnumType; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isInterfaceType; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isPrimitiveType; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isSameType; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isSimpleType; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isTypeElement; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.listDeclaredTypes; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.listTypeElements; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.ofDeclaredType; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.ofDeclaredTypes; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.ofTypeElement; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * The {@link TypeUtils} Test + * + * @since 2.7.6 + */ +public class TypeUtilsTest extends AbstractAnnotationProcessingTest { + + private TypeElement testType; + + @Override + protected void addCompiledClasses(Set> classesToBeCompiled) { + classesToBeCompiled.add(ArrayTypeModel.class); + classesToBeCompiled.add(Color.class); + } + + @Override + protected void beforeEach() { + testType = getType(TestServiceImpl.class); + } + + @Test + public void testIsSimpleType() { + + assertTrue(isSimpleType(getType(Void.class))); + assertTrue(isSimpleType(getType(Boolean.class))); + assertTrue(isSimpleType(getType(Character.class))); + assertTrue(isSimpleType(getType(Byte.class))); + assertTrue(isSimpleType(getType(Short.class))); + assertTrue(isSimpleType(getType(Integer.class))); + assertTrue(isSimpleType(getType(Long.class))); + assertTrue(isSimpleType(getType(Float.class))); + assertTrue(isSimpleType(getType(Double.class))); + assertTrue(isSimpleType(getType(String.class))); + assertTrue(isSimpleType(getType(BigDecimal.class))); + assertTrue(isSimpleType(getType(BigInteger.class))); + assertTrue(isSimpleType(getType(Date.class))); + assertTrue(isSimpleType(getType(Object.class))); + + assertFalse(isSimpleType(getType(getClass()))); + assertFalse(isSimpleType((TypeElement) null)); + assertFalse(isSimpleType((TypeMirror) null)); + } + + @Test + public void testIsSameType() { + assertTrue(isSameType(getType(Void.class).asType(), "java.lang.Void")); + assertFalse(isSameType(getType(String.class).asType(), "java.lang.Void")); + + assertFalse(isSameType(getType(Void.class).asType(), (Type) null)); + assertFalse(isSameType(null, (Type) null)); + + assertFalse(isSameType(getType(Void.class).asType(), (String) null)); + assertFalse(isSameType(null, (String) null)); + } + + @Test + public void testIsArrayType() { + TypeElement type = getType(ArrayTypeModel.class); + assertTrue(isArrayType(findField(type.asType(), "integers").asType())); + assertTrue(isArrayType(findField(type.asType(), "strings").asType())); + assertTrue(isArrayType(findField(type.asType(), "primitiveTypeModels").asType())); + assertTrue(isArrayType(findField(type.asType(), "models").asType())); + assertTrue(isArrayType(findField(type.asType(), "colors").asType())); + + assertFalse(isArrayType((Element) null)); + assertFalse(isArrayType((TypeMirror) null)); + } + + @Test + public void testIsEnumType() { + TypeElement type = getType(Color.class); + assertTrue(isEnumType(type.asType())); + + type = getType(ArrayTypeModel.class); + assertFalse(isEnumType(type.asType())); + + assertFalse(isEnumType((Element) null)); + assertFalse(isEnumType((TypeMirror) null)); + } + + @Test + public void testIsClassType() { + TypeElement type = getType(ArrayTypeModel.class); + assertTrue(isClassType(type.asType())); + + type = getType(Model.class); + assertTrue(isClassType(type.asType())); + + assertFalse(isClassType((Element) null)); + assertFalse(isClassType((TypeMirror) null)); + } + + @Test + public void testIsPrimitiveType() { + TypeElement type = getType(PrimitiveTypeModel.class); + getDeclaredFields(type.asType()) + .stream() + .map(VariableElement::asType) + .forEach(t -> assertTrue(isPrimitiveType(t))); + + assertFalse(isPrimitiveType(getType(ArrayTypeModel.class))); + + assertFalse(isPrimitiveType((Element) null)); + assertFalse(isPrimitiveType((TypeMirror) null)); + } + + @Test + public void testIsInterfaceType() { + TypeElement type = getType(CharSequence.class); + assertTrue(isInterfaceType(type)); + assertTrue(isInterfaceType(type.asType())); + + type = getType(Model.class); + assertFalse(isInterfaceType(type)); + assertFalse(isInterfaceType(type.asType())); + + assertFalse(isInterfaceType((Element) null)); + assertFalse(isInterfaceType((TypeMirror) null)); + } + + @Test + public void testIsAnnotationType() { + TypeElement type = getType(Override.class); + + assertTrue(isAnnotationType(type)); + assertTrue(isAnnotationType(type.asType())); + + type = getType(Model.class); + assertFalse(isAnnotationType(type)); + assertFalse(isAnnotationType(type.asType())); + + assertFalse(isAnnotationType((Element) null)); + assertFalse(isAnnotationType((TypeMirror) null)); + } + + @Test + public void testGetHierarchicalTypes() { + Set hierarchicalTypes = getHierarchicalTypes(testType.asType(), true, true, true); + Iterator iterator = hierarchicalTypes.iterator(); + assertEquals(8, hierarchicalTypes.size()); + assertEquals("org.apache.dubbo.metadata.tools.TestServiceImpl", iterator.next().toString()); + assertEquals("org.apache.dubbo.metadata.tools.GenericTestService", iterator.next().toString()); + assertEquals("org.apache.dubbo.metadata.tools.DefaultTestService", iterator.next().toString()); + assertEquals("java.lang.Object", iterator.next().toString()); + assertEquals("org.apache.dubbo.metadata.tools.TestService", iterator.next().toString()); + assertEquals("java.lang.AutoCloseable", iterator.next().toString()); + assertEquals("java.io.Serializable", iterator.next().toString()); + assertEquals("java.util.EventListener", iterator.next().toString()); + + hierarchicalTypes = getHierarchicalTypes(testType); + iterator = hierarchicalTypes.iterator(); + assertEquals(8, hierarchicalTypes.size()); + assertEquals("org.apache.dubbo.metadata.tools.TestServiceImpl", iterator.next().toString()); + assertEquals("org.apache.dubbo.metadata.tools.GenericTestService", iterator.next().toString()); + assertEquals("org.apache.dubbo.metadata.tools.DefaultTestService", iterator.next().toString()); + assertEquals("java.lang.Object", iterator.next().toString()); + assertEquals("org.apache.dubbo.metadata.tools.TestService", iterator.next().toString()); + assertEquals("java.lang.AutoCloseable", iterator.next().toString()); + assertEquals("java.io.Serializable", iterator.next().toString()); + assertEquals("java.util.EventListener", iterator.next().toString()); + + hierarchicalTypes = getHierarchicalTypes(testType.asType(), Object.class); + iterator = hierarchicalTypes.iterator(); + assertEquals(7, hierarchicalTypes.size()); + assertEquals("org.apache.dubbo.metadata.tools.TestServiceImpl", iterator.next().toString()); + assertEquals("org.apache.dubbo.metadata.tools.GenericTestService", iterator.next().toString()); + assertEquals("org.apache.dubbo.metadata.tools.DefaultTestService", iterator.next().toString()); + assertEquals("org.apache.dubbo.metadata.tools.TestService", iterator.next().toString()); + assertEquals("java.lang.AutoCloseable", iterator.next().toString()); + assertEquals("java.io.Serializable", iterator.next().toString()); + assertEquals("java.util.EventListener", iterator.next().toString()); + + hierarchicalTypes = getHierarchicalTypes(testType.asType(), true, true, false); + iterator = hierarchicalTypes.iterator(); + assertEquals(4, hierarchicalTypes.size()); + assertEquals("org.apache.dubbo.metadata.tools.TestServiceImpl", iterator.next().toString()); + assertEquals("org.apache.dubbo.metadata.tools.GenericTestService", iterator.next().toString()); + assertEquals("org.apache.dubbo.metadata.tools.DefaultTestService", iterator.next().toString()); + assertEquals("java.lang.Object", iterator.next().toString()); + + hierarchicalTypes = getHierarchicalTypes(testType.asType(), true, false, true); + iterator = hierarchicalTypes.iterator(); + assertEquals(5, hierarchicalTypes.size()); + assertEquals("org.apache.dubbo.metadata.tools.TestServiceImpl", iterator.next().toString()); + assertEquals("org.apache.dubbo.metadata.tools.TestService", iterator.next().toString()); + assertEquals("java.lang.AutoCloseable", iterator.next().toString()); + assertEquals("java.io.Serializable", iterator.next().toString()); + assertEquals("java.util.EventListener", iterator.next().toString()); + + hierarchicalTypes = getHierarchicalTypes(testType.asType(), false, false, true); + iterator = hierarchicalTypes.iterator(); + assertEquals(4, hierarchicalTypes.size()); + assertEquals("org.apache.dubbo.metadata.tools.TestService", iterator.next().toString()); + assertEquals("java.lang.AutoCloseable", iterator.next().toString()); + assertEquals("java.io.Serializable", iterator.next().toString()); + assertEquals("java.util.EventListener", iterator.next().toString()); + + hierarchicalTypes = getHierarchicalTypes(testType.asType(), true, false, false); + iterator = hierarchicalTypes.iterator(); + assertEquals(1, hierarchicalTypes.size()); + assertEquals("org.apache.dubbo.metadata.tools.TestServiceImpl", iterator.next().toString()); + + hierarchicalTypes = getHierarchicalTypes(testType.asType(), false, false, false); + assertEquals(0, hierarchicalTypes.size()); + + assertTrue(getHierarchicalTypes((TypeElement) null).isEmpty()); + assertTrue(getHierarchicalTypes((TypeMirror) null).isEmpty()); + } + + + @Test + public void testGetInterfaces() { + TypeElement type = getType(Model.class); + List interfaces = getInterfaces(type); + assertTrue(interfaces.isEmpty()); + + interfaces = getInterfaces(testType.asType()); + + assertEquals(3, interfaces.size()); + assertEquals("org.apache.dubbo.metadata.tools.TestService", interfaces.get(0).toString()); + assertEquals("java.lang.AutoCloseable", interfaces.get(1).toString()); + assertEquals("java.io.Serializable", interfaces.get(2).toString()); + + assertTrue(getInterfaces((TypeElement) null).isEmpty()); + assertTrue(getInterfaces((TypeMirror) null).isEmpty()); + } + + @Test + public void testGetAllInterfaces() { + Set interfaces = getAllInterfaces(testType.asType()); + assertEquals(4, interfaces.size()); + Iterator iterator = interfaces.iterator(); + assertEquals("org.apache.dubbo.metadata.tools.TestService", iterator.next().toString()); + assertEquals("java.lang.AutoCloseable", iterator.next().toString()); + assertEquals("java.io.Serializable", iterator.next().toString()); + assertEquals("java.util.EventListener", iterator.next().toString()); + + Set allInterfaces = getAllInterfaces(testType); + assertEquals(4, interfaces.size()); + + Iterator allIterator = allInterfaces.iterator(); + assertEquals("org.apache.dubbo.metadata.tools.TestService", allIterator.next().toString()); + assertEquals("java.lang.AutoCloseable", allIterator.next().toString()); + assertEquals("java.io.Serializable", allIterator.next().toString()); + assertEquals("java.util.EventListener", allIterator.next().toString()); + + assertTrue(getAllInterfaces((TypeElement) null).isEmpty()); + assertTrue(getAllInterfaces((TypeMirror) null).isEmpty()); + } + + @Test + public void testGetType() { + TypeElement element = TypeUtils.getType(processingEnv, String.class); + assertEquals(element, TypeUtils.getType(processingEnv, element.asType())); + assertEquals(element, TypeUtils.getType(processingEnv, "java.lang.String")); + + assertNull(TypeUtils.getType(processingEnv, (Type) null)); + assertNull(TypeUtils.getType(processingEnv, (TypeMirror) null)); + assertNull(TypeUtils.getType(processingEnv, (CharSequence) null)); + assertNull(TypeUtils.getType(null, (CharSequence) null)); + } + + @Test + public void testGetSuperType() { + TypeElement gtsTypeElement = getSuperType(testType); + assertEquals(gtsTypeElement, getType(GenericTestService.class)); + TypeElement dtsTypeElement = getSuperType(gtsTypeElement); + assertEquals(dtsTypeElement, getType(DefaultTestService.class)); + + TypeMirror gtsType = getSuperType(testType.asType()); + assertEquals(gtsType, getType(GenericTestService.class).asType()); + TypeMirror dtsType = getSuperType(gtsType); + assertEquals(dtsType, getType(DefaultTestService.class).asType()); + + assertNull(getSuperType((TypeElement) null)); + assertNull(getSuperType((TypeMirror) null)); + } + + @Test + public void testGetAllSuperTypes() { + Set allSuperTypes = getAllSuperTypes(testType); + Iterator iterator = allSuperTypes.iterator(); + assertEquals(3, allSuperTypes.size()); + assertEquals(iterator.next(), getType(GenericTestService.class)); + assertEquals(iterator.next(), getType(DefaultTestService.class)); + assertEquals(iterator.next(), getType(Object.class)); + + allSuperTypes = getAllSuperTypes(testType); + iterator = allSuperTypes.iterator(); + assertEquals(3, allSuperTypes.size()); + assertEquals(iterator.next(), getType(GenericTestService.class)); + assertEquals(iterator.next(), getType(DefaultTestService.class)); + assertEquals(iterator.next(), getType(Object.class)); + + assertTrue(getAllSuperTypes((TypeElement) null).isEmpty()); + assertTrue(getAllSuperTypes((TypeMirror) null).isEmpty()); + } + + @Test + public void testIsDeclaredType() { + assertTrue(isDeclaredType(testType)); + assertTrue(isDeclaredType(testType.asType())); + assertFalse(isDeclaredType((Element) null)); + assertFalse(isDeclaredType((TypeMirror) null)); + assertFalse(isDeclaredType(types.getNullType())); + assertFalse(isDeclaredType(types.getPrimitiveType(TypeKind.BYTE))); + assertFalse(isDeclaredType(types.getArrayType(types.getPrimitiveType(TypeKind.BYTE)))); + } + + @Test + public void testOfDeclaredType() { + assertEquals(testType.asType(), ofDeclaredType(testType)); + assertEquals(testType.asType(), ofDeclaredType(testType.asType())); + assertEquals(ofDeclaredType(testType), ofDeclaredType(testType.asType())); + + assertNull(ofDeclaredType((Element) null)); + assertNull(ofDeclaredType((TypeMirror) null)); + } + + @Test + public void testIsTypeElement() { + assertTrue(isTypeElement(testType)); + assertTrue(isTypeElement(testType.asType())); + + assertFalse(isTypeElement((Element) null)); + assertFalse(isTypeElement((TypeMirror) null)); + } + + @Test + public void testOfTypeElement() { + assertEquals(testType, ofTypeElement(testType)); + assertEquals(testType, ofTypeElement(testType.asType())); + + assertNull(ofTypeElement((Element) null)); + assertNull(ofTypeElement((TypeMirror) null)); + } + + @Test + public void testOfDeclaredTypes() { + Set declaredTypes = ofDeclaredTypes(asList(getType(String.class), getType(TestServiceImpl.class), getType(Color.class))); + assertTrue(declaredTypes.contains(getType(String.class).asType())); + assertTrue(declaredTypes.contains(getType(TestServiceImpl.class).asType())); + assertTrue(declaredTypes.contains(getType(Color.class).asType())); + + assertTrue(ofDeclaredTypes(null).isEmpty()); + } + + @Test + public void testListDeclaredTypes() { + List types = listDeclaredTypes(asList(testType, testType, testType)); + assertEquals(1, types.size()); + assertEquals(ofDeclaredType(testType), types.get(0)); + + types = listDeclaredTypes(asList(new Element[]{null})); + assertTrue(types.isEmpty()); + } + + @Test + public void testListTypeElements() { + List typeElements = listTypeElements(asList(testType.asType(), ofDeclaredType(testType))); + assertEquals(1, typeElements.size()); + assertEquals(testType, typeElements.get(0)); + + typeElements = listTypeElements(asList(types.getPrimitiveType(TypeKind.BYTE), types.getNullType(), types.getNoType(TypeKind.NONE))); + assertTrue(typeElements.isEmpty()); + + typeElements = listTypeElements(asList(new TypeMirror[]{null})); + assertTrue(typeElements.isEmpty()); + + typeElements = listTypeElements(null); + assertTrue(typeElements.isEmpty()); + } + + @Test + public void testGetResource() throws URISyntaxException { + URL resource = getResource(processingEnv, testType); + assertNotNull(resource); + assertTrue(new File(resource.toURI()).exists()); + assertEquals(resource, getResource(processingEnv, testType.asType())); + assertEquals(resource, getResource(processingEnv, "org.apache.dubbo.metadata.tools.TestServiceImpl")); + + assertThrows(RuntimeException.class, () -> getResource(processingEnv, "NotFound")); + } + + @Test + public void testGetResourceName() { + assertEquals("java/lang/String.class", getResourceName("java.lang.String")); + assertNull(getResourceName(null)); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/rest/DefaultRestService.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/rest/DefaultRestService.java new file mode 100644 index 0000000000..2c2245741f --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/rest/DefaultRestService.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.rest; + +import org.apache.dubbo.config.annotation.Service; + +import java.util.Map; + +/** + * The default implementation of {@link RestService} + * + * @since 2.7.6 + */ +@Service(version = "1.0.0", group = "default") +public class DefaultRestService implements RestService { + + @Override + public String param(String param) { + return null; + } + + @Override + public String params(int a, String b) { + return null; + } + + @Override + public String headers(String header, String header2, Integer param) { + return null; + } + + @Override + public String pathVariables(String path1, String path2, String param) { + return null; + } + + @Override + public String form(String form) { + return null; + } + + @Override + public User requestBodyMap(Map data, String param) { + return null; + } + + @Override + public Map requestBodyUser(User user) { + return null; + } + + public User user(User user) { + return user; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/rest/RestService.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/rest/RestService.java new file mode 100644 index 0000000000..65d67ab475 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/rest/RestService.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.rest; + + +import java.util.Map; + +/** + * An interface for REST service + * + * @since 2.7.6 + */ +public interface RestService { + + String param(String param); + + String params(int a, String b); + + String headers(String header, String header2, Integer param); + + String pathVariables(String path1, String path2, String param); + + String form(String form); + + User requestBodyMap(Map data, String param); + + Map requestBodyUser(User user); +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/rest/SpringRestService.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/rest/SpringRestService.java new file mode 100644 index 0000000000..ed4a8a25be --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/rest/SpringRestService.java @@ -0,0 +1,97 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.rest; + +import org.apache.dubbo.config.annotation.Service; + +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.HashMap; +import java.util.Map; + +/** + * Spring MVC {@link RestService} + * + * @since 2.7.6 + */ +@Service(version = "2.0.0", group = "spring") +@RestController +public class SpringRestService implements RestService { + + @Override + @GetMapping(value = "/param") + public String param(@RequestParam(defaultValue = "value-param") String param) { + return param; + } + + @Override + @PostMapping("/params") + public String params(@RequestParam(defaultValue = "value-a") int a, @RequestParam(defaultValue = "value-b") String b) { + return a + b; + } + + @Override + @GetMapping("/headers") + public String headers(@RequestHeader(name = "h", defaultValue = "value-h") String header, + @RequestHeader(name = "h2", defaultValue = "value-h2") String header2, + @RequestParam(value = "v", defaultValue = "1") Integer param) { + String result = header + " , " + header2 + " , " + param; + return result; + } + + @Override + @GetMapping("/path-variables/{p1}/{p2}") + public String pathVariables(@PathVariable("p1") String path1, + @PathVariable("p2") String path2, @RequestParam("v") String param) { + String result = path1 + " , " + path2 + " , " + param; + return result; + } + + @Override + @PostMapping("/form") + public String form(@RequestParam("f") String form) { + return String.valueOf(form); + } + + @Override + @PostMapping(value = "/request/body/map", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + public User requestBodyMap(@RequestBody Map data, + @RequestParam("param") String param) { + User user = new User(); + user.setId(((Integer) data.get("id")).longValue()); + user.setName((String) data.get("name")); + user.setAge((Integer) data.get("age")); + return user; + } + + @PostMapping(value = "/request/body/user", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE) + @Override + public Map requestBodyUser(@RequestBody User user) { + Map map = new HashMap<>(); + map.put("id", user.getId()); + map.put("name", user.getName()); + map.put("age", user.getAge()); + return map; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/rest/StandardRestService.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/rest/StandardRestService.java new file mode 100644 index 0000000000..f5d94b7c1e --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/rest/StandardRestService.java @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.rest; + +import org.apache.dubbo.config.annotation.Service; + +import javax.ws.rs.Consumes; +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import java.util.HashMap; +import java.util.Map; + + +/** + * JAX-RS {@link RestService} + */ +@Service(version = "3.0.0", protocol = {"dubbo", "rest"}, group = "standard") +@Path("/") +public class StandardRestService implements RestService { + + @Override + @Path("param") + @GET + public String param(@QueryParam("param") String param) { + return param; + } + + @Override + @Path("params") + @POST + public String params(@QueryParam("a") int a, @QueryParam("b") String b) { + return a + b; + } + + @Override + @Path("headers") + @GET + public String headers(@HeaderParam("h") String header, + @HeaderParam("h2") String header2, @QueryParam("v") Integer param) { + String result = header + " , " + header2 + " , " + param; + return result; + } + + @Override + @Path("path-variables/{p1}/{p2}") + @GET + public String pathVariables(@PathParam("p1") String path1, + @PathParam("p2") String path2, @QueryParam("v") String param) { + String result = path1 + " , " + path2 + " , " + param; + return result; + } + + // @CookieParam does not support : https://github.com/OpenFeign/feign/issues/913 + // @CookieValue also does not support + + @Override + @Path("form") + @POST + public String form(@FormParam("f") String form) { + return String.valueOf(form); + } + + @Override + @Path("request/body/map") + @POST + @Produces("application/json;charset=UTF-8") + public User requestBodyMap(Map data, + @QueryParam("param") String param) { + User user = new User(); + user.setId(((Integer) data.get("id")).longValue()); + user.setName((String) data.get("name")); + user.setAge((Integer) data.get("age")); + return user; + } + + @Path("request/body/user") + @POST + @Override + @Consumes("application/json;charset=UTF-8") + public Map requestBodyUser(User user) { + Map map = new HashMap<>(); + map.put("id", user.getId()); + map.put("name", user.getName()); + map.put("age", user.getAge()); + return map; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/rest/User.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/rest/User.java new file mode 100644 index 0000000000..2ad6a514cf --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/rest/User.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.rest; + +import java.io.Serializable; + +/** + * User Entity + * + * @since 2.7.6 + */ +public class User implements Serializable { + + private Long id; + + private String name; + + private Integer age; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getAge() { + return age; + } + + public void setAge(Integer age) { + this.age = age; + } + + @Override + public String toString() { + return "User{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + '}'; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/Ancestor.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/Ancestor.java new file mode 100644 index 0000000000..52ccaf6ab3 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/Ancestor.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.tools; + +import java.io.Serializable; + +/** + * Ancestor + */ +public class Ancestor implements Serializable { + + private boolean z; + + public boolean isZ() { + return z; + } + + public void setZ(boolean z) { + this.z = z; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/Compiler.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/Compiler.java new file mode 100644 index 0000000000..a4ee1af30a --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/Compiler.java @@ -0,0 +1,116 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.tools; + +import javax.annotation.processing.Processor; +import javax.tools.JavaCompiler; +import javax.tools.JavaFileObject; +import javax.tools.StandardJavaFileManager; +import javax.tools.StandardLocation; +import javax.tools.ToolProvider; +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.Set; + +import static java.util.Arrays.asList; + +/** + * The Java Compiler + */ +public class Compiler { + + private final File sourceDirectory; + + private final JavaCompiler javaCompiler; + + private final StandardJavaFileManager javaFileManager; + + private final Set processors = new LinkedHashSet<>(); + + public Compiler() throws IOException { + this(defaultTargetDirectory()); + } + + public Compiler(File targetDirectory) throws IOException { + this(defaultSourceDirectory(), targetDirectory); + } + + public Compiler(File sourceDirectory, File targetDirectory) throws IOException { + this.sourceDirectory = sourceDirectory; + this.javaCompiler = ToolProvider.getSystemJavaCompiler(); + this.javaFileManager = javaCompiler.getStandardFileManager(null, null, null); + this.javaFileManager.setLocation(StandardLocation.CLASS_OUTPUT, Collections.singleton(targetDirectory)); + this.javaFileManager.setLocation(StandardLocation.SOURCE_OUTPUT, Collections.singleton(targetDirectory)); + } + + private static File defaultSourceDirectory() { + return new File(defaultRootDirectory(), "src/test/java"); + } + + private static File defaultRootDirectory() { + return detectClassPath(Compiler.class).getParentFile().getParentFile(); + } + + private static File defaultTargetDirectory() { + File dir = new File(defaultRootDirectory(), "target/generated-classes"); + dir.mkdirs(); + return dir; + } + + private static File detectClassPath(Class targetClass) { + URL classFileURL = targetClass.getProtectionDomain().getCodeSource().getLocation(); + if ("file".equals(classFileURL.getProtocol())) { + return new File(classFileURL.getPath()); + } else { + throw new RuntimeException("No support"); + } + } + + public Compiler processors(Processor... processors) { + this.processors.addAll(asList(processors)); + return this; + } + + private Iterable getJavaFileObjects(Class... sourceClasses) { + int size = sourceClasses == null ? 0 : sourceClasses.length; + File[] javaSourceFiles = new File[size]; + for (int i = 0; i < size; i++) { + File javaSourceFile = javaSourceFile(sourceClasses[i].getName()); + javaSourceFiles[i] = javaSourceFile; + } + return javaFileManager.getJavaFileObjects(javaSourceFiles); + } + + private File javaSourceFile(String sourceClassName) { + String javaSourceFilePath = sourceClassName.replace('.', '/').concat(".java"); + return new File(sourceDirectory, javaSourceFilePath); + } + + public boolean compile(Class... sourceClasses) { + JavaCompiler.CompilationTask task = javaCompiler.getTask(null, this.javaFileManager, null, + asList("-parameters"), +// null, + null, getJavaFileObjects(sourceClasses)); + if (!processors.isEmpty()) { + task.setProcessors(processors); + } + return task.call(); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/CompilerTest.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/CompilerTest.java new file mode 100644 index 0000000000..e633e0fba8 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/CompilerTest.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.tools; + +import org.junit.jupiter.api.Test; + +import java.io.IOException; + +/** + * The Compiler test case + */ +public class CompilerTest { + + @Test + public void testCompile() throws IOException { + Compiler compiler = new Compiler(); + compiler.compile( + TestServiceImpl.class, + DefaultTestService.class, + GenericTestService.class); + } +} + diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/DefaultRestServiceTest.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/DefaultRestServiceTest.java new file mode 100644 index 0000000000..6921bbd96a --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/DefaultRestServiceTest.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.tools; + +import org.apache.dubbo.metadata.rest.DefaultRestService; +import org.apache.dubbo.metadata.rest.RestService; +import org.apache.dubbo.metadata.rest.SpringRestService; +import org.apache.dubbo.metadata.rest.StandardRestService; +import org.apache.dubbo.metadata.rest.User; + +import org.junit.jupiter.api.Test; + +import java.io.IOException; + +/** + * The test case for {@link DefaultRestService} + * + * @since 2.7.6 + */ +public class DefaultRestServiceTest { + + @Test + public void test() throws IOException { + Compiler compiler = new Compiler(); + compiler.compile(User.class, + RestService.class, + DefaultRestService.class, + SpringRestService.class, + StandardRestService.class); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/DefaultTestService.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/DefaultTestService.java new file mode 100644 index 0000000000..85bce6924d --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/DefaultTestService.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.tools; + + +import org.apache.dubbo.config.annotation.Service; +import org.apache.dubbo.metadata.annotation.processing.model.Model; + +import java.util.concurrent.TimeUnit; + +/** + * {@link TestService} Implementation + * + * @since 2.7.6 + */ +@Service( + interfaceName = "org.apache.dubbo.metadata.tools.TestService", + version = "1.0.0", + group = "default" +) +public class DefaultTestService implements TestService { + + private String name; + + @Override + public String echo(String message) { + return "[ECHO] " + message; + } + + @Override + public Model model(Model model) { + return model; + } + + @Override + public String testPrimitive(boolean z, int i) { + return null; + } + + @Override + public Model testEnum(TimeUnit timeUnit) { + return null; + } + + @Override + public String testArray(String[] strArray, int[] intArray, Model[] modelArray) { + return null; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/GenericTestService.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/GenericTestService.java new file mode 100644 index 0000000000..83cf19ff2c --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/GenericTestService.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.tools; + + +import com.alibaba.dubbo.config.annotation.Service; + +import java.util.EventListener; + +/** + * {@link TestService} Implementation + * + * @since 2.7.6 + */ +@Service( + version = "2.0.0", + group = "generic" +) +public class GenericTestService extends DefaultTestService implements TestService, EventListener { + @Override + public String echo(String message) { + return "[ECHO] " + message; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/Parent.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/Parent.java new file mode 100644 index 0000000000..4273a0fb70 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/Parent.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.tools; + +/** + * Parent + */ +public class Parent extends Ancestor { + + private byte b; + + private short s; + + private int i; + + private long l; + + public byte getB() { + return b; + } + + public void setB(byte b) { + this.b = b; + } + + public short getS() { + return s; + } + + public void setS(short s) { + this.s = s; + } + + public int getI() { + return i; + } + + public void setI(int i) { + this.i = i; + } + + public long getL() { + return l; + } + + public void setL(long l) { + this.l = l; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/RestServiceTest.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/RestServiceTest.java new file mode 100644 index 0000000000..fcb444e251 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/RestServiceTest.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.tools; + +import org.apache.dubbo.metadata.rest.RestService; +import org.apache.dubbo.metadata.rest.SpringRestService; +import org.apache.dubbo.metadata.rest.StandardRestService; +import org.apache.dubbo.metadata.rest.User; + +import org.junit.jupiter.api.Test; + +import java.io.IOException; + +/** + * {@link RestService} Test + * + * @since 2.7.6 + */ +public class RestServiceTest { + + @Test + public void test() throws IOException { + Compiler compiler = new Compiler(); + compiler.compile(User.class, RestService.class, + StandardRestService.class, + SpringRestService.class); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/SpringRestServiceTest.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/SpringRestServiceTest.java new file mode 100644 index 0000000000..f2ebe1d3dd --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/SpringRestServiceTest.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.tools; + +import org.apache.dubbo.metadata.rest.RestService; +import org.apache.dubbo.metadata.rest.SpringRestService; +import org.apache.dubbo.metadata.rest.User; + +import org.junit.jupiter.api.Test; + +import java.io.IOException; + +/** + * {@link SpringRestService} Test + * + * @since 2.7.6 + */ +public class SpringRestServiceTest { + + @Test + public void test() throws IOException { + Compiler compiler = new Compiler(); + compiler.compile(User.class, RestService.class, SpringRestService.class); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/StandardRestServiceTest.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/StandardRestServiceTest.java new file mode 100644 index 0000000000..bba4d54d2d --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/StandardRestServiceTest.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.tools; + +import org.apache.dubbo.metadata.rest.RestService; +import org.apache.dubbo.metadata.rest.StandardRestService; +import org.apache.dubbo.metadata.rest.User; + +import org.junit.jupiter.api.Test; + +import java.io.IOException; + +/** + * The test case for {@link StandardRestService} + * + * @since 2.7.6 + */ +public class StandardRestServiceTest { + + @Test + public void test() throws IOException { + Compiler compiler = new Compiler(); + compiler.compile(User.class, RestService.class, StandardRestService.class); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/TestProcessor.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/TestProcessor.java new file mode 100644 index 0000000000..4eda0b0b71 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/TestProcessor.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.tools; + +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.ProcessingEnvironment; +import javax.annotation.processing.Processor; +import javax.annotation.processing.RoundEnvironment; +import javax.annotation.processing.SupportedAnnotationTypes; +import javax.annotation.processing.SupportedSourceVersion; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.TypeElement; +import java.util.Set; + +/** + * {@link Processor} for test + * + * @since 2.7.6 + */ +@SupportedAnnotationTypes("*") +@SupportedSourceVersion(SourceVersion.RELEASE_8) +public class TestProcessor extends AbstractProcessor { + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + return false; + } + + public ProcessingEnvironment getProcessingEnvironment() { + return super.processingEnv; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/TestService.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/TestService.java new file mode 100644 index 0000000000..83c0ef6aff --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/TestService.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.tools; + +import org.apache.dubbo.metadata.annotation.processing.model.Model; + +import javax.ws.rs.DefaultValue; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import java.util.concurrent.TimeUnit; + +/** + * Test Service + * + * @since 2.7.6 + */ +@Path("/echo") +public interface TestService { + + @GET + String echo(@PathParam("message") @DefaultValue("mercyblitz") String message); + + @POST + Model model(@PathParam("model") Model model); + + // Test primitive + @PUT + String testPrimitive(boolean z, int i); + + // Test enumeration + @PUT + Model testEnum(TimeUnit timeUnit); + + // Test Array + @GET + String testArray(String[] strArray, int[] intArray, Model[] modelArray); +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/TestServiceImpl.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/TestServiceImpl.java new file mode 100644 index 0000000000..713e8e701b --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/TestServiceImpl.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.tools; + + +import org.apache.dubbo.config.annotation.Service; + +import java.io.Serializable; + +/** + * {@link TestService} Implementation + * + * @since 2.7.6 + */ +@com.alibaba.dubbo.config.annotation.Service( + interfaceName = "org.apache.dubbo.metadata.tools.TestService", + interfaceClass = TestService.class, + version = "3.0.0", + group = "test" +) +@Service( + interfaceName = "org.apache.dubbo.metadata.tools.TestService", + interfaceClass = TestService.class, + version = "3.0.0", + group = "test" +) +public class TestServiceImpl extends GenericTestService implements TestService, AutoCloseable, Serializable { + + @Override + public String echo(String message) { + return "[ECHO] " + message; + } + + @Override + public void close() throws Exception { + } +} diff --git a/dubbo-metadata/pom.xml b/dubbo-metadata/pom.xml index fefa36493d..17ceada829 100644 --- a/dubbo-metadata/pom.xml +++ b/dubbo-metadata/pom.xml @@ -35,6 +35,7 @@ dubbo-metadata-report-consul dubbo-metadata-report-etcd dubbo-metadata-report-nacos + dubbo-metadata-processor
diff --git a/pom.xml b/pom.xml index e47e65590e..dc085b3202 100644 --- a/pom.xml +++ b/pom.xml @@ -467,7 +467,10 @@ maven-compiler-plugin ${maven_compiler_version} - -proc:none + + -proc:none + -parameters + true ${java_source_version} ${java_target_version}