diff --git a/dubbo-common/pom.xml b/dubbo-common/pom.xml index d9881957309..80d1ee3ff0b 100644 --- a/dubbo-common/pom.xml +++ b/dubbo-common/pom.xml @@ -15,7 +15,8 @@ limitations under the License. --> - + 4.0.0 org.apache.dubbo @@ -31,11 +32,19 @@ false + + + + javax.annotation + javax.annotation-api + + org.slf4j slf4j-api provided + commons-logging commons-logging @@ -44,11 +53,13 @@ log4j log4j + org.apache.logging.log4j log4j-api provided + org.apache.logging.log4j log4j-core diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/convert/Converter.java b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/Converter.java new file mode 100644 index 00000000000..c4e8dbc95bc --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/Converter.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.common.convert; + +import org.apache.dubbo.common.lang.Prioritized; + +import java.util.function.Function; + +/** + * An interface converts an source instance of type {@link S} to an target instance of type {@link T} + * + * @param the source type + * @param the target type + * @since 2.7.5 + */ +public interface Converter extends Function, Prioritized { + + /** + * Tests whether or not the specified the source type and the target type + * + * @param sourceType the source type + * @param targetType the target type + * @return true if support to convert + */ + default boolean accept(Class sourceType, Class targetType) { + return true; + } + + /** + * Converts an source instance of type {@link S} to an target instance of type {@link T} + * + * @param source an source instance of type {@link S} + * @return an target instance of type {@link T} + */ + T convert(S source); + + @Override + default T apply(S s) { + return convert(s); + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringConverter.java b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringConverter.java new file mode 100644 index 00000000000..ddb99a12b95 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringConverter.java @@ -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.common.convert; + +/** + * A converter converts a {@link String} value to the target instance of type {@link T} + * + * @param the target type + * @since 2.7.5 + */ +public interface StringConverter extends Converter { +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/function/Predicates.java b/dubbo-common/src/main/java/org/apache/dubbo/common/function/Predicates.java new file mode 100644 index 00000000000..7bc1b483c51 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/function/Predicates.java @@ -0,0 +1,115 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.common.function; + +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.function.Predicate; + +import static java.lang.Boolean.TRUE; +import static java.util.stream.Stream.of; + +/** + * The utilities class for Java {@link Predicate} + * + * @since 2.7.5 + */ +public interface Predicates { + + Predicate[] EMPTY_ARRAY = new Predicate[0]; + + /** + * {@link Predicate} always return true + * + * @param the type to test + * @return true + */ + static Predicate alwaysTrue() { + return e -> true; + } + + /** + * {@link Predicate} always return false + * + * @param the type to test + * @return false + */ + static Predicate alwaysFalse() { + return e -> false; + } + + + static Predicate map(Function> function, E element) { + return function.apply(element); + } + + // +// static Predicate map(Function> function, E... elements) { +// return and(predicates(function, elements)); +// } +// + + static Predicate[] predicates(Function> function, E... elements) { + return of(elements) + .map(e -> function.apply(e)) + .toArray(Predicate[]::new); + } + + static Predicate[] predicates(BiFunction> function, T value, E... elements) { + return of(elements) + .map(e -> function.apply(e, value)) + .toArray(Predicate[]::new); + } + + static Predicate predicate(BiFunction> function, T value, E... elements) { + return and(predicates(function, value, elements)); + } + + /** + * Convert a {@link Function} to {@link Predicate} + * + * @param function a {@link Function} + * @param the type to test + * @return non-null + */ + static Predicate predicate(Function function) { + return t -> TRUE.equals(function.apply(t)); + } + + /** + * a composed predicate that represents a short-circuiting logical AND of {@link Predicate predicates} + * + * @param predicates {@link Predicate predicates} + * @param the type to test + * @return non-null + */ + static Predicate and(Predicate... predicates) { + return of(predicates).reduce((a, b) -> a.and(b)).orElseGet(Predicates::alwaysTrue); + } + + /** + * a composed predicate that represents a short-circuiting logical OR of {@link Predicate predicates} + * + * @param predicates {@link Predicate predicates} + * @param the detected type + * @return non-null + */ + static Predicate or(Predicate... predicates) { + return of(predicates).reduce((a, b) -> a.or(b)).orElse(e -> true); + } + +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/function/Streams.java b/dubbo-common/src/main/java/org/apache/dubbo/common/function/Streams.java new file mode 100644 index 00000000000..65e4fa6faec --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/function/Streams.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.common.function; + +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; +import java.util.function.Predicate; +import java.util.stream.Stream; + +import static java.util.stream.Collectors.toList; +import static java.util.stream.StreamSupport.stream; +import static org.apache.dubbo.common.function.Predicates.and; +import static org.apache.dubbo.common.function.Predicates.or; + +/** + * The utilities class for {@link Stream} + * + * @since 2.7.5 + */ +public interface Streams { + + static > Stream filterStream(S values, Predicate predicate) { + return stream(values.spliterator(), false).filter(predicate); + } + + static > List filterList(S values, Predicate predicate) { + return filterStream(values, predicate).collect(toList()); + } + + static > Set filterSet(S values, Predicate predicate) { + // new Set with insertion order + return filterStream(values, predicate).collect(LinkedHashSet::new, Set::add, Set::addAll); + } + + static > S filter(S values, Predicate predicate) { + final boolean isSet = Set.class.isAssignableFrom(values.getClass()); + return (S) (isSet ? filterSet(values, predicate) : filterList(values, predicate)); + } + + static > S filterAll(S values, Predicate... predicates) { + return filter(values, and(predicates)); + } + + static > S filterAny(S values, Predicate... predicates) { + return filter(values, or(predicates)); + } + + static T filterFirst(Iterable values, Predicate... predicates) { + return stream(values.spliterator(), false) + .filter(and(predicates)) + .findFirst() + .orElse(null); + } +} + + diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/lang/ShutdownHookCallbacks.java b/dubbo-common/src/main/java/org/apache/dubbo/common/lang/ShutdownHookCallbacks.java index a5555e88dd8..41d6dee5332 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/lang/ShutdownHookCallbacks.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/lang/ShutdownHookCallbacks.java @@ -22,7 +22,7 @@ import static java.util.Collections.sort; import static org.apache.dubbo.common.function.ThrowableAction.execute; -import static org.apache.dubbo.common.utils.DubboServiceLoader.load; +import static org.apache.dubbo.common.utils.PrioritizedServiceLoader.load; /** * The compose {@link ShutdownHookCallback} class to manipulate one and more {@link ShutdownHookCallback} instances diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/CollectionUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/CollectionUtils.java index 40baecdd2db..d3d8cc028c9 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/CollectionUtils.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/CollectionUtils.java @@ -21,8 +21,14 @@ import java.util.Collections; import java.util.Comparator; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; + +import static java.util.Arrays.asList; +import static java.util.Collections.emptySet; +import static java.util.Collections.unmodifiableSet; public class CollectionUtils { @@ -217,4 +223,17 @@ public static boolean isNotEmptyMap(Map map) { return !isEmptyMap(map); } + /** + * Convert to multiple values to be {@link HashSet} + * + * @param values one or more values + * @param the type of values + * @return read-only {@link HashSet} + */ + public static Set asHashSet(T... values) { + if (values == null || values.length < 1) { + return emptySet(); + } + return unmodifiableSet(new HashSet(asList(values))); + } } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/DubboServiceLoader.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/PrioritizedServiceLoader.java similarity index 95% rename from dubbo-common/src/main/java/org/apache/dubbo/common/utils/DubboServiceLoader.java rename to dubbo-common/src/main/java/org/apache/dubbo/common/utils/PrioritizedServiceLoader.java index 637440af30a..dcbcd270005 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/DubboServiceLoader.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/PrioritizedServiceLoader.java @@ -27,13 +27,13 @@ import static java.util.stream.StreamSupport.stream; /** - * An extension class of {@link ServiceLoader} to help the ease for use of Dubbo services/components + * An extension class of {@link ServiceLoader} with {@link Prioritized} feature * * @see ServiceLoader * @see Prioritized * @since 2.7.5 */ -public class DubboServiceLoader { +public interface PrioritizedServiceLoader { /** * Load a {@link Stream stream} of services by the specified {@link Class type} and {@link ClassLoader} @@ -51,7 +51,7 @@ public static Stream load(Class serviceClass, ClassLoader classLoader) ClassLoader actualClassLoader = classLoader; if (actualClassLoader == null) { - actualClassLoader = DubboServiceLoader.class.getClassLoader(); + actualClassLoader = PrioritizedServiceLoader.class.getClassLoader(); } ServiceLoader serviceLoader = ServiceLoader.load(serviceClass, actualClassLoader); diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/StringUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/StringUtils.java index 53557a31bd0..c3d81a10134 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/StringUtils.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/StringUtils.java @@ -32,6 +32,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import static java.lang.String.valueOf; import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SEPARATOR; import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SPLIT_PATTERN; import static org.apache.dubbo.common.constants.CommonConstants.DOT_REGEX; @@ -57,6 +58,34 @@ public final class StringUtils { private static final Pattern INT_PATTERN = Pattern.compile("^\\d+$"); private static final int PAD_LIMIT = 8192; + /** + * @since 2.7.5 + */ + public static final char EQUAL_CHAR = '='; + + public static final String EQUAL = valueOf(EQUAL_CHAR); + + public static final char AND_CHAR = '&'; + + public static final String AND = valueOf(AND_CHAR); + + public static final char SEMICOLON_CHAR = ';'; + + public static final String SEMICOLON = valueOf(SEMICOLON_CHAR); + + public static final char QUESTION_MASK_CHAR = '?'; + + public static final String QUESTION_MASK = valueOf(QUESTION_MASK_CHAR); + + public static final char SLASH_CHAR = '/'; + + public static final String SLASH = valueOf(SLASH_CHAR); + + /** + * The empty value + */ + public static final String EMPTY_VALUE = ""; + private StringUtils() { } @@ -819,7 +848,7 @@ public static boolean isAllUpperCase(String str) { if (str != null && !isEmpty(str)) { int sz = str.length(); - for(int i = 0; i < sz; ++i) { + for (int i = 0; i < sz; ++i) { if (!Character.isUpperCase(str.charAt(i))) { return false; } diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/DubboServiceLoaderTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/DubboServiceLoaderTest.java index b3b27e63456..d2d0cf69904 100644 --- a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/DubboServiceLoaderTest.java +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/DubboServiceLoaderTest.java @@ -20,11 +20,11 @@ import java.util.List; -import static org.apache.dubbo.common.utils.DubboServiceLoader.loadServices; +import static org.apache.dubbo.common.utils.PrioritizedServiceLoader.loadServices; import static org.junit.jupiter.api.Assertions.assertEquals; /** - * {@link DubboServiceLoader} Test + * {@link PrioritizedServiceLoader} Test * * @since 2.7.5 */ diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/annotation/Service.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/annotation/Service.java index 8b13373b963..867d5d8e226 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/annotation/Service.java +++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/annotation/Service.java @@ -274,6 +274,7 @@ /** * methods support + * * @return */ Method[] methods() default {}; diff --git a/dubbo-dependencies-bom/pom.xml b/dubbo-dependencies-bom/pom.xml index 3c5b4327508..f95cee22c1d 100644 --- a/dubbo-dependencies-bom/pom.xml +++ b/dubbo-dependencies-bom/pom.xml @@ -89,6 +89,16 @@ + + 3.1.0 + 1.3.1 + 1.1.0.Final + 2.0 + 1.0.0 + 2.2.7 + 1.2.0 + 2.0 + 4.3.16.RELEASE 3.20.0-GA @@ -110,12 +120,10 @@ 0.12.0 4.0.38 3.6.0 - 3.1.0 + 9.4.11.v20180605 - 1.1.0.Final 5.4.1.Final 3.0.1-b08 - 1.0.0 4.0.1 0.42 2.48-jdk-6 @@ -125,7 +133,6 @@ 3.8.1 1.5.9 - 2.0 3.0.19.Final 8.5.31 0.3.0 @@ -144,8 +151,6 @@ 1.9.12 - 2.2.7 - 1.2.0 1.11.2 0.3.0 3.2.5 @@ -157,13 +162,62 @@ 2.8.5 1.2.0 6.1.26 - 2.0 1.1.0 2.7.5-cloudnative-SNAPSHOT + + + + javax.servlet + javax.servlet-api + ${servlet_version} + + + + javax.annotation + javax.annotation-api + ${annotation_version} + + + + javax.validation + validation-api + ${validation_version} + + + + javax.cache + cache-api + ${jcache_version} + + + + javax.ws.rs + javax.ws.rs-api + ${rs_api_version} + + + + javax.xml.bind + jaxb-api + ${jaxb_version} + + + + javax.activation + javax.activation-api + ${activation_version} + + + + javax.portlet + portlet-api + ${portlet_version} + + org.springframework @@ -311,11 +365,7 @@ protobuf-java-util ${protobuf-java_version} - - javax.servlet - javax.servlet-api - ${servlet_version} - + org.eclipse.jetty jetty-server @@ -332,11 +382,7 @@ ${mortbay_jetty_version} true - - javax.validation - validation-api - ${validation_version} - + org.hibernate hibernate-validator @@ -347,11 +393,6 @@ javax.el ${jel_version} - - javax.cache - cache-api - ${jcache_version} - com.esotericsoftware kryo @@ -382,11 +423,6 @@ protostuff-runtime ${protostuff_version} - - javax.ws.rs - javax.ws.rs-api - ${rs_api_version} - org.jboss.resteasy resteasy-jaxrs @@ -512,11 +548,6 @@ - - javax.xml.bind - jaxb-api - ${jaxb_version} - com.sun.xml.bind jaxb-impl @@ -527,11 +558,7 @@ jaxb-core ${jaxb_version} - - javax.activation - javax.activation-api - ${activation_version} - + com.sun.activation javax.activation @@ -620,11 +647,6 @@ jsonrpc4j ${jsonrpc_version} - - javax.portlet - portlet-api - ${portlet_version} - io.etcd diff --git a/dubbo-metadata/dubbo-metadata-api/pom.xml b/dubbo-metadata/dubbo-metadata-api/pom.xml index 8c9a80c80dc..cb3002ab0c3 100644 --- a/dubbo-metadata/dubbo-metadata-api/pom.xml +++ b/dubbo-metadata/dubbo-metadata-api/pom.xml @@ -44,7 +44,7 @@ dubbo-cluster ${project.parent.version} - + com.google.code.gson gson diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/RequestMetadata.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/RequestMetadata.java new file mode 100644 index 00000000000..830840dcce7 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/RequestMetadata.java @@ -0,0 +1,225 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.rest; + + +import org.apache.dubbo.common.utils.CollectionUtils; + +import java.io.Serializable; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +import static java.util.Collections.unmodifiableMap; +import static org.apache.dubbo.common.utils.StringUtils.isBlank; +import static org.apache.dubbo.metadata.util.HttpUtils.normalizePath; + +/** + * The metadata class for REST request + * + * @since 2.7.5 + */ +public class RequestMetadata implements Serializable { + + private static final long serialVersionUID = -240099840085329958L; + + private String method; + + private String path; + + private Map> params = new LinkedHashMap<>(); + + private Map> headers = new LinkedHashMap<>(); + + private Set consumes = new LinkedHashSet<>(); + + private Set produces = new LinkedHashSet<>(); + + /** + * Default Constructor + */ + public RequestMetadata() { + } + + public String getMethod() { + return method; + } + + public void setMethod(String method) { + this.method = method == null ? null : method.toUpperCase(); + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = normalizePath(path); + } + + public Map> getParams() { + return unmodifiableMap(params); + } + + public void setParams(Map> params) { + params(params); + } + + private static void add(Map> multiValueMap, String key, String value) { + if (isBlank(key)) { + return; + } + List values = get(multiValueMap, key, true); + values.add(value); + } + + private static > void addAll(Map> multiValueMap, + Map source) { + for (Map.Entry entry : source.entrySet()) { + String key = entry.getKey(); + for (String value : entry.getValue()) { + add(multiValueMap, key, value); + } + } + } + + private static String getFirst(Map> multiValueMap, String key) { + List values = get(multiValueMap, key); + return CollectionUtils.isNotEmpty(values) ? values.get(0) : null; + } + + private static List get(Map> multiValueMap, String key) { + return get(multiValueMap, key, false); + } + + private static List get(Map> multiValueMap, String key, boolean createIfAbsent) { + return createIfAbsent ? multiValueMap.computeIfAbsent(key, k -> new LinkedList<>()) : multiValueMap.get(key); + } + + public Map> getHeaders() { + return unmodifiableMap(headers); + } + + public void setHeaders(Map> headers) { + headers(headers); + } + + public Set getConsumes() { + return consumes; + } + + public void setConsumes(Set consumes) { + this.consumes = consumes; + } + + public Set getProduces() { + return produces; + } + + public void setProduces(Set produces) { + this.produces = produces; + } + + public Set getParamNames() { + return params.keySet(); + } + + public Set getHeaderNames() { + return headers.keySet(); + } + +// public List getConsumeMediaTypes() { +// return toMediaTypes(consumes); +// } +// +// public List getProduceMediaTypes() { +// return toMediaTypes(produces); +// } + + public String getParameter(String name) { + return this.getFirst(params, name); + } + + public String getHeader(String name) { + return this.getFirst(headers, name); + } + + public RequestMetadata addParam(String name, String value) { + add(params, name, value); + return this; + } + + public RequestMetadata addHeader(String name, String value) { + add(headers, name, value); + return this; + } + + private > RequestMetadata params(Map params) { + addAll(this.params, params); + return this; + } + + private > RequestMetadata headers(Map> headers) { + if (headers != null && !headers.isEmpty()) { + Map> httpHeaders = new LinkedHashMap<>(); + // Add all headers + addAll(headers, httpHeaders); + // Handles "Content-Type" and "Accept" headers if present +// mediaTypes(httpHeaders, HttpHeaders.CONTENT_TYPE, this.consumes); +// mediaTypes(httpHeaders, HttpHeaders.ACCEPT, this.produces); + this.headers.putAll(httpHeaders); + } + return this; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof RequestMetadata)) { + return false; + } + RequestMetadata that = (RequestMetadata) o; + return Objects.equals(method, that.method) && Objects.equals(path, that.path) + && Objects.equals(consumes, that.consumes) + && Objects.equals(produces, that.produces) && + // Metadata should not compare the values + Objects.equals(getParamNames(), that.getParamNames()) + && Objects.equals(getHeaderNames(), that.getHeaderNames()); + + } + + @Override + public int hashCode() { + // The values of metadata should not use for the hashCode() method + return Objects.hash(method, path, consumes, produces, getParamNames(), + getHeaderNames()); + } + + @Override + public String toString() { + return "RequestMetadata{" + "method='" + method + '\'' + ", path='" + path + '\'' + + ", params=" + params + ", headers=" + headers + ", consumes=" + consumes + + ", produces=" + produces + '}'; + } +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/RestMethodMetadata.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/RestMethodMetadata.java new file mode 100644 index 00000000000..e43fce7af47 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/RestMethodMetadata.java @@ -0,0 +1,187 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.rest; + +import org.apache.dubbo.metadata.definition.model.MethodDefinition; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import static java.util.Collections.emptyList; + +/** + * The metadata class for {@link RequestMetadata HTTP(REST) request} and + * its binding {@link MethodDefinition method definition} + * + * @since 2.7.5 + */ +public class RestMethodMetadata implements Serializable { + + private static final long serialVersionUID = 2935252016200830694L; + + private MethodDefinition method; + + private RequestMetadata request; + + private Integer urlIndex; + + private Integer bodyIndex; + + private Integer headerMapIndex; + + private String bodyType; + + private Map> indexToName; + + private List formParams; + + private Map indexToEncoded; + + public MethodDefinition getMethod() { + if (method == null) { + method = new MethodDefinition(); + } + return method; + } + + public void setMethod(MethodDefinition method) { + this.method = method; + } + + public RequestMetadata getRequest() { + if (request == null) { + request = new RequestMetadata(); + } + return request; + } + + public void setRequest(RequestMetadata request) { + this.request = request; + } + + public Integer getUrlIndex() { + return urlIndex; + } + + public void setUrlIndex(Integer urlIndex) { + this.urlIndex = urlIndex; + } + + public Integer getBodyIndex() { + return bodyIndex; + } + + public void setBodyIndex(Integer bodyIndex) { + this.bodyIndex = bodyIndex; + } + + public Integer getHeaderMapIndex() { + return headerMapIndex; + } + + public void setHeaderMapIndex(Integer headerMapIndex) { + this.headerMapIndex = headerMapIndex; + } + + public String getBodyType() { + return bodyType; + } + + public void setBodyType(String bodyType) { + this.bodyType = bodyType; + } + + public Map> getIndexToName() { + if (indexToName == null) { + indexToName = new HashMap<>(); + } + return indexToName; + } + + public void setIndexToName(Map> indexToName) { + this.indexToName = indexToName; + } + + public void addIndexToName(Integer index, String name) { + Map> indexToName = getIndexToName(); + Collection parameterNames = indexToName.computeIfAbsent(index, i -> new ArrayList<>(1)); + parameterNames.add(name); + } + + public boolean hasIndexedName(Integer index, String name) { + Map> indexToName = getIndexToName(); + return indexToName.getOrDefault(index, emptyList()).contains(name); + } + + public List getFormParams() { + return formParams; + } + + public void setFormParams(List formParams) { + this.formParams = formParams; + } + + public Map getIndexToEncoded() { + return indexToEncoded; + } + + public void setIndexToEncoded(Map indexToEncoded) { + this.indexToEncoded = indexToEncoded; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof RestMethodMetadata)) return false; + RestMethodMetadata that = (RestMethodMetadata) o; + return Objects.equals(getMethod(), that.getMethod()) && + Objects.equals(getRequest(), that.getRequest()) && + Objects.equals(getUrlIndex(), that.getUrlIndex()) && + Objects.equals(getBodyIndex(), that.getBodyIndex()) && + Objects.equals(getHeaderMapIndex(), that.getHeaderMapIndex()) && + Objects.equals(getBodyType(), that.getBodyType()) && + Objects.equals(getIndexToName(), that.getIndexToName()) && + Objects.equals(getFormParams(), that.getFormParams()) && + Objects.equals(getIndexToEncoded(), that.getIndexToEncoded()); + } + + @Override + public int hashCode() { + return Objects.hash(getMethod(), getRequest(), getUrlIndex(), getBodyIndex(), getHeaderMapIndex(), getBodyType(), getIndexToName(), getFormParams(), getIndexToEncoded()); + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("RestMethodMetadata{"); + sb.append("method=").append(method); + sb.append(", request=").append(request); + sb.append(", urlIndex=").append(urlIndex); + sb.append(", bodyIndex=").append(bodyIndex); + sb.append(", headerMapIndex=").append(headerMapIndex); + sb.append(", bodyType='").append(bodyType).append('\''); + sb.append(", indexToName=").append(indexToName); + sb.append(", formParams=").append(formParams); + sb.append(", indexToEncoded=").append(indexToEncoded); + sb.append('}'); + return sb.toString(); + } +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/ServiceRestMetadata.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/ServiceRestMetadata.java new file mode 100644 index 00000000000..34cddd69fab --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/ServiceRestMetadata.java @@ -0,0 +1,103 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.rest; + +import java.io.Serializable; +import java.util.LinkedHashSet; +import java.util.Objects; +import java.util.Set; + +/** + * The metadata class for {@link RequestMetadata HTTP(REST) request} and + * its binding Dubbo service metadata + * + * @since 2.7.5 + */ +public class ServiceRestMetadata implements Serializable { + + private static final long serialVersionUID = -4549723140727443569L; + + private String serviceInterface; + + private String version; + + private String group; + + private Set meta; + + public String getServiceInterface() { + return serviceInterface; + } + + public void setServiceInterface(String serviceInterface) { + this.serviceInterface = serviceInterface; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getGroup() { + return group; + } + + public void setGroup(String group) { + this.group = group; + } + + public Set getMeta() { + if (meta == null) { + meta = new LinkedHashSet<>(); + } + return meta; + } + + public void setMeta(Set meta) { + this.meta = meta; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof ServiceRestMetadata)) return false; + ServiceRestMetadata that = (ServiceRestMetadata) o; + return Objects.equals(getServiceInterface(), that.getServiceInterface()) && + Objects.equals(getVersion(), that.getVersion()) && + Objects.equals(getGroup(), that.getGroup()) && + Objects.equals(getMeta(), that.getMeta()); + } + + @Override + public int hashCode() { + return Objects.hash(getServiceInterface(), getVersion(), getGroup(), getMeta()); + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("ServiceRestMetadata{"); + sb.append("serviceInterface='").append(serviceInterface).append('\''); + sb.append(", version='").append(version).append('\''); + sb.append(", group='").append(group).append('\''); + sb.append(", meta=").append(meta); + sb.append('}'); + return sb.toString(); + } +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/store/BaseWritableMetadataService.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/store/BaseWritableMetadataService.java index c751226fa58..764d0358d6a 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/store/BaseWritableMetadataService.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/store/BaseWritableMetadataService.java @@ -4,17 +4,13 @@ import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.metadata.MetadataService; -import org.apache.dubbo.metadata.report.identifier.ServiceMetadataIdentifier; import java.util.Collection; import java.util.Map; import java.util.SortedSet; import java.util.concurrent.ConcurrentNavigableMap; import java.util.concurrent.ConcurrentSkipListMap; -import java.util.function.BiConsumer; import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.Supplier; /** * @author cvictory ON 2019-08-14 diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/store/RemoteWritableMetadataServiceDelegate.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/store/RemoteWritableMetadataServiceDelegate.java index eed9e437031..448ddc8d059 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/store/RemoteWritableMetadataServiceDelegate.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/store/RemoteWritableMetadataServiceDelegate.java @@ -1,7 +1,6 @@ package org.apache.dubbo.metadata.store; import org.apache.dubbo.common.URL; -import org.apache.dubbo.common.config.InmemoryConfiguration; import org.apache.dubbo.metadata.WritableMetadataService; import java.util.SortedSet; diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/util/HttpUtils.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/util/HttpUtils.java new file mode 100644 index 00000000000..20095a4ea1f --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/util/HttpUtils.java @@ -0,0 +1,266 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.util; + + +import org.apache.dubbo.common.utils.StringUtils; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import static java.util.Arrays.asList; +import static java.util.Collections.unmodifiableSet; +import static org.apache.dubbo.common.utils.StringUtils.AND; +import static org.apache.dubbo.common.utils.StringUtils.EQUAL; +import static org.apache.dubbo.common.utils.StringUtils.QUESTION_MASK; +import static org.apache.dubbo.common.utils.StringUtils.SLASH; +import static org.apache.dubbo.common.utils.StringUtils.isEmpty; +import static org.apache.dubbo.common.utils.StringUtils.replace; + +/** + * Http Utilities class + * + * @since 2.7.5 + */ +public abstract class HttpUtils { + + private static final String UTF_8 = "UTF-8"; + + /** + * HTTP GET method. + */ + public static final String GET = "GET"; + /** + * HTTP POST method. + */ + public static final String POST = "POST"; + /** + * HTTP PUT method. + */ + public static final String PUT = "PUT"; + /** + * HTTP DELETE method. + */ + public static final String DELETE = "DELETE"; + /** + * HTTP HEAD method. + */ + public static final String HEAD = "HEAD"; + /** + * HTTP OPTIONS method. + */ + public static final String OPTIONS = "OPTIONS"; + + /** + * The HTTP methods to support + */ + public static final Set HTTP_METHODS = unmodifiableSet(new LinkedHashSet<>(asList( + GET, POST, POST, PUT, DELETE, HEAD, OPTIONS + ))); + + + public static String buildPath(String rootPath, String... subPaths) { + + Set paths = new LinkedHashSet<>(); + paths.add(rootPath); + paths.addAll(asList(subPaths)); + + return normalizePath(paths.stream() + .filter(StringUtils::isNotEmpty) + .collect(Collectors.joining(SLASH))); + } + + /** + * Normalize path: + *
    + *
  1. To remove query string if presents
  2. + *
  3. To remove duplicated slash("/") if exists
  4. + *
+ * + * @param path path to be normalized + * @return a normalized path if required + */ + public static String normalizePath(String path) { + if (isEmpty(path)) { + return SLASH; + } + String normalizedPath = path; + int index = normalizedPath.indexOf(QUESTION_MASK); + if (index > -1) { + normalizedPath = normalizedPath.substring(0, index); + } + return replace(normalizedPath, "//", "/"); + } + +// /** +// * Get Parameters from the specified query string. +// *

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

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

+// * +// * @param pairs The pairs of name-value +// * @return The query parameters +// */ +// public static MultivaluedMap getParameters(String... pairs) { +// return getParameters(asList(pairs)); +// } + + // /** + // * Parse a read-only {@link MultivaluedMap} of {@link HttpCookie} from {@link + // HttpHeaders} + // * + // * @param httpHeaders {@link HttpHeaders} + // * @return non-null, the key is a cookie name , the value is {@link HttpCookie} + // */ + // public static MultivaluedMap parseCookies(HttpHeaders + // httpHeaders) { + // + // String cookie = httpHeaders.getFirst(COOKIE); + // + // String[] cookieNameAndValues = StringUtils.delimitedListToStringArray(cookie, + // SEMICOLON); + // + // MultivaluedMap cookies = new + // LinkedMultiValueMap<>(cookieNameAndValues.length); + // + // for (String cookeNameAndValue : cookieNameAndValues) { + // String[] nameAndValue = + // delimitedListToStringArray(trimWhitespace(cookeNameAndValue), EQUAL); + // String name = nameAndValue[0]; + // String value = nameAndValue.length < 2 ? null : nameAndValue[1]; + // HttpCookie httpCookie = new HttpCookie(name, value); + // cookies.add(name, httpCookie); + // } + // + // return cookies; + // } + + /** + * To the name and value line sets + * + * @param nameAndValuesMap the map of name and values + * @return non-null + */ + public static Set toNameAndValuesSet( + Map> nameAndValuesMap) { + Set nameAndValues = new LinkedHashSet<>(); + for (Map.Entry> entry : nameAndValuesMap.entrySet()) { + String name = entry.getKey(); + List values = entry.getValue(); + for (String value : values) { + String nameAndValue = name + EQUAL + value; + nameAndValues.add(nameAndValue); + } + } + return nameAndValues; + } + + public static String[] toNameAndValues(Map> nameAndValuesMap) { + return toNameAndValuesSet(nameAndValuesMap).toArray(new String[0]); + } + + /** + * Generate a string of query string from the specified request parameters {@link Map} + * + * @param params the specified request parameters {@link Map} + * @return non-null + */ + public static String toQueryString(Map> params) { + StringBuilder builder = new StringBuilder(); + for (String line : toNameAndValuesSet(params)) { + builder.append(line).append(AND); + } + return builder.toString(); + } + + /** + * Decode value + * + * @param value the value requires to decode + * @return the decoded value + */ + public static String decode(String value) { + if (value == null) { + return value; + } + String decodedValue = value; + try { + decodedValue = URLDecoder.decode(value, UTF_8); + } catch (UnsupportedEncodingException ex) { + } + return decodedValue; + } + + /** + * encode value + * + * @param value the value requires to encode + * @return the encoded value + */ + public static String encode(String value) { + String encodedValue = value; + try { + encodedValue = URLEncoder.encode(value, UTF_8); + } catch (UnsupportedEncodingException ex) { + } + return encodedValue; + } + +// private static void addParam(MultivaluedMap paramsMap, String name, +// String value) { +// String paramValue = trim(value); +// if (isEmpty(paramValue)) { +// paramValue = EMPTY_VALUE; +// } +// paramsMap.add(trim(name), paramValue); +// } +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/report/identifier/MetadataIdentifierTest.java b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/report/identifier/MetadataIdentifierTest.java index 90df3dbc80a..3a58933e167 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/report/identifier/MetadataIdentifierTest.java +++ b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/report/identifier/MetadataIdentifierTest.java @@ -17,7 +17,6 @@ package org.apache.dubbo.metadata.report.identifier; import org.apache.dubbo.metadata.MetadataConstants; -import org.apache.dubbo.metadata.report.identifier.KeyTypeEnum; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; diff --git a/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/store/InMemoryWritableMetadataServiceTest.java b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/store/InMemoryWritableMetadataServiceTest.java index c032843f28d..2bd91376fbc 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/store/InMemoryWritableMetadataServiceTest.java +++ b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/store/InMemoryWritableMetadataServiceTest.java @@ -2,7 +2,6 @@ import org.apache.dubbo.common.URL; import org.apache.dubbo.common.utils.NetUtils; -import org.apache.dubbo.metadata.report.MetadataReportInstance; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; diff --git a/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/store/RemoteWritableMeatadataServiceTest.java b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/store/RemoteWritableMeatadataServiceTest.java index b6dfa486445..94cc577b2e7 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/store/RemoteWritableMeatadataServiceTest.java +++ b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/store/RemoteWritableMeatadataServiceTest.java @@ -18,7 +18,6 @@ import org.apache.dubbo.common.URL; import org.apache.dubbo.common.utils.NetUtils; -import org.apache.dubbo.metadata.WritableMetadataService; import org.apache.dubbo.metadata.definition.model.FullServiceDefinition; import org.apache.dubbo.metadata.report.MetadataReportInstance; import org.apache.dubbo.metadata.report.identifier.KeyTypeEnum; @@ -34,8 +33,6 @@ import java.util.Map; -import static org.apache.dubbo.common.constants.CommonConstants.REMOTE_METADATA_STORAGE_TYPE; - /** * 2018/9/14 */ diff --git a/dubbo-metadata/dubbo-metadata-processor/pom.xml b/dubbo-metadata/dubbo-metadata-processor/pom.xml new file mode 100644 index 00000000000..9be4ddbf4d4 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/pom.xml @@ -0,0 +1,161 @@ + + + + org.apache.dubbo + dubbo-metadata + ${revision} + ../pom.xml + + 4.0.0 + + dubbo-metadata-processor + jar + dubbo-metadata-processor + The metadata processor module of Dubbo project + + + + org.apache.dubbo + dubbo-metadata-api + ${project.parent.version} + + + org.apache.dubbo + dubbo-rpc-api + + + org.apache.dubbo + dubbo-cluster + + + com.google.code.gson + gson + + + + + + org.apache.dubbo + dubbo-common + ${project.parent.version} + + + javax.annotation + javax.annotation-api + + + + org.slf4j + slf4j-api + + + + commons-logging + commons-logging + + + log4j + log4j + + + + org.apache.logging.log4j + log4j-api + + + + org.apache.logging.log4j + log4j-core + + + org.javassist + javassist + + + com.alibaba + hessian-lite + + + com.alibaba + fastjson + + + com.esotericsoftware + kryo + + + de.javakaffee + kryo-serializers + + + de.ruedigermoeller + fst + + + commons-io + commons-io + + + + + + + com.google.code.gson + gson + + + + + org.apache.dubbo + dubbo-config-api + ${project.parent.version} + test + + + org.apache.dubbo + dubbo-registry-api + + + org.apache.dubbo + dubbo-metadata-api + + + org.apache.dubbo + dubbo-monitor-api + + + org.apache.dubbo + dubbo-remoting-api + + + org.apache.dubbo + dubbo-rpc-injvm + + + org.apache.dubbo + dubbo-filter-validation + + + org.apache.dubbo + dubbo-filter-cache + + + + + + + javax.ws.rs + javax.ws.rs-api + test + + + + + org.springframework + spring-web + test + + + \ No newline at end of file diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/AbstractServiceAnnotationProcessor.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/AbstractServiceAnnotationProcessor.java new file mode 100644 index 00000000000..e5af1ad842d --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/AbstractServiceAnnotationProcessor.java @@ -0,0 +1,108 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing; + +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.ProcessingEnvironment; +import javax.annotation.processing.Processor; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.PackageElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.util.Elements; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static javax.lang.model.util.ElementFilter.methodsIn; +import static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.SUPPORTED_ANNOTATION_TYPES; + +/** + * Abstract {@link Processor} for the classes that were annotated by Dubbo's @Service + * + * @since 2.7.5 + */ +public abstract class AbstractServiceAnnotationProcessor extends AbstractProcessor { + + protected Elements elements; + + private List objectMembers; + + public synchronized void init(ProcessingEnvironment processingEnv) { + super.init(processingEnv); + this.elements = processingEnv.getElementUtils(); + this.objectMembers = elements.getAllMembers(elements.getTypeElement(Object.class.getName())); + } + + protected List getActualMembers(TypeElement type) { + List members = new LinkedList<>(elements.getAllMembers(type)); + members.removeAll(objectMembers); + return members; + } + + protected List getActualMethods(TypeElement type) { + return methodsIn(getActualMembers(type)); + } + + protected Map getActualMethodsMap(TypeElement type) { + Map methodsMap = new HashMap<>(); + getActualMethods(type).forEach(method -> { + methodsMap.put(method.toString(), method); + }); + return methodsMap; + } + + public static String getMethodSignature(ExecutableElement method) { + if (!ElementKind.METHOD.equals(method.getKind())) { + throw new IllegalArgumentException("The argument must be Method Kind"); + } + + StringBuilder methodSignatureBuilder = new StringBuilder(); + + method.getModifiers().forEach(member -> { + methodSignatureBuilder.append(member).append(" "); + }); + + methodSignatureBuilder.append(method.getReturnType()) + .append(" ") + .append(method.toString()); + + return methodSignatureBuilder.toString(); + } + + protected TypeElement getTypeElement(CharSequence className) { + return elements.getTypeElement(className); + } + + protected PackageElement getPackageElement(Element type) { + return this.elements.getPackageOf(type); + } + + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latest(); + } + + @Override + public final Set getSupportedAnnotationTypes() { + return SUPPORTED_ANNOTATION_TYPES; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/ClassPathMetadataStorage.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/ClassPathMetadataStorage.java new file mode 100644 index 00000000000..9e1032c590d --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/ClassPathMetadataStorage.java @@ -0,0 +1,105 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing; + + +import javax.annotation.processing.Filer; +import javax.annotation.processing.ProcessingEnvironment; +import javax.tools.FileObject; +import java.io.File; +import java.io.IOException; +import java.io.Reader; +import java.io.Writer; +import java.util.Optional; +import java.util.function.Function; +import java.util.function.Supplier; + +import static java.util.Optional.empty; +import static java.util.Optional.ofNullable; +import static javax.tools.StandardLocation.CLASS_OUTPUT; +import static org.apache.dubbo.metadata.annotation.processing.util.LoggerUtils.info; +import static org.apache.dubbo.metadata.annotation.processing.util.LoggerUtils.warn; + +/** + * A storage class for metadata under class path + */ +public class ClassPathMetadataStorage { + + private final Filer filer; + + public ClassPathMetadataStorage(ProcessingEnvironment processingEnv) { + this.filer = processingEnv.getFiler(); + } + + public void write(Supplier contentSupplier, String resourceName) { + try (Writer writer = getWriter(resourceName)) { + writer.write(contentSupplier.get()); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public Optional read(String resourceName, Function consumer) { + if (exists(resourceName)) { + try (Reader reader = getReader(resourceName)) { + return ofNullable(consumer.apply(reader)); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + return empty(); + } + + private boolean exists(String resourceName) { + + return getResource(resourceName) + .map(FileObject::toUri) + .map(File::new) + .map(File::exists) + .orElse(false); + } + + private Reader getReader(String resourceName) { + return getResource(resourceName).map(fileObject -> { + try { + return fileObject.openReader(false); + } catch (IOException e) { + } + return null; + }).orElse(null); + } + + private FileObject createResource(String resourceName) throws IOException { + return filer.createResource(CLASS_OUTPUT, "", resourceName); + } + + private Optional getResource(String resourceName) { + try { + FileObject fileObject = filer.getResource(CLASS_OUTPUT, "", resourceName); + return ofNullable(fileObject); + } catch (IOException e) { + warn(e.getMessage()); + } + return empty(); + } + + private Writer getWriter(String resourceName) throws IOException { + FileObject fileObject = createResource(resourceName); + info("The resource[path : %s , deleted : %s] will be written", fileObject.toUri().getPath(), fileObject.delete()); + return fileObject.openWriter(); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/ServiceDefinitionMetadataAnnotationProcessor.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/ServiceDefinitionMetadataAnnotationProcessor.java new file mode 100644 index 00000000000..837cdec6390 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/ServiceDefinitionMetadataAnnotationProcessor.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing; + +import org.apache.dubbo.metadata.definition.model.ServiceDefinition; + +import com.google.gson.Gson; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.annotation.processing.Processor; +import javax.annotation.processing.RoundEnvironment; +import javax.lang.model.element.TypeElement; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +import static javax.lang.model.util.ElementFilter.typesIn; +import static org.apache.dubbo.metadata.annotation.processing.builder.ServiceDefinitionBuilder.build; + +/** + * The {@link Processor} class to generate the metadata of {@link ServiceDefinition} whose classes are annotated by Dubbo's @Service + * + * @see Processor + * @since 2.7.5 + */ +public class ServiceDefinitionMetadataAnnotationProcessor extends AbstractServiceAnnotationProcessor { + + private List serviceDefinitions = new LinkedList<>(); + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + + typesIn(roundEnv.getRootElements()).forEach(serviceType -> process(processingEnv, serviceType, annotations)); + + if (roundEnv.processingOver()) { + ClassPathMetadataStorage writer = new ClassPathMetadataStorage(processingEnv); + writer.write(() -> new Gson().toJson(serviceDefinitions), "META-INF/dubbo/service-definitions.json"); + } + + return false; + } + + private void process(ProcessingEnvironment processingEnv, TypeElement serviceType, Set annotations) { + serviceDefinitions.add(build(processingEnv, serviceType)); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/ArrayTypeDefinitionBuilder.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/ArrayTypeDefinitionBuilder.java new file mode 100644 index 00000000000..d7ebc3ae06e --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/ArrayTypeDefinitionBuilder.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.builder; + +import org.apache.dubbo.metadata.definition.model.TypeDefinition; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.type.ArrayType; +import javax.lang.model.type.TypeMirror; +import java.lang.reflect.Array; + +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isArrayType; + +/** + * {@link TypeDefinitionBuilder} for Java {@link Array} + * + * @since 2.7.5 + */ +public class ArrayTypeDefinitionBuilder implements TypeDefinitionBuilder { + + @Override + public boolean accept(ProcessingEnvironment processingEnv, TypeMirror type) { + return isArrayType(type); + } + + @Override + public void build(ProcessingEnvironment processingEnv, ArrayType type, TypeDefinition typeDefinition) { + TypeMirror componentType = type.getComponentType(); + typeDefinition.getItems().add(TypeDefinitionBuilder.build(processingEnv, componentType)); + } + + @Override + public int getPriority() { + return MIN_PRIORITY - 4; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/CollectionTypeDefinitionBuilder.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/CollectionTypeDefinitionBuilder.java new file mode 100644 index 00000000000..3ed2b455fbf --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/CollectionTypeDefinitionBuilder.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.builder; + +import org.apache.dubbo.metadata.definition.model.TypeDefinition; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.Elements; +import javax.lang.model.util.Types; +import java.util.Collection; +import java.util.Objects; + +/** + * {@link TypeDefinitionBuilder} for Java {@link Collection} + * + * @since 2.7.5 + */ +public class CollectionTypeDefinitionBuilder implements DeclaredTypeDefinitionBuilder { + + @Override + public boolean accept(ProcessingEnvironment processingEnv, DeclaredType type) { + Elements elements = processingEnv.getElementUtils(); + TypeElement collectionTypeElement = elements.getTypeElement(Collection.class.getTypeName()); + TypeMirror collectionType = collectionTypeElement.asType(); + Types types = processingEnv.getTypeUtils(); + TypeMirror erasedType = types.erasure(type); + return types.isAssignable(erasedType, collectionType); + } + + @Override + public void build(ProcessingEnvironment processingEnv, DeclaredType type, TypeDefinition typeDefinition) { + // Generic Type arguments + type.getTypeArguments() + .stream() + .map(typeArgument -> TypeDefinitionBuilder.build(processingEnv, typeArgument)) // build the TypeDefinition from typeArgument + .filter(Objects::nonNull) + .forEach(typeDefinition.getItems()::add); // Add into the declared TypeDefinition + } + + @Override + public int getPriority() { + return MIN_PRIORITY - 5; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/DeclaredTypeDefinitionBuilder.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/DeclaredTypeDefinitionBuilder.java new file mode 100644 index 00000000000..b12dcefcc4f --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/DeclaredTypeDefinitionBuilder.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.builder; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeMirror; + +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.ofDeclaredType; + +/** + * An interface of {@link TypeDefinitionBuilder} for {@link DeclaredType} + * + * @since 2.7.5 + */ +public interface DeclaredTypeDefinitionBuilder extends TypeDefinitionBuilder { + + @Override + default boolean accept(ProcessingEnvironment processingEnv, TypeMirror type) { + DeclaredType declaredType = ofDeclaredType(type); + if (declaredType == null) { + return false; + } + return accept(processingEnv, declaredType); + } + + /** + * Test the specified {@link DeclaredType type} is accepted or not + * + * @param processingEnv {@link ProcessingEnvironment} + * @param type {@link DeclaredType type} + * @return true if accepted + */ + boolean accept(ProcessingEnvironment processingEnv, DeclaredType type); +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/EnumTypeDefinitionBuilder.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/EnumTypeDefinitionBuilder.java new file mode 100644 index 00000000000..c0ed002be76 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/EnumTypeDefinitionBuilder.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.builder; + +import org.apache.dubbo.metadata.annotation.processing.util.FieldUtils; +import org.apache.dubbo.metadata.definition.model.TypeDefinition; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.Element; +import javax.lang.model.element.Name; +import javax.lang.model.type.DeclaredType; + +import static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.getDeclaredFields; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isEnumType; + +/** + * {@link TypeDefinitionBuilder} for Java {@link Enum} + * + * @since 2.7.5 + */ +public class EnumTypeDefinitionBuilder implements DeclaredTypeDefinitionBuilder { + + @Override + public boolean accept(ProcessingEnvironment processingEnv, DeclaredType type) { + return isEnumType(type); + } + + @Override + public void build(ProcessingEnvironment processingEnv, DeclaredType type, TypeDefinition typeDefinition) { + getDeclaredFields(type, FieldUtils::isEnumMemberField) + .stream() + .map(Element::getSimpleName) + .map(Name::toString) + .forEach(typeDefinition.getEnums()::add); + } + + @Override + public int getPriority() { + return MIN_PRIORITY - 2; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/GeneralTypeDefinitionBuilder.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/GeneralTypeDefinitionBuilder.java new file mode 100644 index 00000000000..f9c648ce24c --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/GeneralTypeDefinitionBuilder.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.builder; + +import org.apache.dubbo.metadata.definition.model.TypeDefinition; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.DeclaredType; + +import static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.getNonStaticFields; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.getType; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isClassType; + +/** + * {@link TypeDefinitionBuilder} for General Object + * + * @since 2.7.5 + */ +public class GeneralTypeDefinitionBuilder implements DeclaredTypeDefinitionBuilder { + + @Override + public boolean accept(ProcessingEnvironment processingEnv, DeclaredType type) { + return isClassType(type); + } + + @Override + public void build(ProcessingEnvironment processingEnv, DeclaredType type, TypeDefinition typeDefinition) { + + String typeName = type.toString(); + + TypeElement typeElement = getType(processingEnv, typeName); + + buildProperties(processingEnv, typeElement, typeDefinition); + } + + protected void buildProperties(ProcessingEnvironment processingEnv, TypeElement type, TypeDefinition definition) { + getNonStaticFields(type).forEach(field -> { + String fieldName = field.getSimpleName().toString(); + TypeDefinition propertyType = TypeDefinitionBuilder.build(processingEnv, field); + if (propertyType != null) { + definition.getProperties().put(fieldName, propertyType); + } + }); + } + + @Override + public int getPriority() { + return MIN_PRIORITY; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/MapTypeDefinitionBuilder.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/MapTypeDefinitionBuilder.java new file mode 100644 index 00000000000..a0a204da646 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/MapTypeDefinitionBuilder.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.builder; + +import org.apache.dubbo.metadata.definition.model.TypeDefinition; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.Elements; +import javax.lang.model.util.Types; +import java.util.Map; +import java.util.Objects; + +/** + * {@link TypeDefinitionBuilder} for Java {@link Map} + * + * @since 2.7.5 + */ +public class MapTypeDefinitionBuilder implements DeclaredTypeDefinitionBuilder { + + @Override + public boolean accept(ProcessingEnvironment processingEnv, DeclaredType type) { + Elements elements = processingEnv.getElementUtils(); + TypeElement mapTypeElement = elements.getTypeElement(Map.class.getTypeName()); + TypeMirror mapType = mapTypeElement.asType(); + Types types = processingEnv.getTypeUtils(); + TypeMirror erasedType = types.erasure(type); + return types.isAssignable(erasedType, mapType); + } + + @Override + public void build(ProcessingEnvironment processingEnv, DeclaredType type, TypeDefinition typeDefinition) { + // Generic Type arguments + type.getTypeArguments() + .stream() + .map(typeArgument -> TypeDefinitionBuilder.build(processingEnv, typeArgument)) // build the TypeDefinition from typeArgument + .filter(Objects::nonNull) + .forEach(typeDefinition.getItems()::add); // Add into the declared TypeDefinition + + } + + @Override + public int getPriority() { + return MIN_PRIORITY - 6; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/MethodDefinitionBuilder.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/MethodDefinitionBuilder.java new file mode 100644 index 00000000000..c2bad78f516 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/MethodDefinitionBuilder.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.builder; + +import org.apache.dubbo.metadata.definition.model.MethodDefinition; +import org.apache.dubbo.metadata.definition.model.TypeDefinition; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.ExecutableElement; +import java.util.List; +import java.util.stream.Collectors; + +import static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.getMethodName; +import static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.getMethodParameterTypes; +import static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.getReturnType; + +/** + * A Builder class for {@link MethodDefinition} + * + * @see MethodDefinition + * @since 2.7.5 + */ +public interface MethodDefinitionBuilder { + + static MethodDefinition build(ProcessingEnvironment processingEnv, ExecutableElement method) { + MethodDefinition methodDefinition = new MethodDefinition(); + methodDefinition.setName(getMethodName(method)); + methodDefinition.setReturnType(getReturnType(method)); + methodDefinition.setParameterTypes(getMethodParameterTypes(method)); + methodDefinition.setParameters(getMethodParameters(processingEnv, method)); + return methodDefinition; + } + + static List getMethodParameters(ProcessingEnvironment processingEnv, ExecutableElement method) { + return method.getParameters().stream() + .map(element -> TypeDefinitionBuilder.build(processingEnv, element)) + .collect(Collectors.toList()); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/PrimitiveTypeDefinitionBuilder.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/PrimitiveTypeDefinitionBuilder.java new file mode 100644 index 00000000000..903c15f1738 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/PrimitiveTypeDefinitionBuilder.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.builder; + +import org.apache.dubbo.metadata.definition.model.TypeDefinition; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.type.PrimitiveType; +import javax.lang.model.type.TypeMirror; + +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isPrimitiveType; + +/** + * {@link TypeDefinitionBuilder} for Java {@link PrimitiveType primitve type} + * + * @since 2.7.5 + */ +public class PrimitiveTypeDefinitionBuilder implements TypeDefinitionBuilder { + + @Override + public boolean accept(ProcessingEnvironment processingEnv, TypeMirror type) { + return isPrimitiveType(type); + } + + @Override + public void build(ProcessingEnvironment processingEnv, PrimitiveType type, TypeDefinition typeDefinition) { + // DO NOTHING + } + + @Override + public int getPriority() { + return MIN_PRIORITY - 3; + } +} \ No newline at end of file diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/ServiceDefinitionBuilder.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/ServiceDefinitionBuilder.java new file mode 100644 index 00000000000..8563e008766 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/ServiceDefinitionBuilder.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.builder; + +import org.apache.dubbo.metadata.definition.model.ServiceDefinition; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.TypeElement; + +import static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.getPublicNonStaticMethods; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.getHierarchicalTypes; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.getResourceName; + +/** + * A Builder for {@link ServiceDefinition} + * + * @see ServiceDefinition + * @since 2.7.5 + */ +public interface ServiceDefinitionBuilder { + + static ServiceDefinition build(ProcessingEnvironment processingEnv, TypeElement type) { + ServiceDefinition serviceDefinition = new ServiceDefinition(); + serviceDefinition.setCanonicalName(type.toString()); + serviceDefinition.setCodeSource(getResourceName(type.toString())); + + // Get all super types and interface excluding the specified type + // and then the result will be added into ServiceDefinition#getTypes() + getHierarchicalTypes(type.asType(), Object.class) + .stream() + .map(t -> TypeDefinitionBuilder.build(processingEnv, t)) + .forEach(serviceDefinition.getTypes()::add); + + // Get all declared methods that will be added into ServiceDefinition#getMethods() + getPublicNonStaticMethods(type, Object.class) + .stream() + .map(method -> MethodDefinitionBuilder.build(processingEnv, method)) + .forEach(serviceDefinition.getMethods()::add); + + return serviceDefinition; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/SimpleTypeDefinitionBuilder.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/SimpleTypeDefinitionBuilder.java new file mode 100644 index 00000000000..634d7be4f4e --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/SimpleTypeDefinitionBuilder.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.builder; + +import org.apache.dubbo.metadata.annotation.processing.util.TypeUtils; +import org.apache.dubbo.metadata.definition.model.TypeDefinition; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.type.DeclaredType; + +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isSimpleType; + + +/** + * {@link TypeDefinitionBuilder} for {@link TypeUtils#SIMPLE_TYPES Java Simple Type} + * + * @since 2.7.5 + */ +public class SimpleTypeDefinitionBuilder implements DeclaredTypeDefinitionBuilder { + + @Override + public boolean accept(ProcessingEnvironment processingEnv, DeclaredType type) { + return isSimpleType(type); + } + + @Override + public void build(ProcessingEnvironment processingEnv, DeclaredType type, TypeDefinition typeDefinition) { + // DO NOTHING + } + + @Override + public int getPriority() { + return MIN_PRIORITY - 1; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/TypeDefinitionBuilder.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/TypeDefinitionBuilder.java new file mode 100644 index 00000000000..415754b93ca --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/TypeDefinitionBuilder.java @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.builder; + +import org.apache.dubbo.common.lang.Prioritized; +import org.apache.dubbo.metadata.definition.model.TypeDefinition; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.Element; +import javax.lang.model.type.TypeMirror; + +import static org.apache.dubbo.common.utils.PrioritizedServiceLoader.load; + +/** + * A class builds the instance of {@link TypeDefinition} + * + * @since 2.7.5 + */ +public interface TypeDefinitionBuilder extends Prioritized { + + /** + * Test the specified {@link TypeMirror type} is accepted or not + * + * @param processingEnv {@link ProcessingEnvironment} + * @param type {@link TypeMirror type} + * @return true if accepted + */ + boolean accept(ProcessingEnvironment processingEnv, TypeMirror type); + + /** + * Build the instance of {@link TypeDefinition} + * + * @param processingEnv {@link ProcessingEnvironment} + * @param type {@link T type} + * @param typeDefinition {@link TypeDefinition} to be built + * @return an instance of {@link TypeDefinition} + */ + void build(ProcessingEnvironment processingEnv, T type, TypeDefinition typeDefinition); + + /** + * Build the instance of {@link TypeDefinition} from the specified {@link Element element} + * + * @param processingEnv {@link ProcessingEnvironment} + * @param element {@link Element source element} + * @return non-null + */ + static TypeDefinition build(ProcessingEnvironment processingEnv, Element element) { + TypeDefinition typeDefinition = build(processingEnv, element.asType()); + typeDefinition.set$ref(element.toString()); + return typeDefinition; + } + + /** + * Build the instance of {@link TypeDefinition} from the specified {@link TypeMirror type} + * + * @param processingEnv {@link ProcessingEnvironment} + * @param type {@link TypeMirror type} + * @return non-null + */ + static TypeDefinition build(ProcessingEnvironment processingEnv, TypeMirror type) { + String typeName = type.toString(); + TypeDefinition typeDefinition = new TypeDefinition(typeName); + + // Build by all instances of TypeDefinitionBuilder that were loaded By Java SPI + load(TypeDefinitionBuilder.class, TypeDefinitionBuilder.class.getClassLoader()) + .filter(builder -> builder.accept(processingEnv, type)) + .findFirst() + .ifPresent(builder -> { + builder.build(processingEnv, type, typeDefinition); + // typeDefinition.setTypeBuilderName(builder.getClass().getName()); + }); + + return typeDefinition; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/AbstractAnnotatedMethodParameterProcessor.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/AbstractAnnotatedMethodParameterProcessor.java new file mode 100644 index 00000000000..51ef7865e6d --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/AbstractAnnotatedMethodParameterProcessor.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.rest; + +import org.apache.dubbo.metadata.rest.RestMethodMetadata; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.VariableElement; + +import static org.apache.dubbo.metadata.annotation.processing.rest.AnnotatedMethodParameterProcessor.buildDefaultValue; +import static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.getValue; + +/** + * The abstract {@link AnnotatedMethodParameterProcessor} implementation + * + * @since 2.7.5 + */ +public abstract class AbstractAnnotatedMethodParameterProcessor implements AnnotatedMethodParameterProcessor { + + @Override + public final void process(AnnotationMirror annotation, VariableElement parameter, int parameterIndex, ExecutableElement method, RestMethodMetadata restMethodMetadata) { + String annotationValue = getAnnotationValue(annotation, parameter, parameterIndex); + String defaultValue = getDefaultValue(annotation, parameter, parameterIndex); + process(annotationValue, defaultValue, annotation, parameter, parameterIndex, method, restMethodMetadata); + } + + protected abstract void process(String annotationValue, String defaultValue, AnnotationMirror annotation, VariableElement parameter, int parameterIndex, + ExecutableElement method, RestMethodMetadata restMethodMetadata); + + protected String getAnnotationValue(AnnotationMirror annotation, VariableElement parameter, int parameterIndex) { + return getValue(annotation); + } + + protected String getDefaultValue(AnnotationMirror annotation, VariableElement parameter, int parameterIndex) { + return buildDefaultValue(parameterIndex); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/AbstractServiceRestMetadataProcessor.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/AbstractServiceRestMetadataProcessor.java new file mode 100644 index 00000000000..36fee79628c --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/AbstractServiceRestMetadataProcessor.java @@ -0,0 +1,232 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.rest; + +import org.apache.dubbo.metadata.definition.model.MethodDefinition; +import org.apache.dubbo.metadata.rest.RequestMetadata; +import org.apache.dubbo.metadata.rest.RestMethodMetadata; +import org.apache.dubbo.metadata.rest.ServiceRestMetadata; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +import static java.lang.ThreadLocal.withInitial; +import static java.util.Collections.emptyList; +import static java.util.Optional.empty; +import static java.util.Optional.of; +import static org.apache.dubbo.common.utils.PrioritizedServiceLoader.load; +import static org.apache.dubbo.metadata.annotation.processing.builder.MethodDefinitionBuilder.build; +import static org.apache.dubbo.metadata.annotation.processing.util.LoggerUtils.info; +import static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.getPublicNonStaticMethods; +import static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.getAnnotation; +import static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.getGroup; +import static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.getVersion; +import static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.resolveServiceInterfaceName; + +/** + * Abstract {@link ServiceRestMetadataProcessor} implementation + * + * @since 2.7.5 + */ +public abstract class AbstractServiceRestMetadataProcessor implements ServiceRestMetadataProcessor { + + private final static ThreadLocal> threadLocalCache = withInitial(HashMap::new); + + private final static Map> parameterProcessorsMap = loadAnnotatedMethodParameterProcessors(); + + private final String processorName = getClass().getSimpleName(); + + @Override + public final ServiceRestMetadata process(ProcessingEnvironment processingEnv, + TypeElement serviceType, + Set annotations) { + + info("%s is processing the service type[%s] with annotations[%s]", processorName, serviceType, + annotations.stream().map(t -> "@" + t.toString()).collect(Collectors.joining(","))); + + ServiceRestMetadata serviceRestMetadata = new ServiceRestMetadata(); + + try { + AnnotationMirror serviceAnnotation = getAnnotation(serviceType); + serviceRestMetadata.setServiceInterface(resolveServiceInterfaceName(serviceType, serviceAnnotation)); + serviceRestMetadata.setGroup(getGroup(serviceAnnotation)); + serviceRestMetadata.setVersion(getVersion(serviceAnnotation)); + + List methods = getPublicNonStaticMethods(serviceType, Object.class); + + methods.forEach(method -> { + processRestMethodMetadata(processingEnv, serviceType, method) + .ifPresent(serviceRestMetadata.getMeta()::add); + }); + } finally { + clearCache(); + } + + info("The %s's process result : %s", processorName, serviceRestMetadata); + + return serviceRestMetadata; + } + + protected Optional processRestMethodMetadata(ProcessingEnvironment processingEnv, + TypeElement serviceType, ExecutableElement method) { + + String requestPath = getRequestPath(processingEnv, serviceType, method); // requestPath is required + + if (requestPath == null) { + return empty(); + } + + String requestMethod = getRequestMethod(processingEnv, serviceType, method); // requestMethod is required + + if (requestMethod == null) { + return empty(); + } + + RestMethodMetadata metadata = new RestMethodMetadata(); + + MethodDefinition methodDefinition = getMethodDefinition(processingEnv, serviceType, method); + // Set MethodDefinition + metadata.setMethod(methodDefinition); + + // process the annotated method parameters + processAnnotatedMethodParameters(method, serviceType, metadata); + + // process produces + Set produces = new LinkedHashSet<>(); + processProduces(processingEnv, serviceType, method, produces); + + // process consumes + Set consumes = new LinkedHashSet<>(); + processConsumes(processingEnv, serviceType, method, consumes); + + // Initialize RequestMetadata + RequestMetadata request = metadata.getRequest(); + request.setPath(requestPath); + request.setMethod(requestMethod); + request.setProduces(produces); + request.setConsumes(consumes); + + // Post-Process + postProcessRestMethodMetadata(processingEnv, serviceType, method, metadata); + + return of(metadata); + } + + /** + * Post-Process for {@link RestMethodMetadata}, sub-type could override this method for further works + * + * @param processingEnv {@link ProcessingEnvironment} + * @param serviceType The type that @Service annotated + * @param method The public method of serviceType + * @param metadata {@link RestMethodMetadata} maybe updated + */ + protected void postProcessRestMethodMetadata(ProcessingEnvironment processingEnv, TypeElement serviceType, + ExecutableElement method, RestMethodMetadata metadata) { + } + + protected abstract String getRequestPath(ProcessingEnvironment processingEnv, TypeElement serviceType, + ExecutableElement method); + + protected abstract String getRequestMethod(ProcessingEnvironment processingEnv, TypeElement serviceType, + ExecutableElement method); + + protected MethodDefinition getMethodDefinition(ProcessingEnvironment processingEnv, TypeElement serviceType, + ExecutableElement method) { + return build(processingEnv, method); + } + + protected void processAnnotatedMethodParameters(ExecutableElement method, TypeElement type, + RestMethodMetadata metadata) { + List methodParameters = method.getParameters(); + int size = methodParameters.size(); + for (int i = 0; i < size; i++) { + VariableElement parameter = methodParameters.get(i); + // Add indexed parameter name + metadata.addIndexToName(i, parameter.getSimpleName().toString()); + processAnnotatedMethodParameter(parameter, i, method, type, metadata); + } + } + + protected void processAnnotatedMethodParameter(VariableElement parameter, int parameterIndex, + ExecutableElement method, TypeElement serviceType, + RestMethodMetadata metadata) { + + parameter.getAnnotationMirrors().forEach(annotation -> { + String annotationType = annotation.getAnnotationType().toString(); + parameterProcessorsMap.getOrDefault(annotationType, emptyList()) + .forEach(parameterProcessor -> { + parameterProcessor.process(annotation, parameter, parameterIndex, method, metadata); + }); + }); + } + + protected abstract void processProduces(ProcessingEnvironment processingEnv, TypeElement serviceType, + ExecutableElement method, Set produces); + + protected abstract void processConsumes(ProcessingEnvironment processingEnv, TypeElement serviceType, + ExecutableElement method, Set consumes); + + protected static final void put(String name, Object value) { + Map cache = getCache(); + cache.put(name, value); + } + + protected static final T get(String name) throws ClassCastException { + Map cache = getCache(); + return (T) cache.get(name); + } + + protected static final V computeIfAbsent(String name, Function mappingFunction) { + return (V) getCache().computeIfAbsent(name, mappingFunction); + } + + private static Map> loadAnnotatedMethodParameterProcessors() { + Map> parameterProcessorsMap = new LinkedHashMap<>(); + + load(AnnotatedMethodParameterProcessor.class, AnnotatedMethodParameterProcessor.class.getClassLoader()) + .forEach(processor -> { + List processors = + parameterProcessorsMap.computeIfAbsent(processor.getAnnotationType(), k -> new LinkedList<>()); + processors.add(processor); + }); + + return parameterProcessorsMap; + } + + private static Map getCache() { + return threadLocalCache.get(); + } + + private static void clearCache() { + Map cache = getCache(); + cache.clear(); + threadLocalCache.remove(); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/AnnotatedMethodParameterProcessor.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/AnnotatedMethodParameterProcessor.java new file mode 100644 index 00000000000..523f932c7bb --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/AnnotatedMethodParameterProcessor.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.rest; + +import org.apache.dubbo.common.lang.Prioritized; +import org.apache.dubbo.metadata.rest.RestMethodMetadata; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.VariableElement; + +/** + * The interface to process the parameter of method that was annotated + * + * @since 2.7.5 + */ +public interface AnnotatedMethodParameterProcessor extends Prioritized { + + /** + * The string presenting the annotation type + * + * @return non-null + */ + String getAnnotationType(); + + /** + * Process the specified method {@link VariableElement parameter} + * + * @param annotation {@link AnnotationMirror the target annotation} whose type is {@link #getAnnotationType()} + * @param parameter {@link VariableElement method parameter} + * @param parameterIndex the index of parameter in the method + * @param method {@link ExecutableElement method that parameter belongs to} + * @param restMethodMetadata {@link RestMethodMetadata the metadata is used to update} + */ + void process(AnnotationMirror annotation, VariableElement parameter, int parameterIndex, ExecutableElement method, + RestMethodMetadata restMethodMetadata); + + + /** + * Build the default value + * + * @param parameterIndex the index of parameter + * @return the placeholder + */ + static String buildDefaultValue(int parameterIndex) { + return "{" + parameterIndex + "}"; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/DefaultServiceRestMetadataProcessor.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/DefaultServiceRestMetadataProcessor.java new file mode 100644 index 00000000000..73772db2530 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/DefaultServiceRestMetadataProcessor.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.rest; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import java.util.Set; + +/** + * The default implementation of {@link ServiceRestMetadataProcessor} + * + * @since 2.7.5 + */ +public class DefaultServiceRestMetadataProcessor extends AbstractServiceRestMetadataProcessor { + + @Override + public boolean supports(ProcessingEnvironment processingEnvironment, TypeElement serviceType) { + return true; + } + + @Override + protected String getRequestPath(ProcessingEnvironment processingEnv, TypeElement serviceType, + ExecutableElement method) { + return null; + } + + @Override + protected String getRequestMethod(ProcessingEnvironment processingEnv, TypeElement serviceType, + ExecutableElement method) { + return null; + } + + @Override + protected void processProduces(ProcessingEnvironment processingEnv, TypeElement serviceType, + ExecutableElement method, Set produces) { + + } + + @Override + protected void processConsumes(ProcessingEnvironment processingEnv, TypeElement serviceType, + ExecutableElement method, Set consumes) { + + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/ServiceRestMetadataAnnotationProcessor.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/ServiceRestMetadataAnnotationProcessor.java new file mode 100644 index 00000000000..5c1a40080df --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/ServiceRestMetadataAnnotationProcessor.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.annotation.processing.rest; + +import org.apache.dubbo.metadata.annotation.processing.AbstractServiceAnnotationProcessor; +import org.apache.dubbo.metadata.rest.ServiceRestMetadata; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.annotation.processing.Processor; +import javax.annotation.processing.RoundEnvironment; +import javax.lang.model.element.TypeElement; +import java.io.IOException; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +import static javax.lang.model.util.ElementFilter.typesIn; +import static org.apache.dubbo.common.utils.PrioritizedServiceLoader.loadServices; +import static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.isServiceAnnotationPresent; + +/** + * The {@link Processor} class to generate the metadata of REST from the classes that are annotated by Dubbo's + * + * @Service + * @see Processor + * @since 2.7.5 + */ +public class ServiceRestMetadataAnnotationProcessor extends AbstractServiceAnnotationProcessor { + + private List metadataProcessors; + + private ServiceRestMetadataStorage serviceRestMetadataWriter; + + private Set serviceRestMetadata = new LinkedHashSet<>(); + + @Override + public synchronized void init(ProcessingEnvironment processingEnv) { + super.init(processingEnv); + this.metadataProcessors = loadServices(ServiceRestMetadataProcessor.class, getClass().getClassLoader()); + this.serviceRestMetadataWriter = new ServiceRestMetadataStorage(processingEnv); + } + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + + typesIn(roundEnv.getRootElements()).forEach(serviceType -> process(processingEnv, serviceType, annotations)); + + if (roundEnv.processingOver()) { + try { + serviceRestMetadataWriter.append(serviceRestMetadata); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + return false; + } + + private void process(ProcessingEnvironment processingEnv, TypeElement serviceType, + Set annotations) { + metadataProcessors + .stream() + .filter(processor -> supports(processor, processingEnv, serviceType)) + .map(processor -> processor.process(processingEnv, serviceType, annotations)) + .forEach(serviceRestMetadata::add); + } + + private boolean supports(ServiceRestMetadataProcessor processor, ProcessingEnvironment processingEnv, + TypeElement serviceType) { + // @Service must be present in service type + return isServiceAnnotationPresent(serviceType) && processor.supports(processingEnv, serviceType); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/ServiceRestMetadataProcessor.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/ServiceRestMetadataProcessor.java new file mode 100644 index 00000000000..8e2af64fad0 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/ServiceRestMetadataProcessor.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.rest; + +import org.apache.dubbo.common.lang.Prioritized; +import org.apache.dubbo.metadata.rest.ServiceRestMetadata; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.TypeElement; +import java.util.Set; + +/** + * The class to process {@link ServiceRestMetadata} based on Annotation Processor Tool + * + * @since 2.7.5 + */ +public interface ServiceRestMetadataProcessor extends Prioritized { + + /** + * Supports or not to the specified service type + * + * @param processingEnvironment {@link ProcessingEnvironment} + * @param serviceType Dubbo service type or interface + * @return if supports, return true, or false + */ + boolean supports(ProcessingEnvironment processingEnvironment, TypeElement serviceType); + + /** + * Process the {@link ServiceRestMetadata} from given service type + * + * @param processingEnvironment {@link ProcessingEnvironment} + * @param serviceType Dubbo service type or interface + * @param annotations + * @return non-null + */ + ServiceRestMetadata process(ProcessingEnvironment processingEnvironment, + TypeElement serviceType, + Set annotations); +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/ServiceRestMetadataStorage.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/ServiceRestMetadataStorage.java new file mode 100644 index 00000000000..73653639fd7 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/ServiceRestMetadataStorage.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.rest; + +import org.apache.dubbo.metadata.annotation.processing.ClassPathMetadataStorage; +import org.apache.dubbo.metadata.rest.ServiceRestMetadata; + +import com.google.gson.Gson; + +import javax.annotation.processing.ProcessingEnvironment; +import java.io.IOException; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +import static com.google.gson.reflect.TypeToken.getParameterized; + +/** + * The storage for {@link ServiceRestMetadata} + */ +public class ServiceRestMetadataStorage { + + public static final String METADATA_RESOURCE_PATH = "META-INF/dubbo/service-rest-metadata.json"; + + private final ClassPathMetadataStorage storage; + + public ServiceRestMetadataStorage(ProcessingEnvironment processingEnv) { + this.storage = new ClassPathMetadataStorage(processingEnv); + } + + public void append(Set serviceRestMetadata) throws IOException { + Set allServiceRestMetadata = new LinkedHashSet<>(); + storage.read(METADATA_RESOURCE_PATH, reader -> { + Gson gson = new Gson(); + return (List) gson.fromJson(reader, getParameterized(List.class, ServiceRestMetadata.class).getType()); + }).ifPresent(existedMetadata -> { + // Add all existed ServiceRestMetadata + allServiceRestMetadata.addAll(existedMetadata); + }); + // Add all new ServiceRestMetadata + allServiceRestMetadata.addAll(serviceRestMetadata); + write(serviceRestMetadata); + } + + public void write(Set serviceRestMetadata) throws IOException { + if (serviceRestMetadata.isEmpty()) { + return; + } + storage.write(() -> new Gson().toJson(serviceRestMetadata), METADATA_RESOURCE_PATH); + } + +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/jaxrs/DefaultValueParameterProcessor.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/jaxrs/DefaultValueParameterProcessor.java new file mode 100644 index 00000000000..0818ff3e5f0 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/jaxrs/DefaultValueParameterProcessor.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.annotation.processing.rest.jaxrs; + +import org.apache.dubbo.metadata.annotation.processing.rest.AbstractAnnotatedMethodParameterProcessor; +import org.apache.dubbo.metadata.annotation.processing.rest.AnnotatedMethodParameterProcessor; +import org.apache.dubbo.metadata.rest.RequestMetadata; +import org.apache.dubbo.metadata.rest.RestMethodMetadata; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.VariableElement; +import java.util.List; +import java.util.Map; + + +/** + * The {@link AnnotatedMethodParameterProcessor} implementation for JAX-RS's @DefaultValue + * * + * + * @since 2.7.5 + */ +public class DefaultValueParameterProcessor extends AbstractAnnotatedMethodParameterProcessor { + + /** + * The annotation class name of @DefaultValue + */ + public static final String DEFAULT_VALUE_ANNOTATION_CLASS_NAME = "javax.ws.rs.DefaultValue"; + + @Override + public String getAnnotationType() { + return DEFAULT_VALUE_ANNOTATION_CLASS_NAME; + } + + @Override + protected void process(String annotationValue, String defaultValue, AnnotationMirror annotation, VariableElement parameter, int parameterIndex, ExecutableElement method, RestMethodMetadata restMethodMetadata) { + RequestMetadata requestMetadata = restMethodMetadata.getRequest(); + + // process the request parameters + setDefaultValue(requestMetadata.getParams(), defaultValue, annotationValue); + // process the request headers + setDefaultValue(requestMetadata.getHeaders(), defaultValue, annotationValue); + + } + + private void setDefaultValue(Map> source, String placeholderValue, String defaultValue) { + OUTTER: + for (Map.Entry> entry : source.entrySet()) { + List values = entry.getValue(); + int size = values.size(); + for (int i = 0; i < size; i++) { + String value = values.get(i); + if (placeholderValue.equals(value)) { + values.set(i, defaultValue); + break OUTTER; + } + } + } + } + + public int getPriority() { + return MIN_PRIORITY; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/jaxrs/FormParamParameterProcessor.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/jaxrs/FormParamParameterProcessor.java new file mode 100644 index 00000000000..c323e8aa0f5 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/jaxrs/FormParamParameterProcessor.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.rest.jaxrs; + +import org.apache.dubbo.metadata.annotation.processing.rest.AnnotatedMethodParameterProcessor; + +/** + * The {@link AnnotatedMethodParameterProcessor} implementation for JAX-RS's @FormParam + * + * @since 2.7.5 + */ +public class FormParamParameterProcessor extends ParamAnnotationParameterProcessor { + + @Override + public String getAnnotationType() { + return "javax.ws.rs.FormParam"; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/jaxrs/HeaderParamParameterProcessor.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/jaxrs/HeaderParamParameterProcessor.java new file mode 100644 index 00000000000..278cf93590a --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/jaxrs/HeaderParamParameterProcessor.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.rest.jaxrs; + +import org.apache.dubbo.metadata.annotation.processing.rest.AbstractAnnotatedMethodParameterProcessor; +import org.apache.dubbo.metadata.annotation.processing.rest.AnnotatedMethodParameterProcessor; +import org.apache.dubbo.metadata.rest.RequestMetadata; +import org.apache.dubbo.metadata.rest.RestMethodMetadata; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.VariableElement; + +import static org.apache.dubbo.metadata.annotation.processing.rest.AnnotatedMethodParameterProcessor.buildDefaultValue; + +/** + * The {@link AnnotatedMethodParameterProcessor} implementation for JAX-RS's @HeaderParam + * + * @since 2.7.5 + */ +public class HeaderParamParameterProcessor extends AbstractAnnotatedMethodParameterProcessor { + + @Override + public String getAnnotationType() { + return "javax.ws.rs.HeaderParam"; + } + + @Override + protected void process(String headerName, String defaultValue, AnnotationMirror annotation, + VariableElement parameter, int parameterIndex, + ExecutableElement method, RestMethodMetadata restMethodMetadata) { + RequestMetadata requestMetadata = restMethodMetadata.getRequest(); + // Add the placeholder as header value + requestMetadata.addHeader(headerName, buildDefaultValue(parameterIndex)); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/jaxrs/JAXRSServiceRestMetadataProcessor.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/jaxrs/JAXRSServiceRestMetadataProcessor.java new file mode 100644 index 00000000000..564760f1f41 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/jaxrs/JAXRSServiceRestMetadataProcessor.java @@ -0,0 +1,113 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.rest.jaxrs; + +import org.apache.dubbo.metadata.annotation.processing.rest.AbstractServiceRestMetadataProcessor; +import org.apache.dubbo.metadata.annotation.processing.rest.ServiceRestMetadataProcessor; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.AnnotatedConstruct; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import java.util.Set; +import java.util.stream.Stream; + +import static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.findAnnotation; +import static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.findMetaAnnotation; +import static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.getAnnotation; +import static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.getValue; +import static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.isAnnotationPresent; +import static org.apache.dubbo.metadata.util.HttpUtils.buildPath; + +/** + * {@link ServiceRestMetadataProcessor} implementation for JAX-RS 2 and 1 + * + * @since 2.7.5 + */ +public class JAXRSServiceRestMetadataProcessor extends AbstractServiceRestMetadataProcessor { + + /** + * The annotation name of @Path + */ + public static final String PATH_ANNOTATION_CLASS_NAME = "javax.ws.rs.Path"; + + /** + * The annotation name of @HttpMethod + */ + public static final String HTTP_METHOD_ANNOTATION_CLASS_NAME = "javax.ws.rs.HttpMethod"; + + /** + * The annotation class name of @Produces + */ + public static final String PRODUCES_ANNOTATION_CLASS_NAME = "javax.ws.rs.Produces"; + + /** + * The annotation class name of @Consumes + */ + public static final String CONSUMES_ANNOTATION_CLASS_NAME = "javax.ws.rs.Consumes"; + + @Override + public boolean supports(ProcessingEnvironment processingEnvironment, TypeElement serviceType) { + return isAnnotationPresent(serviceType, PATH_ANNOTATION_CLASS_NAME); + } + + @Override + protected String getRequestPath(ProcessingEnvironment processingEnv, TypeElement serviceType, ExecutableElement method) { + String pathFromType = getPathValue(processingEnv, serviceType); + String pathFromMethod = getPathValue(method); + return buildPath(pathFromType, pathFromMethod); + } + + @Override + protected String getRequestMethod(ProcessingEnvironment processingEnv, TypeElement serviceType, ExecutableElement method) { + AnnotationMirror annotation = findMetaAnnotation(method, HTTP_METHOD_ANNOTATION_CLASS_NAME); + return getValue(annotation); + } + + @Override + protected void processProduces(ProcessingEnvironment processingEnv, TypeElement serviceType, + ExecutableElement method, Set produces) { + addAnnotationValues(method, PRODUCES_ANNOTATION_CLASS_NAME, produces); + } + + @Override + protected void processConsumes(ProcessingEnvironment processingEnv, TypeElement serviceType, + ExecutableElement method, Set consumes) { + addAnnotationValues(method, CONSUMES_ANNOTATION_CLASS_NAME, consumes); + } + + + private void addAnnotationValues(Element element, String annotationAttributeName, Set result) { + AnnotationMirror annotation = findAnnotation(element, annotationAttributeName); + String[] value = getValue(annotation); + if (value != null) { + Stream.of(value).forEach(result::add); + } + } + + private String getPathValue(ProcessingEnvironment processingEnv, TypeElement serviceType) { + AnnotationMirror annotation = findAnnotation(serviceType, PATH_ANNOTATION_CLASS_NAME); + return getValue(annotation); + } + + private String getPathValue(AnnotatedConstruct annotatedConstruct) { + AnnotationMirror annotation = getAnnotation(annotatedConstruct, PATH_ANNOTATION_CLASS_NAME); + return getValue(annotation); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/jaxrs/MatrixParamParameterProcessor.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/jaxrs/MatrixParamParameterProcessor.java new file mode 100644 index 00000000000..026b648676a --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/jaxrs/MatrixParamParameterProcessor.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.rest.jaxrs; + +import org.apache.dubbo.metadata.annotation.processing.rest.AnnotatedMethodParameterProcessor; + +/** + * The {@link AnnotatedMethodParameterProcessor} implementation for JAX-RS's @MatrixParam + * + * @since 2.7.5 + */ +public class MatrixParamParameterProcessor extends ParamAnnotationParameterProcessor { + + @Override + public String getAnnotationType() { + return "javax.ws.rs.MatrixParam"; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/jaxrs/ParamAnnotationParameterProcessor.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/jaxrs/ParamAnnotationParameterProcessor.java new file mode 100644 index 00000000000..d615cdcb33f --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/jaxrs/ParamAnnotationParameterProcessor.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.rest.jaxrs; + +import org.apache.dubbo.metadata.annotation.processing.rest.AbstractAnnotatedMethodParameterProcessor; +import org.apache.dubbo.metadata.annotation.processing.rest.AnnotatedMethodParameterProcessor; +import org.apache.dubbo.metadata.rest.RequestMetadata; +import org.apache.dubbo.metadata.rest.RestMethodMetadata; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.VariableElement; + +/** + * The abstract {@link AnnotatedMethodParameterProcessor} implementation for JAX-RS's @*Param + */ +public abstract class ParamAnnotationParameterProcessor extends AbstractAnnotatedMethodParameterProcessor { + + protected void process(String name, String defaultValue, AnnotationMirror annotation, VariableElement parameter, int parameterIndex, + ExecutableElement method, RestMethodMetadata restMethodMetadata) { + RequestMetadata requestMetadata = restMethodMetadata.getRequest(); + requestMetadata.addParam(name, defaultValue); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/jaxrs/QueryParamParameterProcessor.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/jaxrs/QueryParamParameterProcessor.java new file mode 100644 index 00000000000..42e14ab996a --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/jaxrs/QueryParamParameterProcessor.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.rest.jaxrs; + +import org.apache.dubbo.metadata.annotation.processing.rest.AnnotatedMethodParameterProcessor; + +/** + * The {@link AnnotatedMethodParameterProcessor} implementation for JAX-RS's @QueryParam + * + * @since 2.7.5 + */ +public class QueryParamParameterProcessor extends ParamAnnotationParameterProcessor { + + @Override + public String getAnnotationType() { + return "javax.ws.rs.QueryParam"; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/springmvc/AbstractRequestAnnotationParameterProcessor.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/springmvc/AbstractRequestAnnotationParameterProcessor.java new file mode 100644 index 00000000000..1fa5285ef20 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/springmvc/AbstractRequestAnnotationParameterProcessor.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.rest.springmvc; + +import org.apache.dubbo.metadata.annotation.processing.rest.AbstractAnnotatedMethodParameterProcessor; +import org.apache.dubbo.metadata.annotation.processing.rest.AnnotatedMethodParameterProcessor; +import org.apache.dubbo.metadata.rest.RestMethodMetadata; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.VariableElement; + +import static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.getAttribute; + +/** + * The abstract {@link AnnotatedMethodParameterProcessor} implementation for Spring Web MVC's @Request* + */ +public abstract class AbstractRequestAnnotationParameterProcessor extends AbstractAnnotatedMethodParameterProcessor { + + + protected abstract void process(String name, String defaultValue, AnnotationMirror annotation, + VariableElement parameter, int parameterIndex, + ExecutableElement method, + RestMethodMetadata restMethodMetadata); + + @Override + protected String getAnnotationValue(AnnotationMirror annotation, VariableElement parameter, int parameterIndex) { + // try to get "value" attribute first + String name = super.getAnnotationValue(annotation, parameter, parameterIndex); + + // try to get "name" attribute if required + if (isEmpty(name)) { + name = getAttribute(annotation, "name"); + } + + // finally , try to the name of parameter + if (isEmpty(name)) { + name = parameter.getSimpleName().toString(); + } + + return name; + } + + protected String getDefaultValue(AnnotationMirror annotation, VariableElement parameter, int parameterIndex) { + String defaultValue = getAttribute(annotation, "defaultValue"); + if (isEmpty(defaultValue)) { + defaultValue = super.getDefaultValue(annotation, parameter, parameterIndex); + } + return defaultValue; + } + + protected boolean isEmpty(String str) { + return str == null || str.isEmpty(); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/springmvc/RequestHeaderParameterProcessor.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/springmvc/RequestHeaderParameterProcessor.java new file mode 100644 index 00000000000..94929bc176d --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/springmvc/RequestHeaderParameterProcessor.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.rest.springmvc; + +import org.apache.dubbo.metadata.annotation.processing.rest.AnnotatedMethodParameterProcessor; +import org.apache.dubbo.metadata.rest.RestMethodMetadata; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.VariableElement; + +/** + * The {@link AnnotatedMethodParameterProcessor} implementation for Spring Web MVC's @RequestHeader + */ +public class RequestHeaderParameterProcessor extends AbstractRequestAnnotationParameterProcessor { + + @Override + public String getAnnotationType() { + return "org.springframework.web.bind.annotation.RequestHeader"; + } + + @Override + protected void process(String name, String defaultValue, AnnotationMirror annotation, VariableElement parameter, int parameterIndex, ExecutableElement method, RestMethodMetadata restMethodMetadata) { + restMethodMetadata.getRequest().addHeader(name, defaultValue); + } + +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/springmvc/RequestParamParameterProcessor.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/springmvc/RequestParamParameterProcessor.java new file mode 100644 index 00000000000..1292025cb3f --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/springmvc/RequestParamParameterProcessor.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.rest.springmvc; + +import org.apache.dubbo.metadata.annotation.processing.rest.AnnotatedMethodParameterProcessor; +import org.apache.dubbo.metadata.rest.RestMethodMetadata; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.VariableElement; + +/** + * The {@link AnnotatedMethodParameterProcessor} implementation for Spring Web MVC's @RequestParam + */ +public class RequestParamParameterProcessor extends AbstractRequestAnnotationParameterProcessor { + + @Override + public String getAnnotationType() { + return "org.springframework.web.bind.annotation.RequestParam"; + } + + @Override + protected void process(String name, String defaultValue, AnnotationMirror annotation, + VariableElement parameter, int parameterIndex, + ExecutableElement method, RestMethodMetadata restMethodMetadata) { + restMethodMetadata.getRequest().addParam(name, defaultValue); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/springmvc/SpringMvcServiceRestMetadataProcessor.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/springmvc/SpringMvcServiceRestMetadataProcessor.java new file mode 100644 index 00000000000..b9f7009962c --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/rest/springmvc/SpringMvcServiceRestMetadataProcessor.java @@ -0,0 +1,157 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.rest.springmvc; + +import org.apache.dubbo.metadata.annotation.processing.rest.AbstractServiceRestMetadataProcessor; +import org.apache.dubbo.metadata.annotation.processing.rest.ServiceRestMetadataProcessor; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.DeclaredType; +import java.lang.reflect.Array; +import java.util.Set; + +import static java.lang.String.valueOf; +import static java.lang.reflect.Array.getLength; +import static java.util.stream.Stream.of; +import static org.apache.dubbo.common.function.Streams.filterFirst; +import static org.apache.dubbo.common.utils.ArrayUtils.isEmpty; +import static org.apache.dubbo.common.utils.ArrayUtils.isNotEmpty; +import static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.findAnnotation; +import static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.findMetaAnnotation; +import static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.getAllAnnotations; +import static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.getAttribute; +import static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.isAnnotationPresent; +import static org.apache.dubbo.metadata.util.HttpUtils.buildPath; + +/** + * {@link ServiceRestMetadataProcessor} + * + * @since 2.7.5 + */ +public class SpringMvcServiceRestMetadataProcessor extends AbstractServiceRestMetadataProcessor { + + private static final int FIRST_ELEMENT_INDEX = 0; + + public static final String CONTROLLER_ANNOTATION_CLASS_NAME = "org.springframework.stereotype.Controller"; + + public static final String REQUEST_MAPPING_ANNOTATION_CLASS_NAME = "org.springframework.web.bind.annotation.RequestMapping"; + + @Override + public boolean supports(ProcessingEnvironment processingEnvironment, TypeElement serviceType) { + return isAnnotationPresent(serviceType, CONTROLLER_ANNOTATION_CLASS_NAME); + } + + @Override + protected String getRequestPath(ProcessingEnvironment processingEnv, TypeElement serviceType, + ExecutableElement method) { + + String requestPathFromType = getRequestPath(serviceType); + + String requestPathFromMethod = getRequestPath(method); + + return buildPath(requestPathFromType, requestPathFromMethod); + } + + + @Override + protected String getRequestMethod(ProcessingEnvironment processingEnv, TypeElement serviceType, + ExecutableElement method) { + + AnnotationMirror requestMapping = getRequestMapping(method); + + // httpMethod is an array of RequestMethod + Object httpMethod = getAttribute(requestMapping, "method"); + + if (httpMethod == null || getLength(httpMethod) < 1) { + return null; + } + + // TODO Is is required to support more request methods? + return valueOf(Array.get(httpMethod, FIRST_ELEMENT_INDEX)); + } + + private AnnotationMirror getRequestMapping(Element element) { + // try "@RequestMapping" first + AnnotationMirror requestMapping = findAnnotation(element, REQUEST_MAPPING_ANNOTATION_CLASS_NAME); + // try the annotation meta-annotated later + if (requestMapping == null) { + requestMapping = findMetaAnnotation(element, REQUEST_MAPPING_ANNOTATION_CLASS_NAME); + } + return requestMapping; + } + + @Override + protected void processProduces(ProcessingEnvironment processingEnv, TypeElement serviceType, + ExecutableElement method, Set produces) { + addMediaTypes(method, "produces", produces); + } + + @Override + protected void processConsumes(ProcessingEnvironment processingEnv, TypeElement serviceType, + ExecutableElement method, Set consumes) { + addMediaTypes(method, "consumes", consumes); + } + + private void addMediaTypes(ExecutableElement method, String annotationAttributeName, Set mediaTypesSet) { + + AnnotationMirror mappingAnnotation = getMappingAnnotation(method); + + String[] mediaTypes = getAttribute(mappingAnnotation, annotationAttributeName); + + if (isNotEmpty(mediaTypes)) { + of(mediaTypes).forEach(mediaTypesSet::add); + } + } + + private AnnotationMirror getMappingAnnotation(Element element) { + return computeIfAbsent(valueOf(element), key -> + filterFirst(getAllAnnotations(element), annotation -> { + DeclaredType annotationType = annotation.getAnnotationType(); + // try "@RequestMapping" first + if (REQUEST_MAPPING_ANNOTATION_CLASS_NAME.equals(annotationType.toString())) { + return true; + } + // try meta annotation + return isAnnotationPresent(annotationType.asElement(), REQUEST_MAPPING_ANNOTATION_CLASS_NAME); + }) + ); + } + + private String getRequestPath(Element element) { + AnnotationMirror mappingAnnotation = getMappingAnnotation(element); + return getRequestPath(mappingAnnotation); + } + + private String getRequestPath(AnnotationMirror mappingAnnotation) { + // try "value" first + String[] value = getAttribute(mappingAnnotation, "value"); + + if (isEmpty(value)) { // try "path" later + value = getAttribute(mappingAnnotation, "path"); + } + + if (isEmpty(value)) { + return ""; + } + // TODO Is is required to support more request paths? + return value[FIRST_ELEMENT_INDEX]; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/AnnotationUtils.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/AnnotationUtils.java new file mode 100644 index 00000000000..ac3877d10d9 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/AnnotationUtils.java @@ -0,0 +1,233 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.util; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.AnnotatedConstruct; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.AnnotationValue; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.type.ArrayType; +import javax.lang.model.type.TypeMirror; +import java.lang.annotation.Annotation; +import java.lang.reflect.Array; +import java.lang.reflect.Type; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import static java.lang.Enum.valueOf; +import static java.util.Collections.emptyList; +import static org.apache.dubbo.common.function.Predicates.EMPTY_ARRAY; +import static org.apache.dubbo.common.function.Streams.filterAll; +import static org.apache.dubbo.common.function.Streams.filterFirst; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.getHierarchicalTypes; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.getType; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isSameType; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isTypeElement; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.ofTypeElement; + +/** + * The utilities class for annotation in the package "javax.lang.model.*" + * + * @since 2.7.5 + */ +public interface AnnotationUtils { + + static AnnotationMirror getAnnotation(AnnotatedConstruct annotatedConstruct, + Class annotationClass) { + return annotationClass == null ? + null : + getAnnotation(annotatedConstruct, annotationClass.getTypeName()); + } + + static AnnotationMirror getAnnotation(AnnotatedConstruct annotatedConstruct, CharSequence annotationClassName) { + List annotations = getAnnotations(annotatedConstruct, annotationClassName); + return annotations.isEmpty() ? null : annotations.get(0); + } + + static List getAnnotations(AnnotatedConstruct annotatedConstruct, Class annotationClass) { + return annotationClass == null ? + emptyList() : + getAnnotations(annotatedConstruct, annotationClass.getTypeName()); + } + + static List getAnnotations(AnnotatedConstruct annotatedConstruct, + CharSequence annotationClassName) { + return getAnnotations(annotatedConstruct, + annotation -> isSameType(annotation.getAnnotationType(), annotationClassName)); + } + + static List getAnnotations(AnnotatedConstruct annotatedConstruct) { + return getAnnotations(annotatedConstruct, EMPTY_ARRAY); + } + + static List getAnnotations(AnnotatedConstruct annotatedConstruct, + Predicate... annotationFilters) { + + AnnotatedConstruct actualAnnotatedConstruct = annotatedConstruct; + + if (annotatedConstruct instanceof TypeMirror) { + actualAnnotatedConstruct = ofTypeElement((TypeMirror) actualAnnotatedConstruct); + } + + return actualAnnotatedConstruct == null ? + emptyList() : + filterAll((List) actualAnnotatedConstruct.getAnnotationMirrors(), annotationFilters); + } + + static List getAllAnnotations(TypeMirror type) { + return getAllAnnotations(ofTypeElement(type)); + } + + static List getAllAnnotations(Element element) { + return getAllAnnotations(element, EMPTY_ARRAY); + } + + static List getAllAnnotations(TypeMirror type, Class annotationClass) { + return getAllAnnotations(ofTypeElement(type), annotationClass); + } + + static List getAllAnnotations(Element element, Class annotationClass) { + return element == null || annotationClass == null ? + emptyList() : + getAllAnnotations(element, annotationClass.getTypeName()); + } + + static List getAllAnnotations(TypeMirror type, CharSequence annotationClassName) { + return getAllAnnotations(ofTypeElement(type), annotationClassName); + } + + static List getAllAnnotations(Element element, CharSequence annotationClassName) { + return getAllAnnotations(element, annotation -> isSameType(annotation.getAnnotationType(), annotationClassName)); + } + + static List getAllAnnotations(TypeMirror type, Predicate... annotationFilters) { + return getAllAnnotations(ofTypeElement(type), annotationFilters); + } + + static List getAllAnnotations(Element element, Predicate... annotationFilters) { + + List allAnnotations = isTypeElement(element) ? + getHierarchicalTypes(ofTypeElement(element)) + .stream() + .map(AnnotationUtils::getAnnotations) + .flatMap(Collection::stream) + .collect(Collectors.toList()) : + element == null ? emptyList() : (List) element.getAnnotationMirrors(); + + return filterAll(allAnnotations, annotationFilters); + } + + static List getAllAnnotations(ProcessingEnvironment processingEnv, Type annotatedType) { + return getAllAnnotations(processingEnv, annotatedType, EMPTY_ARRAY); + } + + static List getAllAnnotations(ProcessingEnvironment processingEnv, Type annotatedType, + Predicate... annotationFilters) { + return annotatedType == null ? + emptyList() : + getAllAnnotations(processingEnv, annotatedType.getTypeName(), annotationFilters); + } + + static List getAllAnnotations(ProcessingEnvironment processingEnv, CharSequence annotatedTypeName, + Predicate... annotationFilters) { + return getAllAnnotations(getType(processingEnv, annotatedTypeName), annotationFilters); + } + + static AnnotationMirror findAnnotation(TypeMirror type, Class annotationClass) { + return annotationClass == null ? null : findAnnotation(type, annotationClass.getTypeName()); + } + + static AnnotationMirror findAnnotation(TypeMirror type, CharSequence annotationClassName) { + return findAnnotation(ofTypeElement(type), annotationClassName); + } + + static AnnotationMirror findAnnotation(Element element, Class annotationClass) { + return annotationClass == null ? null : findAnnotation(element, annotationClass.getTypeName()); + } + + static AnnotationMirror findAnnotation(Element element, CharSequence annotationClassName) { + return filterFirst(getAllAnnotations(element, annotation -> isSameType(annotation.getAnnotationType(), annotationClassName))); + } + + static AnnotationMirror findMetaAnnotation(Element annotatedConstruct, CharSequence metaAnnotationClassName) { + return annotatedConstruct == null ? + null : + getAnnotations(annotatedConstruct) + .stream() + .map(annotation -> findAnnotation(annotation.getAnnotationType(), metaAnnotationClassName)) + .filter(Objects::nonNull) + .findFirst() + .orElse(null); + } + + static boolean isAnnotationPresent(Element element, CharSequence annotationClassName) { + return findAnnotation(element, annotationClassName) != null || + findMetaAnnotation(element, annotationClassName) != null; + } + + static T getAttribute(AnnotationMirror annotation, String attributeName) { + return annotation == null ? null : getAttribute(annotation.getElementValues(), attributeName); + } + + static T getAttribute(Map attributesMap, + String attributeName) { + T annotationValue = null; + for (Map.Entry entry : attributesMap.entrySet()) { + ExecutableElement attributeMethod = entry.getKey(); + if (Objects.equals(attributeName, attributeMethod.getSimpleName().toString())) { + TypeMirror attributeType = attributeMethod.getReturnType(); + AnnotationValue value = entry.getValue(); + if (attributeType instanceof ArrayType) { // array-typed attribute values + ArrayType arrayType = (ArrayType) attributeType; + String componentType = arrayType.getComponentType().toString(); + ClassLoader classLoader = AnnotationUtils.class.getClassLoader(); + List values = (List) value.getValue(); + int size = values.size(); + try { + Class componentClass = classLoader.loadClass(componentType); + boolean isEnum = componentClass.isEnum(); + Object array = Array.newInstance(componentClass, values.size()); + for (int i = 0; i < size; i++) { + Object element = values.get(i).getValue(); + if (isEnum) { + element = valueOf(componentClass, element.toString()); + } + Array.set(array, i, element); + } + annotationValue = (T) array; + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + } else { + annotationValue = (T) value.getValue(); + } + break; + } + } + return annotationValue; + } + + static T getValue(AnnotationMirror annotation) { + return (T) getAttribute(annotation, "value"); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/FieldUtils.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/FieldUtils.java new file mode 100644 index 00000000000..b6c73467267 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/FieldUtils.java @@ -0,0 +1,146 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.util; + +import javax.lang.model.element.Element; +import javax.lang.model.element.Modifier; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.TypeMirror; +import java.util.Collection; +import java.util.List; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import static java.util.Collections.emptyList; +import static javax.lang.model.element.ElementKind.ENUM_CONSTANT; +import static javax.lang.model.element.ElementKind.FIELD; +import static javax.lang.model.element.Modifier.STATIC; +import static javax.lang.model.util.ElementFilter.fieldsIn; +import static org.apache.dubbo.common.function.Predicates.EMPTY_ARRAY; +import static org.apache.dubbo.common.function.Streams.filterAll; +import static org.apache.dubbo.common.function.Streams.filterFirst; +import static org.apache.dubbo.metadata.annotation.processing.util.MemberUtils.getDeclaredMembers; +import static org.apache.dubbo.metadata.annotation.processing.util.MemberUtils.hasModifiers; +import static org.apache.dubbo.metadata.annotation.processing.util.MemberUtils.matches; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.getHierarchicalTypes; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isEnumType; + +/** + * The utilities class for the field in the package "javax.lang.model." + * + * @since 2.7.5 + */ +public interface FieldUtils { + + static List getDeclaredFields(Element element, Predicate... fieldFilters) { + return element == null ? emptyList() : getDeclaredFields(element.asType(), fieldFilters); + } + + static List getDeclaredFields(Element element) { + return getDeclaredFields(element, EMPTY_ARRAY); + } + + static List getDeclaredFields(TypeMirror type, Predicate... fieldFilters) { + return filterAll(fieldsIn(getDeclaredMembers(type)), fieldFilters); + } + + static List getDeclaredFields(TypeMirror type) { + return getDeclaredFields(type, EMPTY_ARRAY); + } + + static List getAllDeclaredFields(Element element, Predicate... fieldFilters) { + return element == null ? emptyList() : getAllDeclaredFields(element.asType(), fieldFilters); + } + + static List getAllDeclaredFields(Element element) { + return getAllDeclaredFields(element, EMPTY_ARRAY); + } + + static List getAllDeclaredFields(TypeMirror type, Predicate... fieldFilters) { + return getHierarchicalTypes(type) + .stream() + .map(t -> getDeclaredFields(t, fieldFilters)) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + } + + static List getAllDeclaredFields(TypeMirror type) { + return getAllDeclaredFields(type, EMPTY_ARRAY); + } + + static VariableElement getDeclaredField(Element element, String fieldName) { + return element == null ? null : getDeclaredField(element.asType(), fieldName); + } + + static VariableElement getDeclaredField(TypeMirror type, String fieldName) { + return filterFirst(getDeclaredFields(type, field -> fieldName.equals(field.getSimpleName().toString()))); + } + + static VariableElement findField(Element element, String fieldName) { + return element == null ? null : findField(element.asType(), fieldName); + } + + static VariableElement findField(TypeMirror type, String fieldName) { + return filterFirst(getAllDeclaredFields(type, field -> equals(field, fieldName))); + } + + /** + * is Enum's member field or not + * + * @param field {@link VariableElement} must be public static final fields + * @return if field is public static final, return true, or false + */ + static boolean isEnumMemberField(VariableElement field) { + if (field == null || !isEnumType(field.getEnclosingElement())) { + return false; + } + return ENUM_CONSTANT.equals(field.getKind()); + } + + static boolean isNonStaticField(VariableElement field) { + return isField(field) && !hasModifiers(field, STATIC); + } + + static boolean isField(VariableElement field) { + return matches(field, FIELD) || isEnumMemberField(field); + } + + static boolean isField(VariableElement field, Modifier... modifiers) { + return isField(field) && hasModifiers(field, modifiers); + } + + static List getNonStaticFields(TypeMirror type) { + return getDeclaredFields(type, FieldUtils::isNonStaticField); + } + + static List getNonStaticFields(Element element) { + return element == null ? emptyList() : getNonStaticFields(element.asType()); + } + + static List getAllNonStaticFields(TypeMirror type) { + return getAllDeclaredFields(type, FieldUtils::isNonStaticField); + } + + static List getAllNonStaticFields(Element element) { + return element == null ? emptyList() : getAllNonStaticFields(element.asType()); + } + + static boolean equals(VariableElement field, CharSequence fieldName) { + return field != null && fieldName != null && field.getSimpleName().toString().equals(fieldName.toString()); + } + +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/LoggerUtils.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/LoggerUtils.java new file mode 100644 index 00000000000..f43ffd9829f --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/LoggerUtils.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.util; + + +import org.apache.dubbo.common.logger.Logger; +import org.apache.dubbo.common.logger.LoggerFactory; + +import static java.lang.String.format; + +/** + * Logger Utils + * + * @since 2.7.5 + */ +public interface LoggerUtils { + + Logger LOGGER = LoggerFactory.getLogger("dubbo-metadata-processor"); + + static void info(String format, Object... args) { + if (LOGGER.isInfoEnabled()) { + LOGGER.info(format(format, args)); + } + } + + static void warn(String format, Object... args) { + if (LOGGER.isWarnEnabled()) { + LOGGER.warn(format(format, args)); + } + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/MemberUtils.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/MemberUtils.java new file mode 100644 index 00000000000..fc617a1d805 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/MemberUtils.java @@ -0,0 +1,94 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.util; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.Modifier; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.TypeMirror; +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +import static java.util.Collections.emptyList; +import static javax.lang.model.element.Modifier.PUBLIC; +import static javax.lang.model.element.Modifier.STATIC; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.getHierarchicalTypes; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.ofTypeElement; + +/** + * The utilities class for the members in the package "javax.lang.model.", such as "field", "method", "constructor" + * + * @since 2.7.5 + */ +public interface MemberUtils { + + static boolean matches(Element member, ElementKind kind) { + return member == null || kind == null ? false : kind.equals(member.getKind()); + } + + static boolean isPublicNonStatic(Element member) { + return hasModifiers(member, PUBLIC) && !hasModifiers(member, STATIC); + } + + static boolean hasModifiers(Element member, Modifier... modifiers) { + if (member == null || modifiers == null) { + return false; + } + Set actualModifiers = member.getModifiers(); + for (Modifier modifier : modifiers) { + if (!actualModifiers.contains(modifier)) { + return false; + } + } + return true; + } + + static List getDeclaredMembers(TypeMirror type) { + TypeElement element = ofTypeElement(type); + return element == null ? emptyList() : element.getEnclosedElements(); + } + + static List getAllDeclaredMembers(TypeMirror type) { + return getHierarchicalTypes(type) + .stream() + .map(MemberUtils::getDeclaredMembers) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + } + + static boolean matchParameterTypes(List parameters, CharSequence... parameterTypes) { + + int size = parameters.size(); + + if (size != parameterTypes.length) { + return false; + } + + for (int i = 0; i < size; i++) { + VariableElement parameter = parameters.get(i); + if (!Objects.equals(parameter.asType().toString(), parameterTypes[i])) { + return false; + } + } + return true; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/MethodUtils.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/MethodUtils.java new file mode 100644 index 00000000000..ab7c8c7151b --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/MethodUtils.java @@ -0,0 +1,155 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.util; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.Elements; +import java.lang.reflect.Type; +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import static java.util.Arrays.asList; +import static java.util.Collections.emptyList; +import static javax.lang.model.element.ElementKind.METHOD; +import static javax.lang.model.util.ElementFilter.methodsIn; +import static org.apache.dubbo.common.function.Predicates.EMPTY_ARRAY; +import static org.apache.dubbo.common.function.Streams.filter; +import static org.apache.dubbo.common.function.Streams.filterAll; +import static org.apache.dubbo.common.function.Streams.filterFirst; +import static org.apache.dubbo.metadata.annotation.processing.util.MemberUtils.getDeclaredMembers; +import static org.apache.dubbo.metadata.annotation.processing.util.MemberUtils.isPublicNonStatic; +import static org.apache.dubbo.metadata.annotation.processing.util.MemberUtils.matchParameterTypes; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.getHierarchicalTypes; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.ofDeclaredType; + +/** + * The utilities class for method in the package "javax.lang.model." + * + * @since 2.7.5 + */ +public interface MethodUtils { + + static List getDeclaredMethods(TypeElement type, Predicate... methodFilters) { + return type == null ? emptyList() : getDeclaredMethods(type.asType(), methodFilters); + } + + static List getDeclaredMethods(TypeMirror type, Predicate... methodFilters) { + return filterAll(methodsIn(getDeclaredMembers(type)), methodFilters); + } + + static List getAllDeclaredMethods(TypeElement type, Predicate... methodFilters) { + return type == null ? emptyList() : getAllDeclaredMethods(type.asType(), methodFilters); + } + + static List getAllDeclaredMethods(TypeElement type) { + return getAllDeclaredMethods(type, EMPTY_ARRAY); + } + + static List getAllDeclaredMethods(TypeMirror type, Predicate... methodFilters) { + return getHierarchicalTypes(type) + .stream() + .map(t -> getDeclaredMethods(t, methodFilters)) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + } + + static List getAllDeclaredMethods(TypeMirror type) { + return getAllDeclaredMethods(type, EMPTY_ARRAY); + } + + static List getAllDeclaredMethods(TypeElement type, Type... excludedTypes) { + return type == null ? emptyList() : getAllDeclaredMethods(type.asType(), excludedTypes); + } + + static List getAllDeclaredMethods(TypeMirror type, Type... excludedTypes) { + return getHierarchicalTypes(type, excludedTypes) + .stream() + .map(t -> getDeclaredMethods(t)) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + } + + static List getPublicNonStaticMethods(TypeElement type, Type... excludedTypes) { + return getPublicNonStaticMethods(ofDeclaredType(type), excludedTypes); + } + + static List getPublicNonStaticMethods(TypeMirror type, Type... excludedTypes) { + return filter(getAllDeclaredMethods(type, excludedTypes), MethodUtils::isPublicNonStaticMethod); + } + + static boolean isMethod(ExecutableElement method) { + return method == null ? false : METHOD.equals(method.getKind()); + } + + static boolean isPublicNonStaticMethod(ExecutableElement method) { + return isMethod(method) && isPublicNonStatic(method); + } + + static ExecutableElement findMethod(TypeElement type, String methodName, Type oneParameterType, Type... otherParameterTypes) { + return type == null ? null : findMethod(type.asType(), methodName, oneParameterType, otherParameterTypes); + } + + static ExecutableElement findMethod(TypeMirror type, String methodName, Type oneParameterType, Type... otherParameterTypes) { + List parameterTypes = new LinkedList<>(); + parameterTypes.add(oneParameterType); + parameterTypes.addAll(asList(otherParameterTypes)); + return findMethod(type, methodName, parameterTypes.stream().map(Type::getTypeName).toArray(String[]::new)); + } + + static ExecutableElement findMethod(TypeElement type, String methodName, CharSequence... parameterTypes) { + return type == null ? null : findMethod(type.asType(), methodName, parameterTypes); + } + + static ExecutableElement findMethod(TypeMirror type, String methodName, CharSequence... parameterTypes) { + return filterFirst(getAllDeclaredMethods(type), + method -> methodName.equals(method.getSimpleName().toString()), + method -> matchParameterTypes(method.getParameters(), parameterTypes) + ); + } + + static ExecutableElement getOverrideMethod(ProcessingEnvironment processingEnv, TypeElement type, + ExecutableElement declaringMethod) { + Elements elements = processingEnv.getElementUtils(); + return filterFirst(getAllDeclaredMethods(type), method -> elements.overrides(method, declaringMethod, type)); + } + + + static String getMethodName(ExecutableElement method) { + return method == null ? null : method.getSimpleName().toString(); + } + + static String getReturnType(ExecutableElement method) { + return method == null ? null : method.getReturnType().toString(); + } + + static String[] getMethodParameterTypes(ExecutableElement method) { + return method == null ? + new String[0] : + method.getParameters() + .stream() + .map(Element::asType) + .map(TypeMirror::toString) + .toArray(String[]::new); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/ServiceAnnotationUtils.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/ServiceAnnotationUtils.java new file mode 100644 index 00000000000..889e59f1d1b --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/ServiceAnnotationUtils.java @@ -0,0 +1,121 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.util; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.TypeElement; +import java.util.HashSet; +import java.util.Set; + +import static java.lang.String.valueOf; +import static java.util.Arrays.asList; +import static java.util.Collections.unmodifiableSet; +import static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.getAttribute; +import static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.isAnnotationPresent; + +/** + * The utilities class for @Service annotation + * + * @since 2.7.5 + */ +public interface ServiceAnnotationUtils { + + /** + * The class name of @Service + */ + String SERVICE_ANNOTATION_TYPE = "org.apache.dubbo.config.annotation.Service"; + + /** + * The class name of the legacy @Service + */ + @Deprecated + String LEGACY_SERVICE_ANNOTATION_TYPE = "com.alibaba.dubbo.config.annotation.Service"; + + /** + * the attribute name of @Service.interfaceClass() + */ + String INTERFACE_CLASS_ATTRIBUTE_NAME = "interfaceClass"; + + /** + * the attribute name of @Service.interfaceName() + */ + String INTERFACE_NAME_ATTRIBUTE_NAME = "interfaceName"; + + /** + * the attribute name of @Service.group() + */ + String GROUP_ATTRIBUTE_NAME = "group"; + + /** + * the attribute name of @Service.version() + */ + String VERSION_ATTRIBUTE_NAME = "version"; + + Set SUPPORTED_ANNOTATION_TYPES = unmodifiableSet(new HashSet(asList(SERVICE_ANNOTATION_TYPE, LEGACY_SERVICE_ANNOTATION_TYPE))); + + static boolean isServiceAnnotationPresent(TypeElement annotatedType) { + return isAnnotationPresent(annotatedType, SERVICE_ANNOTATION_TYPE) || + isAnnotationPresent(annotatedType, LEGACY_SERVICE_ANNOTATION_TYPE); + } + + static AnnotationMirror getAnnotation(TypeElement annotatedClass) { + return getAnnotation(annotatedClass.getAnnotationMirrors()); + } + + static AnnotationMirror getAnnotation(Iterable annotationMirrors) { + AnnotationMirror matchedAnnotationMirror = null; + for (AnnotationMirror annotationMirror : annotationMirrors) { + String annotationType = annotationMirror.getAnnotationType().toString(); + if (SERVICE_ANNOTATION_TYPE.equals(annotationType)) { + matchedAnnotationMirror = annotationMirror; + break; + } else if (LEGACY_SERVICE_ANNOTATION_TYPE.equals(annotationType)) { + matchedAnnotationMirror = annotationMirror; + } + } + + if (matchedAnnotationMirror == null) { + throw new IllegalArgumentException("The annotated element must be implemented the interface " + + SERVICE_ANNOTATION_TYPE + " or " + LEGACY_SERVICE_ANNOTATION_TYPE); + } + + return matchedAnnotationMirror; + } + + static String resolveServiceInterfaceName(TypeElement annotatedClass, AnnotationMirror serviceAnnotation) { + Object interfaceClass = getAttribute(serviceAnnotation, INTERFACE_CLASS_ATTRIBUTE_NAME); + + if (interfaceClass == null) { // try to find the "interfaceName" attribute + interfaceClass = getAttribute(serviceAnnotation, INTERFACE_NAME_ATTRIBUTE_NAME); + } + + if (interfaceClass == null) { + // last, get the interface class from first one + interfaceClass = ((TypeElement) annotatedClass).getInterfaces().get(0); + } + + return valueOf(interfaceClass); + } + + static String getGroup(AnnotationMirror serviceAnnotation) { + return getAttribute(serviceAnnotation, GROUP_ATTRIBUTE_NAME); + } + + static String getVersion(AnnotationMirror serviceAnnotation) { + return getAttribute(serviceAnnotation, VERSION_ATTRIBUTE_NAME); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/TypeUtils.java b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/TypeUtils.java new file mode 100644 index 00000000000..3283d500c89 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/TypeUtils.java @@ -0,0 +1,382 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.util; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.Elements; +import javax.tools.FileObject; +import javax.tools.StandardLocation; +import java.io.IOException; +import java.lang.reflect.Type; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.net.URL; +import java.util.ArrayList; +import java.util.Date; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.function.Predicate; + +import static java.lang.String.valueOf; +import static java.util.Arrays.asList; +import static java.util.Collections.emptyList; +import static java.util.Collections.emptySet; +import static java.util.stream.Collectors.toSet; +import static java.util.stream.Stream.of; +import static java.util.stream.StreamSupport.stream; +import static javax.lang.model.element.ElementKind.ANNOTATION_TYPE; +import static javax.lang.model.element.ElementKind.CLASS; +import static javax.lang.model.element.ElementKind.ENUM; +import static javax.lang.model.element.ElementKind.INTERFACE; +import static org.apache.dubbo.common.function.Predicates.EMPTY_ARRAY; +import static org.apache.dubbo.common.function.Streams.filterAll; + +/** + * The utilities class for type in the package "javax.lang.model.*" + * + * @since 2.7.5 + */ +public interface TypeUtils { + + List SIMPLE_TYPES = asList( + Void.class.getName(), + Boolean.class.getName(), + Character.class.getName(), + Byte.class.getName(), + Short.class.getName(), + Integer.class.getName(), + Long.class.getName(), + Float.class.getName(), + Double.class.getName(), + String.class.getName(), + BigDecimal.class.getName(), + BigInteger.class.getName(), + Date.class.getName() + ); + + static boolean isSimpleType(Element element) { + return element != null && isSimpleType(element.asType()); + } + + static boolean isSimpleType(TypeMirror type) { + return type != null && SIMPLE_TYPES.contains(type.toString()); + } + + static boolean isSameType(TypeMirror type, CharSequence typeName) { + if (type == null || typeName == null) { + return false; + } + return Objects.equals(valueOf(type), valueOf(typeName)); + } + + static boolean isSameType(TypeMirror typeMirror, Type type) { + return type != null && isSameType(typeMirror, type.getTypeName()); + } + + static boolean isArrayType(TypeMirror type) { + return type != null && TypeKind.ARRAY.equals(type.getKind()); + } + + static boolean isArrayType(Element element) { + return element != null && isArrayType(element.asType()); + } + + static boolean isEnumType(TypeMirror type) { + DeclaredType declaredType = ofDeclaredType(type); + return declaredType != null && ENUM.equals(declaredType.asElement().getKind()); + } + + static boolean isEnumType(Element element) { + return element != null && isEnumType(element.asType()); + } + + static boolean isClassType(TypeMirror type) { + DeclaredType declaredType = ofDeclaredType(type); + return declaredType != null && isClassType(declaredType.asElement()); + } + + static boolean isClassType(Element element) { + return element != null && CLASS.equals(element.getKind()); + } + + static boolean isPrimitiveType(TypeMirror type) { + return type != null && type.getKind().isPrimitive(); + } + + static boolean isPrimitiveType(Element element) { + return element != null && isPrimitiveType(element.asType()); + } + + static boolean isInterfaceType(TypeMirror type) { + DeclaredType declaredType = ofDeclaredType(type); + return declaredType != null && isInterfaceType(declaredType.asElement()); + } + + static boolean isInterfaceType(Element element) { + return element != null && INTERFACE.equals(element.getKind()); + } + + static boolean isAnnotationType(TypeMirror type) { + DeclaredType declaredType = ofDeclaredType(type); + return declaredType != null && isAnnotationType(declaredType.asElement()); + } + + static boolean isAnnotationType(Element element) { + return element != null && ANNOTATION_TYPE.equals(element.getKind()); + } + + static Set getHierarchicalTypes(TypeElement type) { + return getHierarchicalTypes(type, true, true, true); + } + + static Set getHierarchicalTypes(TypeMirror type) { + return getHierarchicalTypes(type, EMPTY_ARRAY); + } + + static Set getHierarchicalTypes(TypeMirror type, Predicate... typeFilters) { + return filterAll(ofDeclaredTypes(getHierarchicalTypes(ofTypeElement(type))), typeFilters); + } + + static Set getHierarchicalTypes(TypeMirror type, Type... excludedTypes) { + return getHierarchicalTypes(type, of(excludedTypes).map(Type::getTypeName).toArray(String[]::new)); + } + + static Set getHierarchicalTypes(TypeMirror type, CharSequence... excludedTypeNames) { + Set typeNames = of(excludedTypeNames).map(CharSequence::toString).collect(toSet()); + return getHierarchicalTypes(type, t -> !typeNames.contains(t.toString())); + } + + static Set getHierarchicalTypes(TypeElement type, + boolean includeSelf, + boolean includeSuperTypes, + boolean includeSuperInterfaces, + Predicate... typeFilters) { + + if (type == null) { + return emptySet(); + } + + Set hierarchicalTypes = new LinkedHashSet<>(); + + if (includeSelf) { + hierarchicalTypes.add(type); + } + + if (includeSuperTypes) { + hierarchicalTypes.addAll(getAllSuperTypes(type)); + } + + if (includeSuperInterfaces) { + hierarchicalTypes.addAll(getAllInterfaces(type)); + } + + return filterAll(hierarchicalTypes, typeFilters); + } + + static Set getHierarchicalTypes(TypeMirror type, + boolean includeSelf, + boolean includeSuperTypes, + boolean includeSuperInterfaces) { + return ofDeclaredTypes(getHierarchicalTypes(ofTypeElement(type), + includeSelf, + includeSuperTypes, + includeSuperInterfaces)); + } + + static List getInterfaces(TypeElement type, Predicate... interfaceFilters) { + return type == null ? emptyList() : filterAll((List) ofTypeElement(type).getInterfaces(), interfaceFilters); + } + + static List getInterfaces(TypeMirror type, Predicate... interfaceFilters) { + return getInterfaces(ofTypeElement(type), interfaceFilters); + } + + static Set getAllInterfaces(TypeElement type, Predicate... interfaceFilters) { + return type == null ? emptySet() : filterAll(ofTypeElements(getAllInterfaces(type.asType())), interfaceFilters); + } + + static Set getAllInterfaces(TypeMirror type, Predicate... interfaceFilters) { + if (type == null) { + return emptySet(); + } + Set allInterfaces = new LinkedHashSet<>(); + getInterfaces(type).forEach(i -> { + // Add current type's interfaces + allInterfaces.add(i); + // Add + allInterfaces.addAll(getAllInterfaces(i)); + }); + // Add all super types' interfaces + getAllSuperTypes(type).forEach(superType -> allInterfaces.addAll(getAllInterfaces(superType))); + return filterAll(allInterfaces, interfaceFilters); + } + + static TypeElement getType(ProcessingEnvironment processingEnv, Type type) { + return type == null ? null : getType(processingEnv, type.getTypeName()); + } + + static TypeElement getType(ProcessingEnvironment processingEnv, TypeMirror type) { + return type == null ? null : getType(processingEnv, type.toString()); + } + + static TypeElement getType(ProcessingEnvironment processingEnv, CharSequence typeName) { + if (processingEnv == null || typeName == null) { + return null; + } + Elements elements = processingEnv.getElementUtils(); + return elements.getTypeElement(typeName); + } + + static TypeElement getSuperType(TypeElement type) { + return type == null ? null : ofTypeElement(type.getSuperclass()); + } + + static DeclaredType getSuperType(TypeMirror type) { + TypeElement superType = getSuperType(ofTypeElement(type)); + return superType == null ? null : ofDeclaredType(superType.asType()); + } + + static Set getAllSuperTypes(TypeElement type) { + return getAllSuperTypes(type, EMPTY_ARRAY); + } + + static Set getAllSuperTypes(TypeElement type, Predicate... typeFilters) { + if (type == null) { + return emptySet(); + } + + Set allSuperTypes = new LinkedHashSet<>(); + TypeElement superType = getSuperType(type); + if (superType != null) { + // add super type + allSuperTypes.add(superType); + // add ancestors' types + allSuperTypes.addAll(getAllSuperTypes(superType)); + } + return filterAll(allSuperTypes, typeFilters); + } + + static Set getAllSuperTypes(TypeMirror type) { + return getAllSuperTypes(type, EMPTY_ARRAY); + } + + static Set getAllSuperTypes(TypeMirror type, Predicate... typeFilters) { + return filterAll(ofDeclaredTypes(getAllSuperTypes(ofTypeElement(type))), typeFilters); + } + + static boolean isDeclaredType(Element element) { + return element != null && isDeclaredType(element.asType()); + } + + static boolean isDeclaredType(TypeMirror type) { + return type instanceof DeclaredType; + } + + static DeclaredType ofDeclaredType(Element element) { + return element == null ? null : ofDeclaredType(element.asType()); + } + + static DeclaredType ofDeclaredType(TypeMirror type) { + return isDeclaredType(type) ? DeclaredType.class.cast(type) : null; + } + + static boolean isTypeElement(Element element) { + return element instanceof TypeElement; + } + + static boolean isTypeElement(TypeMirror type) { + DeclaredType declaredType = ofDeclaredType(type); + return declaredType != null && isTypeElement(declaredType.asElement()); + } + + static TypeElement ofTypeElement(Element element) { + return isTypeElement(element) ? TypeElement.class.cast(element) : null; + } + + static TypeElement ofTypeElement(TypeMirror type) { + DeclaredType declaredType = ofDeclaredType(type); + if (declaredType != null) { + return ofTypeElement(declaredType.asElement()); + } + return null; + } + + static Set ofDeclaredTypes(Iterable elements) { + return elements == null ? + emptySet() : + stream(elements.spliterator(), false) + .map(TypeUtils::ofTypeElement) + .filter(Objects::nonNull) + .map(Element::asType) + .map(TypeUtils::ofDeclaredType) + .filter(Objects::nonNull) + .collect(LinkedHashSet::new, Set::add, Set::addAll); + } + + static Set ofTypeElements(Iterable types) { + return types == null ? + emptySet() : + stream(types.spliterator(), false) + .map(TypeUtils::ofTypeElement) + .filter(Objects::nonNull) + .collect(LinkedHashSet::new, Set::add, Set::addAll); + } + + static List listDeclaredTypes(Iterable elements) { + return new ArrayList<>(ofDeclaredTypes(elements)); + } + + static List listTypeElements(Iterable types) { + return new ArrayList<>(ofTypeElements(types)); + } + + static URL getResource(ProcessingEnvironment processingEnv, Element type) { + return getResource(processingEnv, ofDeclaredType(type)); + } + + static URL getResource(ProcessingEnvironment processingEnv, TypeMirror type) { + return type == null ? null : getResource(processingEnv, type.toString()); + } + + static URL getResource(ProcessingEnvironment processingEnv, CharSequence type) { + String relativeName = getResourceName(type); + URL resource = null; + try { + if (relativeName != null) { + FileObject fileObject = processingEnv.getFiler().getResource(StandardLocation.CLASS_OUTPUT, "", relativeName); + resource = fileObject.toUri().toURL(); + // try to open it + resource.getContent(); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + + return resource; + } + + static String getResourceName(CharSequence type) { + return type == null ? null : type.toString().replace('.', '/').concat(".class"); + } +} \ No newline at end of file diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/resources/META-INF/services/javax.annotation.processing.Processor b/dubbo-metadata/dubbo-metadata-processor/src/main/resources/META-INF/services/javax.annotation.processing.Processor new file mode 100644 index 00000000000..6c5909c26ff --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/resources/META-INF/services/javax.annotation.processing.Processor @@ -0,0 +1,2 @@ +org.apache.dubbo.metadata.annotation.processing.ServiceDefinitionMetadataAnnotationProcessor +org.apache.dubbo.metadata.annotation.processing.rest.ServiceRestMetadataAnnotationProcessor diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/resources/META-INF/services/org.apache.dubbo.metadata.annotation.processing.builder.TypeDefinitionBuilder b/dubbo-metadata/dubbo-metadata-processor/src/main/resources/META-INF/services/org.apache.dubbo.metadata.annotation.processing.builder.TypeDefinitionBuilder new file mode 100644 index 00000000000..2ec903aff1b --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/resources/META-INF/services/org.apache.dubbo.metadata.annotation.processing.builder.TypeDefinitionBuilder @@ -0,0 +1,7 @@ +org.apache.dubbo.metadata.annotation.processing.builder.ArrayTypeDefinitionBuilder +org.apache.dubbo.metadata.annotation.processing.builder.CollectionTypeDefinitionBuilder +org.apache.dubbo.metadata.annotation.processing.builder.EnumTypeDefinitionBuilder +org.apache.dubbo.metadata.annotation.processing.builder.GeneralTypeDefinitionBuilder +org.apache.dubbo.metadata.annotation.processing.builder.MapTypeDefinitionBuilder +org.apache.dubbo.metadata.annotation.processing.builder.PrimitiveTypeDefinitionBuilder +org.apache.dubbo.metadata.annotation.processing.builder.SimpleTypeDefinitionBuilder \ No newline at end of file diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/resources/META-INF/services/org.apache.dubbo.metadata.annotation.processing.rest.AnnotatedMethodParameterProcessor b/dubbo-metadata/dubbo-metadata-processor/src/main/resources/META-INF/services/org.apache.dubbo.metadata.annotation.processing.rest.AnnotatedMethodParameterProcessor new file mode 100644 index 00000000000..042862691d4 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/resources/META-INF/services/org.apache.dubbo.metadata.annotation.processing.rest.AnnotatedMethodParameterProcessor @@ -0,0 +1,10 @@ +# JAX-RS's implementations +org.apache.dubbo.metadata.annotation.processing.rest.jaxrs.QueryParamParameterProcessor +org.apache.dubbo.metadata.annotation.processing.rest.jaxrs.FormParamParameterProcessor +org.apache.dubbo.metadata.annotation.processing.rest.jaxrs.MatrixParamParameterProcessor +org.apache.dubbo.metadata.annotation.processing.rest.jaxrs.HeaderParamParameterProcessor +org.apache.dubbo.metadata.annotation.processing.rest.jaxrs.DefaultValueParameterProcessor + +# Spring Web MVC's implementations +org.apache.dubbo.metadata.annotation.processing.rest.springmvc.RequestParamParameterProcessor +org.apache.dubbo.metadata.annotation.processing.rest.springmvc.RequestHeaderParameterProcessor \ No newline at end of file diff --git a/dubbo-metadata/dubbo-metadata-processor/src/main/resources/META-INF/services/org.apache.dubbo.metadata.annotation.processing.rest.ServiceRestMetadataProcessor b/dubbo-metadata/dubbo-metadata-processor/src/main/resources/META-INF/services/org.apache.dubbo.metadata.annotation.processing.rest.ServiceRestMetadataProcessor new file mode 100644 index 00000000000..43c307d3572 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/main/resources/META-INF/services/org.apache.dubbo.metadata.annotation.processing.rest.ServiceRestMetadataProcessor @@ -0,0 +1,3 @@ +# org.apache.dubbo.metadata.annotation.processing.rest.DefaultServiceRestMetadataProcessor +org.apache.dubbo.metadata.annotation.processing.rest.jaxrs.JAXRSServiceRestMetadataProcessor +org.apache.dubbo.metadata.annotation.processing.rest.springmvc.SpringMvcServiceRestMetadataProcessor \ No newline at end of file diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/AbstractAnnotationProcessingTest.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/AbstractAnnotationProcessingTest.java new file mode 100644 index 00000000000..0e5adf4b5e7 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/AbstractAnnotationProcessingTest.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing; + +import org.apache.dubbo.metadata.annotation.processing.util.TypeUtils; +import org.apache.dubbo.metadata.tools.Compiler; +import org.apache.dubbo.metadata.tools.TestProcessor; + +import org.junit.jupiter.api.BeforeEach; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.TypeElement; +import javax.lang.model.util.Elements; +import javax.lang.model.util.Types; +import java.io.IOException; +import java.lang.annotation.Annotation; +import java.util.LinkedHashSet; +import java.util.Set; + +/** + * Abstract {@link Annotation} Processing Test case + * + * @since 2.7.5 + */ +public abstract class AbstractAnnotationProcessingTest { + + protected ProcessingEnvironment processingEnv; + + protected Elements elements; + + protected Types types; + + @BeforeEach + public final void init() throws IOException { + Set> classesToBeCompiled = new LinkedHashSet<>(); + classesToBeCompiled.add(getClass()); + addCompiledClasses(classesToBeCompiled); + TestProcessor testProcessor = new TestProcessor(); + Compiler compiler = new Compiler(); + compiler.processors(testProcessor); + compiler.compile(classesToBeCompiled.toArray(new Class[0])); + processingEnv = testProcessor.getProcessingEnvironment(); + elements = processingEnv.getElementUtils(); + types = processingEnv.getTypeUtils(); + beforeEach(); + } + + protected abstract void addCompiledClasses(Set> classesToBeCompiled); + + protected abstract void beforeEach(); + + protected TypeElement getType(Class type) { + return TypeUtils.getType(processingEnv, type); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/ArrayTypeDefinitionBuilderTest.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/ArrayTypeDefinitionBuilderTest.java new file mode 100644 index 00000000000..efab557db75 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/ArrayTypeDefinitionBuilderTest.java @@ -0,0 +1,121 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.builder; + +import org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest; +import org.apache.dubbo.metadata.annotation.processing.model.ArrayTypeModel; +import org.apache.dubbo.metadata.definition.model.TypeDefinition; + +import org.junit.jupiter.api.Test; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import java.util.Set; +import java.util.function.BiConsumer; +import java.util.stream.Stream; + +import static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.findField; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link ArrayTypeDefinitionBuilder} Test + * + * @since 2.7.5 + */ +public class ArrayTypeDefinitionBuilderTest extends AbstractAnnotationProcessingTest { + + private ArrayTypeDefinitionBuilder builder; + + private TypeElement testType; + + private VariableElement integersField; + + private VariableElement stringsField; + + private VariableElement primitiveTypeModelsField; + + private VariableElement modelsField; + + private VariableElement colorsField; + + @Override + protected void addCompiledClasses(Set> classesToBeCompiled) { + classesToBeCompiled.add(ArrayTypeModel.class); + } + + @Override + protected void beforeEach() { + builder = new ArrayTypeDefinitionBuilder(); + testType = getType(ArrayTypeModel.class); + integersField = findField(testType, "integers"); + stringsField = findField(testType, "strings"); + primitiveTypeModelsField = findField(testType, "primitiveTypeModels"); + modelsField = findField(testType, "models"); + colorsField = findField(testType, "colors"); + } + + @Test + public void testAccept() { + assertTrue(builder.accept(processingEnv, integersField.asType())); + assertTrue(builder.accept(processingEnv, stringsField.asType())); + assertTrue(builder.accept(processingEnv, primitiveTypeModelsField.asType())); + assertTrue(builder.accept(processingEnv, modelsField.asType())); + assertTrue(builder.accept(processingEnv, colorsField.asType())); + } + + @Test + public void testBuild() { + + buildAndAssertTypeDefinition(processingEnv, integersField, "int[]", "int", builder); + + buildAndAssertTypeDefinition(processingEnv, stringsField, "java.lang.String[]", "java.lang.String", builder); + + buildAndAssertTypeDefinition(processingEnv, primitiveTypeModelsField, + "org.apache.dubbo.metadata.annotation.processing.model.PrimitiveTypeModel[]", + "org.apache.dubbo.metadata.annotation.processing.model.PrimitiveTypeModel", builder); + + buildAndAssertTypeDefinition(processingEnv, modelsField, + "org.apache.dubbo.metadata.annotation.processing.model.Model[]", + "org.apache.dubbo.metadata.annotation.processing.model.Model", builder, (def, subDef) -> { + TypeElement subType = elements.getTypeElement(subDef.getType()); + assertEquals(ElementKind.CLASS, subType.getKind()); + }); + + buildAndAssertTypeDefinition(processingEnv, colorsField, + "org.apache.dubbo.metadata.annotation.processing.model.Color[]", + "org.apache.dubbo.metadata.annotation.processing.model.Color", builder, (def, subDef) -> { + TypeElement subType = elements.getTypeElement(subDef.getType()); + assertEquals(ElementKind.ENUM, subType.getKind()); + }); + + } + + static void buildAndAssertTypeDefinition(ProcessingEnvironment processingEnv, VariableElement field, + String expectedType, String compositeType, TypeDefinitionBuilder builder, + BiConsumer... assertions) { + TypeDefinition typeDefinition = TypeDefinitionBuilder.build(processingEnv, field); + TypeDefinition subTypeDefinition = typeDefinition.getItems().get(0); + assertEquals(expectedType, typeDefinition.getType()); + assertEquals(field.getSimpleName().toString(), typeDefinition.get$ref()); + assertEquals(compositeType, subTypeDefinition.getType()); +// assertEquals(builder.getClass().getName(), typeDefinition.getTypeBuilderName()); + Stream.of(assertions).forEach(assertion -> assertion.accept(typeDefinition, subTypeDefinition)); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/CollectionTypeDefinitionBuilderTest.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/CollectionTypeDefinitionBuilderTest.java new file mode 100644 index 00000000000..1bfb32e0d43 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/CollectionTypeDefinitionBuilderTest.java @@ -0,0 +1,105 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.builder; + +import org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest; +import org.apache.dubbo.metadata.annotation.processing.model.CollectionTypeModel; + +import org.junit.jupiter.api.Test; + +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import java.util.Set; + +import static org.apache.dubbo.metadata.annotation.processing.builder.ArrayTypeDefinitionBuilderTest.buildAndAssertTypeDefinition; +import static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.findField; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link CollectionTypeDefinitionBuilder} Test + * + * @since 2.7.5 + */ +public class CollectionTypeDefinitionBuilderTest extends AbstractAnnotationProcessingTest { + + private CollectionTypeDefinitionBuilder builder; + + private VariableElement stringsField; + + private VariableElement colorsField; + + private VariableElement primitiveTypeModelsField; + + private VariableElement modelsField; + + private VariableElement modelArraysField; + + @Override + protected void addCompiledClasses(Set> classesToBeCompiled) { + classesToBeCompiled.add(CollectionTypeModel.class); + } + + @Override + protected void beforeEach() { + builder = new CollectionTypeDefinitionBuilder(); + TypeElement testType = getType(CollectionTypeModel.class); + stringsField = findField( testType, "strings"); + colorsField = findField( testType, "colors"); + primitiveTypeModelsField = findField( testType, "primitiveTypeModels"); + modelsField = findField( testType, "models"); + modelArraysField = findField( testType, "modelArrays"); + + assertEquals("strings", stringsField.getSimpleName().toString()); + assertEquals("colors", colorsField.getSimpleName().toString()); + assertEquals("primitiveTypeModels", primitiveTypeModelsField.getSimpleName().toString()); + assertEquals("models", modelsField.getSimpleName().toString()); + assertEquals("modelArrays", modelArraysField.getSimpleName().toString()); + } + + @Test + public void testAccept() { + assertTrue(builder.accept(processingEnv, stringsField.asType())); + assertTrue(builder.accept(processingEnv, colorsField.asType())); + assertTrue(builder.accept(processingEnv, primitiveTypeModelsField.asType())); + assertTrue(builder.accept(processingEnv, modelsField.asType())); + assertTrue(builder.accept(processingEnv, modelArraysField.asType())); + } + + @Test + public void testBuild() { + + buildAndAssertTypeDefinition(processingEnv, stringsField, "java.util.Collection", "java.lang.String", builder); + + buildAndAssertTypeDefinition(processingEnv, colorsField, "java.util.List", + "org.apache.dubbo.metadata.annotation.processing.model.Color", builder); + + buildAndAssertTypeDefinition(processingEnv, primitiveTypeModelsField, + "java.util.Queue", + "org.apache.dubbo.metadata.annotation.processing.model.PrimitiveTypeModel", builder); + + buildAndAssertTypeDefinition(processingEnv, modelsField, + "java.util.Deque", + "org.apache.dubbo.metadata.annotation.processing.model.Model", builder); + + buildAndAssertTypeDefinition(processingEnv, modelArraysField, + "java.util.Set", + "org.apache.dubbo.metadata.annotation.processing.model.Model[]", builder); + + + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/EnumTypeDefinitionBuilderTest.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/EnumTypeDefinitionBuilderTest.java new file mode 100644 index 00000000000..52f33aa31df --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/EnumTypeDefinitionBuilderTest.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.builder; + +import org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest; +import org.apache.dubbo.metadata.annotation.processing.model.Color; +import org.apache.dubbo.metadata.definition.model.TypeDefinition; + +import org.junit.jupiter.api.Test; + +import javax.lang.model.element.TypeElement; +import java.util.Set; + +import static java.util.Arrays.asList; +import static org.apache.dubbo.metadata.annotation.processing.builder.TypeDefinitionBuilder.build; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link EnumTypeDefinitionBuilder} Test + * + * @since 2.7.5 + */ +public class EnumTypeDefinitionBuilderTest extends AbstractAnnotationProcessingTest { + + private EnumTypeDefinitionBuilder builder; + + @Override + protected void addCompiledClasses(Set> classesToBeCompiled) { + classesToBeCompiled.add(Color.class); + } + + @Override + protected void beforeEach() { + builder = new EnumTypeDefinitionBuilder(); + } + + @Test + public void testAccept() { + TypeElement typeElement = getType(Color.class); + assertTrue(builder.accept(processingEnv, typeElement.asType())); + } + + @Test + public void testBuild() { + TypeElement typeElement = getType(Color.class); + TypeDefinition typeDefinition = build(processingEnv, typeElement); + assertEquals(Color.class.getName(), typeDefinition.getType()); + assertEquals(asList("RED", "YELLOW", "BLUE"), typeDefinition.getEnums()); +// assertEquals(typeDefinition.getTypeBuilderName(), builder.getClass().getName()); + } + +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/GeneralTypeDefinitionBuilderTest.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/GeneralTypeDefinitionBuilderTest.java new file mode 100644 index 00000000000..8be38dc86fe --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/GeneralTypeDefinitionBuilderTest.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.builder; + +import org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest; +import org.apache.dubbo.metadata.annotation.processing.model.ArrayTypeModel; +import org.apache.dubbo.metadata.annotation.processing.model.CollectionTypeModel; +import org.apache.dubbo.metadata.annotation.processing.model.Color; +import org.apache.dubbo.metadata.annotation.processing.model.Model; +import org.apache.dubbo.metadata.annotation.processing.model.PrimitiveTypeModel; +import org.apache.dubbo.metadata.annotation.processing.model.SimpleTypeModel; + +import org.junit.jupiter.api.Test; + +import java.util.Set; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link GeneralTypeDefinitionBuilder} Test + * + * @since 2.7.5 + */ +public class GeneralTypeDefinitionBuilderTest extends AbstractAnnotationProcessingTest { + + private GeneralTypeDefinitionBuilder builder; + + @Override + protected void addCompiledClasses(Set> classesToBeCompiled) { + classesToBeCompiled.add(Model.class); + } + + @Override + protected void beforeEach() { + builder = new GeneralTypeDefinitionBuilder(); + } + + @Test + public void testAccept() { + assertTrue(builder.accept(processingEnv, getType(Model.class).asType())); + assertTrue(builder.accept(processingEnv, getType(PrimitiveTypeModel.class).asType())); + assertTrue(builder.accept(processingEnv, getType(SimpleTypeModel.class).asType())); + assertTrue(builder.accept(processingEnv, getType(ArrayTypeModel.class).asType())); + assertTrue(builder.accept(processingEnv, getType(CollectionTypeModel.class).asType())); + assertFalse(builder.accept(processingEnv, getType(Color.class).asType())); + } + + @Test + public void testBuild() { + + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/MapTypeDefinitionBuilderTest.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/MapTypeDefinitionBuilderTest.java new file mode 100644 index 00000000000..3229c31b3de --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/MapTypeDefinitionBuilderTest.java @@ -0,0 +1,134 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.builder; + +import org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest; +import org.apache.dubbo.metadata.annotation.processing.model.MapTypeModel; +import org.apache.dubbo.metadata.definition.model.TypeDefinition; + +import org.junit.jupiter.api.Test; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import java.util.Set; +import java.util.function.BiConsumer; +import java.util.stream.Stream; + +import static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.findField; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link MapTypeDefinitionBuilder} Test + * + * @since 2.7.5 + */ +public class MapTypeDefinitionBuilderTest extends AbstractAnnotationProcessingTest { + + private MapTypeDefinitionBuilder builder; + + private VariableElement stringsField; + + private VariableElement colorsField; + + private VariableElement primitiveTypeModelsField; + + private VariableElement modelsField; + + private VariableElement modelArraysField; + + @Override + protected void addCompiledClasses(Set> classesToBeCompiled) { + classesToBeCompiled.add(MapTypeModel.class); + } + + @Override + protected void beforeEach() { + builder = new MapTypeDefinitionBuilder(); + TypeElement testType = getType(MapTypeModel.class); + stringsField = findField( testType, "strings"); + colorsField = findField( testType, "colors"); + primitiveTypeModelsField = findField( testType, "primitiveTypeModels"); + modelsField = findField( testType, "models"); + modelArraysField = findField( testType, "modelArrays"); + + assertEquals("strings", stringsField.getSimpleName().toString()); + assertEquals("colors", colorsField.getSimpleName().toString()); + assertEquals("primitiveTypeModels", primitiveTypeModelsField.getSimpleName().toString()); + assertEquals("models", modelsField.getSimpleName().toString()); + assertEquals("modelArrays", modelArraysField.getSimpleName().toString()); + } + + @Test + public void testAccept() { + assertTrue(builder.accept(processingEnv, stringsField.asType())); + assertTrue(builder.accept(processingEnv, colorsField.asType())); + assertTrue(builder.accept(processingEnv, primitiveTypeModelsField.asType())); + assertTrue(builder.accept(processingEnv, modelsField.asType())); + assertTrue(builder.accept(processingEnv, modelArraysField.asType())); + } + + @Test + public void testBuild() { + + buildAndAssertTypeDefinition(processingEnv, stringsField, + "java.util.Map", + "java.lang.String", + "java.lang.String", + builder); + + buildAndAssertTypeDefinition(processingEnv, colorsField, + "java.util.SortedMap", + "java.lang.String", + "org.apache.dubbo.metadata.annotation.processing.model.Color", + builder); + + buildAndAssertTypeDefinition(processingEnv, primitiveTypeModelsField, + "java.util.NavigableMap", + "org.apache.dubbo.metadata.annotation.processing.model.Color", + "org.apache.dubbo.metadata.annotation.processing.model.PrimitiveTypeModel", + builder); + + buildAndAssertTypeDefinition(processingEnv, modelsField, + "java.util.HashMap", + "java.lang.String", + "org.apache.dubbo.metadata.annotation.processing.model.Model", + builder); + + buildAndAssertTypeDefinition(processingEnv, modelArraysField, + "java.util.TreeMap", + "org.apache.dubbo.metadata.annotation.processing.model.PrimitiveTypeModel", + "org.apache.dubbo.metadata.annotation.processing.model.Model[]", + builder); + } + + static void buildAndAssertTypeDefinition(ProcessingEnvironment processingEnv, VariableElement field, + String expectedType, String keyType, String valueType, + TypeDefinitionBuilder builder, + BiConsumer... assertions) { + TypeDefinition typeDefinition = TypeDefinitionBuilder.build(processingEnv, field); + TypeDefinition keyTypeDefinition = typeDefinition.getItems().get(0); + TypeDefinition valueTypeDefinition = typeDefinition.getItems().get(1); + assertEquals(expectedType, typeDefinition.getType()); + assertEquals(field.getSimpleName().toString(), typeDefinition.get$ref()); + assertEquals(keyType, keyTypeDefinition.getType()); + assertEquals(valueType, valueTypeDefinition.getType()); +// assertEquals(builder.getClass().getName(), typeDefinition.getTypeBuilderName()); + Stream.of(assertions).forEach(assertion -> assertion.accept(typeDefinition, keyTypeDefinition)); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/PrimitiveTypeDefinitionBuilderTest.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/PrimitiveTypeDefinitionBuilderTest.java new file mode 100644 index 00000000000..0953885dbe7 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/PrimitiveTypeDefinitionBuilderTest.java @@ -0,0 +1,130 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.builder; + +import org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest; +import org.apache.dubbo.metadata.annotation.processing.model.PrimitiveTypeModel; +import org.apache.dubbo.metadata.definition.model.TypeDefinition; + +import org.junit.jupiter.api.Test; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import java.util.Set; + +import static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.findField; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link PrimitiveTypeDefinitionBuilder} Test + * + * @since 2.7.5 + */ +public class PrimitiveTypeDefinitionBuilderTest extends AbstractAnnotationProcessingTest { + + private PrimitiveTypeDefinitionBuilder builder; + + private VariableElement zField; + + private VariableElement bField; + + private VariableElement cField; + + private VariableElement sField; + + private VariableElement iField; + + private VariableElement lField; + + private VariableElement fField; + + private VariableElement dField; + + @Override + protected void addCompiledClasses(Set> classesToBeCompiled) { + classesToBeCompiled.add(PrimitiveTypeModel.class); + } + + @Override + protected void beforeEach() { + + builder = new PrimitiveTypeDefinitionBuilder(); + + TypeElement testType = getType(PrimitiveTypeModel.class); + + zField = findField( testType, "z"); + bField = findField( testType, "b"); + cField = findField( testType, "c"); + sField = findField( testType, "s"); + iField = findField( testType, "i"); + lField = findField( testType, "l"); + fField = findField( testType, "f"); + dField = findField( testType, "d"); + + assertEquals("boolean", zField.asType().toString()); + assertEquals("byte", bField.asType().toString()); + assertEquals("char", cField.asType().toString()); + assertEquals("short", sField.asType().toString()); + assertEquals("int", iField.asType().toString()); + assertEquals("long", lField.asType().toString()); + assertEquals("float", fField.asType().toString()); + assertEquals("double", dField.asType().toString()); + } + + @Test + public void testAccept() { + assertTrue(builder.accept(processingEnv, zField.asType())); + assertTrue(builder.accept(processingEnv, bField.asType())); + assertTrue(builder.accept(processingEnv, cField.asType())); + assertTrue(builder.accept(processingEnv, sField.asType())); + assertTrue(builder.accept(processingEnv, iField.asType())); + assertTrue(builder.accept(processingEnv, lField.asType())); + assertTrue(builder.accept(processingEnv, fField.asType())); + assertTrue(builder.accept(processingEnv, dField.asType())); + } + + @Test + public void testBuild() { + buildAndAssertTypeDefinition(processingEnv, zField, builder); + buildAndAssertTypeDefinition(processingEnv, bField, builder); + buildAndAssertTypeDefinition(processingEnv, cField, builder); + buildAndAssertTypeDefinition(processingEnv, sField, builder); + buildAndAssertTypeDefinition(processingEnv, iField, builder); + buildAndAssertTypeDefinition(processingEnv, lField, builder); + buildAndAssertTypeDefinition(processingEnv, zField, builder); + buildAndAssertTypeDefinition(processingEnv, fField, builder); + buildAndAssertTypeDefinition(processingEnv, dField, builder); + } + + static void buildAndAssertTypeDefinition(ProcessingEnvironment processingEnv, VariableElement field, TypeDefinitionBuilder builder) { + TypeDefinition typeDefinition = TypeDefinitionBuilder.build(processingEnv, field); + assertBasicTypeDefinition(typeDefinition, field.asType().toString(), builder); + assertEquals(field.getSimpleName().toString(), typeDefinition.get$ref()); + } + + static void assertBasicTypeDefinition(TypeDefinition typeDefinition, String type, TypeDefinitionBuilder builder) { + assertEquals(type, typeDefinition.getType()); +// assertEquals(builder.getClass().getName(), typeDefinition.getTypeBuilderName()); + assertTrue(typeDefinition.getProperties().isEmpty()); + assertTrue(typeDefinition.getItems().isEmpty()); + assertTrue(typeDefinition.getEnums().isEmpty()); + assertNull(typeDefinition.getId()); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/ServiceDefinitionBuilderTest.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/ServiceDefinitionBuilderTest.java new file mode 100644 index 00000000000..c891f870482 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/ServiceDefinitionBuilderTest.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.builder; + +import org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest; +import org.apache.dubbo.metadata.definition.model.ServiceDefinition; +import org.apache.dubbo.metadata.tools.TestServiceImpl; + +import org.junit.jupiter.api.Test; + +import java.util.Set; + +import static org.apache.dubbo.metadata.annotation.processing.builder.ServiceDefinitionBuilder.build; +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * {@link ServiceDefinitionBuilder} Test + * + * @since 2.7.5 + */ +public class ServiceDefinitionBuilderTest extends AbstractAnnotationProcessingTest { + + + @Override + protected void addCompiledClasses(Set> classesToBeCompiled) { + classesToBeCompiled.add(TestServiceImpl.class); + } + + @Override + protected void beforeEach() { + } + + @Test + public void testBuild() { + ServiceDefinition serviceDefinition = build(processingEnv, getType(TestServiceImpl.class)); + assertEquals(TestServiceImpl.class.getTypeName(), serviceDefinition.getCanonicalName()); + assertEquals("org/apache/dubbo/metadata/tools/TestServiceImpl.class", serviceDefinition.getCodeSource()); + // types + int i = 0; + assertEquals("org.apache.dubbo.metadata.tools.TestServiceImpl", serviceDefinition.getTypes().get(i++).getType()); + assertEquals("org.apache.dubbo.metadata.tools.GenericTestService", serviceDefinition.getTypes().get(i++).getType()); + assertEquals("org.apache.dubbo.metadata.tools.DefaultTestService", serviceDefinition.getTypes().get(i++).getType()); + assertEquals("org.apache.dubbo.metadata.tools.TestService", serviceDefinition.getTypes().get(i++).getType()); + assertEquals("java.lang.AutoCloseable", serviceDefinition.getTypes().get(i++).getType()); + assertEquals("java.io.Serializable", serviceDefinition.getTypes().get(i++).getType()); + assertEquals("java.util.EventListener", serviceDefinition.getTypes().get(i++).getType()); + // methods + assertEquals(14, serviceDefinition.getMethods().size()); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/SimpleTypeDefinitionBuilderTest.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/SimpleTypeDefinitionBuilderTest.java new file mode 100644 index 00000000000..365ac56e96c --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/SimpleTypeDefinitionBuilderTest.java @@ -0,0 +1,146 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.builder; + +import org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest; +import org.apache.dubbo.metadata.annotation.processing.model.SimpleTypeModel; + +import org.junit.jupiter.api.Test; + +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import java.util.Set; + +import static org.apache.dubbo.metadata.annotation.processing.builder.PrimitiveTypeDefinitionBuilderTest.buildAndAssertTypeDefinition; +import static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.findField; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link SimpleTypeDefinitionBuilder} Test + * + * @since 2.7.5 + */ +public class SimpleTypeDefinitionBuilderTest extends AbstractAnnotationProcessingTest { + + private SimpleTypeDefinitionBuilder builder; + + private VariableElement vField; + + private VariableElement zField; + + private VariableElement cField; + + private VariableElement bField; + + private VariableElement sField; + + private VariableElement iField; + + private VariableElement lField; + + private VariableElement fField; + + private VariableElement dField; + + private VariableElement strField; + + private VariableElement bdField; + + private VariableElement biField; + + private VariableElement dtField; + + private VariableElement invalidField; + + + @Override + protected void addCompiledClasses(Set> classesToBeCompiled) { + classesToBeCompiled.add(SimpleTypeModel.class); + } + + @Override + protected void beforeEach() { + builder = new SimpleTypeDefinitionBuilder(); + TypeElement testType = getType(SimpleTypeModel.class); + vField = findField(testType, "v"); + zField = findField(testType, "z"); + cField = findField(testType, "c"); + bField = findField(testType, "b"); + sField = findField(testType, "s"); + iField = findField(testType, "i"); + lField = findField(testType, "l"); + fField = findField(testType, "f"); + dField = findField(testType, "d"); + strField = findField(testType, "str"); + bdField = findField(testType, "bd"); + biField = findField(testType, "bi"); + dtField = findField(testType, "dt"); + invalidField = findField(testType, "invalid"); + + assertEquals("java.lang.Void", vField.asType().toString()); + assertEquals("java.lang.Boolean", zField.asType().toString()); + assertEquals("java.lang.Character", cField.asType().toString()); + assertEquals("java.lang.Byte", bField.asType().toString()); + assertEquals("java.lang.Short", sField.asType().toString()); + assertEquals("java.lang.Integer", iField.asType().toString()); + assertEquals("java.lang.Long", lField.asType().toString()); + assertEquals("java.lang.Float", fField.asType().toString()); + assertEquals("java.lang.Double", dField.asType().toString()); + assertEquals("java.lang.String", strField.asType().toString()); + assertEquals("java.math.BigDecimal", bdField.asType().toString()); + assertEquals("java.math.BigInteger", biField.asType().toString()); + assertEquals("java.util.Date", dtField.asType().toString()); + assertEquals("int", invalidField.asType().toString()); + } + + @Test + public void testAccept() { + assertTrue(builder.accept(processingEnv, vField.asType())); + assertTrue(builder.accept(processingEnv, zField.asType())); + assertTrue(builder.accept(processingEnv, cField.asType())); + assertTrue(builder.accept(processingEnv, bField.asType())); + assertTrue(builder.accept(processingEnv, sField.asType())); + assertTrue(builder.accept(processingEnv, iField.asType())); + assertTrue(builder.accept(processingEnv, lField.asType())); + assertTrue(builder.accept(processingEnv, fField.asType())); + assertTrue(builder.accept(processingEnv, dField.asType())); + assertTrue(builder.accept(processingEnv, strField.asType())); + assertTrue(builder.accept(processingEnv, bdField.asType())); + assertTrue(builder.accept(processingEnv, biField.asType())); + assertTrue(builder.accept(processingEnv, dtField.asType())); + // false condition + assertFalse(builder.accept(processingEnv, invalidField.asType())); + } + + @Test + public void testBuild() { + buildAndAssertTypeDefinition(processingEnv, vField, builder); + buildAndAssertTypeDefinition(processingEnv, zField, builder); + buildAndAssertTypeDefinition(processingEnv, cField, builder); + buildAndAssertTypeDefinition(processingEnv, sField, builder); + buildAndAssertTypeDefinition(processingEnv, iField, builder); + buildAndAssertTypeDefinition(processingEnv, lField, builder); + buildAndAssertTypeDefinition(processingEnv, fField, builder); + buildAndAssertTypeDefinition(processingEnv, dField, builder); + buildAndAssertTypeDefinition(processingEnv, strField, builder); + buildAndAssertTypeDefinition(processingEnv, bdField, builder); + buildAndAssertTypeDefinition(processingEnv, biField, builder); + buildAndAssertTypeDefinition(processingEnv, dtField, builder); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/ArrayTypeModel.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/ArrayTypeModel.java new file mode 100644 index 00000000000..db6874ae429 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/ArrayTypeModel.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.model; + +/** + * Array Type Model + * + * @since 2.7.5 + */ +public class ArrayTypeModel { + + private int[] integers; // Primitive type array + + private String[] strings; // Simple type array + + private PrimitiveTypeModel[] primitiveTypeModels; // Complex type array + + private Model[] models; // Hierarchical Complex type array + + private Color[] colors; // Enum type array + +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/CollectionTypeModel.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/CollectionTypeModel.java new file mode 100644 index 00000000000..b2ce91d81ce --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/CollectionTypeModel.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.model; + +import java.util.Collection; +import java.util.Deque; +import java.util.List; +import java.util.Queue; +import java.util.Set; + +/** + * {@link Collection} Type Model + * + * @since 2.7.5 + */ +public class CollectionTypeModel { + + private Collection strings; // The composite element is simple type + + private List colors; // The composite element is Enum type + + private Queue primitiveTypeModels; // The composite element is POJO type + + private Deque models; // The composite element is hierarchical POJO type + + private Set modelArrays; // The composite element is hierarchical POJO type + +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/Color.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/Color.java new file mode 100644 index 00000000000..6c34404cbab --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/Color.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.model; + +/** + * Color enumeration + * + * @since 2.7.5 + */ +public enum Color { + + RED(1), + YELLOW(2), + BLUE(3); + + private final int value; + + Color(int value) { + this.value = value; + } + + @Override + public String toString() { + return "Color{" + + "value=" + value + + "} " + super.toString(); + } + + public int getValue() { + return value; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/MapTypeModel.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/MapTypeModel.java new file mode 100644 index 00000000000..f1613ae33de --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/MapTypeModel.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.model; + +import java.util.HashMap; +import java.util.Map; +import java.util.NavigableMap; +import java.util.SortedMap; +import java.util.TreeMap; + +/** + * {@link Map} Type model + * + * @since 2.7.5 + */ +public class MapTypeModel { + + private Map strings; // The composite element is simple type + + private SortedMap colors; // The composite element is Enum type + + private NavigableMap primitiveTypeModels; // The composite element is POJO type + + private HashMap models; // The composite element is hierarchical POJO type + + private TreeMap modelArrays; // The composite element is hierarchical POJO type +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/Model.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/Model.java new file mode 100644 index 00000000000..e3c72a5e326 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/Model.java @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.model; + +import org.apache.dubbo.metadata.tools.Parent; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.concurrent.TimeUnit; + +/** + * Model Object + */ +public class Model extends Parent { + + private float f; + + private double d; + + private TimeUnit tu; + + private String str; + + private BigInteger bi; + + private BigDecimal bd; + + public float getF() { + return f; + } + + public void setF(float f) { + this.f = f; + } + + public double getD() { + return d; + } + + public void setD(double d) { + this.d = d; + } + + public TimeUnit getTu() { + return tu; + } + + public void setTu(TimeUnit tu) { + this.tu = tu; + } + + public String getStr() { + return str; + } + + public void setStr(String str) { + this.str = str; + } + + public BigInteger getBi() { + return bi; + } + + public void setBi(BigInteger bi) { + this.bi = bi; + } + + public BigDecimal getBd() { + return bd; + } + + public void setBd(BigDecimal bd) { + this.bd = bd; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/PrimitiveTypeModel.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/PrimitiveTypeModel.java new file mode 100644 index 00000000000..7adc685daa7 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/PrimitiveTypeModel.java @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.model; + +/** + * Primitive Type model + * + * @since 2.7.5 + */ +public class PrimitiveTypeModel { + + private boolean z; + + private byte b; + + private char c; + + private short s; + + private int i; + + private long l; + + private float f; + + private double d; + + public boolean isZ() { + return z; + } + + public byte getB() { + return b; + } + + public char getC() { + return c; + } + + public short getS() { + return s; + } + + public int getI() { + return i; + } + + public long getL() { + return l; + } + + public float getF() { + return f; + } + + public double getD() { + return d; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/SimpleTypeModel.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/SimpleTypeModel.java new file mode 100644 index 00000000000..b6f40ecb15d --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/SimpleTypeModel.java @@ -0,0 +1,161 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License; Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing; software + * distributed under the License is distributed on an "AS IS" BASIS; + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND; either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.model; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.Date; + +/** + * Simple Type model + * + * @since 2.7.5 + */ +public class SimpleTypeModel { + + private Void v; + + private Boolean z; + + private Character c; + + private Byte b; + + private Short s; + + private Integer i; + + private Long l; + + private Float f; + + private Double d; + + private String str; + + private BigDecimal bd; + + private BigInteger bi; + + private Date dt; + + private int invalid; + + public Void getV() { + return v; + } + + public void setV(Void v) { + this.v = v; + } + + public Boolean getZ() { + return z; + } + + public void setZ(Boolean z) { + this.z = z; + } + + public Character getC() { + return c; + } + + public void setC(Character c) { + this.c = c; + } + + public Byte getB() { + return b; + } + + public void setB(Byte b) { + this.b = b; + } + + public Short getS() { + return s; + } + + public void setS(Short s) { + this.s = s; + } + + public Integer getI() { + return i; + } + + public void setI(Integer i) { + this.i = i; + } + + public Long getL() { + return l; + } + + public void setL(Long l) { + this.l = l; + } + + public Float getF() { + return f; + } + + public void setF(Float f) { + this.f = f; + } + + public Double getD() { + return d; + } + + public void setD(Double d) { + this.d = d; + } + + public String getStr() { + return str; + } + + public void setStr(String str) { + this.str = str; + } + + public BigDecimal getBd() { + return bd; + } + + public void setBd(BigDecimal bd) { + this.bd = bd; + } + + public BigInteger getBi() { + return bi; + } + + public void setBi(BigInteger bi) { + this.bi = bi; + } + + public Date getDt() { + return dt; + } + + public void setDt(Date dt) { + this.dt = dt; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/AnnotationUtilsTest.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/AnnotationUtilsTest.java new file mode 100644 index 00000000000..a68cc2354d9 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/AnnotationUtilsTest.java @@ -0,0 +1,232 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.util; + +import org.apache.dubbo.config.annotation.Service; +import org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest; +import org.apache.dubbo.metadata.tools.SpringRestService; +import org.apache.dubbo.metadata.tools.TestService; +import org.apache.dubbo.metadata.tools.TestServiceImpl; + +import org.junit.jupiter.api.Test; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.TypeMirror; +import javax.ws.rs.Path; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.findAnnotation; +import static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.findMetaAnnotation; +import static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.getAllAnnotations; +import static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.getAnnotation; +import static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.getAnnotations; +import static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.getAttribute; +import static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.getValue; +import static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.isAnnotationPresent; +import static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.findMethod; +import static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.getAllDeclaredMethods; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * The {@link AnnotationUtils} Test + * + * @since 2.7.5 + */ +public class AnnotationUtilsTest extends AbstractAnnotationProcessingTest { + + private TypeElement testType; + + @Override + protected void addCompiledClasses(Set> classesToBeCompiled) { + } + + @Override + protected void beforeEach() { + testType = getType(TestServiceImpl.class); + } + + @Test + public void testGetAnnotation() { + AnnotationMirror serviceAnnotation = getAnnotation(testType, Service.class); + assertEquals("3.0.0", getAttribute(serviceAnnotation, "version")); + assertEquals("test", getAttribute(serviceAnnotation, "group")); + assertEquals("org.apache.dubbo.metadata.tools.TestService", getAttribute(serviceAnnotation, "interfaceName")); + + assertNull(getAnnotation(testType, (Class) null)); + assertNull(getAnnotation(testType, (String) null)); + + assertNull(getAnnotation(testType.asType(), (Class) null)); + assertNull(getAnnotation(testType.asType(), (String) null)); + + assertNull(getAnnotation((Element) null, (Class) null)); + assertNull(getAnnotation((Element) null, (String) null)); + + assertNull(getAnnotation((TypeElement) null, (Class) null)); + assertNull(getAnnotation((TypeElement) null, (String) null)); + } + + @Test + public void testGetAnnotations() { + List annotations = getAnnotations(testType); + Iterator iterator = annotations.iterator(); + + assertEquals(2, annotations.size()); + assertEquals("com.alibaba.dubbo.config.annotation.Service", iterator.next().getAnnotationType().toString()); + assertEquals("org.apache.dubbo.config.annotation.Service", iterator.next().getAnnotationType().toString()); + + annotations = getAnnotations(testType, Service.class); + iterator = annotations.iterator(); + assertEquals(1, annotations.size()); + assertEquals("org.apache.dubbo.config.annotation.Service", iterator.next().getAnnotationType().toString()); + + annotations = getAnnotations(testType.asType(), Service.class); + iterator = annotations.iterator(); + assertEquals(1, annotations.size()); + assertEquals("org.apache.dubbo.config.annotation.Service", iterator.next().getAnnotationType().toString()); + + annotations = getAnnotations(testType.asType(), Service.class.getTypeName()); + iterator = annotations.iterator(); + assertEquals(1, annotations.size()); + assertEquals("org.apache.dubbo.config.annotation.Service", iterator.next().getAnnotationType().toString()); + + annotations = getAnnotations(testType, Override.class); + assertEquals(0, annotations.size()); + + annotations = getAnnotations(testType, com.alibaba.dubbo.config.annotation.Service.class); + assertEquals(1, annotations.size()); + + assertTrue(getAnnotations(null, (Class) null).isEmpty()); + assertTrue(getAnnotations(null, (String) null).isEmpty()); + assertTrue(getAnnotations(testType, (Class) null).isEmpty()); + assertTrue(getAnnotations(testType, (String) null).isEmpty()); + + assertTrue(getAnnotations(null, Service.class).isEmpty()); + assertTrue(getAnnotations(null, Service.class.getTypeName()).isEmpty()); + } + + @Test + public void testGetAllAnnotations() { + + List annotations = getAllAnnotations(testType); + assertEquals(5, annotations.size()); + + annotations = getAllAnnotations(testType.asType(), annotation -> true); + assertEquals(5, annotations.size()); + + annotations = getAllAnnotations(processingEnv, TestServiceImpl.class); + assertEquals(5, annotations.size()); + + annotations = getAllAnnotations(testType.asType(), Service.class); + assertEquals(2, annotations.size()); + + annotations = getAllAnnotations(testType, Override.class); + assertEquals(0, annotations.size()); + + annotations = getAllAnnotations(testType.asType(), com.alibaba.dubbo.config.annotation.Service.class); + assertEquals(2, annotations.size()); + + assertTrue(getAllAnnotations((Element) null, (Class) null).isEmpty()); + assertTrue(getAllAnnotations((TypeMirror) null, (String) null).isEmpty()); + assertTrue(getAllAnnotations((ProcessingEnvironment) null, (Class) null).isEmpty()); + assertTrue(getAllAnnotations((ProcessingEnvironment) null, (String) null).isEmpty()); + + assertTrue(getAllAnnotations((Element) null).isEmpty()); + assertTrue(getAllAnnotations((TypeMirror) null).isEmpty()); + assertTrue(getAllAnnotations(processingEnv, (Class) null).isEmpty()); + assertTrue(getAllAnnotations(processingEnv, (String) null).isEmpty()); + + + assertTrue(getAllAnnotations(testType, (Class) null).isEmpty()); + assertTrue(getAllAnnotations(testType.asType(), (Class) null).isEmpty()); + + assertTrue(getAllAnnotations(testType, (String) null).isEmpty()); + assertTrue(getAllAnnotations(testType.asType(), (String) null).isEmpty()); + + assertTrue(getAllAnnotations((Element) null, Service.class).isEmpty()); + assertTrue(getAllAnnotations((TypeMirror) null, Service.class.getTypeName()).isEmpty()); + } + + + @Test + public void testFindAnnotation() { + + assertEquals("org.apache.dubbo.config.annotation.Service", findAnnotation(testType, Service.class).getAnnotationType().toString()); + assertEquals("com.alibaba.dubbo.config.annotation.Service", findAnnotation(testType, com.alibaba.dubbo.config.annotation.Service.class).getAnnotationType().toString()); + assertEquals("javax.ws.rs.Path", findAnnotation(testType, Path.class).getAnnotationType().toString()); + assertEquals("javax.ws.rs.Path", findAnnotation(testType.asType(), Path.class).getAnnotationType().toString()); + assertEquals("javax.ws.rs.Path", findAnnotation(testType.asType(), Path.class.getTypeName()).getAnnotationType().toString()); + assertNull(findAnnotation(testType, Override.class)); + + assertNull(findAnnotation((Element) null, (Class) null)); + assertNull(findAnnotation((Element) null, (String) null)); + assertNull(findAnnotation((TypeMirror) null, (Class) null)); + assertNull(findAnnotation((TypeMirror) null, (String) null)); + + assertNull(findAnnotation(testType, (Class) null)); + assertNull(findAnnotation(testType, (String) null)); + assertNull(findAnnotation(testType.asType(), (Class) null)); + assertNull(findAnnotation(testType.asType(), (String) null)); + } + + @Test + public void testFindMetaAnnotation() { + getAllDeclaredMethods(getType(TestService.class)).forEach(method -> { + assertEquals("javax.ws.rs.HttpMethod", findMetaAnnotation(method, "javax.ws.rs.HttpMethod").getAnnotationType().toString()); + }); + } + + @Test + public void testGetAttribute() { + assertEquals("org.apache.dubbo.metadata.tools.TestService", getAttribute(findAnnotation(testType, Service.class), "interfaceName")); + assertEquals("org.apache.dubbo.metadata.tools.TestService", getAttribute(findAnnotation(testType, Service.class).getElementValues(), "interfaceName")); + assertEquals("/echo", getAttribute(findAnnotation(testType, Path.class), "value")); + + assertNull(getAttribute(findAnnotation(testType, Path.class), null)); + assertNull(getAttribute(findAnnotation(testType, (Class) null), null)); + + ExecutableElement method = findMethod(getType(SpringRestService.class), "param", String.class); + + AnnotationMirror annotation = findAnnotation(method, GetMapping.class); + + assertArrayEquals(new String[]{"/param"}, (String[]) getAttribute(annotation, "value")); + assertNull(getAttribute(annotation, "path")); + } + + @Test + public void testGetValue() { + AnnotationMirror pathAnnotation = getAnnotation(getType(TestService.class), Path.class); + assertEquals("/echo", getValue(pathAnnotation)); + } + + @Test + public void testIsAnnotationPresent() { + assertTrue(isAnnotationPresent(testType, "org.apache.dubbo.config.annotation.Service")); + assertTrue(isAnnotationPresent(testType, "com.alibaba.dubbo.config.annotation.Service")); + assertTrue(isAnnotationPresent(testType, "javax.ws.rs.Path")); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/FieldUtilsTest.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/FieldUtilsTest.java new file mode 100644 index 00000000000..57767917ec3 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/FieldUtilsTest.java @@ -0,0 +1,259 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.util; + +import org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest; +import org.apache.dubbo.metadata.annotation.processing.model.Color; +import org.apache.dubbo.metadata.annotation.processing.model.Model; +import org.apache.dubbo.metadata.tools.TestServiceImpl; + +import org.junit.jupiter.api.Test; + +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.TypeMirror; +import java.lang.reflect.Type; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.List; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import static javax.lang.model.element.Modifier.FINAL; +import static javax.lang.model.element.Modifier.PRIVATE; +import static javax.lang.model.element.Modifier.PUBLIC; +import static javax.lang.model.element.Modifier.STATIC; +import static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.findField; +import static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.getAllDeclaredFields; +import static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.getAllNonStaticFields; +import static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.getDeclaredField; +import static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.getDeclaredFields; +import static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.getNonStaticFields; +import static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.isEnumMemberField; +import static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.isField; +import static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.isNonStaticField; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link FieldUtils} Test + * + * @since 2.7.5 + */ +public class FieldUtilsTest extends AbstractAnnotationProcessingTest { + + private TypeElement testType; + + @Override + protected void addCompiledClasses(Set> classesToBeCompiled) { + } + + @Override + protected void beforeEach() { + testType = getType(TestServiceImpl.class); + } + + @Test + public void testGetDeclaredFields() { + TypeElement type = getType(Model.class); + List fields = getDeclaredFields(type); + assertModelFields(fields); + + fields = getDeclaredFields(type.asType()); + assertModelFields(fields); + + assertTrue(getDeclaredFields((Element) null).isEmpty()); + assertTrue(getDeclaredFields((TypeMirror) null).isEmpty()); + + fields = getDeclaredFields(type, f -> "f".equals(f.getSimpleName().toString())); + assertEquals(1, fields.size()); + assertEquals("f", fields.get(0).getSimpleName().toString()); + } + + @Test + public void testGetAllDeclaredFields() { + TypeElement type = getType(Model.class); + + List fields = getAllDeclaredFields(type); + + assertModelAllFields(fields); + + assertTrue(getAllDeclaredFields((Element) null).isEmpty()); + assertTrue(getAllDeclaredFields((TypeMirror) null).isEmpty()); + + fields = getAllDeclaredFields(type, f -> "f".equals(f.getSimpleName().toString())); + assertEquals(1, fields.size()); + assertEquals("f", fields.get(0).getSimpleName().toString()); + } + + @Test + public void testGetDeclaredField() { + TypeElement type = getType(Model.class); + testGetDeclaredField(type, "f", float.class); + testGetDeclaredField(type, "d", double.class); + testGetDeclaredField(type, "tu", TimeUnit.class); + testGetDeclaredField(type, "str", String.class); + testGetDeclaredField(type, "bi", BigInteger.class); + testGetDeclaredField(type, "bd", BigDecimal.class); + + assertNull(getDeclaredField(type, "b")); + assertNull(getDeclaredField(type, "s")); + assertNull(getDeclaredField(type, "i")); + assertNull(getDeclaredField(type, "l")); + assertNull(getDeclaredField(type, "z")); + + assertNull(getDeclaredField((Element) null, "z")); + assertNull(getDeclaredField((TypeMirror) null, "z")); + } + + @Test + public void testFindField() { + TypeElement type = getType(Model.class); + testFindField(type, "f", float.class); + testFindField(type, "d", double.class); + testFindField(type, "tu", TimeUnit.class); + testFindField(type, "str", String.class); + testFindField(type, "bi", BigInteger.class); + testFindField(type, "bd", BigDecimal.class); + testFindField(type, "b", byte.class); + testFindField(type, "s", short.class); + testFindField(type, "i", int.class); + testFindField(type, "l", long.class); + testFindField(type, "z", boolean.class); + + assertNull(findField((Element) null, "f")); + assertNull(findField((Element) null, null)); + + assertNull(findField((TypeMirror) null, "f")); + assertNull(findField((TypeMirror) null, null)); + + assertNull(findField(type, null)); + assertNull(findField(type.asType(), null)); + } + + @Test + public void testIsEnumField() { + TypeElement type = getType(Color.class); + VariableElement field = findField(type, "RED"); + assertTrue(isEnumMemberField(field)); + + field = findField(type, "YELLOW"); + assertTrue(isEnumMemberField(field)); + + field = findField(type, "BLUE"); + assertTrue(isEnumMemberField(field)); + + type = getType(Model.class); + field = findField(type, "f"); + assertFalse(isEnumMemberField(field)); + + assertFalse(isEnumMemberField(null)); + } + + @Test + public void testIsNonStaticField() { + TypeElement type = getType(Model.class); + assertTrue(isNonStaticField(findField(type, "f"))); + + type = getType(Color.class); + assertFalse(isNonStaticField(findField(type, "BLUE"))); + } + + @Test + public void testIsField() { + TypeElement type = getType(Model.class); + assertTrue(isField(findField(type, "f"))); + assertTrue(isField(findField(type, "f"), PRIVATE)); + + type = getType(Color.class); + assertTrue(isField(findField(type, "BLUE"), PUBLIC, STATIC, FINAL)); + + + assertFalse(isField(null)); + assertFalse(isField(null, PUBLIC, STATIC, FINAL)); + } + + @Test + public void testGetNonStaticFields() { + TypeElement type = getType(Model.class); + + List fields = getNonStaticFields(type); + assertModelFields(fields); + + fields = getNonStaticFields(type.asType()); + assertModelFields(fields); + + assertTrue(getAllNonStaticFields((Element) null).isEmpty()); + assertTrue(getAllNonStaticFields((TypeMirror) null).isEmpty()); + } + + @Test + public void testGetAllNonStaticFields() { + TypeElement type = getType(Model.class); + + List fields = getAllNonStaticFields(type); + assertModelAllFields(fields); + + fields = getAllNonStaticFields(type.asType()); + assertModelAllFields(fields); + + assertTrue(getAllNonStaticFields((Element) null).isEmpty()); + assertTrue(getAllNonStaticFields((TypeMirror) null).isEmpty()); + } + + private void assertModelFields(List fields) { + assertEquals(6, fields.size()); + assertEquals("d", fields.get(1).getSimpleName().toString()); + assertEquals("tu", fields.get(2).getSimpleName().toString()); + assertEquals("str", fields.get(3).getSimpleName().toString()); + assertEquals("bi", fields.get(4).getSimpleName().toString()); + assertEquals("bd", fields.get(5).getSimpleName().toString()); + } + + private void assertModelAllFields(List fields) { + assertEquals(11, fields.size()); + assertEquals("f", fields.get(0).getSimpleName().toString()); + assertEquals("d", fields.get(1).getSimpleName().toString()); + assertEquals("tu", fields.get(2).getSimpleName().toString()); + assertEquals("str", fields.get(3).getSimpleName().toString()); + assertEquals("bi", fields.get(4).getSimpleName().toString()); + assertEquals("bd", fields.get(5).getSimpleName().toString()); + assertEquals("b", fields.get(6).getSimpleName().toString()); + assertEquals("s", fields.get(7).getSimpleName().toString()); + assertEquals("i", fields.get(8).getSimpleName().toString()); + assertEquals("l", fields.get(9).getSimpleName().toString()); + assertEquals("z", fields.get(10).getSimpleName().toString()); + } + + private void testGetDeclaredField(TypeElement type, String fieldName, Type fieldType) { + VariableElement field = getDeclaredField(type, fieldName); + assertField(field, fieldName, fieldType); + } + + private void testFindField(TypeElement type, String fieldName, Type fieldType) { + VariableElement field = findField(type, fieldName); + assertField(field, fieldName, fieldType); + } + + private void assertField(VariableElement field, String fieldName, Type fieldType) { + assertEquals(fieldName, field.getSimpleName().toString()); + assertEquals(fieldType.getTypeName(), field.asType().toString()); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/LoggerUtilsTest.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/LoggerUtilsTest.java new file mode 100644 index 00000000000..a48b75966f9 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/LoggerUtilsTest.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.util; + +import org.junit.jupiter.api.Test; + +import static org.apache.dubbo.metadata.annotation.processing.util.LoggerUtils.info; +import static org.apache.dubbo.metadata.annotation.processing.util.LoggerUtils.warn; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +/** + * {@link LoggerUtils} Test + * + * @since 2.7.5 + */ +public class LoggerUtilsTest { + + @Test + public void testLogger() { + assertNotNull(LoggerUtils.LOGGER); + } + + @Test + public void testInfo() { + info("Hello,World"); + info("Hello,%s", "World"); + info("%s,%s", "Hello", "World"); + } + + @Test + public void testWarn() { + warn("Hello,World"); + warn("Hello,%s", "World"); + warn("%s,%s", "Hello", "World"); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/MemberUtilsTest.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/MemberUtilsTest.java new file mode 100644 index 00000000000..3d3be6bfd25 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/MemberUtilsTest.java @@ -0,0 +1,113 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.util; + +import org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest; +import org.apache.dubbo.metadata.annotation.processing.model.Model; +import org.apache.dubbo.metadata.tools.TestServiceImpl; + +import org.junit.jupiter.api.Test; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import java.util.List; +import java.util.Set; + +import static javax.lang.model.element.Modifier.PRIVATE; +import static javax.lang.model.util.ElementFilter.fieldsIn; +import static javax.lang.model.util.ElementFilter.methodsIn; +import static org.apache.dubbo.metadata.annotation.processing.util.MemberUtils.getAllDeclaredMembers; +import static org.apache.dubbo.metadata.annotation.processing.util.MemberUtils.getDeclaredMembers; +import static org.apache.dubbo.metadata.annotation.processing.util.MemberUtils.hasModifiers; +import static org.apache.dubbo.metadata.annotation.processing.util.MemberUtils.isPublicNonStatic; +import static org.apache.dubbo.metadata.annotation.processing.util.MemberUtils.matchParameterTypes; +import static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.findMethod; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link MemberUtils} Test + * + * @since 2.7.5 + */ +public class MemberUtilsTest extends AbstractAnnotationProcessingTest { + + private TypeElement testType; + + @Override + protected void addCompiledClasses(Set> classesToBeCompiled) { + } + + @Override + protected void beforeEach() { + testType = getType(TestServiceImpl.class); + } + + @Test + public void testIsPublicNonStatic() { + assertFalse(isPublicNonStatic(null)); + methodsIn(getDeclaredMembers(testType.asType())).forEach(method -> assertTrue(isPublicNonStatic(method))); + } + + @Test + public void testHasModifiers() { + assertFalse(hasModifiers(null)); + List members = getAllDeclaredMembers(testType.asType()); + List fields = fieldsIn(members); + assertTrue(hasModifiers(fields.get(0), PRIVATE)); + } + + @Test + public void testDeclaredMembers() { + TypeElement type = getType(Model.class); + List members = getDeclaredMembers(type.asType()); + List fields = fieldsIn(members); + assertEquals(19, members.size()); + assertEquals(6, fields.size()); + assertEquals("f", fields.get(0).getSimpleName().toString()); + assertEquals("d", fields.get(1).getSimpleName().toString()); + assertEquals("tu", fields.get(2).getSimpleName().toString()); + assertEquals("str", fields.get(3).getSimpleName().toString()); + assertEquals("bi", fields.get(4).getSimpleName().toString()); + assertEquals("bd", fields.get(5).getSimpleName().toString()); + + members = getAllDeclaredMembers(type.asType()); + fields = fieldsIn(members); + assertEquals(11, fields.size()); + assertEquals("f", fields.get(0).getSimpleName().toString()); + assertEquals("d", fields.get(1).getSimpleName().toString()); + assertEquals("tu", fields.get(2).getSimpleName().toString()); + assertEquals("str", fields.get(3).getSimpleName().toString()); + assertEquals("bi", fields.get(4).getSimpleName().toString()); + assertEquals("bd", fields.get(5).getSimpleName().toString()); + assertEquals("b", fields.get(6).getSimpleName().toString()); + assertEquals("s", fields.get(7).getSimpleName().toString()); + assertEquals("i", fields.get(8).getSimpleName().toString()); + assertEquals("l", fields.get(9).getSimpleName().toString()); + assertEquals("z", fields.get(10).getSimpleName().toString()); + } + + @Test + public void testMatchParameterTypes() { + ExecutableElement method = findMethod(testType, "echo", "java.lang.String"); + assertTrue(matchParameterTypes(method.getParameters(), "java.lang.String")); + assertFalse(matchParameterTypes(method.getParameters(), "java.lang.Object")); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/MethodUtilsTest.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/MethodUtilsTest.java new file mode 100644 index 00000000000..b2f9162f8f5 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/MethodUtilsTest.java @@ -0,0 +1,195 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.util; + +import org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest; +import org.apache.dubbo.metadata.annotation.processing.model.Model; +import org.apache.dubbo.metadata.tools.TestService; +import org.apache.dubbo.metadata.tools.TestServiceImpl; + +import org.junit.jupiter.api.Test; + +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.TypeMirror; +import java.util.List; +import java.util.Set; + +import static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.findMethod; +import static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.getAllDeclaredMethods; +import static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.getDeclaredMethods; +import static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.getMethodName; +import static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.getMethodParameterTypes; +import static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.getOverrideMethod; +import static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.getPublicNonStaticMethods; +import static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.getReturnType; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link MethodUtils} Test + * + * @since 2.7.5 + */ +public class MethodUtilsTest extends AbstractAnnotationProcessingTest { + + private TypeElement testType; + + @Override + protected void addCompiledClasses(Set> classesToBeCompiled) { + } + + @Override + protected void beforeEach() { + testType = getType(TestServiceImpl.class); + } + + @Test + public void testDeclaredMethods() { + TypeElement type = getType(Model.class); + List methods = getDeclaredMethods(type); + assertEquals(12, methods.size()); + + methods = getAllDeclaredMethods(type); + assertEquals(34, methods.size()); + + assertTrue(getAllDeclaredMethods((TypeElement) null).isEmpty()); + assertTrue(getAllDeclaredMethods((TypeMirror) null).isEmpty()); + } + + private List doGetAllDeclaredMethods() { + return getAllDeclaredMethods(testType, Object.class); + } + + @Test + public void testGetAllDeclaredMethods() { + List methods = doGetAllDeclaredMethods(); + assertEquals(14, methods.size()); + } + + @Test + public void testGetPublicNonStaticMethods() { + List methods = getPublicNonStaticMethods(testType, Object.class); + assertEquals(14, methods.size()); + + methods = getPublicNonStaticMethods(testType.asType(), Object.class); + assertEquals(14, methods.size()); + } + + @Test + public void testIsMethod() { + List methods = getPublicNonStaticMethods(testType, Object.class); + assertEquals(14, methods.stream().map(MethodUtils::isMethod).count()); + } + + @Test + public void testIsPublicNonStaticMethod() { + List methods = getPublicNonStaticMethods(testType, Object.class); + assertEquals(14, methods.stream().map(MethodUtils::isPublicNonStaticMethod).count()); + } + + @Test + public void testFindMethod() { + TypeElement type = getType(Model.class); + // Test methods from java.lang.Object + // Object#toString() + String methodName = "toString"; + ExecutableElement method = findMethod(type.asType(), methodName); + assertEquals(method.getSimpleName().toString(), methodName); + + // Object#hashCode() + methodName = "hashCode"; + method = findMethod(type.asType(), methodName); + assertEquals(method.getSimpleName().toString(), methodName); + + // Object#getClass() + methodName = "getClass"; + method = findMethod(type.asType(), methodName); + assertEquals(method.getSimpleName().toString(), methodName); + + // Object#finalize() + methodName = "finalize"; + method = findMethod(type.asType(), methodName); + assertEquals(method.getSimpleName().toString(), methodName); + + // Object#clone() + methodName = "clone"; + method = findMethod(type.asType(), methodName); + assertEquals(method.getSimpleName().toString(), methodName); + + // Object#notify() + methodName = "notify"; + method = findMethod(type.asType(), methodName); + assertEquals(method.getSimpleName().toString(), methodName); + + // Object#notifyAll() + methodName = "notifyAll"; + method = findMethod(type.asType(), methodName); + assertEquals(method.getSimpleName().toString(), methodName); + + // Object#wait(long) + methodName = "wait"; + method = findMethod(type.asType(), methodName, long.class); + assertEquals(method.getSimpleName().toString(), methodName); + + // Object#wait(long,int) + methodName = "wait"; + method = findMethod(type.asType(), methodName, long.class, int.class); + assertEquals(method.getSimpleName().toString(), methodName); + + // Object#equals(Object) + methodName = "equals"; + method = findMethod(type.asType(), methodName, Object.class); + assertEquals(method.getSimpleName().toString(), methodName); + } + + @Test + public void testGetOverrideMethod() { + List methods = doGetAllDeclaredMethods(); + + ExecutableElement overrideMethod = getOverrideMethod(processingEnv, testType, methods.get(0)); + assertNull(overrideMethod); + + ExecutableElement declaringMethod = findMethod(getType(TestService.class), "echo", "java.lang.String"); + + overrideMethod = getOverrideMethod(processingEnv, testType, declaringMethod); + assertEquals(methods.get(0), overrideMethod); + } + + @Test + public void testGetMethodName() { + ExecutableElement method = findMethod(testType, "echo", "java.lang.String"); + assertEquals("echo", getMethodName(method)); + assertNull(getMethodName(null)); + } + + @Test + public void testReturnType() { + ExecutableElement method = findMethod(testType, "echo", "java.lang.String"); + assertEquals("java.lang.String", getReturnType(method)); + assertNull(getReturnType(null)); + } + + @Test + public void testMatchParameterTypes() { + ExecutableElement method = findMethod(testType, "echo", "java.lang.String"); + assertArrayEquals(new String[]{"java.lang.String"}, getMethodParameterTypes(method)); + assertTrue(getMethodParameterTypes(null).length == 0); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/ServiceAnnotationUtilsTest.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/ServiceAnnotationUtilsTest.java new file mode 100644 index 00000000000..a575d4ea3a3 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/ServiceAnnotationUtilsTest.java @@ -0,0 +1,136 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.util; + +import org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest; +import org.apache.dubbo.metadata.tools.DefaultTestService; +import org.apache.dubbo.metadata.tools.GenericTestService; +import org.apache.dubbo.metadata.tools.TestService; +import org.apache.dubbo.metadata.tools.TestServiceImpl; + +import org.junit.jupiter.api.Test; + +import javax.lang.model.element.TypeElement; +import java.util.HashSet; +import java.util.Set; + +import static java.util.Arrays.asList; +import static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.GROUP_ATTRIBUTE_NAME; +import static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.INTERFACE_CLASS_ATTRIBUTE_NAME; +import static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.INTERFACE_NAME_ATTRIBUTE_NAME; +import static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.LEGACY_SERVICE_ANNOTATION_TYPE; +import static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.SERVICE_ANNOTATION_TYPE; +import static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.SUPPORTED_ANNOTATION_TYPES; +import static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.VERSION_ATTRIBUTE_NAME; +import static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.getAnnotation; +import static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.getGroup; +import static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.getVersion; +import static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.isServiceAnnotationPresent; +import static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.resolveServiceInterfaceName; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link ServiceAnnotationUtils} Test + * + * @since 2.7.5 + */ +public class ServiceAnnotationUtilsTest extends AbstractAnnotationProcessingTest { + + @Override + protected void addCompiledClasses(Set> classesToBeCompiled) { + + } + + @Override + protected void beforeEach() { + + } + + @Test + public void testConstants() { + assertEquals("org.apache.dubbo.config.annotation.Service", SERVICE_ANNOTATION_TYPE); + assertEquals("com.alibaba.dubbo.config.annotation.Service", LEGACY_SERVICE_ANNOTATION_TYPE); + assertEquals("interfaceClass", INTERFACE_CLASS_ATTRIBUTE_NAME); + assertEquals("interfaceName", INTERFACE_NAME_ATTRIBUTE_NAME); + assertEquals("group", GROUP_ATTRIBUTE_NAME); + assertEquals("version", VERSION_ATTRIBUTE_NAME); + assertEquals(new HashSet(asList("org.apache.dubbo.config.annotation.Service", "com.alibaba.dubbo.config.annotation.Service")), SUPPORTED_ANNOTATION_TYPES); + } + + @Test + public void testIsServiceAnnotationPresent() { + + assertTrue(isServiceAnnotationPresent(getType(TestServiceImpl.class))); + assertTrue(isServiceAnnotationPresent(getType(GenericTestService.class))); + assertTrue(isServiceAnnotationPresent(getType(DefaultTestService.class))); + + assertFalse(isServiceAnnotationPresent(getType(TestService.class))); + } + + @Test + public void testGetAnnotation() { + TypeElement type = getType(TestServiceImpl.class); + assertEquals("org.apache.dubbo.config.annotation.Service", getAnnotation(type).getAnnotationType().toString()); + + type = getType(GenericTestService.class); + assertEquals("com.alibaba.dubbo.config.annotation.Service", getAnnotation(type).getAnnotationType().toString()); + + type = getType(DefaultTestService.class); + assertEquals("org.apache.dubbo.config.annotation.Service", getAnnotation(type).getAnnotationType().toString()); + + assertThrows(IllegalArgumentException.class, () -> getAnnotation(getType(TestService.class))); + } + + @Test + public void testResolveServiceInterfaceName() { + TypeElement type = getType(TestServiceImpl.class); + assertEquals("org.apache.dubbo.metadata.tools.TestService", resolveServiceInterfaceName(type, getAnnotation(type))); + + type = getType(GenericTestService.class); + assertEquals("org.apache.dubbo.metadata.tools.TestService", resolveServiceInterfaceName(type, getAnnotation(type))); + + type = getType(DefaultTestService.class); + assertEquals("org.apache.dubbo.metadata.tools.TestService", resolveServiceInterfaceName(type, getAnnotation(type))); + } + + @Test + public void testGetVersion() { + TypeElement type = getType(TestServiceImpl.class); + assertEquals("3.0.0", getVersion(getAnnotation(type))); + + type = getType(GenericTestService.class); + assertEquals("2.0.0", getVersion(getAnnotation(type))); + + type = getType(DefaultTestService.class); + assertEquals("1.0.0", getVersion(getAnnotation(type))); + } + + @Test + public void testGetGroup() { + TypeElement type = getType(TestServiceImpl.class); + assertEquals("test",getGroup(getAnnotation(type))); + + type = getType(GenericTestService.class); + assertEquals("generic", getGroup(getAnnotation(type))); + + type = getType(DefaultTestService.class); + assertEquals("default", getGroup(getAnnotation(type))); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/TypeUtilsTest.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/TypeUtilsTest.java new file mode 100644 index 00000000000..b3d5050aa2f --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/TypeUtilsTest.java @@ -0,0 +1,467 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.annotation.processing.util; + +import org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest; +import org.apache.dubbo.metadata.annotation.processing.model.ArrayTypeModel; +import org.apache.dubbo.metadata.annotation.processing.model.Color; +import org.apache.dubbo.metadata.annotation.processing.model.Model; +import org.apache.dubbo.metadata.annotation.processing.model.PrimitiveTypeModel; +import org.apache.dubbo.metadata.tools.DefaultTestService; +import org.apache.dubbo.metadata.tools.GenericTestService; +import org.apache.dubbo.metadata.tools.TestServiceImpl; + +import org.junit.jupiter.api.Test; + +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; +import java.io.File; +import java.lang.reflect.Type; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.Date; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import static java.util.Arrays.asList; +import static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.findField; +import static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.getDeclaredFields; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.getAllInterfaces; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.getAllSuperTypes; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.getHierarchicalTypes; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.getInterfaces; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.getResource; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.getResourceName; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.getSuperType; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isAnnotationType; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isArrayType; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isClassType; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isDeclaredType; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isEnumType; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isInterfaceType; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isPrimitiveType; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isSameType; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isSimpleType; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isTypeElement; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.listDeclaredTypes; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.listTypeElements; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.ofDeclaredType; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.ofDeclaredTypes; +import static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.ofTypeElement; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * The {@link TypeUtils} Test + * + * @since 2.7.5 + */ +public class TypeUtilsTest extends AbstractAnnotationProcessingTest { + + private TypeElement testType; + + @Override + protected void addCompiledClasses(Set> classesToBeCompiled) { + classesToBeCompiled.add(ArrayTypeModel.class); + classesToBeCompiled.add(Color.class); + } + + @Override + protected void beforeEach() { + testType = getType(TestServiceImpl.class); + } + + @Test + public void testIsSimpleType() { + + assertTrue(isSimpleType(getType(Void.class))); + assertTrue(isSimpleType(getType(Boolean.class))); + assertTrue(isSimpleType(getType(Character.class))); + assertTrue(isSimpleType(getType(Byte.class))); + assertTrue(isSimpleType(getType(Short.class))); + assertTrue(isSimpleType(getType(Integer.class))); + assertTrue(isSimpleType(getType(Long.class))); + assertTrue(isSimpleType(getType(Float.class))); + assertTrue(isSimpleType(getType(Double.class))); + assertTrue(isSimpleType(getType(String.class))); + assertTrue(isSimpleType(getType(BigDecimal.class))); + assertTrue(isSimpleType(getType(BigInteger.class))); + assertTrue(isSimpleType(getType(Date.class))); + + assertFalse(isSimpleType(getType(getClass()))); + assertFalse(isSimpleType((TypeElement) null)); + assertFalse(isSimpleType((TypeMirror) null)); + } + + @Test + public void testIsSameType() { + assertTrue(isSameType(getType(Void.class).asType(), "java.lang.Void")); + assertFalse(isSameType(getType(String.class).asType(), "java.lang.Void")); + + assertFalse(isSameType(getType(Void.class).asType(), (Type) null)); + assertFalse(isSameType(null, (Type) null)); + + assertFalse(isSameType(getType(Void.class).asType(), (String) null)); + assertFalse(isSameType(null, (String) null)); + } + + @Test + public void testIsArrayType() { + TypeElement type = getType(ArrayTypeModel.class); + assertTrue(isArrayType(findField(type.asType(), "integers").asType())); + assertTrue(isArrayType(findField(type.asType(), "strings").asType())); + assertTrue(isArrayType(findField(type.asType(), "primitiveTypeModels").asType())); + assertTrue(isArrayType(findField(type.asType(), "models").asType())); + assertTrue(isArrayType(findField(type.asType(), "colors").asType())); + + assertFalse(isArrayType((Element) null)); + assertFalse(isArrayType((TypeMirror) null)); + } + + @Test + public void testIsEnumType() { + TypeElement type = getType(Color.class); + assertTrue(isEnumType(type.asType())); + + type = getType(ArrayTypeModel.class); + assertFalse(isEnumType(type.asType())); + + assertFalse(isEnumType((Element) null)); + assertFalse(isEnumType((TypeMirror) null)); + } + + @Test + public void testIsClassType() { + TypeElement type = getType(ArrayTypeModel.class); + assertTrue(isClassType(type.asType())); + + type = getType(Model.class); + assertTrue(isClassType(type.asType())); + + assertFalse(isClassType((Element) null)); + assertFalse(isClassType((TypeMirror) null)); + } + + @Test + public void testIsPrimitiveType() { + TypeElement type = getType(PrimitiveTypeModel.class); + getDeclaredFields(type.asType()) + .stream() + .map(VariableElement::asType) + .forEach(t -> assertTrue(isPrimitiveType(t))); + + assertFalse(isPrimitiveType(getType(ArrayTypeModel.class))); + + assertFalse(isPrimitiveType((Element) null)); + assertFalse(isPrimitiveType((TypeMirror) null)); + } + + @Test + public void testIsInterfaceType() { + TypeElement type = getType(CharSequence.class); + assertTrue(isInterfaceType(type)); + assertTrue(isInterfaceType(type.asType())); + + type = getType(Model.class); + assertFalse(isInterfaceType(type)); + assertFalse(isInterfaceType(type.asType())); + + assertFalse(isInterfaceType((Element) null)); + assertFalse(isInterfaceType((TypeMirror) null)); + } + + @Test + public void testIsAnnotationType() { + TypeElement type = getType(Override.class); + + assertTrue(isAnnotationType(type)); + assertTrue(isAnnotationType(type.asType())); + + type = getType(Model.class); + assertFalse(isAnnotationType(type)); + assertFalse(isAnnotationType(type.asType())); + + assertFalse(isAnnotationType((Element) null)); + assertFalse(isAnnotationType((TypeMirror) null)); + } + + @Test + public void testGetHierarchicalTypes() { + Set hierarchicalTypes = getHierarchicalTypes(testType.asType(), true, true, true); + Iterator iterator = hierarchicalTypes.iterator(); + assertEquals(8, hierarchicalTypes.size()); + assertEquals("org.apache.dubbo.metadata.tools.TestServiceImpl", iterator.next().toString()); + assertEquals("org.apache.dubbo.metadata.tools.GenericTestService", iterator.next().toString()); + assertEquals("org.apache.dubbo.metadata.tools.DefaultTestService", iterator.next().toString()); + assertEquals("java.lang.Object", iterator.next().toString()); + assertEquals("org.apache.dubbo.metadata.tools.TestService", iterator.next().toString()); + assertEquals("java.lang.AutoCloseable", iterator.next().toString()); + assertEquals("java.io.Serializable", iterator.next().toString()); + assertEquals("java.util.EventListener", iterator.next().toString()); + + hierarchicalTypes = getHierarchicalTypes(testType); + iterator = hierarchicalTypes.iterator(); + assertEquals(8, hierarchicalTypes.size()); + assertEquals("org.apache.dubbo.metadata.tools.TestServiceImpl", iterator.next().toString()); + assertEquals("org.apache.dubbo.metadata.tools.GenericTestService", iterator.next().toString()); + assertEquals("org.apache.dubbo.metadata.tools.DefaultTestService", iterator.next().toString()); + assertEquals("java.lang.Object", iterator.next().toString()); + assertEquals("org.apache.dubbo.metadata.tools.TestService", iterator.next().toString()); + assertEquals("java.lang.AutoCloseable", iterator.next().toString()); + assertEquals("java.io.Serializable", iterator.next().toString()); + assertEquals("java.util.EventListener", iterator.next().toString()); + + hierarchicalTypes = getHierarchicalTypes(testType.asType(), Object.class); + iterator = hierarchicalTypes.iterator(); + assertEquals(7, hierarchicalTypes.size()); + assertEquals("org.apache.dubbo.metadata.tools.TestServiceImpl", iterator.next().toString()); + assertEquals("org.apache.dubbo.metadata.tools.GenericTestService", iterator.next().toString()); + assertEquals("org.apache.dubbo.metadata.tools.DefaultTestService", iterator.next().toString()); + assertEquals("org.apache.dubbo.metadata.tools.TestService", iterator.next().toString()); + assertEquals("java.lang.AutoCloseable", iterator.next().toString()); + assertEquals("java.io.Serializable", iterator.next().toString()); + assertEquals("java.util.EventListener", iterator.next().toString()); + + hierarchicalTypes = getHierarchicalTypes(testType.asType(), true, true, false); + iterator = hierarchicalTypes.iterator(); + assertEquals(4, hierarchicalTypes.size()); + assertEquals("org.apache.dubbo.metadata.tools.TestServiceImpl", iterator.next().toString()); + assertEquals("org.apache.dubbo.metadata.tools.GenericTestService", iterator.next().toString()); + assertEquals("org.apache.dubbo.metadata.tools.DefaultTestService", iterator.next().toString()); + assertEquals("java.lang.Object", iterator.next().toString()); + + hierarchicalTypes = getHierarchicalTypes(testType.asType(), true, false, true); + iterator = hierarchicalTypes.iterator(); + assertEquals(5, hierarchicalTypes.size()); + assertEquals("org.apache.dubbo.metadata.tools.TestServiceImpl", iterator.next().toString()); + assertEquals("org.apache.dubbo.metadata.tools.TestService", iterator.next().toString()); + assertEquals("java.lang.AutoCloseable", iterator.next().toString()); + assertEquals("java.io.Serializable", iterator.next().toString()); + assertEquals("java.util.EventListener", iterator.next().toString()); + + hierarchicalTypes = getHierarchicalTypes(testType.asType(), false, false, true); + iterator = hierarchicalTypes.iterator(); + assertEquals(4, hierarchicalTypes.size()); + assertEquals("org.apache.dubbo.metadata.tools.TestService", iterator.next().toString()); + assertEquals("java.lang.AutoCloseable", iterator.next().toString()); + assertEquals("java.io.Serializable", iterator.next().toString()); + assertEquals("java.util.EventListener", iterator.next().toString()); + + hierarchicalTypes = getHierarchicalTypes(testType.asType(), true, false, false); + iterator = hierarchicalTypes.iterator(); + assertEquals(1, hierarchicalTypes.size()); + assertEquals("org.apache.dubbo.metadata.tools.TestServiceImpl", iterator.next().toString()); + + hierarchicalTypes = getHierarchicalTypes(testType.asType(), false, false, false); + assertEquals(0, hierarchicalTypes.size()); + + assertTrue(getHierarchicalTypes((TypeElement) null).isEmpty()); + assertTrue(getHierarchicalTypes((TypeMirror) null).isEmpty()); + } + + + @Test + public void testGetInterfaces() { + TypeElement type = getType(Model.class); + List interfaces = getInterfaces(type); + assertTrue(interfaces.isEmpty()); + + interfaces = getInterfaces(testType.asType()); + + assertEquals(3, interfaces.size()); + assertEquals("org.apache.dubbo.metadata.tools.TestService", interfaces.get(0).toString()); + assertEquals("java.lang.AutoCloseable", interfaces.get(1).toString()); + assertEquals("java.io.Serializable", interfaces.get(2).toString()); + + assertTrue(getInterfaces((TypeElement) null).isEmpty()); + assertTrue(getInterfaces((TypeMirror) null).isEmpty()); + } + + @Test + public void testGetAllInterfaces() { + Set interfaces = getAllInterfaces(testType.asType()); + assertEquals(4, interfaces.size()); + Iterator iterator = interfaces.iterator(); + assertEquals("org.apache.dubbo.metadata.tools.TestService", iterator.next().toString()); + assertEquals("java.lang.AutoCloseable", iterator.next().toString()); + assertEquals("java.io.Serializable", iterator.next().toString()); + assertEquals("java.util.EventListener", iterator.next().toString()); + + Set allInterfaces = getAllInterfaces(testType); + assertEquals(4, interfaces.size()); + + Iterator allIterator = allInterfaces.iterator(); + assertEquals("org.apache.dubbo.metadata.tools.TestService", allIterator.next().toString()); + assertEquals("java.lang.AutoCloseable", allIterator.next().toString()); + assertEquals("java.io.Serializable", allIterator.next().toString()); + assertEquals("java.util.EventListener", allIterator.next().toString()); + + assertTrue(getAllInterfaces((TypeElement) null).isEmpty()); + assertTrue(getAllInterfaces((TypeMirror) null).isEmpty()); + } + + @Test + public void testGetType() { + TypeElement element = TypeUtils.getType(processingEnv, String.class); + assertEquals(element, TypeUtils.getType(processingEnv, element.asType())); + assertEquals(element, TypeUtils.getType(processingEnv, "java.lang.String")); + + assertNull(TypeUtils.getType(processingEnv, (Type) null)); + assertNull(TypeUtils.getType(processingEnv, (TypeMirror) null)); + assertNull(TypeUtils.getType(processingEnv, (CharSequence) null)); + assertNull(TypeUtils.getType(null, (CharSequence) null)); + } + + @Test + public void testGetSuperType() { + TypeElement gtsTypeElement = getSuperType(testType); + assertEquals(gtsTypeElement, getType(GenericTestService.class)); + TypeElement dtsTypeElement = getSuperType(gtsTypeElement); + assertEquals(dtsTypeElement, getType(DefaultTestService.class)); + + TypeMirror gtsType = getSuperType(testType.asType()); + assertEquals(gtsType, getType(GenericTestService.class).asType()); + TypeMirror dtsType = getSuperType(gtsType); + assertEquals(dtsType, getType(DefaultTestService.class).asType()); + + assertNull(getSuperType((TypeElement) null)); + assertNull(getSuperType((TypeMirror) null)); + } + + @Test + public void testGetAllSuperTypes() { + Set allSuperTypes = getAllSuperTypes(testType); + Iterator iterator = allSuperTypes.iterator(); + assertEquals(3, allSuperTypes.size()); + assertEquals(iterator.next(), getType(GenericTestService.class)); + assertEquals(iterator.next(), getType(DefaultTestService.class)); + assertEquals(iterator.next(), getType(Object.class)); + + allSuperTypes = getAllSuperTypes(testType); + iterator = allSuperTypes.iterator(); + assertEquals(3, allSuperTypes.size()); + assertEquals(iterator.next(), getType(GenericTestService.class)); + assertEquals(iterator.next(), getType(DefaultTestService.class)); + assertEquals(iterator.next(), getType(Object.class)); + + assertTrue(getAllSuperTypes((TypeElement) null).isEmpty()); + assertTrue(getAllSuperTypes((TypeMirror) null).isEmpty()); + } + + @Test + public void testIsDeclaredType() { + assertTrue(isDeclaredType(testType)); + assertTrue(isDeclaredType(testType.asType())); + assertFalse(isDeclaredType((Element) null)); + assertFalse(isDeclaredType((TypeMirror) null)); + assertFalse(isDeclaredType(types.getNullType())); + assertFalse(isDeclaredType(types.getPrimitiveType(TypeKind.BYTE))); + assertFalse(isDeclaredType(types.getArrayType(types.getPrimitiveType(TypeKind.BYTE)))); + } + + @Test + public void testOfDeclaredType() { + assertEquals(testType.asType(), ofDeclaredType(testType)); + assertEquals(testType.asType(), ofDeclaredType(testType.asType())); + assertEquals(ofDeclaredType(testType), ofDeclaredType(testType.asType())); + + assertNull(ofDeclaredType((Element) null)); + assertNull(ofDeclaredType((TypeMirror) null)); + } + + @Test + public void testIsTypeElement() { + assertTrue(isTypeElement(testType)); + assertTrue(isTypeElement(testType.asType())); + + assertFalse(isTypeElement((Element) null)); + assertFalse(isTypeElement((TypeMirror) null)); + } + + @Test + public void testOfTypeElement() { + assertEquals(testType, ofTypeElement(testType)); + assertEquals(testType, ofTypeElement(testType.asType())); + + assertNull(ofTypeElement((Element) null)); + assertNull(ofTypeElement((TypeMirror) null)); + } + + @Test + public void testOfDeclaredTypes() { + Set declaredTypes = ofDeclaredTypes(asList(getType(String.class), getType(TestServiceImpl.class), getType(Color.class))); + assertTrue(declaredTypes.contains(getType(String.class).asType())); + assertTrue(declaredTypes.contains(getType(TestServiceImpl.class).asType())); + assertTrue(declaredTypes.contains(getType(Color.class).asType())); + + assertTrue(ofDeclaredTypes(null).isEmpty()); + } + + @Test + public void testListDeclaredTypes() { + List types = listDeclaredTypes(asList(testType, testType, testType)); + assertEquals(1, types.size()); + assertEquals(ofDeclaredType(testType), types.get(0)); + + types = listDeclaredTypes(asList(new Element[]{null})); + assertTrue(types.isEmpty()); + } + + @Test + public void testListTypeElements() { + List typeElements = listTypeElements(asList(testType.asType(), ofDeclaredType(testType))); + assertEquals(1, typeElements.size()); + assertEquals(testType, typeElements.get(0)); + + typeElements = listTypeElements(asList(types.getPrimitiveType(TypeKind.BYTE), types.getNullType(), types.getNoType(TypeKind.NONE))); + assertTrue(typeElements.isEmpty()); + + typeElements = listTypeElements(asList(new TypeMirror[]{null})); + assertTrue(typeElements.isEmpty()); + + typeElements = listTypeElements(null); + assertTrue(typeElements.isEmpty()); + } + + @Test + public void testGetResource() throws URISyntaxException { + URL resource = getResource(processingEnv, testType); + assertNotNull(resource); + assertTrue(new File(resource.toURI()).exists()); + assertEquals(resource, getResource(processingEnv, testType.asType())); + assertEquals(resource, getResource(processingEnv, "org.apache.dubbo.metadata.tools.TestServiceImpl")); + + assertThrows(RuntimeException.class, () -> getResource(processingEnv, "NotFound")); + } + + @Test + public void testGetResourceName() { + assertEquals("java/lang/String.class", getResourceName("java.lang.String")); + assertNull(getResourceName(null)); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/Ancestor.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/Ancestor.java new file mode 100644 index 00000000000..52ccaf6ab3e --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/Ancestor.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.tools; + +import java.io.Serializable; + +/** + * Ancestor + */ +public class Ancestor implements Serializable { + + private boolean z; + + public boolean isZ() { + return z; + } + + public void setZ(boolean z) { + this.z = z; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/Compiler.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/Compiler.java new file mode 100644 index 00000000000..a4ee1af30a2 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/Compiler.java @@ -0,0 +1,116 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.tools; + +import javax.annotation.processing.Processor; +import javax.tools.JavaCompiler; +import javax.tools.JavaFileObject; +import javax.tools.StandardJavaFileManager; +import javax.tools.StandardLocation; +import javax.tools.ToolProvider; +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.Set; + +import static java.util.Arrays.asList; + +/** + * The Java Compiler + */ +public class Compiler { + + private final File sourceDirectory; + + private final JavaCompiler javaCompiler; + + private final StandardJavaFileManager javaFileManager; + + private final Set processors = new LinkedHashSet<>(); + + public Compiler() throws IOException { + this(defaultTargetDirectory()); + } + + public Compiler(File targetDirectory) throws IOException { + this(defaultSourceDirectory(), targetDirectory); + } + + public Compiler(File sourceDirectory, File targetDirectory) throws IOException { + this.sourceDirectory = sourceDirectory; + this.javaCompiler = ToolProvider.getSystemJavaCompiler(); + this.javaFileManager = javaCompiler.getStandardFileManager(null, null, null); + this.javaFileManager.setLocation(StandardLocation.CLASS_OUTPUT, Collections.singleton(targetDirectory)); + this.javaFileManager.setLocation(StandardLocation.SOURCE_OUTPUT, Collections.singleton(targetDirectory)); + } + + private static File defaultSourceDirectory() { + return new File(defaultRootDirectory(), "src/test/java"); + } + + private static File defaultRootDirectory() { + return detectClassPath(Compiler.class).getParentFile().getParentFile(); + } + + private static File defaultTargetDirectory() { + File dir = new File(defaultRootDirectory(), "target/generated-classes"); + dir.mkdirs(); + return dir; + } + + private static File detectClassPath(Class targetClass) { + URL classFileURL = targetClass.getProtectionDomain().getCodeSource().getLocation(); + if ("file".equals(classFileURL.getProtocol())) { + return new File(classFileURL.getPath()); + } else { + throw new RuntimeException("No support"); + } + } + + public Compiler processors(Processor... processors) { + this.processors.addAll(asList(processors)); + return this; + } + + private Iterable getJavaFileObjects(Class... sourceClasses) { + int size = sourceClasses == null ? 0 : sourceClasses.length; + File[] javaSourceFiles = new File[size]; + for (int i = 0; i < size; i++) { + File javaSourceFile = javaSourceFile(sourceClasses[i].getName()); + javaSourceFiles[i] = javaSourceFile; + } + return javaFileManager.getJavaFileObjects(javaSourceFiles); + } + + private File javaSourceFile(String sourceClassName) { + String javaSourceFilePath = sourceClassName.replace('.', '/').concat(".java"); + return new File(sourceDirectory, javaSourceFilePath); + } + + public boolean compile(Class... sourceClasses) { + JavaCompiler.CompilationTask task = javaCompiler.getTask(null, this.javaFileManager, null, + asList("-parameters"), +// null, + null, getJavaFileObjects(sourceClasses)); + if (!processors.isEmpty()) { + task.setProcessors(processors); + } + return task.call(); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/CompilerTest.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/CompilerTest.java new file mode 100644 index 00000000000..e633e0fba81 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/CompilerTest.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.tools; + +import org.junit.jupiter.api.Test; + +import java.io.IOException; + +/** + * The Compiler test case + */ +public class CompilerTest { + + @Test + public void testCompile() throws IOException { + Compiler compiler = new Compiler(); + compiler.compile( + TestServiceImpl.class, + DefaultTestService.class, + GenericTestService.class); + } +} + diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/DefaultTestService.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/DefaultTestService.java new file mode 100644 index 00000000000..5ac82570dad --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/DefaultTestService.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.tools; + + +import org.apache.dubbo.config.annotation.Service; +import org.apache.dubbo.metadata.annotation.processing.model.Model; + +import java.util.concurrent.TimeUnit; + +/** + * {@link TestService} Implementation + * + * @since 2.7.5 + */ +@Service( + interfaceName = "org.apache.dubbo.metadata.tools.TestService", + version = "1.0.0", + group = "default" +) +public class DefaultTestService implements TestService { + + private String name; + + @Override + public String echo(String message) { + return "[ECHO] " + message; + } + + @Override + public Model model(Model model) { + return model; + } + + @Override + public String testPrimitive(boolean z, int i) { + return null; + } + + @Override + public Model testEnum(TimeUnit timeUnit) { + return null; + } + + @Override + public String testArray(String[] strArray, int[] intArray, Model[] modelArray) { + return null; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/GenericTestService.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/GenericTestService.java new file mode 100644 index 00000000000..c60953b9dd4 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/GenericTestService.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.tools; + + +import com.alibaba.dubbo.config.annotation.Service; + +import java.util.EventListener; + +/** + * {@link TestService} Implementation + * + * @since 2.7.5 + */ +@Service( + version = "2.0.0", + group = "generic" +) +public class GenericTestService extends DefaultTestService implements TestService, EventListener { + @Override + public String echo(String message) { + return "[ECHO] " + message; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/Parent.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/Parent.java new file mode 100644 index 00000000000..4273a0fb701 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/Parent.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.tools; + +/** + * Parent + */ +public class Parent extends Ancestor { + + private byte b; + + private short s; + + private int i; + + private long l; + + public byte getB() { + return b; + } + + public void setB(byte b) { + this.b = b; + } + + public short getS() { + return s; + } + + public void setS(short s) { + this.s = s; + } + + public int getI() { + return i; + } + + public void setI(int i) { + this.i = i; + } + + public long getL() { + return l; + } + + public void setL(long l) { + this.l = l; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/RestService.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/RestService.java new file mode 100644 index 00000000000..8db18d74d5b --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/RestService.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.tools; + + +import java.util.Map; + +/** + * An interface for REST service + * + * @since 2.7.5 + */ +public interface RestService { + + String param(String param); + + String params(int a, String b); + + String headers(String header, String header2, Integer param); + + String pathVariables(String path1, String path2, String param); + + String form(String form); + + User requestBodyMap(Map data, String param); + + Map requestBodyUser(User user); +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/RestServiceTest.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/RestServiceTest.java new file mode 100644 index 00000000000..3e318d24a8b --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/RestServiceTest.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.tools; + +import org.junit.jupiter.api.Test; + +import java.io.IOException; + +/** + * {@link RestService} Test + * + * @since 2.7.5 + */ +public class RestServiceTest { + + @Test + public void test() throws IOException { + Compiler compiler = new Compiler(); + compiler.compile(User.class, RestService.class, + StandardRestService.class, + SpringRestService.class); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/SpringRestService.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/SpringRestService.java new file mode 100644 index 00000000000..c684cb36209 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/SpringRestService.java @@ -0,0 +1,97 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.tools; + +import org.apache.dubbo.config.annotation.Service; + +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.HashMap; +import java.util.Map; + +/** + * Spring MVC {@link RestService} + * + * @since 2.7.5 + */ +@Service(version = "2.0.0") +@RestController +public class SpringRestService implements RestService { + + @Override + @GetMapping(value = "/param") + public String param(@RequestParam(defaultValue = "value-param") String param) { + return param; + } + + @Override + @PostMapping("/params") + public String params(@RequestParam(defaultValue = "value-a") int a, @RequestParam(defaultValue = "value-b") String b) { + return a + b; + } + + @Override + @GetMapping("/headers") + public String headers(@RequestHeader(name = "h", defaultValue = "value-h") String header, + @RequestHeader(name = "h2", defaultValue = "value-h2") String header2, + @RequestParam(value = "v", defaultValue = "1") Integer param) { + String result = header + " , " + header2 + " , " + param; + return result; + } + + @Override + @GetMapping("/path-variables/{p1}/{p2}") + public String pathVariables(@PathVariable("p1") String path1, + @PathVariable("p2") String path2, @RequestParam("v") String param) { + String result = path1 + " , " + path2 + " , " + param; + return result; + } + + @Override + @PostMapping("/form") + public String form(@RequestParam("f") String form) { + return String.valueOf(form); + } + + @Override + @PostMapping(value = "/request/body/map", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + public User requestBodyMap(@RequestBody Map data, + @RequestParam("param") String param) { + User user = new User(); + user.setId(((Integer) data.get("id")).longValue()); + user.setName((String) data.get("name")); + user.setAge((Integer) data.get("age")); + return user; + } + + @PostMapping(value = "/request/body/user", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE) + @Override + public Map requestBodyUser(@RequestBody User user) { + Map map = new HashMap<>(); + map.put("id", user.getId()); + map.put("name", user.getName()); + map.put("age", user.getAge()); + return map; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/SpringRestServiceTest.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/SpringRestServiceTest.java new file mode 100644 index 00000000000..d240da1aeca --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/SpringRestServiceTest.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.tools; + +import org.junit.jupiter.api.Test; + +import java.io.IOException; + +/** + * {@link SpringRestService} Test + * + * @since 2.7.5 + */ +public class SpringRestServiceTest { + + @Test + public void test() throws IOException { + Compiler compiler = new Compiler(); + compiler.compile(User.class, RestService.class, SpringRestService.class); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/StandardRestService.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/StandardRestService.java new file mode 100644 index 00000000000..064f28c7b68 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/StandardRestService.java @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.tools; + +import org.apache.dubbo.config.annotation.Service; + +import javax.ws.rs.Consumes; +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import java.util.HashMap; +import java.util.Map; + + +/** + * JAX-RS {@link RestService} + */ +@Service(version = "3.0.0", protocol = {"dubbo", "rest"}) +@Path("/") +public class StandardRestService implements RestService { + + @Override + @Path("param") + @GET + public String param(@QueryParam("param") String param) { + return param; + } + + @Override + @Path("params") + @POST + public String params(@QueryParam("a") int a, @QueryParam("b") String b) { + return a + b; + } + + @Override + @Path("headers") + @GET + public String headers(@HeaderParam("h") String header, + @HeaderParam("h2") String header2, @QueryParam("v") Integer param) { + String result = header + " , " + header2 + " , " + param; + return result; + } + + @Override + @Path("path-variables/{p1}/{p2}") + @GET + public String pathVariables(@PathParam("p1") String path1, + @PathParam("p2") String path2, @QueryParam("v") String param) { + String result = path1 + " , " + path2 + " , " + param; + return result; + } + + // @CookieParam does not support : https://github.com/OpenFeign/feign/issues/913 + // @CookieValue also does not support + + @Override + @Path("form") + @POST + public String form(@FormParam("f") String form) { + return String.valueOf(form); + } + + @Override + @Path("request/body/map") + @POST + @Produces("application/json;charset=UTF-8") + public User requestBodyMap(Map data, + @QueryParam("param") String param) { + User user = new User(); + user.setId(((Integer) data.get("id")).longValue()); + user.setName((String) data.get("name")); + user.setAge((Integer) data.get("age")); + return user; + } + + @Path("request/body/user") + @POST + @Override + @Consumes("application/json;charset=UTF-8") + public Map requestBodyUser(User user) { + Map map = new HashMap<>(); + map.put("id", user.getId()); + map.put("name", user.getName()); + map.put("age", user.getAge()); + return map; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/StandardRestServiceTest.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/StandardRestServiceTest.java new file mode 100644 index 00000000000..8eab99e0d0e --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/StandardRestServiceTest.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.tools; + +import org.junit.jupiter.api.Test; + +import java.io.IOException; + +/** + * The test case for {@link StandardRestService} + * + * @since 2.7.5 + */ +public class StandardRestServiceTest { + + @Test + public void test() throws IOException { + Compiler compiler = new Compiler(); + compiler.compile(User.class, RestService.class, StandardRestService.class); + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/TestProcessor.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/TestProcessor.java new file mode 100644 index 00000000000..58a60042414 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/TestProcessor.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.tools; + +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.ProcessingEnvironment; +import javax.annotation.processing.Processor; +import javax.annotation.processing.RoundEnvironment; +import javax.annotation.processing.SupportedAnnotationTypes; +import javax.annotation.processing.SupportedSourceVersion; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.TypeElement; +import java.util.Set; + +/** + * {@link Processor} for test + * + * @since 2.7.5 + */ +@SupportedAnnotationTypes("*") +@SupportedSourceVersion(SourceVersion.RELEASE_8) +public class TestProcessor extends AbstractProcessor { + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + return false; + } + + public ProcessingEnvironment getProcessingEnvironment() { + return super.processingEnv; + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/TestService.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/TestService.java new file mode 100644 index 00000000000..d397b3f771f --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/TestService.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.tools; + +import org.apache.dubbo.metadata.annotation.processing.model.Model; + +import javax.ws.rs.DefaultValue; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import java.util.concurrent.TimeUnit; + +/** + * Test Service + * + * @since 2.7.5 + */ +@Path("/echo") +public interface TestService { + + @GET + String echo(@PathParam("message") @DefaultValue("mercyblitz") String message); + + @POST + Model model(@PathParam("model") Model model); + + // Test primitive + @PUT + String testPrimitive(boolean z, int i); + + // Test enumeration + @PUT + Model testEnum(TimeUnit timeUnit); + + // Test Array + @GET + String testArray(String[] strArray, int[] intArray, Model[] modelArray); +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/TestServiceImpl.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/TestServiceImpl.java new file mode 100644 index 00000000000..aeb45305373 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/TestServiceImpl.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.tools; + + +import org.apache.dubbo.config.annotation.Service; + +import java.io.Serializable; + +/** + * {@link TestService} Implementation + * + * @since 2.7.5 + */ +@com.alibaba.dubbo.config.annotation.Service( + interfaceName = "org.apache.dubbo.metadata.tools.TestService", + interfaceClass = TestService.class, + version = "3.0.0", + group = "test" +) +@Service( + interfaceName = "org.apache.dubbo.metadata.tools.TestService", + interfaceClass = TestService.class, + version = "3.0.0", + group = "test" +) +public class TestServiceImpl extends GenericTestService implements TestService, AutoCloseable, Serializable { + + @Override + public String echo(String message) { + return "[ECHO] " + message; + } + + @Override + public void close() throws Exception { + } +} diff --git a/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/User.java b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/User.java new file mode 100644 index 00000000000..e79f7c40c88 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/User.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.tools; + +import java.io.Serializable; + +/** + * User Entity + * + * @since 2.7.5 + */ +public class User implements Serializable { + + private Long id; + + private String name; + + private Integer age; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getAge() { + return age; + } + + public void setAge(Integer age) { + this.age = age; + } + + @Override + public String toString() { + return "User{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + '}'; + } +} diff --git a/dubbo-metadata/pom.xml b/dubbo-metadata/pom.xml index fefa36493d8..17ceada829f 100644 --- a/dubbo-metadata/pom.xml +++ b/dubbo-metadata/pom.xml @@ -35,6 +35,7 @@ dubbo-metadata-report-consul dubbo-metadata-report-etcd dubbo-metadata-report-nacos + dubbo-metadata-processor diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistry.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistry.java index 4f8363d63ab..7132c32e142 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistry.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistry.java @@ -21,7 +21,7 @@ import org.apache.dubbo.common.extension.SPI; import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.LoggerFactory; -import org.apache.dubbo.common.utils.DubboServiceLoader; +import org.apache.dubbo.common.utils.PrioritizedServiceLoader; import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.metadata.MetadataService; import org.apache.dubbo.metadata.ServiceNameMapping; @@ -77,7 +77,7 @@ import static org.apache.dubbo.common.function.ThrowableAction.execute; import static org.apache.dubbo.common.utils.CollectionUtils.isEmpty; import static org.apache.dubbo.common.utils.CollectionUtils.isNotEmpty; -import static org.apache.dubbo.common.utils.DubboServiceLoader.loadServices; +import static org.apache.dubbo.common.utils.PrioritizedServiceLoader.loadServices; import static org.apache.dubbo.common.utils.StringUtils.isBlank; import static org.apache.dubbo.metadata.MetadataService.toURLs; import static org.apache.dubbo.registry.client.ServiceDiscoveryFactory.getExtension; @@ -190,10 +190,10 @@ protected ServiceDiscovery createServiceDiscovery(URL registryURL) { /** * Initialize {@link SubscribedURLsSynthesizer} instances that are - * {@link DubboServiceLoader#loadServices(Class, ClassLoader) loaded} by {@link DubboServiceLoader} + * {@link PrioritizedServiceLoader#loadServices(Class, ClassLoader) loaded} by {@link PrioritizedServiceLoader} * * @return non-null {@link List} - * @see DubboServiceLoader#loadServices(Class, ClassLoader) + * @see PrioritizedServiceLoader#loadServices(Class, ClassLoader) */ private List initSubscribedURLsSynthesizers() { return loadServices(SubscribedURLsSynthesizer.class, this.getClass().getClassLoader()); diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/event/listener/CustomizableServiceInstanceListener.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/event/listener/CustomizableServiceInstanceListener.java index 68abcdb52e7..e5d613cddfd 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/event/listener/CustomizableServiceInstanceListener.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/event/listener/CustomizableServiceInstanceListener.java @@ -23,7 +23,7 @@ import java.util.ServiceLoader; -import static org.apache.dubbo.common.utils.DubboServiceLoader.load; +import static org.apache.dubbo.common.utils.PrioritizedServiceLoader.load; /**