Dynamically generate native image config (#11795)
* ADD dubbo-maven-plugin * add dubbo-maven-plugin module Signed-off-by: crazyhzm <crazyhzm@gmail.com> * fix license and compiler error Signed-off-by: crazyhzm <crazyhzm@gmail.com> * fix license and ci error Signed-off-by: crazyhzm <crazyhzm@gmail.com> * fix ci error Signed-off-by: crazyhzm <crazyhzm@gmail.com> * Remove proxy-config, hard code Signed-off-by: crazyhzm <crazyhzm@gmail.com> * ignoredModulesInDubboAll Signed-off-by: crazyhzm <crazyhzm@gmail.com> * throw exception for generated adaptive class sources Signed-off-by: crazyhzm <crazyhzm@gmail.com> * remove useless reflect config Signed-off-by: crazyhzm <crazyhzm@gmail.com> * Dynamically generate native image config for graalvm, and remove the original native image config Signed-off-by: crazyhzm <crazyhzm@gmail.com> * fix conflict Signed-off-by: crazyhzm <crazyhzm@gmail.com> * remove .git.exec.error Signed-off-by: crazyhzm <crazyhzm@gmail.com> * remove .git.exec.error Signed-off-by: crazyhzm <crazyhzm@gmail.com> * remove useless import Signed-off-by: crazyhzm <crazyhzm@gmail.com> --------- Signed-off-by: crazyhzm <crazyhzm@gmail.com> Co-authored-by: Albumen Kevin <jhq0812@gmail.com>
This commit is contained in:
parent
e6ee6088bf
commit
69edf4ef8c
|
|
@ -48,3 +48,5 @@ dubbo-demo/dubbo-demo-triple/build/*
|
|||
# global registry center
|
||||
.tmp
|
||||
|
||||
.git.exec.error
|
||||
|
||||
|
|
|
|||
|
|
@ -95,6 +95,9 @@ header:
|
|||
- 'dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/MatchingGroupIdFilter.java'
|
||||
- 'dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/RunArguments.java'
|
||||
- 'dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/RunProcess.java'
|
||||
- 'dubbo-native/src/main/java/org/apache/dubbo/aot/generate/BasicJsonWriter.java'
|
||||
- 'dubbo-native/src/main/java/org/apache/dubbo/aot/generate/ExecutableMode.java'
|
||||
- 'dubbo-native/src/main/java/org/apache/dubbo/aot/generate/MemberCategory.java'
|
||||
|
||||
comment: on-failure
|
||||
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ public class ScopeBeanFactory {
|
|||
private final List<BeanInfo> registeredBeanInfos = new CopyOnWriteArrayList<>();
|
||||
private InstantiationStrategy instantiationStrategy;
|
||||
private final AtomicBoolean destroyed = new AtomicBoolean();
|
||||
private List<Class<?>> registeredClasses = new ArrayList<>();
|
||||
|
||||
public ScopeBeanFactory(ScopeBeanFactory parent, ExtensionAccessor extensionAccessor) {
|
||||
this.parent = parent;
|
||||
|
|
@ -131,6 +132,7 @@ public class ScopeBeanFactory {
|
|||
}
|
||||
}
|
||||
}
|
||||
registeredClasses.add(type);
|
||||
return bean;
|
||||
}
|
||||
|
||||
|
|
@ -281,4 +283,8 @@ public class ScopeBeanFactory {
|
|||
this.instance = instance;
|
||||
}
|
||||
}
|
||||
|
||||
public List<Class<?>> getRegisteredClasses() {
|
||||
return registeredClasses;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
[
|
||||
{
|
||||
"name": "org.apache.zookeeper.ClientCnxnSocketNIO",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": [
|
||||
"org.apache.zookeeper.client.ZKClientConfig"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
@ -18,8 +18,10 @@
|
|||
#
|
||||
|
||||
|
||||
log4j.rootLogger=error, console
|
||||
|
||||
log4j.appender.console=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.console.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.console.layout.ConversionPattern=[%-12d{HH\:mm\:ss.SS}] [%p] %l %m%n
|
||||
###set log levels###
|
||||
log4j.rootLogger=info, stdout
|
||||
###output to the console###
|
||||
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.stdout.Target=System.out
|
||||
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.stdout.layout.ConversionPattern=[%d{dd/MM/yy HH:mm:ss:SSS z}] %t %5p %c{2}: %m%n
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
[
|
||||
{
|
||||
"name": "org.apace.dubbo.graalvm.demo.DemoService",
|
||||
"allPublicMethods": true
|
||||
},
|
||||
{
|
||||
"name": "org.apache.dubbo.demo.graalvm.provider.DemoServiceImpl",
|
||||
"allDeclaredMethods": true
|
||||
},
|
||||
{
|
||||
"name": "org.apache.zookeeper.ClientCnxnSocketNIO",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": [
|
||||
"org.apache.zookeeper.client.ZKClientConfig"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"resources": {
|
||||
"includes": [
|
||||
{
|
||||
"pattern": "\\Qdubbo.properties\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\Qlog4j.properties\\E"
|
||||
}
|
||||
]
|
||||
},
|
||||
"bundles": []
|
||||
}
|
||||
|
|
@ -17,18 +17,14 @@
|
|||
package org.apache.dubbo.maven.plugin.aot;
|
||||
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.maven.plugins.annotations.LifecyclePhase;
|
||||
import org.apache.maven.plugins.annotations.Mojo;
|
||||
import org.apache.maven.plugins.annotations.Parameter;
|
||||
import org.apache.maven.plugins.annotations.ResolutionScope;
|
||||
import org.apache.maven.project.MavenProject;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@Mojo(name = "dubbo-process-aot", defaultPhase = LifecyclePhase.PREPARE_PACKAGE, threadSafe = true,
|
||||
|
|
@ -36,7 +32,7 @@ import java.util.List;
|
|||
requiresDependencyCollection = ResolutionScope.COMPILE_PLUS_RUNTIME)
|
||||
public class DubboProcessAotMojo extends AbstractAotMojo {
|
||||
|
||||
private static final String AOT_PROCESSOR_CLASS_NAME = "org.apache.dubbo.aot.generate.CodeGenerator";
|
||||
private static final String AOT_PROCESSOR_CLASS_NAME = "org.apache.dubbo.aot.generate.AotProcessor";
|
||||
|
||||
/**
|
||||
* Directory containing the classes and resource files that should be packaged into
|
||||
|
|
@ -83,7 +79,6 @@ public class DubboProcessAotMojo extends AbstractAotMojo {
|
|||
URL[] classPath = getClassPath().toArray(new URL[0]);
|
||||
generateAotAssets(classPath, AOT_PROCESSOR_CLASS_NAME, getAotArguments(mainClass));
|
||||
compileSourceFiles(classPath, this.generatedSources, this.classesDirectory);
|
||||
copyNativeConfigFile(project);
|
||||
copyAll(this.generatedResources.toPath(), this.classesDirectory.toPath());
|
||||
copyAll(this.generatedClasses.toPath(), this.classesDirectory.toPath());
|
||||
}
|
||||
|
|
@ -104,35 +99,4 @@ public class DubboProcessAotMojo extends AbstractAotMojo {
|
|||
File[] directories = new File[]{this.classesDirectory, this.generatedClasses};
|
||||
return getClassPath(directories, new ExcludeTestScopeArtifactFilter());
|
||||
}
|
||||
|
||||
private void copyNativeConfigFile(MavenProject project) {
|
||||
String[] nativeFiles = {"META-INF/native-image/reflect-config.json",
|
||||
"META-INF/native-image/jni-config.json",
|
||||
"META-INF/native-image/proxy-config.json",
|
||||
"META-INF/native-image/resource-config.json",
|
||||
"META-INF/native-image/serialization-config.json"};
|
||||
|
||||
Arrays.stream(nativeFiles).forEach(nativeFile -> {
|
||||
InputStream is = this.getClass().getClassLoader().getResourceAsStream(nativeFile);
|
||||
project.getResources().stream().findFirst().ifPresent(resource -> {
|
||||
try {
|
||||
String path = generatedResources + File.separator + "META-INF" + File.separator + "native-image" + File.separator
|
||||
+ File.separator + this.project.getGroupId() + File.separator + this.project.getArtifactId();
|
||||
FileUtils.forceMkdir(new File(path));
|
||||
String[] str = nativeFile.split("/");
|
||||
File file = new File(path + File.separator + str[str.length - 1]);
|
||||
if (!file.exists()) {
|
||||
FileUtils.copyInputStreamToFile(is, file);
|
||||
getLog().info("Copy native config file:" + file);
|
||||
} else {
|
||||
getLog().info("Skip copy config file:" + file);
|
||||
}
|
||||
} catch (Throwable ex) {
|
||||
getLog().error("Copy native config file error:" + ex.getMessage());
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,2 +0,0 @@
|
|||
[
|
||||
]
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
[
|
||||
|
||||
]
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,169 +0,0 @@
|
|||
{
|
||||
"resources": {
|
||||
"includes": [
|
||||
{
|
||||
"pattern": "\\QDENY_CLASS\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/dubbo/internal/org.apache.dubbo.common.compiler.Compiler\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/dubbo/internal/org.apache.dubbo.common.config.configcenter.DynamicConfigurationFactory\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/dubbo/internal/org.apache.dubbo.common.context.ApplicationExt\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/dubbo/internal/org.apache.dubbo.common.context.ModuleExt\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/dubbo/internal/org.apache.dubbo.common.extension.ExtensionInjector\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/dubbo/internal/org.apache.dubbo.common.infra.InfraAdapter\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/dubbo/internal/org.apache.dubbo.common.logger.LoggerAdapter\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/dubbo/internal/org.apache.dubbo.common.serialize.Serialization\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/dubbo/internal/org.apache.dubbo.common.threadpool.ThreadPool\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/dubbo/internal/org.apache.dubbo.common.threadpool.manager.ExecutorRepository\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/dubbo/internal/org.apache.dubbo.common.url.component.param.DynamicParamSource\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/dubbo/internal/org.apache.dubbo.metadata.MetadataServiceExporter\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/dubbo/internal/org.apache.dubbo.metadata.ServiceNameMapping\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/dubbo/internal/org.apache.dubbo.metadata.definition.builder.TypeBuilder\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/dubbo/internal/org.apache.dubbo.registry.AddressListener\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/dubbo/internal/org.apache.dubbo.registry.ProviderFirstParams\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/dubbo/internal/org.apache.dubbo.registry.RegistryFactory\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/dubbo/internal/org.apache.dubbo.registry.client.RegistryClusterIdentifier\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/dubbo/internal/org.apache.dubbo.registry.client.ServiceDiscoveryFactory\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/dubbo/internal/org.apache.dubbo.registry.client.ServiceInstanceCustomizer\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/dubbo/internal/org.apache.dubbo.registry.client.migration.MigrationAddressComparator\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/dubbo/internal/org.apache.dubbo.registry.integration.RegistryProtocolListener\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/dubbo/internal/org.apache.dubbo.remoting.Codec2\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/dubbo/internal/org.apache.dubbo.remoting.Dispatcher\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/dubbo/internal/org.apache.dubbo.remoting.Transporter\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/dubbo/internal/org.apache.dubbo.remoting.exchange.Exchanger\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/dubbo/internal/org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/dubbo/internal/org.apache.dubbo.rpc.Filter\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/dubbo/internal/org.apache.dubbo.rpc.InvokerListener\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/dubbo/internal/org.apache.dubbo.rpc.Protocol\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/dubbo/internal/org.apache.dubbo.rpc.ProxyFactory\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.Cluster\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.ConfiguratorFactory\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.LoadBalance\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.ProviderURLMergeProcessor\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.RouterFactory\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.filter.ClusterFilter\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.filter.FilterChainBuilder\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.governance.GovernanceRuleRepository\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.router.state.StateRouterFactory\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/dubbo/internal/org.apache.dubbo.rpc.model.BuiltinServiceDetector\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/dubbo/internal/org.apache.dubbo.rpc.model.ScopeModelInitializer\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/services/org.apache.dubbo.common.extension.LoadingStrategy\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\Qdubbo.properties\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\Qlog4j.properties\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\Qorg/apache/dubbo/common/Version.class\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\Qorg/apache/dubbo/remoting/RemotingException.class\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\Qorg/apache/dubbo/remoting/Transporters.class\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\Qorg/apache/dubbo/remoting/exchange/Exchangers.class\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/dubbo/internal/org.apache.dubbo.common.store.DataStore\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\QMETA-INF/dubbo/internal/org.apache.dubbo.metrics.service.MetricsServiceExporter\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\Qsecurity/serialize.blockedlist\\E"
|
||||
},
|
||||
{
|
||||
"pattern": "\\Qsecurity/serialize.allowlist\\E"
|
||||
}
|
||||
]
|
||||
},
|
||||
"bundles": []
|
||||
}
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
[
|
||||
]
|
||||
|
|
@ -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.aot.generate;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* generate related self-adaptive code (native image does not support dynamic code generation. Therefore, code needs to be generated before compilation)
|
||||
*/
|
||||
public class AotProcessor {
|
||||
|
||||
public static void main(String[] args) {
|
||||
String generatedSources = args[1];
|
||||
|
||||
List<Class<?>> classes = ClassSourceScanner.INSTANCE.spiClassesWithAdaptive();
|
||||
NativeClassSourceWriter.INSTANCE.writeTo(classes, generatedSources);
|
||||
|
||||
NativeConfigurationWriter writer = new NativeConfigurationWriter(Paths.get(args[2]), args[4], args[5]);
|
||||
|
||||
ResourceConfigMetadataRepository resourceRepository = new ResourceConfigMetadataRepository();
|
||||
resourceRepository.registerIncludesPatterns(ResourceScanner.INSTANCE.distinctSpiResource().toArray(new String[]{}));
|
||||
resourceRepository.registerIncludesPatterns(ResourceScanner.INSTANCE.distinctSecurityResource().toArray(new String[]{}));
|
||||
writer.writeResourceConfig(resourceRepository);
|
||||
|
||||
|
||||
ReflectConfigMetadataRepository reflectRepository = new ReflectConfigMetadataRepository();
|
||||
reflectRepository
|
||||
.registerSpiExtensionType(new ArrayList<>(ClassSourceScanner.INSTANCE.distinctSpiExtensionClasses(ResourceScanner.INSTANCE.distinctSpiResource()).values()))
|
||||
.registerAdaptiveType(new ArrayList<>(ClassSourceScanner.INSTANCE.adaptiveClasses().values()))
|
||||
.registerBeanType(ClassSourceScanner.INSTANCE.scopeModelInitializer())
|
||||
.registerConfigType(ClassSourceScanner.INSTANCE.configClasses());
|
||||
writer.writeReflectionConfig(reflectRepository);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,288 @@
|
|||
/*
|
||||
* Copyright 2002-2023 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.aot.generate;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
|
||||
/**
|
||||
* Very basic json writer for the purposes of translating runtime hints to native
|
||||
* configuration.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
class BasicJsonWriter {
|
||||
|
||||
private final IndentingWriter writer;
|
||||
|
||||
/**
|
||||
* Create a new instance with the specified indent value.
|
||||
*
|
||||
* @param writer the writer to use
|
||||
* @param singleIndent the value of one indent
|
||||
*/
|
||||
public BasicJsonWriter(Writer writer, String singleIndent) {
|
||||
this.writer = new IndentingWriter(writer, singleIndent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance using two whitespaces for the indent.
|
||||
*
|
||||
* @param writer the writer to use
|
||||
*/
|
||||
public BasicJsonWriter(Writer writer) {
|
||||
this(writer, " ");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write an object with the specified attributes. Each attribute is
|
||||
* written according to its value type:
|
||||
* <ul>
|
||||
* <li>Map: write the value as a nested object</li>
|
||||
* <li>List: write the value as a nested array</li>
|
||||
* <li>Otherwise, write a single value</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param attributes the attributes of the object
|
||||
*/
|
||||
public void writeObject(Map<String, Object> attributes) {
|
||||
writeObject(attributes, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an array with the specified items. Each item in the
|
||||
* list is written either as a nested object or as an attribute
|
||||
* depending on its type.
|
||||
*
|
||||
* @param items the items to write
|
||||
* @see #writeObject(Map)
|
||||
*/
|
||||
public void writeArray(List<?> items) {
|
||||
writeArray(items, true);
|
||||
}
|
||||
|
||||
private void writeObject(Map<String, Object> attributes, boolean newLine) {
|
||||
if (attributes.isEmpty()) {
|
||||
this.writer.print("{ }");
|
||||
} else {
|
||||
this.writer.println("{").indented(writeAll(attributes.entrySet().iterator(),
|
||||
entry -> writeAttribute(entry.getKey(), entry.getValue()))).print("}");
|
||||
}
|
||||
if (newLine) {
|
||||
this.writer.println();
|
||||
}
|
||||
}
|
||||
|
||||
private void writeArray(List<?> items, boolean newLine) {
|
||||
if (items.isEmpty()) {
|
||||
this.writer.print("[ ]");
|
||||
} else {
|
||||
this.writer.println("[")
|
||||
.indented(writeAll(items.iterator(), this::writeValue)).print("]");
|
||||
}
|
||||
if (newLine) {
|
||||
this.writer.println();
|
||||
}
|
||||
}
|
||||
|
||||
private <T> Runnable writeAll(Iterator<T> it, Consumer<T> writer) {
|
||||
return () -> {
|
||||
while (it.hasNext()) {
|
||||
writer.accept(it.next());
|
||||
if (it.hasNext()) {
|
||||
this.writer.println(",");
|
||||
} else {
|
||||
this.writer.println();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void writeAttribute(String name, Object value) {
|
||||
this.writer.print(quote(name) + ": ");
|
||||
writeValue(value);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void writeValue(Object value) {
|
||||
if (value instanceof Map<?, ?>) {
|
||||
writeObject((Map<String, Object>) value, false);
|
||||
} else if (value instanceof List<?>) {
|
||||
writeArray((List<?>) value, false);
|
||||
} else if (value instanceof CharSequence) {
|
||||
this.writer.print(quote(escape((CharSequence) value)));
|
||||
} else if (value instanceof Boolean) {
|
||||
this.writer.print(Boolean.toString((Boolean) value));
|
||||
} else {
|
||||
throw new IllegalStateException("unsupported type: " + value.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
private String quote(String name) {
|
||||
return "\"" + name + "\"";
|
||||
}
|
||||
|
||||
|
||||
private static String escape(CharSequence input) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
input.chars().forEach(c -> {
|
||||
if (c == '"') {
|
||||
builder.append("\\\"");
|
||||
} else if (c == '\\') {
|
||||
builder.append("\\\\");
|
||||
} else if (c == '\b') {
|
||||
builder.append("\\b");
|
||||
} else if (c == '\f') {
|
||||
builder.append("\\f");
|
||||
} else if (c == '\n') {
|
||||
builder.append("\\n");
|
||||
} else if (c == '\r') {
|
||||
builder.append("\\r");
|
||||
} else if (c == '\t') {
|
||||
builder.append("\\t");
|
||||
} else if (c <= 0x1F) {
|
||||
builder.append(String.format("\\u%04x", c));
|
||||
} else {
|
||||
builder.append((char) c);
|
||||
}
|
||||
});
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
|
||||
static class IndentingWriter extends Writer {
|
||||
|
||||
private final Writer out;
|
||||
|
||||
private final String singleIndent;
|
||||
|
||||
private int level = 0;
|
||||
|
||||
private String currentIndent = "";
|
||||
|
||||
private boolean prependIndent = false;
|
||||
|
||||
IndentingWriter(Writer out, String singleIndent) {
|
||||
this.out = out;
|
||||
this.singleIndent = singleIndent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the specified text.
|
||||
*
|
||||
* @param string the content to write
|
||||
*/
|
||||
public IndentingWriter print(String string) {
|
||||
write(string.toCharArray(), 0, string.length());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the specified text and append a new line.
|
||||
*
|
||||
* @param string the content to write
|
||||
*/
|
||||
public IndentingWriter println(String string) {
|
||||
write(string.toCharArray(), 0, string.length());
|
||||
return println();
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a new line.
|
||||
*/
|
||||
public IndentingWriter println() {
|
||||
String separator = System.lineSeparator();
|
||||
try {
|
||||
this.out.write(separator.toCharArray(), 0, separator.length());
|
||||
} catch (IOException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
this.prependIndent = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increase the indentation level and execute the {@link Runnable}. Decrease the
|
||||
* indentation level on completion.
|
||||
*
|
||||
* @param runnable the code to execute within an extra indentation level
|
||||
*/
|
||||
public IndentingWriter indented(Runnable runnable) {
|
||||
indent();
|
||||
runnable.run();
|
||||
return outdent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Increase the indentation level.
|
||||
*/
|
||||
private IndentingWriter indent() {
|
||||
this.level++;
|
||||
return refreshIndent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrease the indentation level.
|
||||
*/
|
||||
private IndentingWriter outdent() {
|
||||
this.level--;
|
||||
return refreshIndent();
|
||||
}
|
||||
|
||||
private IndentingWriter refreshIndent() {
|
||||
int count = Math.max(0, this.level);
|
||||
StringBuilder str = new StringBuilder();
|
||||
for (int i = 0; i < count; i++) {
|
||||
str.append(this.singleIndent);
|
||||
}
|
||||
this.currentIndent = str.toString();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(char[] chars, int offset, int length) {
|
||||
try {
|
||||
if (this.prependIndent) {
|
||||
this.out.write(this.currentIndent.toCharArray(), 0, this.currentIndent.length());
|
||||
this.prependIndent = false;
|
||||
}
|
||||
this.out.write(chars, offset, length);
|
||||
} catch (IOException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() throws IOException {
|
||||
this.out.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
this.out.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,92 +0,0 @@
|
|||
/*
|
||||
* 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.aot.generate;
|
||||
|
||||
|
||||
import java.io.File;
|
||||
import java.net.JarURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
public class ClassSourceFinder {
|
||||
|
||||
public Set<String> findClassSet(String packageName) {
|
||||
packageName = packageName.replace(".", "/");
|
||||
try {
|
||||
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
|
||||
Enumeration resources = classLoader.getResources(packageName);
|
||||
Set<String> result = new HashSet<>();
|
||||
while (resources.hasMoreElements()) {
|
||||
URL resource = (URL) resources.nextElement();
|
||||
if (resource != null) {
|
||||
String protocol = resource.getProtocol();
|
||||
if ("file".equals(protocol)) {
|
||||
findClassesByFile(packageName, resource.getPath(), result);
|
||||
} else if ("jar".equals(protocol)) {
|
||||
JarFile jar = ((JarURLConnection) resource.openConnection()).getJarFile();
|
||||
System.out.println("findClassSet jar:" + jar.getName());
|
||||
findClassesByJar(packageName, jar, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
} catch (Throwable ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void findClassesByFile(String packageName, String resource, Set<String> result) {
|
||||
File directory = new File(resource);
|
||||
File[] listFiles = directory.listFiles();
|
||||
if (listFiles != null) {
|
||||
for (File file : listFiles) {
|
||||
if (file.isDirectory()) {
|
||||
findClassesByFile(packageName, file.getPath(), result);
|
||||
} else {
|
||||
String path = file.getPath();
|
||||
if (path.endsWith(".class")) {
|
||||
int packageIndex = path.indexOf(packageName.replace("/", File.separator));
|
||||
String classPath = path.substring(packageIndex, path.length() - 6);
|
||||
result.add(classPath.replace(File.separator, "."));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void findClassesByJar(String packageName, JarFile jar, Set<String> classes) {
|
||||
Enumeration<JarEntry> entry = jar.entries();
|
||||
JarEntry jarEntry;
|
||||
String name;
|
||||
while (entry.hasMoreElements()) {
|
||||
jarEntry = entry.nextElement();
|
||||
name = jarEntry.getName();
|
||||
if (name.charAt(0) == '/') {
|
||||
name = name.substring(1);
|
||||
}
|
||||
if (jarEntry.isDirectory() || !name.startsWith(packageName) || !name.endsWith(".class")) {
|
||||
continue;
|
||||
}
|
||||
String className = name.substring(0, name.length() - 6);
|
||||
classes.add(className.replace("/", "."));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
* 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.aot.generate;
|
||||
|
||||
|
||||
import org.apache.dubbo.common.extension.Adaptive;
|
||||
import org.apache.dubbo.common.extension.SPI;
|
||||
import org.apache.dubbo.common.utils.StringUtils;
|
||||
import org.apache.dubbo.config.AbstractConfig;
|
||||
import org.apache.dubbo.rpc.model.FrameworkModel;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* A scanner for processing and filtering specific types of classes
|
||||
*/
|
||||
public class ClassSourceScanner extends JarScanner {
|
||||
|
||||
public static final ClassSourceScanner INSTANCE = new ClassSourceScanner();
|
||||
|
||||
/**
|
||||
* Filter out the spi classes with adaptive annotations
|
||||
* from all the class collections that can be loaded.
|
||||
* @return All spi classes with adaptive annotations
|
||||
*/
|
||||
public List<Class<?>> spiClassesWithAdaptive() {
|
||||
Map<String, Class<?>> allClasses = getClasses();
|
||||
List<Class<?>> spiClasses = new ArrayList<>(allClasses.values()).stream().filter(it -> {
|
||||
if (null == it) {
|
||||
return false;
|
||||
}
|
||||
Annotation anno = it.getAnnotation(SPI.class);
|
||||
if (null == anno) {
|
||||
return false;
|
||||
}
|
||||
Optional<Method> optional = Arrays.stream(it.getMethods()).filter(it2 -> it2.getAnnotation(Adaptive.class) != null).findAny();
|
||||
return optional.isPresent();
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
return spiClasses;
|
||||
}
|
||||
|
||||
/**
|
||||
* The required adaptive class.
|
||||
* For example: LoadBalance$Adaptive.class
|
||||
* @return adaptive class
|
||||
*/
|
||||
public Map<String, Class<?>> adaptiveClasses() {
|
||||
List<String> res = spiClassesWithAdaptive().stream().map((c) -> c.getName() + "$Adaptive").collect(Collectors.toList());
|
||||
return forNames(res);
|
||||
}
|
||||
|
||||
/**
|
||||
* The required configuration class, which is a subclass of AbstractConfig,
|
||||
* but which excludes abstract classes.
|
||||
* @return configuration class
|
||||
*/
|
||||
public List<Class<?>> configClasses() {
|
||||
return getClasses().values().stream().filter(c -> AbstractConfig.class.isAssignableFrom(c) && !Modifier.isAbstract(c.getModifiers())).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public Map<String, Class<?>> distinctSpiExtensionClasses(Set<String> spiResource) {
|
||||
|
||||
Map<String, Class<?>> extensionClasses = new HashMap<>();
|
||||
spiResource.forEach((fileName) -> {
|
||||
Enumeration<URL> resources;
|
||||
try {
|
||||
resources = ClassLoader.getSystemResources(fileName);
|
||||
if (resources != null) {
|
||||
while (resources.hasMoreElements()) {
|
||||
extensionClasses.putAll(loadResource(resources.nextElement()));
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
|
||||
return extensionClasses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Beans that need to be injected in advance in different ScopeModels.
|
||||
* For example, the RouterSnapshotSwitcher that needs to be injected when ClusterScopeModelInitializer executes initializeFrameworkModel
|
||||
* @return Beans that need to be injected in advance
|
||||
*/
|
||||
public List<Class<?>> scopeModelInitializer(){
|
||||
List<Class<?>> classes = new ArrayList<>();
|
||||
classes.addAll(FrameworkModel.defaultModel().getBeanFactory().getRegisteredClasses());
|
||||
classes.addAll(FrameworkModel.defaultModel().defaultApplication().getBeanFactory().getRegisteredClasses());
|
||||
classes.addAll(FrameworkModel.defaultModel().defaultApplication().getDefaultModule().getBeanFactory().getRegisteredClasses());
|
||||
return classes.stream().distinct().collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
private Map<String, Class<?>> loadResource(URL resourceUrl) {
|
||||
Map<String, Class<?>> extensionClasses = new HashMap<>();
|
||||
try {
|
||||
List<String> newContentList = getResourceContent(resourceUrl);
|
||||
String clazz;
|
||||
for (String line : newContentList) {
|
||||
try {
|
||||
int i = line.indexOf('=');
|
||||
if (i > 0) {
|
||||
clazz = line.substring(i + 1).trim();
|
||||
} else {
|
||||
clazz = line;
|
||||
}
|
||||
if (StringUtils.isNotEmpty(clazz)) {
|
||||
extensionClasses.put(clazz, getClasses().get(clazz));
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
}
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
}
|
||||
|
||||
return extensionClasses;
|
||||
}
|
||||
|
||||
private List<String> getResourceContent(URL resourceUrl) throws IOException {
|
||||
List<String> newContentList = new ArrayList<>();
|
||||
|
||||
try (BufferedReader reader = new BufferedReader(
|
||||
new InputStreamReader(resourceUrl.openStream(), StandardCharsets.UTF_8))) {
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
final int ci = line.indexOf('#');
|
||||
if (ci >= 0) {
|
||||
line = line.substring(0, ci);
|
||||
}
|
||||
line = line.trim();
|
||||
if (line.length() > 0) {
|
||||
newContentList.add(line);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
}
|
||||
return newContentList;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* 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.aot.generate;
|
||||
|
||||
/**
|
||||
* A describer that describes the conditions for the configuration to take effect.
|
||||
*/
|
||||
public interface ConditionalDescriber {
|
||||
|
||||
String getReachableType();
|
||||
|
||||
}
|
||||
|
|
@ -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.aot.generate;
|
||||
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Executable;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* A describer that describes the need for reflection on a {@link Executable}.
|
||||
*/
|
||||
public class ExecutableDescriber extends MemberDescriber {
|
||||
|
||||
private final List<String> parameterTypes;
|
||||
|
||||
private final ExecutableMode mode;
|
||||
|
||||
|
||||
public ExecutableDescriber(Constructor<?> constructor, ExecutableMode mode) {
|
||||
this("<init>", Arrays.stream(constructor.getParameterTypes()).map(Class::getName).collect(Collectors.toList()),mode);
|
||||
}
|
||||
|
||||
public ExecutableDescriber(String name, List<String> parameterTypes, ExecutableMode mode) {
|
||||
super(name);
|
||||
this.parameterTypes = parameterTypes;
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
|
||||
public List<String> getParameterTypes() {
|
||||
return parameterTypes;
|
||||
}
|
||||
|
||||
public ExecutableMode getMode() {
|
||||
return mode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
ExecutableDescriber that = (ExecutableDescriber) o;
|
||||
return Objects.equals(parameterTypes, that.parameterTypes) && mode == that.mode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(parameterTypes, mode);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright 2002-2022 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.aot.generate;
|
||||
|
||||
import java.lang.reflect.Executable;
|
||||
|
||||
/**
|
||||
* Represent the need of reflection for a given {@link Executable}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
public enum ExecutableMode {
|
||||
|
||||
/**
|
||||
* Only retrieving the {@link Executable} and its metadata is required.
|
||||
*/
|
||||
INTROSPECT,
|
||||
|
||||
/**
|
||||
* Full reflection support is required, including the ability to invoke
|
||||
* the {@link Executable}.
|
||||
*/
|
||||
INVOKE;
|
||||
|
||||
/**
|
||||
* Specify if this mode already includes the specified {@code other} mode.
|
||||
* @param other the other mode to check
|
||||
* @return {@code true} if this mode includes the other mode
|
||||
*/
|
||||
boolean includes(ExecutableMode other) {
|
||||
return (other == null || this.ordinal() >= other.ordinal());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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.aot.generate;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
/**
|
||||
* A describer that describes the need for reflection on a {@link Field}.
|
||||
*/
|
||||
public class FieldDescriber extends MemberDescriber {
|
||||
protected FieldDescriber(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return super.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return super.equals(obj);
|
||||
}
|
||||
}
|
||||
|
|
@ -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.aot.generate;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.JarURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
/**
|
||||
* A scanner that scan the dependent jar packages
|
||||
* to obtain the classes source and resources in them.
|
||||
*/
|
||||
public class JarScanner {
|
||||
|
||||
private static final String PACKAGE_NAME_PREFIX = "org/apache/dubbo";
|
||||
|
||||
private final Map<String, String> classNameCache;
|
||||
|
||||
private Map<String, Class<?>> classesCache;
|
||||
|
||||
private final List<String> resourcePathCache;
|
||||
|
||||
|
||||
protected Map<String, Class<?>> getClasses() {
|
||||
if (classesCache == null || classesCache.size() == 0) {
|
||||
this.classesCache = forNames(classNameCache.values());
|
||||
}
|
||||
return classesCache;
|
||||
}
|
||||
|
||||
public JarScanner() {
|
||||
classNameCache = new HashMap<>();
|
||||
resourcePathCache = new ArrayList<>();
|
||||
scanURL(PACKAGE_NAME_PREFIX);
|
||||
}
|
||||
|
||||
protected Map<String, Class<?>> forNames(Collection<String> classNames) {
|
||||
Map<String, Class<?>> classes = new HashMap<>();
|
||||
classNames.forEach((it) -> {
|
||||
try {
|
||||
Class<?> c = Class.forName(it);
|
||||
classes.put(it, c);
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
});
|
||||
return classes;
|
||||
}
|
||||
|
||||
|
||||
private void scanURL(String prefixName) {
|
||||
try {
|
||||
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
|
||||
Enumeration<URL> resources = classLoader.getResources(prefixName);
|
||||
while (resources.hasMoreElements()) {
|
||||
URL resource = resources.nextElement();
|
||||
String protocol = resource.getProtocol();
|
||||
if ("file".equals(protocol)) {
|
||||
scanFile(resource.getPath());
|
||||
} else if ("jar".equals(protocol)) {
|
||||
JarFile jar = ((JarURLConnection) resource.openConnection()).getJarFile();
|
||||
scanJar(jar);
|
||||
}
|
||||
}
|
||||
} catch (Throwable ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void scanFile(String resource) {
|
||||
File directory = new File(resource);
|
||||
File[] listFiles = directory.listFiles();
|
||||
if (listFiles != null) {
|
||||
for (File file : listFiles) {
|
||||
System.out.println("scanFile: " + file.getPath());
|
||||
if (file.isDirectory()) {
|
||||
scanFile(file.getPath());
|
||||
} else {
|
||||
String path = file.getPath();
|
||||
if (matchedDubboClasses(path)) {
|
||||
classNameCache.put(path, toClassName(path));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void scanJar(JarFile jar) {
|
||||
Enumeration<JarEntry> entry = jar.entries();
|
||||
JarEntry jarEntry;
|
||||
String name;
|
||||
while (entry.hasMoreElements()) {
|
||||
jarEntry = entry.nextElement();
|
||||
name = jarEntry.getName();
|
||||
|
||||
if (name.charAt(0) == '/') {
|
||||
name = name.substring(1);
|
||||
}
|
||||
|
||||
if (jarEntry.isDirectory()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (matchedDubboClasses(name)) {
|
||||
classNameCache.put(name, toClassName(name));
|
||||
} else {
|
||||
resourcePathCache.add(name);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
protected List<String> getResourcePath() {
|
||||
return resourcePathCache;
|
||||
}
|
||||
|
||||
private boolean matchedDubboClasses(String path) {
|
||||
return path.startsWith(PACKAGE_NAME_PREFIX) && path.endsWith(".class");
|
||||
}
|
||||
|
||||
private String toClassName(String path) {
|
||||
return path.substring(0, path.length() - 6).replace(File.separator, ".");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* Copyright 2002-2022 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.aot.generate;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Member;
|
||||
import java.lang.reflect.Method;
|
||||
/**
|
||||
* Represent predefined {@linkplain Member members} groups.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @author Sebastien Deleuze
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
public enum MemberCategory {
|
||||
|
||||
/**
|
||||
* A category that represents public {@linkplain Field fields}.
|
||||
* @see Class#getFields()
|
||||
*/
|
||||
PUBLIC_FIELDS,
|
||||
|
||||
/**
|
||||
* A category that represents {@linkplain Class#getDeclaredFields() declared
|
||||
* fields}, that is all fields defined by the class, but not inherited ones.
|
||||
* @see Class#getDeclaredFields()
|
||||
*/
|
||||
DECLARED_FIELDS,
|
||||
|
||||
/**
|
||||
* A category that defines public {@linkplain Constructor constructors} can
|
||||
* be introspected, but not invoked.
|
||||
* @see Class#getConstructors()
|
||||
* @see ExecutableMode#INTROSPECT
|
||||
*/
|
||||
INTROSPECT_PUBLIC_CONSTRUCTORS,
|
||||
|
||||
/**
|
||||
* A category that defines {@linkplain Class#getDeclaredConstructors() all
|
||||
* constructors} can be introspected, but not invoked.
|
||||
* @see Class#getDeclaredConstructors()
|
||||
* @see ExecutableMode#INTROSPECT
|
||||
*/
|
||||
INTROSPECT_DECLARED_CONSTRUCTORS,
|
||||
|
||||
/**
|
||||
* A category that defines public {@linkplain Constructor constructors} can
|
||||
* be invoked.
|
||||
* @see Class#getConstructors()
|
||||
* @see ExecutableMode#INVOKE
|
||||
*/
|
||||
INVOKE_PUBLIC_CONSTRUCTORS,
|
||||
|
||||
/**
|
||||
* A category that defines {@linkplain Class#getDeclaredConstructors() all
|
||||
* constructors} can be invoked.
|
||||
* @see Class#getDeclaredConstructors()
|
||||
* @see ExecutableMode#INVOKE
|
||||
*/
|
||||
INVOKE_DECLARED_CONSTRUCTORS,
|
||||
|
||||
/**
|
||||
* A category that defines public {@linkplain Method methods}, including
|
||||
* inherited ones can be introspect, but not invoked.
|
||||
* @see Class#getMethods()
|
||||
* @see ExecutableMode#INTROSPECT
|
||||
*/
|
||||
INTROSPECT_PUBLIC_METHODS,
|
||||
|
||||
/**
|
||||
* A category that defines {@linkplain Class#getDeclaredMethods() all
|
||||
* methods}, excluding inherited ones can be introspected, but not invoked.
|
||||
* @see Class#getDeclaredMethods()
|
||||
* @see ExecutableMode#INTROSPECT
|
||||
*/
|
||||
INTROSPECT_DECLARED_METHODS,
|
||||
|
||||
/**
|
||||
* A category that defines public {@linkplain Method methods}, including
|
||||
* inherited ones can be invoked.
|
||||
* @see Class#getMethods()
|
||||
* @see ExecutableMode#INVOKE
|
||||
*/
|
||||
INVOKE_PUBLIC_METHODS,
|
||||
|
||||
/**
|
||||
* A category that defines {@linkplain Class#getDeclaredMethods() all
|
||||
* methods}, excluding inherited ones can be invoked.
|
||||
* @see Class#getDeclaredMethods()
|
||||
* @see ExecutableMode#INVOKE
|
||||
*/
|
||||
INVOKE_DECLARED_METHODS,
|
||||
|
||||
/**
|
||||
* A category that represents public {@linkplain Class#getClasses() inner
|
||||
* classes}. Contrary to other categories, this does not register any
|
||||
* particular reflection for them but rather make sure they are available
|
||||
* via a call to {@link Class#getClasses}.
|
||||
*/
|
||||
PUBLIC_CLASSES,
|
||||
|
||||
/**
|
||||
* A category that represents all {@linkplain Class#getDeclaredClasses()
|
||||
* inner classes}. Contrary to other categories, this does not register any
|
||||
* particular reflection for them but rather make sure they are available
|
||||
* via a call to {@link Class#getDeclaredClasses}.
|
||||
*/
|
||||
DECLARED_CLASSES;
|
||||
|
||||
}
|
||||
|
|
@ -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.aot.generate;
|
||||
|
||||
import java.lang.reflect.Member;
|
||||
|
||||
/**
|
||||
* Base describer that describes the need for reflection on a {@link Member}.
|
||||
*
|
||||
*/
|
||||
public class MemberDescriber {
|
||||
|
||||
private final String name;
|
||||
|
||||
protected MemberDescriber(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the member.
|
||||
* @return the name
|
||||
*/
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
}
|
||||
|
|
@ -16,54 +16,27 @@
|
|||
*/
|
||||
package org.apache.dubbo.aot.generate;
|
||||
|
||||
import org.apache.dubbo.common.extension.Adaptive;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.dubbo.common.extension.AdaptiveClassCodeGenerator;
|
||||
import org.apache.dubbo.common.extension.SPI;
|
||||
import org.apache.dubbo.common.utils.StringUtils;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* generate related self-adaptive code (native image does not support dynamic code generation. Therefore, code needs to be generated before compilation)
|
||||
* Write the Adaptive bytecode class dynamically generated.
|
||||
*/
|
||||
public class CodeGenerator {
|
||||
public class NativeClassSourceWriter {
|
||||
|
||||
private static final String PACKAGE_NAME_PREFIX = "org.apache.dubbo";
|
||||
public static final NativeClassSourceWriter INSTANCE = new NativeClassSourceWriter();
|
||||
|
||||
public static void main(String[] args) {
|
||||
String generatedSources = args[1];
|
||||
|
||||
List<Class<?>> classes = new ClassSourceFinder().findClassSet(PACKAGE_NAME_PREFIX).stream().map(it -> {
|
||||
try {
|
||||
return Class.forName(it);
|
||||
} catch (Throwable e) {
|
||||
}
|
||||
return null;
|
||||
}).collect(Collectors.toList());
|
||||
new ArrayList<>(classes).stream().filter(it -> {
|
||||
if (null == it) {
|
||||
return false;
|
||||
}
|
||||
Annotation anno = it.getAnnotation(SPI.class);
|
||||
if (null == anno) {
|
||||
return false;
|
||||
}
|
||||
Optional<Method> optional = Arrays.stream(it.getMethods()).filter(it2 -> it2.getAnnotation(Adaptive.class) != null).findAny();
|
||||
return optional.isPresent();
|
||||
}).forEach(it -> {
|
||||
public void writeTo(List<Class<?>> classes, String generatedSources) {
|
||||
classes.forEach(it -> {
|
||||
SPI spi = it.getAnnotation(SPI.class);
|
||||
String value = spi.value();
|
||||
if (StringUtils.isEmpty(value)) {
|
||||
|
|
@ -76,14 +49,14 @@ public class CodeGenerator {
|
|||
String dir = Paths.get(file).getParent().toString();
|
||||
FileUtils.forceMkdir(new File(dir));
|
||||
code = LICENSED_STR + code + "\n";
|
||||
FileUtils.write(new File(file + "$Adaptive.java"), code, Charset.defaultCharset());
|
||||
String fileName = file + "$Adaptive.java";
|
||||
FileUtils.write(new File(fileName), code, Charset.defaultCharset());
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException("Failed to generated adaptive class sources", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private static final String LICENSED_STR = "/*\n" +
|
||||
" * Licensed to the Apache Software Foundation (ASF) under one or more\n" +
|
||||
" * contributor license agreements. See the NOTICE file distributed with\n" +
|
||||
|
|
@ -100,5 +73,4 @@ public class CodeGenerator {
|
|||
" * See the License for the specific language governing permissions and\n" +
|
||||
" * limitations under the License.\n" +
|
||||
" */\n";
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* 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.aot.generate;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.nio.file.Path;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Write Write configuration metadata information in
|
||||
* {@link ResourceConfigMetadataRepository} and {@link ReflectConfigMetadataRepository}
|
||||
* as GraalVM native configuration.
|
||||
* @see <a href="https://www.graalvm.org/latest/reference-manual/native-image/overview/BuildConfiguration/">Native Image Build Configuration</a>
|
||||
*/
|
||||
public class NativeConfigurationWriter {
|
||||
|
||||
private final Path basePath;
|
||||
|
||||
private final String groupId;
|
||||
|
||||
private final String artifactId;
|
||||
|
||||
public NativeConfigurationWriter(Path basePath, String groupId, String artifactId) {
|
||||
this.basePath = basePath;
|
||||
this.groupId = groupId;
|
||||
this.artifactId = artifactId;
|
||||
}
|
||||
|
||||
protected void writeTo(String fileName, Consumer<BasicJsonWriter> writer) {
|
||||
try {
|
||||
File file = createIfNecessary(fileName);
|
||||
try (FileWriter out = new FileWriter(file)) {
|
||||
writer.accept(createJsonWriter(out));
|
||||
}
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new IllegalStateException("Failed to write native configuration for " + fileName, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private File createIfNecessary(String filename) throws IOException {
|
||||
Path outputDirectory = this.basePath.resolve("META-INF").resolve("native-image");
|
||||
if (this.groupId != null && this.artifactId != null) {
|
||||
outputDirectory = outputDirectory.resolve(this.groupId).resolve(this.artifactId);
|
||||
}
|
||||
outputDirectory.toFile().mkdirs();
|
||||
File file = outputDirectory.resolve(filename).toFile();
|
||||
file.createNewFile();
|
||||
return file;
|
||||
}
|
||||
|
||||
|
||||
public void writeReflectionConfig(ReflectConfigMetadataRepository repository) {
|
||||
writeTo("reflect-config.json", writer ->
|
||||
ReflectionConfigWriter.INSTANCE.write(writer, repository));
|
||||
}
|
||||
|
||||
public void writeResourceConfig(ResourceConfigMetadataRepository repository) {
|
||||
writeTo("resource-config.json", writer ->
|
||||
ResourceConfigWriter.INSTANCE.write(writer, repository));
|
||||
}
|
||||
|
||||
private BasicJsonWriter createJsonWriter(Writer out) {
|
||||
return new BasicJsonWriter(out);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -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.aot.generate;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.apache.dubbo.aot.generate.ExecutableMode.INVOKE;
|
||||
|
||||
public class ReflectConfigMetadataRepository {
|
||||
|
||||
List<TypeDescriber> types;
|
||||
|
||||
public ReflectConfigMetadataRepository() {
|
||||
this.types = new ArrayList<>();
|
||||
}
|
||||
|
||||
public ReflectConfigMetadataRepository registerSpiExtensionType(List<Class<?>> classes) {
|
||||
types.addAll(classes.stream().map(this::buildTypeDescriberWithConstructor).collect(Collectors.toList()));
|
||||
return this;
|
||||
}
|
||||
|
||||
public ReflectConfigMetadataRepository registerAdaptiveType(List<Class<?>> classes) {
|
||||
types.addAll(classes.stream().map(this::buildTypeDescriberWithConstructor).collect(Collectors.toList()));
|
||||
return this;
|
||||
}
|
||||
|
||||
public ReflectConfigMetadataRepository registerBeanType(List<Class<?>> classes) {
|
||||
types.addAll(classes.stream().map(this::buildTypeDescriberWithConstructor).collect(Collectors.toList()));
|
||||
return this;
|
||||
}
|
||||
|
||||
public ReflectConfigMetadataRepository registerConfigType(List<Class<?>> classes) {
|
||||
types.addAll(classes.stream().map(this::buildTypeDescriberWithConstructor).collect(Collectors.toList()));
|
||||
return this;
|
||||
}
|
||||
|
||||
private TypeDescriber buildTypeDescriberWithConstructor(Class<?> c) {
|
||||
Set<ExecutableDescriber> constructors = Arrays.stream(c.getConstructors()).map((constructor) -> new ExecutableDescriber(constructor, INVOKE)).collect(Collectors.toSet());
|
||||
Set<MemberCategory> memberCategories = new HashSet<>();
|
||||
memberCategories.add(MemberCategory.INVOKE_PUBLIC_METHODS);
|
||||
return new TypeDescriber(c.getName(), null, new HashSet<>(), constructors, new HashSet<>(), memberCategories);
|
||||
}
|
||||
|
||||
public List<TypeDescriber> getTypes() {
|
||||
return types;
|
||||
}
|
||||
}
|
||||
|
|
@ -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.aot.generate;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Write {@link ReflectConfigMetadataRepository} to the JSON output expected by the GraalVM
|
||||
* {@code native-image} compiler, typically named {@code reflect-config.json}
|
||||
* or {@code jni-config.json}.
|
||||
*/
|
||||
public class ReflectionConfigWriter {
|
||||
|
||||
public static final ReflectionConfigWriter INSTANCE = new ReflectionConfigWriter();
|
||||
|
||||
public void write(BasicJsonWriter writer, ReflectConfigMetadataRepository repository) {
|
||||
writer.writeArray(repository.getTypes().stream().map(this::toAttributes).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
private Map<String, Object> toAttributes(TypeDescriber describer) {
|
||||
Map<String, Object> attributes = new LinkedHashMap<>();
|
||||
attributes.put("name", describer.getName());
|
||||
handleCondition(attributes, describer);
|
||||
handleCategories(attributes, describer.getMemberCategories());
|
||||
handleFields(attributes, describer.getFields());
|
||||
handleExecutables(attributes, describer.getConstructors());
|
||||
handleExecutables(attributes, describer.getMethods());
|
||||
return attributes;
|
||||
}
|
||||
|
||||
private void handleCondition(Map<String, Object> attributes, TypeDescriber describer) {
|
||||
if (describer.getReachableType() != null) {
|
||||
Map<String, Object> conditionAttributes = new LinkedHashMap<>();
|
||||
conditionAttributes.put("typeReachable", describer.getReachableType());
|
||||
attributes.put("condition", conditionAttributes);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleFields(Map<String, Object> attributes, Set<FieldDescriber> fieldDescribers) {
|
||||
addIfNotEmpty(attributes, "fields", fieldDescribers.stream().map(this::toAttributes).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
private Map<String, Object> toAttributes(FieldDescriber describer) {
|
||||
Map<String, Object> attributes = new LinkedHashMap<>();
|
||||
attributes.put("name", describer.getName());
|
||||
return attributes;
|
||||
}
|
||||
|
||||
private void handleExecutables(Map<String, Object> attributes, Set<ExecutableDescriber> executableDescribers) {
|
||||
addIfNotEmpty(attributes, "methods", executableDescribers.stream()
|
||||
.filter(h -> h.getMode().equals(ExecutableMode.INVOKE))
|
||||
.map(this::toAttributes).collect(Collectors.toList()));
|
||||
addIfNotEmpty(attributes, "queriedMethods", executableDescribers.stream()
|
||||
.filter(h -> h.getMode().equals(ExecutableMode.INTROSPECT))
|
||||
.map(this::toAttributes).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
private Map<String, Object> toAttributes(ExecutableDescriber describer) {
|
||||
Map<String, Object> attributes = new LinkedHashMap<>();
|
||||
attributes.put("name", describer.getName());
|
||||
attributes.put("parameterTypes", describer.getParameterTypes());
|
||||
return attributes;
|
||||
}
|
||||
|
||||
private void handleCategories(Map<String, Object> attributes, Set<MemberCategory> categories) {
|
||||
categories.forEach(category -> {
|
||||
switch (category) {
|
||||
case PUBLIC_FIELDS:
|
||||
attributes.put("allPublicFields", true);
|
||||
break;
|
||||
case DECLARED_FIELDS:
|
||||
attributes.put("allDeclaredFields", true);
|
||||
break;
|
||||
case INTROSPECT_PUBLIC_CONSTRUCTORS:
|
||||
attributes.put("queryAllPublicConstructors", true);
|
||||
break;
|
||||
case INTROSPECT_DECLARED_CONSTRUCTORS:
|
||||
attributes.put("queryAllDeclaredConstructors", true);
|
||||
break;
|
||||
case INVOKE_PUBLIC_CONSTRUCTORS:
|
||||
attributes.put("allPublicConstructors", true);
|
||||
break;
|
||||
case INVOKE_DECLARED_CONSTRUCTORS:
|
||||
attributes.put("allDeclaredConstructors", true);
|
||||
break;
|
||||
case INTROSPECT_PUBLIC_METHODS:
|
||||
attributes.put("queryAllPublicMethods", true);
|
||||
break;
|
||||
case INTROSPECT_DECLARED_METHODS:
|
||||
attributes.put("queryAllDeclaredMethods", true);
|
||||
break;
|
||||
case INVOKE_PUBLIC_METHODS:
|
||||
attributes.put("allPublicMethods", true);
|
||||
break;
|
||||
case INVOKE_DECLARED_METHODS:
|
||||
attributes.put("allDeclaredMethods", true);
|
||||
break;
|
||||
case PUBLIC_CLASSES:
|
||||
attributes.put("allPublicClasses", true);
|
||||
break;
|
||||
case DECLARED_CLASSES:
|
||||
attributes.put("allDeclaredClasses", true);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private void addIfNotEmpty(Map<String, Object> attributes, String name, Object value) {
|
||||
if ((value instanceof Collection<?> && ((Collection<?>) value).size() != 0)) {
|
||||
attributes.put(name, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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.aot.generate;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
/**
|
||||
* A describer that describes the need to access a {@link ResourceBundle}.
|
||||
*/
|
||||
public class ResourceBundleDescriber implements ConditionalDescriber {
|
||||
|
||||
private final String name;
|
||||
|
||||
private final List<String> locales;
|
||||
|
||||
private final String reachableType;
|
||||
|
||||
|
||||
public ResourceBundleDescriber(String name, List<String> locales, String reachableType) {
|
||||
this.name = name;
|
||||
this.locales = locales;
|
||||
this.reachableType = reachableType;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public List<String> getLocales() {
|
||||
return locales;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getReachableType() {
|
||||
return reachableType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
ResourceBundleDescriber that = (ResourceBundleDescriber) o;
|
||||
return name.equals(that.name) && locales.equals(that.locales) && reachableType.equals(that.reachableType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(name, locales, reachableType);
|
||||
}
|
||||
}
|
||||
|
|
@ -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.aot.generate;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class ResourceConfigMetadataRepository {
|
||||
|
||||
private final List<ResourcePatternDescriber> includes;
|
||||
|
||||
private final List<ResourcePatternDescriber> excludes;
|
||||
|
||||
private final Set<ResourceBundleDescriber> resourceBundles;
|
||||
|
||||
public ResourceConfigMetadataRepository() {
|
||||
this.includes = new ArrayList<>();
|
||||
this.excludes = new ArrayList<>();
|
||||
this.resourceBundles = new LinkedHashSet<>();
|
||||
}
|
||||
|
||||
public ResourceConfigMetadataRepository registerIncludesPatterns(String... patterns) {
|
||||
for (String pattern : patterns) {
|
||||
registerIncludesPattern(new ResourcePatternDescriber(pattern,null));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public ResourceConfigMetadataRepository registerIncludesPattern(ResourcePatternDescriber describer) {
|
||||
this.includes.add(describer);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ResourceConfigMetadataRepository registerExcludesPattern(ResourcePatternDescriber describer) {
|
||||
this.excludes.add(describer);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ResourceConfigMetadataRepository registerBundles(ResourceBundleDescriber describer) {
|
||||
this.resourceBundles.add(describer);
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<ResourcePatternDescriber> getIncludes() {
|
||||
return includes;
|
||||
}
|
||||
|
||||
public List<ResourcePatternDescriber> getExcludes() {
|
||||
return excludes;
|
||||
}
|
||||
|
||||
public Set<ResourceBundleDescriber> getResourceBundles() {
|
||||
return resourceBundles;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* 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.aot.generate;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Write a {@link ResourceConfigMetadataRepository} to the JSON output expected by the GraalVM
|
||||
* {@code native-image} compiler, typically named {@code resource-config.json}.
|
||||
*/
|
||||
public class ResourceConfigWriter {
|
||||
|
||||
public static final ResourceConfigWriter INSTANCE = new ResourceConfigWriter();
|
||||
|
||||
public void write(BasicJsonWriter writer, ResourceConfigMetadataRepository repository) {
|
||||
Map<String, Object> attributes = new LinkedHashMap<>();
|
||||
addIfNotEmpty(attributes, "resources", toAttributes(repository.getIncludes(), repository.getExcludes()));
|
||||
handleResourceBundles(attributes, repository.getResourceBundles());
|
||||
writer.writeObject(attributes);
|
||||
}
|
||||
|
||||
private Map<String, Object> toAttributes(List<ResourcePatternDescriber> includes, List<ResourcePatternDescriber> excludes) {
|
||||
Map<String, Object> attributes = new LinkedHashMap<>();
|
||||
addIfNotEmpty(attributes, "includes", includes.stream().distinct().map(this::toAttributes).collect(Collectors.toList()));
|
||||
addIfNotEmpty(attributes, "excludes", excludes.stream().distinct().map(this::toAttributes).collect(Collectors.toList()));
|
||||
return attributes;
|
||||
}
|
||||
|
||||
private void handleResourceBundles(Map<String, Object> attributes, Set<ResourceBundleDescriber> resourceBundleDescribers) {
|
||||
addIfNotEmpty(attributes, "bundles", resourceBundleDescribers.stream().map(this::toAttributes).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
private Map<String, Object> toAttributes(ResourceBundleDescriber describer) {
|
||||
Map<String, Object> attributes = new LinkedHashMap<>();
|
||||
handleCondition(attributes, describer);
|
||||
attributes.put("name", describer.getName());
|
||||
return attributes;
|
||||
}
|
||||
|
||||
private Map<String, Object> toAttributes(ResourcePatternDescriber describer) {
|
||||
Map<String, Object> attributes = new LinkedHashMap<>();
|
||||
handleCondition(attributes, describer);
|
||||
attributes.put("pattern", describer.toRegex().toString());
|
||||
return attributes;
|
||||
}
|
||||
|
||||
private void addIfNotEmpty(Map<String, Object> attributes, String name, Object value) {
|
||||
if (value instanceof Collection<?>) {
|
||||
if (!((Collection<?>) value).isEmpty()) {
|
||||
attributes.put(name, value);
|
||||
}
|
||||
} else if (value instanceof Map<?, ?>) {
|
||||
if (!((Map<?, ?>) value).isEmpty()) {
|
||||
attributes.put(name, value);
|
||||
}
|
||||
} else if (value != null) {
|
||||
attributes.put(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleCondition(Map<String, Object> attributes, ConditionalDescriber conditionalDescriber) {
|
||||
if (conditionalDescriber.getReachableType() != null) {
|
||||
Map<String, Object> conditionAttributes = new LinkedHashMap<>();
|
||||
conditionAttributes.put("typeReachable", conditionalDescriber.getReachableType());
|
||||
attributes.put("condition", conditionAttributes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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.aot.generate;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* A describer that describes resources that should be made available at runtime.
|
||||
*/
|
||||
public class ResourcePatternDescriber implements ConditionalDescriber {
|
||||
|
||||
private final String pattern;
|
||||
|
||||
private final String reachableType;
|
||||
|
||||
public ResourcePatternDescriber(String pattern, String reachableType) {
|
||||
this.pattern = pattern;
|
||||
this.reachableType = reachableType;
|
||||
}
|
||||
|
||||
public String getPattern() {
|
||||
return pattern;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getReachableType() {
|
||||
return reachableType;
|
||||
}
|
||||
|
||||
public Pattern toRegex() {
|
||||
String prefix = (this.pattern.startsWith("*") ? ".*" : "");
|
||||
String suffix = (this.pattern.endsWith("*") ? ".*" : "");
|
||||
String regex = Arrays.stream(this.pattern.split("\\*"))
|
||||
.filter(s -> !s.isEmpty())
|
||||
.map(Pattern::quote)
|
||||
.collect(Collectors.joining(".*", prefix, suffix));
|
||||
return Pattern.compile(regex);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* 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.aot.generate;
|
||||
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* A scanner for processing and filtering specific resource.
|
||||
*/
|
||||
public class ResourceScanner extends JarScanner {
|
||||
|
||||
private static final String DUBBO_INTERNAL_RESOURCE_DIRECTORY = "META-INF/dubbo/internal/";
|
||||
|
||||
private static final String DUBBO_RESOURCE_DIRECTORY = "META-INF/dubbo/";
|
||||
|
||||
private static final String SERVICES_RESOURCE_DIRECTORY = "META-INF/services/";
|
||||
|
||||
private static final String SECURITY_RESOURCE_DIRECTORY = "security/";
|
||||
|
||||
public static final ResourceScanner INSTANCE = new ResourceScanner();
|
||||
|
||||
public Set<String> distinctSpiResource() {
|
||||
return getResourcePath().stream().distinct().filter(this::matchedSpiResource).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
public Set<String> distinctSecurityResource() {
|
||||
return getResourcePath().stream().distinct().filter(this::matchedSecurityResource).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
private boolean matchedSecurityResource(String path) {
|
||||
return path.startsWith(SECURITY_RESOURCE_DIRECTORY);
|
||||
}
|
||||
|
||||
private boolean matchedSpiResource(String path) {
|
||||
return path.startsWith(DUBBO_INTERNAL_RESOURCE_DIRECTORY)
|
||||
|| path.startsWith(DUBBO_RESOURCE_DIRECTORY)
|
||||
|| path.startsWith(SERVICES_RESOURCE_DIRECTORY);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -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.aot.generate;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A describer that describes the need for reflection on a type.
|
||||
*/
|
||||
public class TypeDescriber implements ConditionalDescriber {
|
||||
|
||||
private final String name;
|
||||
|
||||
private final String reachableType;
|
||||
|
||||
private final Set<FieldDescriber> fields;
|
||||
|
||||
private final Set<ExecutableDescriber> constructors;
|
||||
|
||||
private final Set<ExecutableDescriber> methods;
|
||||
|
||||
private final Set<MemberCategory> memberCategories;
|
||||
|
||||
public TypeDescriber(String name, String reachableType, Set<FieldDescriber> fields,
|
||||
Set<ExecutableDescriber> constructors, Set<ExecutableDescriber> methods,
|
||||
Set<MemberCategory> memberCategories) {
|
||||
this.name = name;
|
||||
this.reachableType = reachableType;
|
||||
this.fields = fields;
|
||||
this.constructors = constructors;
|
||||
this.methods = methods;
|
||||
this.memberCategories = memberCategories;
|
||||
}
|
||||
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public Set<MemberCategory> getMemberCategories() {
|
||||
return memberCategories;
|
||||
}
|
||||
|
||||
public Set<FieldDescriber> getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
public Set<ExecutableDescriber> getConstructors() {
|
||||
return constructors;
|
||||
}
|
||||
|
||||
public Set<ExecutableDescriber> getMethods() {
|
||||
return methods;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getReachableType() {
|
||||
return reachableType;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* 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.aot.generate;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class ResourcePatternDescriberTest {
|
||||
@Test
|
||||
public void testToRegex() {
|
||||
ResourcePatternDescriber describer = new ResourcePatternDescriber("META-INF/dubbo/internal/org.apache.dubbo.common.extension.ExtensionInjector", null);
|
||||
Assertions.assertEquals("\\QMETA-INF/dubbo/internal/org.apache.dubbo.common.extension.ExtensionInjector\\E",describer.toRegex().toString());
|
||||
}
|
||||
}
|
||||
3
pom.xml
3
pom.xml
|
|
@ -334,6 +334,9 @@
|
|||
**/org/apache/dubbo/maven/plugin/aot/MatchingGroupIdFilter.java,
|
||||
**/org/apache/dubbo/maven/plugin/aot/RunArguments.java,
|
||||
**/org/apache/dubbo/maven/plugin/aot/RunProcess.java,
|
||||
**/org/apache/dubbo/aot/generate/BasicJsonWriter.java,
|
||||
**/org/apache/dubbo/aot/generate/ExecutableMode.java,
|
||||
**/org/apache/dubbo/aot/generate/MemberCategory.java,
|
||||
**/org/apache/dubbo/common/threadpool/serial/SerializingExecutor.java,
|
||||
**/org/apache/dubbo/common/threadlocal/InternalThreadLocal.java,
|
||||
**/org/apache/dubbo/common/threadlocal/InternalThreadLocalMap.java,
|
||||
|
|
|
|||
Loading…
Reference in New Issue