This is an automated email from the ASF dual-hosted git repository. liujun pushed a commit to branch 3.0-metadata-refactor in repository https://gitbox.apache.org/repos/asf/dubbo.git
commit 33d31c4b779af79079eef24d163b378b79a45582 Author: ken.lj <[email protected]> AuthorDate: Thu Nov 4 22:29:21 2021 +0800 add new files --- .../definition/MethodDefinitionBuilder.java | 78 +++++++++ .../definition/ServiceDefinitionBuilder.java | 126 ++++++++++++++ .../metadata/definition/TypeDefinitionBuilder.java | 87 ++++++++++ .../definition/builder/ArrayTypeBuilder.java | 56 +++++++ .../definition/builder/CollectionTypeBuilder.java | 83 ++++++++++ .../definition/builder/DefaultTypeBuilder.java | 65 ++++++++ .../definition/builder/EnumTypeBuilder.java | 69 ++++++++ .../definition/builder/MapTypeBuilder.java | 87 ++++++++++ .../metadata/definition/builder/TypeBuilder.java | 42 +++++ .../definition/model/FullServiceDefinition.java | 43 +++++ .../definition/model/MethodDefinition.java | 117 +++++++++++++ .../definition/model/ServiceDefinition.java | 136 +++++++++++++++ .../metadata/definition/model/TypeDefinition.java | 183 +++++++++++++++++++++ .../dubbo/metadata/definition/util/ClassUtils.java | 164 ++++++++++++++++++ .../definition/util/JaketConfigurationUtils.java | 102 ++++++++++++ 15 files changed, 1438 insertions(+) diff --git a/dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/MethodDefinitionBuilder.java b/dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/MethodDefinitionBuilder.java new file mode 100644 index 0000000..e7c18e6 --- /dev/null +++ b/dubbo-common/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<TypeDefinition> 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-common/src/main/java/org/apache/dubbo/metadata/definition/ServiceDefinitionBuilder.java b/dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/ServiceDefinitionBuilder.java new file mode 100755 index 0000000..cfdec72 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/ServiceDefinitionBuilder.java @@ -0,0 +1,126 @@ +/* + * 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.FullServiceDefinition; +import org.apache.dubbo.metadata.definition.model.MethodDefinition; +import org.apache.dubbo.metadata.definition.model.ServiceDefinition; +import org.apache.dubbo.metadata.definition.model.TypeDefinition; +import org.apache.dubbo.metadata.definition.util.ClassUtils; + +import com.google.gson.Gson; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * 2015/1/27. + */ +public final class ServiceDefinitionBuilder { + + /** + * Describe a Java interface in {@link ServiceDefinition}. + * + * @return Service description + */ + public static ServiceDefinition build(final Class<?> interfaceClass) { + ServiceDefinition sd = new ServiceDefinition(); + build(sd, interfaceClass); + return sd; + } + + public static FullServiceDefinition buildFullDefinition(final Class<?> interfaceClass) { + FullServiceDefinition sd = new FullServiceDefinition(); + build(sd, interfaceClass); + return sd; + } + + public static FullServiceDefinition buildFullDefinition(final Class<?> interfaceClass, Map<String, String> params) { + FullServiceDefinition sd = new FullServiceDefinition(); + build(sd, interfaceClass); + sd.setParameters(params); + return sd; + } + + public static <T extends ServiceDefinition> void build(T sd, final Class<?> interfaceClass) { + sd.setCanonicalName(interfaceClass.getCanonicalName()); + sd.setCodeSource(ClassUtils.getCodeSource(interfaceClass)); + Annotation[] classAnnotations = interfaceClass.getAnnotations(); + sd.setAnnotations(annotationToStringList(classAnnotations)); + + TypeDefinitionBuilder builder = new TypeDefinitionBuilder(); + List<Method> methods = ClassUtils.getPublicNonStaticMethods(interfaceClass); + for (Method method : methods) { + MethodDefinition md = new MethodDefinition(); + md.setName(method.getName()); + + Annotation[] methodAnnotations = method.getAnnotations(); + md.setAnnotations(annotationToStringList(methodAnnotations)); + + // Process parameter types. + Class<?>[] paramTypes = method.getParameterTypes(); + Type[] genericParamTypes = method.getGenericParameterTypes(); + + String[] parameterTypes = new String[paramTypes.length]; + for (int i = 0; i < paramTypes.length; i++) { + TypeDefinition td = builder.build(genericParamTypes[i], paramTypes[i]); + parameterTypes[i] = td.getType(); + } + md.setParameterTypes(parameterTypes); + + // Process return type. + TypeDefinition td = builder.build(method.getGenericReturnType(), method.getReturnType()); + md.setReturnType(td.getType()); + + sd.getMethods().add(md); + } + + sd.setTypes(builder.getTypeDefinitions()); + } + + private static List<String> annotationToStringList(Annotation[] annotations) { + if (annotations == null) { + return Collections.emptyList(); + } + List<String> list = new ArrayList<>(); + for (Annotation annotation : annotations) { + list.add(annotation.toString()); + } + return list; + } + + /** + * Describe a Java interface in Json schema. + * + * @return Service description + */ + public static String schema(final Class<?> clazz) { + ServiceDefinition sd = build(clazz); + Gson gson = new Gson(); + return gson.toJson(sd); + } + + private ServiceDefinitionBuilder() { + } +} + + diff --git a/dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/TypeDefinitionBuilder.java b/dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/TypeDefinitionBuilder.java new file mode 100755 index 0000000..b2758e3 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/TypeDefinitionBuilder.java @@ -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.metadata.definition; + +import org.apache.dubbo.common.extension.ExtensionLoader; +import org.apache.dubbo.common.logger.Logger; +import org.apache.dubbo.common.logger.LoggerFactory; +import org.apache.dubbo.common.utils.ClassUtils; +import org.apache.dubbo.metadata.definition.builder.DefaultTypeBuilder; +import org.apache.dubbo.metadata.definition.builder.TypeBuilder; +import org.apache.dubbo.metadata.definition.model.TypeDefinition; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + + +/** + * 2015/1/27. + */ +public class TypeDefinitionBuilder { + private static final Logger logger = LoggerFactory.getLogger(TypeDefinitionBuilder.class); + static final List<TypeBuilder> BUILDERS; + + static { + ExtensionLoader<TypeBuilder> extensionLoader = ExtensionLoader.getExtensionLoader(TypeBuilder.class); + Set<TypeBuilder> tbs = extensionLoader.getSupportedExtensionInstances(); + BUILDERS = new ArrayList<>(tbs); + } + + public static TypeDefinition build(Type type, Class<?> clazz, Map<String, TypeDefinition> typeCache) { + TypeBuilder builder = getGenericTypeBuilder(clazz); + TypeDefinition td; + + if (clazz.isPrimitive() || ClassUtils.isSimpleType(clazz)) { // changed since 2.7.6 + td = new TypeDefinition(clazz.getCanonicalName()); + typeCache.put(clazz.getCanonicalName(), td); + } else if (builder != null) { + td = builder.build(type, clazz, typeCache); + } else { + td = DefaultTypeBuilder.build(clazz, typeCache); + } + return td; + } + + private static TypeBuilder getGenericTypeBuilder(Class<?> clazz) { + for (TypeBuilder builder : BUILDERS) { + try { + if (builder.accept(clazz)) { + return builder; + } + } catch (NoClassDefFoundError cnfe) { + //ignore + logger.info("Throw classNotFound (" + cnfe.getMessage() + ") in " + builder.getClass()); + } + } + return null; + } + + private Map<String, TypeDefinition> typeCache = new HashMap<>(); + + public TypeDefinition build(Type type, Class<?> clazz) { + return build(type, clazz, typeCache); + } + + public List<TypeDefinition> getTypeDefinitions() { + return new ArrayList<>(typeCache.values()); + } + +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/builder/ArrayTypeBuilder.java b/dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/builder/ArrayTypeBuilder.java new file mode 100755 index 0000000..78cc7a5 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/builder/ArrayTypeBuilder.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.definition.builder; + +import org.apache.dubbo.metadata.definition.TypeDefinitionBuilder; +import org.apache.dubbo.metadata.definition.model.TypeDefinition; + +import java.lang.reflect.Type; +import java.util.Map; + +/** + * 2015/1/27. + */ +public class ArrayTypeBuilder implements TypeBuilder { + + @Override + public boolean accept(Class<?> clazz) { + if (clazz == null) { + return false; + } + return clazz.isArray(); + } + + @Override + public TypeDefinition build(Type type, Class<?> clazz, Map<String, TypeDefinition> typeCache) { + final String canonicalName = clazz.getCanonicalName(); + TypeDefinition td = typeCache.get(canonicalName); + if (td != null) { + return td; + } + td = new TypeDefinition(canonicalName); + typeCache.put(canonicalName, td); + // Process the component type of array. + Class<?> componentType = clazz.getComponentType(); + TypeDefinition itemTd = TypeDefinitionBuilder.build(componentType, componentType, typeCache); + if (itemTd != null) { + td.getItems().add(itemTd.getType()); + } + return td; + } + +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/builder/CollectionTypeBuilder.java b/dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/builder/CollectionTypeBuilder.java new file mode 100755 index 0000000..6c6ee11 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/builder/CollectionTypeBuilder.java @@ -0,0 +1,83 @@ +/* + * 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.builder; + +import org.apache.dubbo.metadata.definition.TypeDefinitionBuilder; +import org.apache.dubbo.metadata.definition.model.TypeDefinition; +import org.apache.dubbo.metadata.definition.util.ClassUtils; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.text.MessageFormat; +import java.util.Arrays; +import java.util.Collection; +import java.util.Map; + +/** + * 2015/1/27. + */ +public class CollectionTypeBuilder implements TypeBuilder { + + @Override + public boolean accept(Class<?> clazz) { + if (clazz == null) { + return false; + } + return Collection.class.isAssignableFrom(clazz); + } + + @Override + public TypeDefinition build(Type type, Class<?> clazz, Map<String, TypeDefinition> typeCache) { + if (!(type instanceof ParameterizedType)) { + return new TypeDefinition(clazz.getCanonicalName()); + } + + ParameterizedType parameterizedType = (ParameterizedType) type; + Type[] actualTypeArgs = parameterizedType.getActualTypeArguments(); + if (actualTypeArgs == null || actualTypeArgs.length != 1) { + throw new IllegalArgumentException(MessageFormat.format( + "[ServiceDefinitionBuilder] Collection type [{0}] with unexpected amount of arguments [{1}]." + + Arrays.toString(actualTypeArgs), + type, actualTypeArgs)); + } + + String colType = ClassUtils.getCanonicalNameForParameterizedType(parameterizedType); + TypeDefinition td = typeCache.get(colType); + if (td != null) { + return td; + } + td = new TypeDefinition(colType); + typeCache.put(colType, td); + + Type actualType = actualTypeArgs[0]; + TypeDefinition itemTd = null; + if (actualType instanceof ParameterizedType) { + // Nested collection or map. + Class<?> rawType = (Class<?>) ((ParameterizedType) actualType).getRawType(); + itemTd = TypeDefinitionBuilder.build(actualType, rawType, typeCache); + } else if (actualType instanceof Class<?>) { + Class<?> actualClass = (Class<?>) actualType; + itemTd = TypeDefinitionBuilder.build(null, actualClass, typeCache); + } + if (itemTd != null) { + td.getItems().add(itemTd.getType()); + } + + return td; + } + +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/builder/DefaultTypeBuilder.java b/dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/builder/DefaultTypeBuilder.java new file mode 100755 index 0000000..4ac52a4 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/builder/DefaultTypeBuilder.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.definition.builder; + +import org.apache.dubbo.metadata.definition.TypeDefinitionBuilder; +import org.apache.dubbo.metadata.definition.model.TypeDefinition; +import org.apache.dubbo.metadata.definition.util.ClassUtils; +import org.apache.dubbo.metadata.definition.util.JaketConfigurationUtils; + +import java.lang.reflect.Field; +import java.lang.reflect.Type; +import java.util.List; +import java.util.Map; + +/** + * 2015/1/27. + */ +public final class DefaultTypeBuilder { + + public static TypeDefinition build(Class<?> clazz, Map<String, TypeDefinition> typeCache) { + final String canonicalName = clazz.getCanonicalName(); + + // Try to get a cached definition + TypeDefinition td = typeCache.get(canonicalName); + if (td != null) { + return td; + } + td = new TypeDefinition(canonicalName); + typeCache.put(canonicalName, td); + + // Primitive type + if (!JaketConfigurationUtils.needAnalyzing(clazz)) { + return td; + } + + // Custom type + List<Field> fields = ClassUtils.getNonStaticFields(clazz); + for (Field field : fields) { + String fieldName = field.getName(); + Class<?> fieldClass = field.getType(); + Type fieldType = field.getGenericType(); + TypeDefinition fieldTd = TypeDefinitionBuilder.build(fieldType, fieldClass, typeCache); + td.getProperties().put(fieldName, fieldTd.getType()); + } + + return td; + } + + private DefaultTypeBuilder() { + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/builder/EnumTypeBuilder.java b/dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/builder/EnumTypeBuilder.java new file mode 100755 index 0000000..1f5d52a --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/builder/EnumTypeBuilder.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.definition.builder; + +import org.apache.dubbo.common.logger.Logger; +import org.apache.dubbo.common.logger.LoggerFactory; +import org.apache.dubbo.metadata.definition.TypeDefinitionBuilder; +import org.apache.dubbo.metadata.definition.model.TypeDefinition; + +import java.lang.reflect.Method; +import java.lang.reflect.Type; +import java.util.Map; + +/** + * 2015/1/27. + */ +public class EnumTypeBuilder implements TypeBuilder { + private static final Logger logger = LoggerFactory.getLogger(TypeDefinitionBuilder.class); + + @Override + public boolean accept(Class<?> clazz) { + if (clazz == null) { + return false; + } + return clazz.isEnum(); + } + + @Override + public TypeDefinition build(Type type, Class<?> clazz, Map<String, TypeDefinition> typeCache) { + String canonicalName = clazz.getCanonicalName(); + + TypeDefinition td = typeCache.get(canonicalName); + if (td != null) { + return td; + } + td = new TypeDefinition(canonicalName); + typeCache.put(canonicalName, td); + + try { + Method methodValues = clazz.getDeclaredMethod("values"); + methodValues.setAccessible(true); + Object[] values = (Object[]) methodValues.invoke(clazz, new Object[0]); + int length = values.length; + for (int i = 0; i < length; i++) { + Object value = values[i]; + td.getEnums().add(value.toString()); + } + return td; + } catch (Throwable t) { + logger.error("There is an error while process class " + clazz, t); + } + return td; + } + +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/builder/MapTypeBuilder.java b/dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/builder/MapTypeBuilder.java new file mode 100755 index 0000000..121198c --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/builder/MapTypeBuilder.java @@ -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.metadata.definition.builder; + +import org.apache.dubbo.metadata.definition.TypeDefinitionBuilder; +import org.apache.dubbo.metadata.definition.model.TypeDefinition; +import org.apache.dubbo.metadata.definition.util.ClassUtils; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.text.MessageFormat; +import java.util.Arrays; +import java.util.Map; + +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. + */ +public class MapTypeBuilder implements TypeBuilder { + + @Override + public boolean accept(Class<?> clazz) { + if (clazz == null) { + return false; + } + return Map.class.isAssignableFrom(clazz); + } + + @Override + public TypeDefinition build(Type type, Class<?> clazz, Map<String, TypeDefinition> typeCache) { + if (!(type instanceof ParameterizedType)) { + return new TypeDefinition(clazz.getCanonicalName()); + } + + ParameterizedType parameterizedType = (ParameterizedType) type; + Type[] actualTypeArgs = parameterizedType.getActualTypeArguments(); + 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)); + } + + String mapType = ClassUtils.getCanonicalNameForParameterizedType(parameterizedType); + + TypeDefinition td = typeCache.get(mapType); + if (td != null) { + return td; + } + td = new TypeDefinition(mapType); + typeCache.put(mapType, td); + + 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. + item = TypeDefinitionBuilder.build(actualType, rawType, typeCache); + } else if (isClass(actualType)) { + item = TypeDefinitionBuilder.build(null, rawType, typeCache); + } + if (item != null) { + td.getItems().add(item.getType()); + } + } + return td; + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/builder/TypeBuilder.java b/dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/builder/TypeBuilder.java new file mode 100755 index 0000000..050de3c --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/builder/TypeBuilder.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.definition.builder; + +import org.apache.dubbo.common.extension.SPI; +import org.apache.dubbo.common.lang.Prioritized; +import org.apache.dubbo.metadata.definition.model.TypeDefinition; + +import java.lang.reflect.Type; +import java.util.Map; + +/** + * 2015/1/27. + */ +@SPI +public interface TypeBuilder extends Prioritized { + + /** + * Whether the build accept the class passed in. + */ + boolean accept(Class<?> clazz); + + /** + * Build type definition with the type or class. + */ + TypeDefinition build(Type type, Class<?> clazz, Map<String, TypeDefinition> typeCache); + +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/model/FullServiceDefinition.java b/dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/model/FullServiceDefinition.java new file mode 100644 index 0000000..fbebcf1 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/model/FullServiceDefinition.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.definition.model; + +import java.util.Map; + +/** + * 2018/10/25 + */ +public class FullServiceDefinition extends ServiceDefinition { + + private Map<String, String> parameters; + + public Map<String, String> getParameters() { + return parameters; + } + + public void setParameters(Map<String, String> parameters) { + this.parameters = parameters; + } + + @Override + public String toString() { + return "FullServiceDefinition{" + + "parameters=" + parameters + + "} " + super.toString(); + } + +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/model/MethodDefinition.java b/dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/model/MethodDefinition.java new file mode 100755 index 0000000..305bfc3 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/model/MethodDefinition.java @@ -0,0 +1,117 @@ +/* + * 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.model; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +import static org.apache.dubbo.metadata.definition.model.TypeDefinition.formatType; +import static org.apache.dubbo.metadata.definition.model.TypeDefinition.formatTypes; + +/** + * 2015/1/27. + */ +public class MethodDefinition implements Serializable { + + private String name; + private String[] parameterTypes; + private String returnType; + + /** + * @deprecated please use parameterTypes, + * and find TypeDefinition in org.apache.dubbo.metadata.definition.model.ServiceDefinition#types + */ + @Deprecated + private List<TypeDefinition> parameters; + + private List<String> annotations; + + public String getName() { + return name; + } + + public List<TypeDefinition> getParameters() { + if (parameters == null) { + parameters = new ArrayList<>(); + } + return parameters; + } + + public String[] getParameterTypes() { + return parameterTypes; + } + + public String getReturnType() { + return returnType; + } + + public void setName(String name) { + this.name = name; + } + + public void setParameters(List<TypeDefinition> parameters) { + this.parameters = parameters; + } + + public void setParameterTypes(String[] parameterTypes) { + this.parameterTypes = formatTypes(parameterTypes); + } + + public void setReturnType(String returnType) { + this.returnType = formatType(returnType); + } + + public List<String> getAnnotations() { + if (annotations == null) { + annotations = Collections.emptyList(); + } + return annotations; + } + + public void setAnnotations(List<String> annotations) { + this.annotations = annotations; + } + + @Override + public String toString() { + return "MethodDefinition [name=" + name + ", parameterTypes=" + Arrays.toString(parameterTypes) + + ", returnType=" + returnType + "]"; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof MethodDefinition)) { + return false; + } + MethodDefinition that = (MethodDefinition) o; + return Objects.equals(getName(), that.getName()) && + Arrays.equals(getParameterTypes(), that.getParameterTypes()) && + Objects.equals(getReturnType(), that.getReturnType()); + } + + @Override + public int hashCode() { + return Objects.hash(getName(), getReturnType(), Arrays.toString(getParameterTypes())); + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/model/ServiceDefinition.java b/dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/model/ServiceDefinition.java new file mode 100755 index 0000000..a16eb6a --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/model/ServiceDefinition.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.definition.model; + +import org.apache.dubbo.metadata.definition.util.ClassUtils; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +/** + * 2015/1/27. + */ +public class ServiceDefinition implements Serializable { + + /** + * the canonical name of interface + * + * @see Class#getCanonicalName() + */ + private String canonicalName; + + /** + * the location of class file + * + * @see ClassUtils#getCodeSource(Class) + */ + private String codeSource; + + private List<MethodDefinition> methods; + + /** + * the definitions of type + */ + private List<TypeDefinition> types; + + /** + * the definitions of annotations + */ + private List<String> annotations; + + public String getCanonicalName() { + return canonicalName; + } + + public String getCodeSource() { + return codeSource; + } + + public List<MethodDefinition> getMethods() { + if (methods == null) { + methods = new ArrayList<>(); + } + return methods; + } + + public List<TypeDefinition> getTypes() { + if (types == null) { + types = new ArrayList<>(); + } + return types; + } + + public String getUniqueId() { + return canonicalName + "@" + codeSource; + } + + public void setCanonicalName(String canonicalName) { + this.canonicalName = canonicalName; + } + + public void setCodeSource(String codeSource) { + this.codeSource = codeSource; + } + + public void setMethods(List<MethodDefinition> methods) { + this.methods = methods; + } + + public void setTypes(List<TypeDefinition> types) { + this.types = types; + } + + public List<String> getAnnotations() { + if (annotations == null) { + annotations = Collections.emptyList(); + } + return annotations; + } + + public void setAnnotations(List<String> annotations) { + this.annotations = annotations; + } + + @Override + public String toString() { + return "ServiceDefinition [canonicalName=" + canonicalName + ", codeSource=" + codeSource + ", methods=" + + methods + "]"; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof ServiceDefinition)) { + return false; + } + ServiceDefinition that = (ServiceDefinition) o; + return Objects.equals(getCanonicalName(), that.getCanonicalName()) && + Objects.equals(getCodeSource(), that.getCodeSource()) && + Objects.equals(getMethods(), that.getMethods()) && + Objects.equals(getTypes(), that.getTypes()); + } + + @Override + public int hashCode() { + return Objects.hash(getCanonicalName(), getCodeSource(), getMethods(), getTypes()); + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/model/TypeDefinition.java b/dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/model/TypeDefinition.java new file mode 100755 index 0000000..6dd0f06 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/model/TypeDefinition.java @@ -0,0 +1,183 @@ +/* + * 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.model; + +import com.google.gson.annotations.SerializedName; + +import java.io.Serializable; +import java.lang.reflect.ParameterizedType; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import static org.apache.dubbo.common.utils.StringUtils.replace; + +/** + * 2015/1/27. + */ +public class TypeDefinition implements Serializable { + + /** + * the name of type + * + * @see Class#getCanonicalName() + * @see org.apache.dubbo.metadata.definition.util.ClassUtils#getCanonicalNameForParameterizedType(ParameterizedType) + */ + private String type; + + /** + * the items(generic parameter) of Map/List(ParameterizedType) + * <p> + * if this type is not ParameterizedType, the items is null or empty + */ + @SerializedName("items") + private List<String> items; + + /** + * the enum's value + * <p> + * If this type is not enum, enums is null or empty + */ + @SerializedName("enum") + private List<String> enums; + + /** + * the key is property name, + * the value is property's type name + */ + private Map<String, String> properties; + + public TypeDefinition() { + } + + public TypeDefinition(String type) { + this.setType(type); + } + + /** + * Format the {@link String} array presenting Java types + * + * @param types the strings presenting Java types + * @return new String array of Java types after be formatted + * @since 2.7.9 + */ + public static String[] formatTypes(String[] types) { + String[] newTypes = new String[types.length]; + for (int i = 0; i < types.length; i++) { + newTypes[i] = formatType(types[i]); + } + return newTypes; + } + + /** + * Format the {@link String} presenting Java type + * + * @param type the String presenting type + * @return new String presenting Java type after be formatted + * @since 2.7.9 + */ + public static String formatType(String type) { + if (isGenericType(type)) { + return formatGenericType(type); + } + return type; + } + + /** + * Replacing <code>", "</code> to <code>","</code> will not change the semantic of + * {@link ParameterizedType#toString()} + * + * @param type + * @return formatted type + * @see sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl + */ + private static String formatGenericType(String type) { + return replace(type, ", ", ","); + } + + private static boolean isGenericType(String type) { + return type.contains("<") && type.contains(">"); + } + + public List<String> getEnums() { + if (enums == null) { + enums = new ArrayList<>(); + } + return enums; + } + + public List<String> getItems() { + if (items == null) { + items = new ArrayList<>(); + } + return items; + } + + public Map<String, String> getProperties() { + if (properties == null) { + properties = new HashMap<>(); + } + return properties; + } + + public String getType() { + return type; + } + + public void setEnums(List<String> enums) { + this.enums = enums; + } + + public void setItems(List<String> items) { + this.items = items; + } + + public void setProperties(Map<String, String> properties) { + this.properties = properties; + } + + public void setType(String type) { + this.type = formatType(type); + } + + @Override + public String toString() { + return "TypeDefinition [type=" + type + ", properties=" + properties + "]"; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof TypeDefinition)) { + return false; + } + TypeDefinition that = (TypeDefinition) o; + return Objects.equals(getType(), that.getType()) && + Objects.equals(getItems(), that.getItems()) && + Objects.equals(getEnums(), that.getEnums()) && + Objects.equals(getProperties(), that.getProperties()); + } + + @Override + public int hashCode() { + return Objects.hash(getType(), getItems(), getEnums(), getProperties()); + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/util/ClassUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/util/ClassUtils.java new file mode 100755 index 0000000..c6f13d5 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/util/ClassUtils.java @@ -0,0 +1,164 @@ +/* + * 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.util; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.net.URL; +import java.security.CodeSource; +import java.security.ProtectionDomain; +import java.util.ArrayList; +import java.util.List; + +/** + * 2015/1/27. + */ +public final class ClassUtils { + + /** + * Get the code source file or class path of the Class passed in. + * + * @param clazz + * @return Jar file name or class path. + */ + public static String getCodeSource(Class<?> clazz) { + ProtectionDomain protectionDomain = clazz.getProtectionDomain(); + if (protectionDomain == null || protectionDomain.getCodeSource() == null) { + return null; + } + + CodeSource codeSource = clazz.getProtectionDomain().getCodeSource(); + URL location = codeSource.getLocation(); + if (location == null) { + return null; + } + + String path = location.toExternalForm(); + + if (path.endsWith(".jar") && path.contains("/")) { + return path.substring(path.lastIndexOf('/') + 1); + } + return path; + } + + /** + * Get all non-static fields of the Class passed in or its super classes. + * <p> + * + * @param clazz Class to parse. + * @return field list + */ + public static List<Field> getNonStaticFields(final Class<?> clazz) { + List<Field> result = new ArrayList<>(); + Class<?> target = clazz; + while (target != null) { + if (JaketConfigurationUtils.isExcludedType(target)) { + break; + } + + Field[] fields = target.getDeclaredFields(); + for (Field field : fields) { + int modifiers = field.getModifiers(); + if (Modifier.isStatic(modifiers) || Modifier.isTransient(modifiers)) { + continue; + } + + result.add(field); + } + target = target.getSuperclass(); + } + + return result; + } + + /** + * Get all public, non-static methods of the Class passed in. + * <p> + * + * @param clazz Class to parse. + * @return methods list + */ + public static List<Method> getPublicNonStaticMethods(final Class<?> clazz) { + List<Method> result = new ArrayList<Method>(); + + Method[] methods = clazz.getMethods(); + for (Method method : methods) { + int mod = method.getModifiers(); + if (Modifier.isPublic(mod) && !Modifier.isStatic(mod)) { + result.add(method); + } + } + return result; + } + + public static String getCanonicalNameForParameterizedType(ParameterizedType parameterizedType) { + StringBuilder sb = new StringBuilder(); + Type ownerType = parameterizedType.getOwnerType(); + Class<?> rawType = (Class) parameterizedType.getRawType(); + Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); + + if (ownerType != null) { + if (ownerType instanceof Class) { + sb.append(((Class) ownerType).getName()); + } else { + sb.append(ownerType); + } + + sb.append('.'); + + if (ownerType instanceof ParameterizedType) { + // Find simple name of nested type by removing the + // shared prefix with owner. + sb.append(rawType.getName().replace(((Class) ((ParameterizedType) ownerType).getRawType()).getName() + "$", + "")); + } else { + sb.append(rawType.getSimpleName()); + } + } else { + sb.append(rawType.getCanonicalName()); + } + + if (actualTypeArguments != null && + actualTypeArguments.length > 0) { + sb.append('<'); + boolean first = true; + for (Type t : actualTypeArguments) { + if (!first) { + sb.append(", "); + } + if (t instanceof Class) { + Class c = (Class) t; + sb.append(c.getCanonicalName()); + } else if (t instanceof ParameterizedType) { + sb.append(getCanonicalNameForParameterizedType((ParameterizedType) t)); + } else { + sb.append(t.toString()); + } + first = false; + } + sb.append('>'); + } + + return sb.toString(); + } + + private ClassUtils() { + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/util/JaketConfigurationUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/util/JaketConfigurationUtils.java new file mode 100755 index 0000000..a21de3f --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/util/JaketConfigurationUtils.java @@ -0,0 +1,102 @@ +/* + * 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.util; + +import org.apache.dubbo.common.utils.StringUtils; + +import java.io.InputStream; +import java.util.Properties; + +/** + * 2015/1/27. + */ +public class JaketConfigurationUtils { + + private static final String CONFIGURATION_FILE = "jaket.properties"; + + private static String[] includedInterfacePackages; + private static String[] includedTypePackages; + private static String[] closedTypes; + + static { + Properties props = new Properties(); + InputStream inStream = JaketConfigurationUtils.class.getClassLoader().getResourceAsStream(CONFIGURATION_FILE); + try { + props.load(inStream); + String value = (String) props.get("included_interface_packages"); + if (StringUtils.isNotEmpty(value)) { + includedInterfacePackages = value.split(","); + } + + value = props.getProperty("included_type_packages"); + if (StringUtils.isNotEmpty(value)) { + includedTypePackages = value.split(","); + } + + value = props.getProperty("closed_types"); + if (StringUtils.isNotEmpty(value)) { + closedTypes = value.split(","); + } + + } catch (Throwable e) { + // Ignore it. + } + } + + public static boolean isExcludedInterface(Class<?> clazz) { + if (includedInterfacePackages == null || includedInterfacePackages.length == 0) { + return false; + } + + for (String packagePrefix : includedInterfacePackages) { + if (clazz.getCanonicalName().startsWith(packagePrefix)) { + return false; + } + } + + return true; + } + + public static boolean isExcludedType(Class<?> clazz) { + if (includedTypePackages == null || includedTypePackages.length == 0) { + return false; + } + + for (String packagePrefix : includedTypePackages) { + if (clazz.getCanonicalName().startsWith(packagePrefix)) { + return false; + } + } + + return true; + } + + public static boolean needAnalyzing(Class<?> clazz) { + String canonicalName = clazz.getCanonicalName(); + + if (closedTypes != null && closedTypes.length > 0) { + for (String type : closedTypes) { + if (canonicalName.startsWith(type)) { + return false; + } + } + } + + return !isExcludedType(clazz); + } + +}
