DeprecatedMethodInvocationCounter.onDeprecatedMethodCalled("....");
+ *
+ * @param originalMethodDecl the method declaration that will add logger statement
+ * @param apContext annotation processor context
+ * @param classSymbol the enclosing class that will be the logger's name
+ * @return generated expression statement
+ */
+ private JCTree.JCExpressionStatement generateCounterStatement(AnnotationProcessorContext apContext,
+ Symbol.ClassSymbol classSymbol,
+ JCTree.JCMethodDecl originalMethodDecl) {
+
+ JCTree.JCExpression fullStatement = apContext.getTreeMaker().Apply(
+ com.sun.tools.javac.util.List.nil(),
+
+ apContext.getTreeMaker().Select(
+ apContext.getTreeMaker().Ident(apContext.getNames().fromString("DeprecatedMethodInvocationCounter")),
+ apContext.getNames().fromString("onDeprecatedMethodCalled")
+ ),
+
+ com.sun.tools.javac.util.List.of(
+ apContext.getTreeMaker().Literal(getMethodDefinition(classSymbol, originalMethodDecl))
+ )
+ );
+
+ return apContext.getTreeMaker().Exec(fullStatement);
+ }
+
+ private String getMethodDefinition(Symbol.ClassSymbol classSymbol, JCTree.JCMethodDecl originalMethodDecl) {
+ return classSymbol.getQualifiedName() + "."
+ + originalMethodDecl.name.toString() + "(" + originalMethodDecl.params.toString() + ")";
+ }
+}
diff --git a/dubbo-annotation-processor/src/main/java/org/apache/dubbo/annotation/permit/Permit.java b/dubbo-annotation-processor/src/main/java/org/apache/dubbo/annotation/permit/Permit.java
new file mode 100644
index 0000000000..3d5c941764
--- /dev/null
+++ b/dubbo-annotation-processor/src/main/java/org/apache/dubbo/annotation/permit/Permit.java
@@ -0,0 +1,429 @@
+/*
+ * Authored by Project Lombok and licensed by MIT License, which is attached below:
+ *
+ * Copyright (C) 2018-2021 The Project Lombok Authors.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package org.apache.dubbo.annotation.permit;
+
+import org.apache.dubbo.annotation.permit.dummy.Parent;
+
+import sun.misc.Unsafe;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+// sunapi suppresses javac's warning about using Unsafe; 'all' suppresses eclipse's warning about the unspecified 'sunapi' key. Leave them both.
+// Yes, javac's definition of the word 'all' is quite contrary to what the dictionary says it means. 'all' does NOT include 'sunapi' according to javac.
+@SuppressWarnings({"sunapi", "all"})
+public class Permit {
+ private Permit() {
+ }
+
+
+ private static final long ACCESSIBLE_OVERRIDE_FIELD_OFFSET;
+ private static final IllegalAccessException INIT_ERROR;
+ private static final sun.misc.Unsafe UNSAFE = (sun.misc.Unsafe) reflectiveStaticFieldAccess(sun.misc.Unsafe.class, "theUnsafe");
+
+ static {
+ Field f;
+ long g;
+ Throwable ex;
+
+ try {
+ g = getOverrideFieldOffset();
+ ex = null;
+ } catch (Throwable t) {
+ f = null;
+ g = -1L;
+ ex = t;
+ }
+
+ ACCESSIBLE_OVERRIDE_FIELD_OFFSET = g;
+ if (ex == null) INIT_ERROR = null;
+ else if (ex instanceof IllegalAccessException) INIT_ERROR = (IllegalAccessException) ex;
+ else {
+ INIT_ERROR = new IllegalAccessException("Cannot initialize Unsafe-based permit");
+ INIT_ERROR.initCause(ex);
+ }
+ }
+
+ public static T setAccessible(T accessor) {
+ if (INIT_ERROR == null) {
+ UNSAFE.putBoolean(accessor, ACCESSIBLE_OVERRIDE_FIELD_OFFSET, true);
+ } else {
+ accessor.setAccessible(true);
+ }
+
+ return accessor;
+ }
+
+ private static long getOverrideFieldOffset() throws Throwable {
+ Field f = null;
+ Throwable saved = null;
+ try {
+ f = AccessibleObject.class.getDeclaredField("override");
+ } catch (Throwable t) {
+ saved = t;
+ }
+
+ if (f != null) {
+ return UNSAFE.objectFieldOffset(f);
+ }
+ // The below seems very risky, but for all AccessibleObjects in java today it does work, and starting with JDK12, making the field accessible is no longer possible.
+ try {
+ return UNSAFE.objectFieldOffset(Fake.class.getDeclaredField("override"));
+ } catch (Throwable t) {
+ throw saved;
+ }
+ }
+
+ static class Fake {
+ boolean override;
+ Object accessCheckCache;
+ }
+
+ public static Method getMethod(Class> c, String mName, Class>... parameterTypes) throws NoSuchMethodException {
+ Method m = null;
+ Class> oc = c;
+ while (c != null) {
+ try {
+ m = c.getDeclaredMethod(mName, parameterTypes);
+ break;
+ } catch (NoSuchMethodException e) {
+ }
+ c = c.getSuperclass();
+ }
+
+ if (m == null) throw new NoSuchMethodException(oc.getName() + " :: " + mName + "(args)");
+ return setAccessible(m);
+ }
+
+ public static Method permissiveGetMethod(Class> c, String mName, Class>... parameterTypes) {
+ try {
+ return getMethod(c, mName, parameterTypes);
+ } catch (Exception ignore) {
+ return null;
+ }
+ }
+
+ public static Field getField(Class> c, String fName) throws NoSuchFieldException {
+ Field f = null;
+ Class> oc = c;
+ while (c != null) {
+ try {
+ f = c.getDeclaredField(fName);
+ break;
+ } catch (NoSuchFieldException e) {
+ }
+ c = c.getSuperclass();
+ }
+
+ if (f == null) throw new NoSuchFieldException(oc.getName() + " :: " + fName);
+
+ return setAccessible(f);
+ }
+
+ public static Field permissiveGetField(Class> c, String fName) {
+ try {
+ return getField(c, fName);
+ } catch (Exception ignore) {
+ return null;
+ }
+ }
+
+ public static T permissiveReadField(Class type, Field f, Object instance) {
+ try {
+ return type.cast(f.get(instance));
+ } catch (Exception ignore) {
+ return null;
+ }
+ }
+
+ public static Constructor getConstructor(Class c, Class>... parameterTypes) throws NoSuchMethodException {
+ return setAccessible(c.getDeclaredConstructor(parameterTypes));
+ }
+
+ private static Object reflectiveStaticFieldAccess(Class> c, String fName) {
+ try {
+ Field f = c.getDeclaredField(fName);
+ f.setAccessible(true);
+ return f.get(null);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ public static boolean isDebugReflection() {
+ return !"false".equals(System.getProperty("lombok.debug.reflection", "false"));
+ }
+
+ public static void handleReflectionDebug(Throwable t, Throwable initError) {
+ if (!isDebugReflection()) return;
+
+ System.err.println("** LOMBOK REFLECTION exception: " + t.getClass() + ": " + (t.getMessage() == null ? "(no message)" : t.getMessage()));
+ t.printStackTrace(System.err);
+ if (initError != null) {
+ System.err.println("*** ADDITIONALLY, exception occurred setting up reflection: ");
+ initError.printStackTrace(System.err);
+ }
+ }
+
+ public static Object invoke(Method m, Object receiver, Object... args) throws IllegalAccessException, InvocationTargetException {
+ return invoke(null, m, receiver, args);
+ }
+
+ public static Object invoke(Throwable initError, Method m, Object receiver, Object... args) throws IllegalAccessException, InvocationTargetException {
+ try {
+ return m.invoke(receiver, args);
+ } catch (IllegalAccessException e) {
+ handleReflectionDebug(e, initError);
+ throw e;
+ } catch (RuntimeException e) {
+ handleReflectionDebug(e, initError);
+ throw e;
+ } catch (Error e) {
+ handleReflectionDebug(e, initError);
+ throw e;
+ }
+ }
+
+ public static Object invokeSneaky(Method m, Object receiver, Object... args) {
+ return invokeSneaky(null, m, receiver, args);
+ }
+
+ public static Object invokeSneaky(Throwable initError, Method m, Object receiver, Object... args) {
+ try {
+ return m.invoke(receiver, args);
+ } catch (NoClassDefFoundError e) {
+ handleReflectionDebug(e, initError);
+ //ignore, we don't have access to the correct ECJ classes, so lombok can't possibly
+ //do anything useful here.
+ return null;
+ } catch (NullPointerException e) {
+ handleReflectionDebug(e, initError);
+ //ignore, we don't have access to the correct ECJ classes, so lombok can't possibly
+ //do anything useful here.
+ return null;
+ } catch (IllegalAccessException e) {
+ handleReflectionDebug(e, initError);
+ throw sneakyThrow(e);
+ } catch (InvocationTargetException e) {
+ throw sneakyThrow(e.getCause());
+ } catch (RuntimeException e) {
+ handleReflectionDebug(e, initError);
+ throw e;
+ } catch (Error e) {
+ handleReflectionDebug(e, initError);
+ throw e;
+ }
+ }
+
+ public static T newInstance(Constructor c, Object... args) throws IllegalAccessException, InvocationTargetException, InstantiationException {
+ return newInstance(null, c, args);
+ }
+
+ public static T newInstance(Throwable initError, Constructor c, Object... args) throws IllegalAccessException, InvocationTargetException, InstantiationException {
+ try {
+ return c.newInstance(args);
+ } catch (IllegalAccessException e) {
+ handleReflectionDebug(e, initError);
+ throw e;
+ } catch (InstantiationException e) {
+ handleReflectionDebug(e, initError);
+ throw e;
+ } catch (RuntimeException e) {
+ handleReflectionDebug(e, initError);
+ throw e;
+ } catch (Error e) {
+ handleReflectionDebug(e, initError);
+ throw e;
+ }
+ }
+
+ public static T newInstanceSneaky(Constructor c, Object... args) {
+ return newInstanceSneaky(null, c, args);
+ }
+
+ public static T newInstanceSneaky(Throwable initError, Constructor c, Object... args) {
+ try {
+ return c.newInstance(args);
+ } catch (NoClassDefFoundError e) {
+ handleReflectionDebug(e, initError);
+ //ignore, we don't have access to the correct ECJ classes, so lombok can't possibly
+ //do anything useful here.
+ return null;
+ } catch (NullPointerException e) {
+ handleReflectionDebug(e, initError);
+ //ignore, we don't have access to the correct ECJ classes, so lombok can't possibly
+ //do anything useful here.
+ return null;
+ } catch (IllegalAccessException e) {
+ handleReflectionDebug(e, initError);
+ throw sneakyThrow(e);
+ } catch (InstantiationException e) {
+ handleReflectionDebug(e, initError);
+ throw sneakyThrow(e);
+ } catch (InvocationTargetException e) {
+ throw sneakyThrow(e.getCause());
+ } catch (RuntimeException e) {
+ handleReflectionDebug(e, initError);
+ throw e;
+ } catch (Error e) {
+ handleReflectionDebug(e, initError);
+ throw e;
+ }
+ }
+
+ public static Object get(Field f, Object receiver) throws IllegalAccessException {
+ try {
+ return f.get(receiver);
+ } catch (IllegalAccessException e) {
+ handleReflectionDebug(e, null);
+ throw e;
+ } catch (RuntimeException e) {
+ handleReflectionDebug(e, null);
+ throw e;
+ } catch (Error e) {
+ handleReflectionDebug(e, null);
+ throw e;
+ }
+ }
+
+ public static void set(Field f, Object receiver, Object newValue) throws IllegalAccessException {
+ try {
+ f.set(receiver, newValue);
+ } catch (IllegalAccessException e) {
+ handleReflectionDebug(e, null);
+ throw e;
+ } catch (RuntimeException e) {
+ handleReflectionDebug(e, null);
+ throw e;
+ } catch (Error e) {
+ handleReflectionDebug(e, null);
+ throw e;
+ }
+ }
+
+ public static void reportReflectionProblem(Throwable initError, String msg) {
+ if (!isDebugReflection()) return;
+ System.err.println("** LOMBOK REFLECTION issue: " + msg);
+ if (initError != null) {
+ System.err.println("*** ADDITIONALLY, exception occurred setting up reflection: ");
+ initError.printStackTrace(System.err);
+ }
+ }
+
+ public static RuntimeException sneakyThrow(Throwable t) {
+ if (t == null) throw new NullPointerException("t");
+ return Permit.sneakyThrow0(t);
+ }
+
+ @SuppressWarnings("unchecked")
+ private static T sneakyThrow0(Throwable t) throws T {
+ throw (T) t;
+ }
+
+ private static Object getJdkCompilerModule() {
+ /* call public api: ModuleLayer.boot().findModule("jdk.compiler").get();
+ but use reflection because we don't want this code to crash on jdk1.7 and below.
+ In that case, none of this stuff was needed in the first place, so we just exit via
+ the catch block and do nothing.
+ */
+
+ try {
+ Class> cModuleLayer = Class.forName("java.lang.ModuleLayer");
+ Method mBoot = cModuleLayer.getDeclaredMethod("boot");
+ Object bootLayer = mBoot.invoke(null);
+ Class> cOptional = Class.forName("java.util.Optional");
+ Method mFindModule = cModuleLayer.getDeclaredMethod("findModule", String.class);
+ Object oCompilerO = mFindModule.invoke(bootLayer, "jdk.compiler");
+ return cOptional.getDeclaredMethod("get").invoke(oCompilerO);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ private static Object getOwnModule() {
+ try {
+ Method m = Permit.getMethod(Class.class, "getModule");
+ return m.invoke(Permit.class);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ private static long getFirstFieldOffset(Unsafe unsafe) {
+ try {
+ return unsafe.objectFieldOffset(Parent.class.getDeclaredField("first"));
+ } catch (NoSuchFieldException e) {
+ // can't happen.
+ throw new RuntimeException(e);
+ } catch (SecurityException e) {
+ // can't happen
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static void addOpens() {
+ Class> cModule;
+ try {
+ cModule = Class.forName("java.lang.Module");
+ } catch (ClassNotFoundException e) {
+ return; //jdk8-; this is not needed.
+ }
+
+ Unsafe unsafe = UNSAFE;
+
+ Object jdkCompilerModule = getJdkCompilerModule();
+ Object ownModule = getOwnModule();
+ String[] allPkgs = {
+ "com.sun.tools.javac.code",
+ "com.sun.tools.javac.comp",
+ "com.sun.tools.javac.file",
+ "com.sun.tools.javac.main",
+ "com.sun.tools.javac.model",
+ "com.sun.tools.javac.parser",
+ "com.sun.tools.javac.processing",
+ "com.sun.tools.javac.tree",
+ "com.sun.tools.javac.util",
+ "com.sun.tools.javac.jvm",
+ "com.sun.tools.javac.api"
+ };
+
+ try {
+ Method m = cModule.getDeclaredMethod("implAddOpens", String.class, cModule);
+ long firstFieldOffset = getFirstFieldOffset(unsafe);
+ unsafe.putBooleanVolatile(m, firstFieldOffset, true);
+ for (String p : allPkgs) m.invoke(jdkCompilerModule, p, ownModule);
+ } catch (Exception ignore) {}
+
+ try {
+ Method m = cModule.getDeclaredMethod("implAddExports", String.class, cModule);
+ long firstFieldOffset = getFirstFieldOffset(unsafe);
+ unsafe.putBooleanVolatile(m, firstFieldOffset, true);
+ for (String p : allPkgs) m.invoke(jdkCompilerModule, p, ownModule);
+ } catch (Exception ignore) {}
+ }
+}
diff --git a/dubbo-annotation-processor/src/main/java/org/apache/dubbo/annotation/permit/dummy/Child.java b/dubbo-annotation-processor/src/main/java/org/apache/dubbo/annotation/permit/dummy/Child.java
new file mode 100644
index 0000000000..46c647bedc
--- /dev/null
+++ b/dubbo-annotation-processor/src/main/java/org/apache/dubbo/annotation/permit/dummy/Child.java
@@ -0,0 +1,33 @@
+/*
+ * Authored by Project Lombok and licensed by MIT License, which is attached below:
+ *
+ * Copyright (C) 2018-2021 The Project Lombok Authors.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package org.apache.dubbo.annotation.permit.dummy;
+
+@SuppressWarnings("all")
+public abstract class Child extends Parent {
+ private transient volatile boolean foo;
+ private transient volatile Object[] bar;
+ private transient volatile Object baz;
+
+}
diff --git a/dubbo-annotation-processor/src/main/java/org/apache/dubbo/annotation/permit/dummy/GrandChild.java b/dubbo-annotation-processor/src/main/java/org/apache/dubbo/annotation/permit/dummy/GrandChild.java
new file mode 100644
index 0000000000..c2bf737629
--- /dev/null
+++ b/dubbo-annotation-processor/src/main/java/org/apache/dubbo/annotation/permit/dummy/GrandChild.java
@@ -0,0 +1,43 @@
+/*
+ * Authored by Project Lombok and licensed by MIT License, which is attached below:
+ *
+ * Copyright (C) 2018-2021 The Project Lombok Authors.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package org.apache.dubbo.annotation.permit.dummy;
+
+@SuppressWarnings("all")
+public final class GrandChild extends Child {
+ private Class> a;
+ private int b;
+ private String c;
+ private Class> d;
+ private Class>[] e;
+ private Class>[] f;
+ private int g;
+ private transient String h;
+ private transient Object i;
+ private byte[] j;
+ private byte[] k;
+ private byte[] l;
+ private volatile Object m;
+ private Object n;
+}
diff --git a/dubbo-annotation-processor/src/main/java/org/apache/dubbo/annotation/permit/dummy/Parent.java b/dubbo-annotation-processor/src/main/java/org/apache/dubbo/annotation/permit/dummy/Parent.java
new file mode 100644
index 0000000000..53cb8c8ce5
--- /dev/null
+++ b/dubbo-annotation-processor/src/main/java/org/apache/dubbo/annotation/permit/dummy/Parent.java
@@ -0,0 +1,36 @@
+/*
+ * Authored by Project Lombok and licensed by MIT License, which is attached below:
+ *
+ * Copyright (C) 2018-2021 The Project Lombok Authors.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package org.apache.dubbo.annotation.permit.dummy;
+
+import java.io.OutputStream;
+
+@SuppressWarnings("all")
+public class Parent {
+ boolean first;
+ static final Object staticObj = OutputStream.class;
+ volatile Object second;
+ private static volatile boolean staticSecond;
+ private static volatile boolean staticThird;
+}
diff --git a/dubbo-annotation-processor/src/main/java/org/apache/dubbo/annotation/permit/dummy/package-info.java b/dubbo-annotation-processor/src/main/java/org/apache/dubbo/annotation/permit/dummy/package-info.java
new file mode 100644
index 0000000000..dcbf5a58a0
--- /dev/null
+++ b/dubbo-annotation-processor/src/main/java/org/apache/dubbo/annotation/permit/dummy/package-info.java
@@ -0,0 +1,32 @@
+/*
+ * Authored by Project Lombok and licensed by MIT License, which is attached below:
+ *
+ * Copyright (C) 2018-2021 The Project Lombok Authors.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * This package recreates the type hierarchy of {@code java.lang.reflect.AccessibleObject} and friends (such as {@code java.lang.reflect.Method});
+ * its purpose is to allow us to ask {@code sun.misc.internal.Unsafe} about the exact offset of the {@code override} field of {@code AccessibleObject};
+ * asking about that field directly doesn't work after jdk14, presumably because the fields of AO are expressly hidden somehow.
+ *
+ * NB: It's usually 12, on the vast majority of OS, VM, and architecture combos.
+ */
+package org.apache.dubbo.annotation.permit.dummy;
diff --git a/dubbo-annotation-processor/src/main/java/org/apache/dubbo/annotation/permit/package-info.java b/dubbo-annotation-processor/src/main/java/org/apache/dubbo/annotation/permit/package-info.java
new file mode 100644
index 0000000000..95b72451c6
--- /dev/null
+++ b/dubbo-annotation-processor/src/main/java/org/apache/dubbo/annotation/permit/package-info.java
@@ -0,0 +1,32 @@
+/*
+ * Authored by Project Lombok and licensed by MIT License, which is attached below:
+ *
+ * Copyright (C) 2018-2021 The Project Lombok Authors.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * This is a reduced copy of the nqzero Permit-reflect project.
+ * https://github.com/nqzero/permit-reflect
+ *
+ * Many thanks to nqzero. The permit-reflect project is, like lombok itself, licensed under the MIT license.
+ * See https://github.com/nqzero/permit-reflect/blob/master/License for license info.
+ */
+package org.apache.dubbo.annotation.permit;
diff --git a/dubbo-annotation-processor/src/main/java/org/apache/dubbo/annotation/util/ASTUtils.java b/dubbo-annotation-processor/src/main/java/org/apache/dubbo/annotation/util/ASTUtils.java
new file mode 100644
index 0000000000..bfd463785f
--- /dev/null
+++ b/dubbo-annotation-processor/src/main/java/org/apache/dubbo/annotation/util/ASTUtils.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.annotation.util;
+
+import org.apache.dubbo.annotation.AnnotationProcessorContext;
+
+import com.sun.source.util.TreePath;
+import com.sun.tools.javac.code.Symbol;
+import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.util.ListBuffer;
+
+import java.util.List;
+
+/**
+ * Some utils about AST manipulating.
+ */
+public final class ASTUtils {
+
+ private ASTUtils() {
+ throw new UnsupportedOperationException("No instance of 'ASTUtils' for you! ");
+ }
+
+ public static void addImportStatement(AnnotationProcessorContext apContext,
+ Symbol.ClassSymbol classSymbol,
+ String packageName,
+ String className) {
+
+ JCTree.JCImport jcImport = apContext.getTreeMaker().Import(
+ apContext.getTreeMaker().Select(
+ apContext.getTreeMaker().Ident(apContext.getNames().fromString(packageName)),
+ apContext.getNames().fromString(className)
+ ), false);
+
+ TreePath treePath = apContext.getTrees().getPath(classSymbol);
+ TreePath parentPath = treePath.getParentPath();
+ JCTree.JCCompilationUnit compilationUnit = (JCTree.JCCompilationUnit) parentPath.getCompilationUnit();
+
+ List imports = compilationUnit.getImports();
+ if (imports.stream().noneMatch(x -> x.qualid.toString().contains(packageName + "." + className))) {
+
+ compilationUnit.accept(new JCTree.Visitor() {
+ @Override
+ public void visitTopLevel(JCTree.JCCompilationUnit that) {
+
+ List defs = compilationUnit.defs;
+
+ ListBuffer newDefs = new ListBuffer<>();
+
+ newDefs.add(defs.get(0));
+ newDefs.add(jcImport);
+ newDefs.addAll(defs.subList(1, defs.size()));
+
+ compilationUnit.defs = newDefs.toList();
+ }
+ });
+ }
+ }
+
+ /**
+ * Insert statement to head of the method.
+ *
+ * @param block the method body
+ * @param originalMethodDecl the method declaration that will add logger statement
+ * @param fullExpressionStatement the statement to insert.
+ */
+ public static void insertStatementToHeadOfMethod(JCTree.JCBlock block,
+ JCTree.JCMethodDecl originalMethodDecl,
+ JCTree.JCStatement fullExpressionStatement) {
+
+ boolean isConstructor = originalMethodDecl.name.toString().equals("");
+ ListBuffer statements = new ListBuffer<>();
+
+ // In constructor, super(...) or this(...) should be the first statement.
+
+ if (isConstructor && !block.stats.isEmpty()) {
+
+ boolean startsWithSuper = block.stats.get(0).toString().startsWith("super(");
+ boolean startsWithThis = block.stats.get(0).toString().startsWith("this(");
+
+ if (startsWithSuper || startsWithThis) {
+ statements.add(block.stats.get(0));
+ statements.add(fullExpressionStatement);
+ statements.addAll(block.stats.subList(1, block.stats.size()));
+ } else {
+ statements.add(fullExpressionStatement);
+ statements.addAll(block.stats);
+ }
+
+ } else {
+ statements.add(fullExpressionStatement);
+ statements.addAll(block.stats);
+ }
+
+ block.stats = statements.toList();
+ }
+}
diff --git a/dubbo-annotation-processor/src/main/java/org/apache/dubbo/annotation/util/FileUtils.java b/dubbo-annotation-processor/src/main/java/org/apache/dubbo/annotation/util/FileUtils.java
new file mode 100644
index 0000000000..66a897913a
--- /dev/null
+++ b/dubbo-annotation-processor/src/main/java/org/apache/dubbo/annotation/util/FileUtils.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.annotation.util;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.Channels;
+import java.nio.channels.FileChannel;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.Scanner;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * Utilities of iterating file.
+ */
+public final class FileUtils {
+
+ private static final Pattern WINDOWS_PATH_PATTERN = Pattern.compile("file:/\\w:/.*");
+
+
+ private FileUtils() {
+ throw new UnsupportedOperationException("No instance of FileUtils for you! ");
+ }
+
+ public static List getAllClassFilePaths(String rootPath) {
+ List targetFolders;
+
+ try (Stream filesStream = Files.walk(Paths.get(rootPath))) {
+ targetFolders = filesStream.filter(x -> !x.toFile().isFile())
+ .filter(x -> x.toString().contains("classes") && !x.toString().contains("test-classes"))
+ .filter(x -> x.toString().contains("\\org\\apache\\dubbo".replace('\\', File.separatorChar)))
+ .collect(Collectors.toList());
+
+ return targetFolders;
+
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static byte[] openFileAsByteArray(String filePath) {
+ try (FileChannel fileChannel = FileChannel.open(Paths.get(filePath))) {
+
+ ByteBuffer byteBuffer = ByteBuffer.allocate((int) fileChannel.size());
+ fileChannel.read(byteBuffer);
+
+ return byteBuffer.array();
+
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static String openFileAsString(String filePath) {
+ return new String(openFileAsByteArray(filePath));
+ }
+
+ public static String getSourceFilePathFromClassFilePath(String classFilePath) {
+
+ String classesPathString = "\\target\\classes\\".replace("\\", File.separator);
+ String sourcesPathString = "\\src\\main\\java\\".replace("\\", File.separator);
+
+ String sourceFilePathByReplace = classFilePath.replace(classesPathString, sourcesPathString)
+ .replace(".class", ".java");
+
+ // Inner classes.
+ if (sourceFilePathByReplace.lastIndexOf('$') != -1) {
+ int dollarCharIndex = sourceFilePathByReplace.lastIndexOf('$');
+ String outerClassPath = sourceFilePathByReplace.substring(0, dollarCharIndex);
+
+ return outerClassPath + ".java";
+ }
+
+ return sourceFilePathByReplace;
+ }
+
+ public static List loadConfigurationFileInResources(String path) {
+
+ ReadableByteChannel resourceReadableByteChannel = Channels.newChannel(
+ Objects.requireNonNull(FileUtils.class.getClassLoader().getResourceAsStream(path)));
+
+ List lines = new ArrayList<>();
+
+ try (Scanner scanner = new Scanner(resourceReadableByteChannel)) {
+
+ while (scanner.hasNextLine()) {
+ String line = scanner.nextLine().trim();
+
+ if (!line.startsWith("#") && !line.isEmpty()) {
+ lines.add(line);
+ }
+ }
+
+ return lines;
+ }
+ }
+
+ /**
+ * Get absolute path of resource.
+ *
+ *
Retained for testing. It won't work in JAR.
+ *
+ * @param path relative path of resources folder.
+ * @return absolute path of resource
+ */
+ public static String getResourceFilePath(String path) {
+ String resourceFilePath = FileUtils.class.getClassLoader().getResource(path).toString();
+
+ if (WINDOWS_PATH_PATTERN.matcher(resourceFilePath).matches()) {
+ resourceFilePath = resourceFilePath.replace("file:/", "");
+ } else {
+ resourceFilePath = resourceFilePath.replace("file:", "");
+ }
+
+ return resourceFilePath;
+ }
+
+ public static List getAllFilesInDirectory(Path targetFolder) {
+
+ try (Stream classFilesStream = Files.walk(targetFolder)) {
+
+ return classFilesStream
+ .filter(x -> x.toFile().isFile())
+ .collect(Collectors.toList());
+
+ } catch (IOException e) {
+ return Collections.emptyList();
+ }
+ }
+}
diff --git a/dubbo-annotation-processor/src/main/resources/META-INF/services/javax.annotation.processing.Processor b/dubbo-annotation-processor/src/main/resources/META-INF/services/javax.annotation.processing.Processor
new file mode 100644
index 0000000000..fe51e15be0
--- /dev/null
+++ b/dubbo-annotation-processor/src/main/resources/META-INF/services/javax.annotation.processing.Processor
@@ -0,0 +1 @@
+org.apache.dubbo.annotation.DispatchingAnnotationProcessor
diff --git a/dubbo-annotation-processor/src/main/resources/handlers.cfg b/dubbo-annotation-processor/src/main/resources/handlers.cfg
new file mode 100644
index 0000000000..bcdca71445
--- /dev/null
+++ b/dubbo-annotation-processor/src/main/resources/handlers.cfg
@@ -0,0 +1,17 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+org.apache.dubbo.annotation.handler.DeprecatedHandler
diff --git a/dubbo-annotation-processor/src/test/java/org/apache/dubbo/annotation/RealInvocationTest.java b/dubbo-annotation-processor/src/test/java/org/apache/dubbo/annotation/RealInvocationTest.java
new file mode 100644
index 0000000000..9544990ffe
--- /dev/null
+++ b/dubbo-annotation-processor/src/test/java/org/apache/dubbo/annotation/RealInvocationTest.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.annotation;
+
+import org.apache.dubbo.annotation.util.FileUtils;
+import org.apache.dubbo.eci.extractor.JavassistUtils;
+
+import javassist.bytecode.ClassFile;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Real invocation test of DispatchingAnnotationProcessor (and DeprecatedHandler).
+ */
+class RealInvocationTest {
+
+ /**
+ * [File name, Should the counter exist in the class file? ]
+ */
+ private static final Map FILES = new HashMap<>(5, 1);
+
+ static {
+ FILES.put("TestConstructorMethod.java", true);
+ FILES.put("TestDeprecatedMethod.java", true);
+ FILES.put("TestInterfaceDeprecatedMethod.java", false);
+ FILES.put("TestConstructorMethodParentClass.java", false);
+ FILES.put("TestConstructorMethodSubClass.java", true);
+ }
+
+ @Test
+ void test() {
+
+ for (Map.Entry i : FILES.entrySet()) {
+ String filePath = FileUtils.getResourceFilePath("org/testing/dm/" + i.getKey());
+
+ Assertions.assertTrue(TestingCommons.compileTheSource(filePath), "Compile failed! ");
+
+ String classFilePath = filePath.replace(".java", ".class");
+ ClassFile classFile = JavassistUtils.openClassFile(classFilePath);
+ List stringItems = JavassistUtils.getConstPoolStringItems(classFile.getConstPool());
+
+ Assertions.assertEquals(i.getValue(), stringItems.contains("org/apache/dubbo/common/DeprecatedMethodInvocationCounter"));
+ }
+ }
+}
diff --git a/dubbo-annotation-processor/src/test/java/org/apache/dubbo/annotation/TestingCommons.java b/dubbo-annotation-processor/src/test/java/org/apache/dubbo/annotation/TestingCommons.java
new file mode 100644
index 0000000000..cca11f56e6
--- /dev/null
+++ b/dubbo-annotation-processor/src/test/java/org/apache/dubbo/annotation/TestingCommons.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.annotation;
+
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileObject;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.ToolProvider;
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.Locale;
+
+import static java.util.Arrays.asList;
+
+/**
+ * Common code of annotation processor testing.
+ */
+public final class TestingCommons {
+ private TestingCommons() {
+ throw new UnsupportedOperationException("No instance of TestingCommons for you! ");
+ }
+
+ private static class ObjectHolders {
+ static final JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
+
+ static final StandardJavaFileManager javaFileManager = javaCompiler.getStandardFileManager(
+ null,
+ Locale.ROOT,
+ StandardCharsets.UTF_8
+ );
+ }
+
+ public static boolean compileTheSource(String filePath) {
+
+
+ JavaCompiler.CompilationTask compilationTask = ObjectHolders.javaCompiler.getTask(
+ null,
+ ObjectHolders.javaFileManager,
+ null,
+ asList("-parameters", "-Xlint:unchecked", "-nowarn", "-Xlint:deprecation"),
+ null,
+ getSourceFileJavaFileObject(filePath)
+ );
+
+ compilationTask.setProcessors(
+ Collections.singletonList(new DispatchingAnnotationProcessor())
+ );
+
+ return compilationTask.call();
+ }
+
+ private static Iterable extends JavaFileObject> getSourceFileJavaFileObject(String filePath) {
+
+ return ObjectHolders.javaFileManager.getJavaFileObjects(filePath);
+ }
+}
diff --git a/dubbo-annotation-processor/src/test/java/org/apache/dubbo/common/DeprecatedMethodInvocationCounter.java b/dubbo-annotation-processor/src/test/java/org/apache/dubbo/common/DeprecatedMethodInvocationCounter.java
new file mode 100644
index 0000000000..cc34299c81
--- /dev/null
+++ b/dubbo-annotation-processor/src/test/java/org/apache/dubbo/common/DeprecatedMethodInvocationCounter.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.common;
+
+/**
+ * Reduced mock of Deprecated method invocation counter.
+ */
+public final class DeprecatedMethodInvocationCounter {
+ private DeprecatedMethodInvocationCounter() {
+ throw new UnsupportedOperationException("No instance of DeprecatedMethodInvocationCounter for you! ");
+ }
+
+ /**
+ * Invoked by (modified) deprecated method.
+ *
+ * @param methodDefinition filled by annotation processor. (like 'org.apache.dubbo.common.URL.getServiceName()')
+ */
+ public static void onDeprecatedMethodCalled(String methodDefinition) {
+ // Intended to be empty.
+ }
+}
diff --git a/dubbo-annotation-processor/src/test/java/org/apache/dubbo/eci/extractor/JavassistUtils.java b/dubbo-annotation-processor/src/test/java/org/apache/dubbo/eci/extractor/JavassistUtils.java
new file mode 100644
index 0000000000..3a2475591a
--- /dev/null
+++ b/dubbo-annotation-processor/src/test/java/org/apache/dubbo/eci/extractor/JavassistUtils.java
@@ -0,0 +1,151 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.eci.extractor;
+
+import org.apache.dubbo.annotation.util.FileUtils;
+
+import javassist.bytecode.ClassFile;
+import javassist.bytecode.ConstPool;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Utilities of Javassist.
+ */
+public class JavassistUtils {
+ private static final Map stringFieldCache = new HashMap<>(2, 1);
+
+ private static Method getItemMethodCache = null;
+
+ private JavassistUtils() {
+ throw new UnsupportedOperationException("No instance of JavassistUtils for you! ");
+ }
+
+ public static ClassFile openClassFile(String classFilePath) {
+ try {
+ byte[] clsB = FileUtils.openFileAsByteArray(classFilePath);
+ return new ClassFile(new DataInputStream(new ByteArrayInputStream(clsB)));
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ static List