From a8e2c41be4589aa04456568ad57482dc8cf2847c Mon Sep 17 00:00:00 2001 From: Mark Zhang Date: Thu, 10 Aug 2023 10:22:44 +0800 Subject: [PATCH] feat: support JDK 17 (#247) --- .github/workflows/build.yml | 10 +- .../model/ParameterizedTypeImpl.java | 218 ++++++++++++++++++ arex-attacher/pom.xml | 1 + .../io/arex/inst/runtime/util/TypeUtil.java | 2 +- .../arex/inst/runtime/util/TypeUtilTest.java | 4 +- arex-instrumentation-foundation/pom.xml | 2 +- .../dynamic/arex-cache/pom.xml | 2 +- .../dynamic/arex-dynamic/pom.xml | 2 +- arex-instrumentation/pom.xml | 1 + pom.xml | 12 +- 10 files changed, 242 insertions(+), 12 deletions(-) create mode 100644 arex-agent-bootstrap/src/main/java/io/arex/agent/bootstrap/model/ParameterizedTypeImpl.java diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2649f5f63..9e496278b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,5 +1,5 @@ # This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time -# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-maven name: Build and Test @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - java-version: [ 8, 11 ] + java-version: [ 8, 11, 17 ] steps: - uses: actions/checkout@v3 - name: "Set up JDK ${{ matrix.java-version }}" @@ -32,10 +32,10 @@ jobs: - uses: actions/checkout@v3 with: fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis - - name: "Set up JDK 11" + - name: "Set up JDK 17" uses: actions/setup-java@v3 with: - java-version: 11 + java-version: 17 distribution: 'temurin' cache: maven - name: Cache SonarCloud packages @@ -55,5 +55,5 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any run: mvn --batch-mode --no-transfer-progress --fail-fast clean test verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Dsonar.projectKey=arextest_arex-agent-java -Dsonar.host.url=https://sonarcloud.io -Dsonar.organization=arextest -Dsonar.token=1f4a261beca6bbf7c93c3cf80bbc198de74d1020 -DskipTests=false - name: Codecov - uses: codecov/codecov-action@v3.1.0 + uses: codecov/codecov-action@v3 diff --git a/arex-agent-bootstrap/src/main/java/io/arex/agent/bootstrap/model/ParameterizedTypeImpl.java b/arex-agent-bootstrap/src/main/java/io/arex/agent/bootstrap/model/ParameterizedTypeImpl.java new file mode 100644 index 000000000..c7eae422e --- /dev/null +++ b/arex-agent-bootstrap/src/main/java/io/arex/agent/bootstrap/model/ParameterizedTypeImpl.java @@ -0,0 +1,218 @@ +package io.arex.agent.bootstrap.model; + +import java.lang.reflect.MalformedParameterizedTypeException; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; +import java.util.Arrays; +import java.util.Objects; + +/** + * ref: + * sun/reflect/generics/reflectiveObjects/ParameterizedTypeImpl.java + * + */ +public class ParameterizedTypeImpl implements ParameterizedType { + private final Type[] actualTypeArguments; + private final Class rawType; + private final Type ownerType; + + private ParameterizedTypeImpl(Class rawType, + Type[] actualTypeArguments, + Type ownerType) { + this.actualTypeArguments = actualTypeArguments; + this.rawType = rawType; + this.ownerType = (ownerType != null) ? ownerType : rawType.getDeclaringClass(); + validateConstructorArguments(); + } + + private void validateConstructorArguments() { + TypeVariable[] formals = rawType.getTypeParameters(); + // check correct arity of actual type args + if (formals.length != actualTypeArguments.length){ + throw new MalformedParameterizedTypeException(); + } + for (int i = 0; i < actualTypeArguments.length; i++) { + // check actuals against formals' bounds + } + } + + /** + * Static factory. Given a (generic) class, actual type arguments + * and an owner type, creates a parameterized type. + * This class can be instantiated with a a raw type that does not + * represent a generic type, provided the list of actual type + * arguments is empty. + * If the ownerType argument is null, the declaring class of the + * raw type is used as the owner type. + *

This method throws a MalformedParameterizedTypeException + * under the following circumstances: + * If the number of actual type arguments (i.e., the size of the + * array typeArgs) does not correspond to the number of + * formal type arguments. + * If any of the actual type arguments is not an instance of the + * bounds on the corresponding formal. + * @param rawType the Class representing the generic type declaration being + * instantiated + * @param actualTypeArguments - a (possibly empty) array of types + * representing the actual type arguments to the parameterized type + * @param ownerType - the enclosing type, if known. + * @return An instance of ParameterizedType + * @throws MalformedParameterizedTypeException - if the instantiation + * is invalid + */ + public static ParameterizedTypeImpl make(Class rawType, + Type[] actualTypeArguments, + Type ownerType) { + return new ParameterizedTypeImpl(rawType, actualTypeArguments, + ownerType); + } + + + /** + * Returns an array of Type objects representing the actual type + * arguments to this type. + * + *

Note that in some cases, the returned array be empty. This can occur + * if this type represents a non-parameterized type nested within + * a parameterized type. + * + * @return an array of Type objects representing the actual type + * arguments to this type + * @throws TypeNotPresentException if any of the + * actual type arguments refers to a non-existent type declaration + * @throws MalformedParameterizedTypeException if any of the + * actual type parameters refer to a parameterized type that cannot + * be instantiated for any reason + * @since 1.5 + */ + public Type[] getActualTypeArguments() { + return actualTypeArguments.clone(); + } + + /** + * Returns the Type object representing the class or interface + * that declared this type. + * + * @return the Type object representing the class or interface + * that declared this type + */ + public Class getRawType() { + return rawType; + } + + + /** + * Returns a Type object representing the type that this type + * is a member of. For example, if this type is O.I, + * return a representation of O. + * + *

If this type is a top-level type, null is returned. + * + * @return a Type object representing the type that + * this type is a member of. If this type is a top-level type, + * null is returned + * @throws TypeNotPresentException if the owner type + * refers to a non-existent type declaration + * @throws MalformedParameterizedTypeException if the owner type + * refers to a parameterized type that cannot be instantiated + * for any reason + * + */ + public Type getOwnerType() { + return ownerType; + } + + /* + * From the JavaDoc for java.lang.reflect.ParameterizedType + * "Instances of classes that implement this interface must + * implement an equals() method that equates any two instances + * that share the same generic type declaration and have equal + * type parameters." + */ + @Override + public boolean equals(Object o) { + if (o instanceof ParameterizedType) { + // Check that information is equivalent + ParameterizedType that = (ParameterizedType) o; + + if (this == that) + return true; + + Type thatOwner = that.getOwnerType(); + Type thatRawType = that.getRawType(); + + if (false) { // Debugging + boolean ownerEquality = (ownerType == null ? + thatOwner == null : + ownerType.equals(thatOwner)); + boolean rawEquality = (rawType == null ? + thatRawType == null : + rawType.equals(thatRawType)); + + boolean typeArgEquality = Arrays.equals(actualTypeArguments, // avoid clone + that.getActualTypeArguments()); + for (Type t : actualTypeArguments) { + System.out.printf("\t\t%s%s%n", t, t.getClass()); + } + + System.out.printf("\towner %s\traw %s\ttypeArg %s%n", + ownerEquality, rawEquality, typeArgEquality); + return ownerEquality && rawEquality && typeArgEquality; + } + + return + Objects.equals(ownerType, thatOwner) && + Objects.equals(rawType, thatRawType) && + Arrays.equals(actualTypeArguments, // avoid clone + that.getActualTypeArguments()); + } else + return false; + } + + @Override + public int hashCode() { + return + Arrays.hashCode(actualTypeArguments) ^ + Objects.hashCode(ownerType) ^ + Objects.hashCode(rawType); + } + + public String toString() { + StringBuilder sb = new StringBuilder(); + + if (ownerType != null) { + if (ownerType instanceof Class) + sb.append(((Class)ownerType).getName()); + else + sb.append(ownerType.toString()); + + sb.append("$"); + + if (ownerType instanceof ParameterizedTypeImpl) { + // Find simple name of nested type by removing the + // shared prefix with owner. + sb.append(rawType.getName().replace( ((ParameterizedTypeImpl)ownerType).rawType.getName() + "$", + "")); + } else + sb.append(rawType.getSimpleName()); + } else + sb.append(rawType.getName()); + + if (actualTypeArguments != null && + actualTypeArguments.length > 0) { + sb.append("<"); + boolean first = true; + for(Type t: actualTypeArguments) { + if (!first) + sb.append(", "); + sb.append(t.getTypeName()); + first = false; + } + sb.append(">"); + } + + return sb.toString(); + } +} diff --git a/arex-attacher/pom.xml b/arex-attacher/pom.xml index 1d77ad7b1..16cb30fc2 100644 --- a/arex-attacher/pom.xml +++ b/arex-attacher/pom.xml @@ -27,6 +27,7 @@ org.apache.maven.plugins maven-jar-plugin + ${maven-jar-plugin.version} package diff --git a/arex-instrumentation-api/src/main/java/io/arex/inst/runtime/util/TypeUtil.java b/arex-instrumentation-api/src/main/java/io/arex/inst/runtime/util/TypeUtil.java index 9a3b53705..42fecfc3e 100644 --- a/arex-instrumentation-api/src/main/java/io/arex/inst/runtime/util/TypeUtil.java +++ b/arex-instrumentation-api/src/main/java/io/arex/inst/runtime/util/TypeUtil.java @@ -1,5 +1,6 @@ package io.arex.inst.runtime.util; +import io.arex.agent.bootstrap.model.ParameterizedTypeImpl; import io.arex.agent.bootstrap.util.ArrayUtils; import io.arex.agent.bootstrap.util.StringUtil; import io.arex.inst.runtime.log.LogManager; @@ -15,7 +16,6 @@ import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl; public class TypeUtil { diff --git a/arex-instrumentation-api/src/test/java/io/arex/inst/runtime/util/TypeUtilTest.java b/arex-instrumentation-api/src/test/java/io/arex/inst/runtime/util/TypeUtilTest.java index f61c173b7..3ec1cc840 100644 --- a/arex-instrumentation-api/src/test/java/io/arex/inst/runtime/util/TypeUtilTest.java +++ b/arex-instrumentation-api/src/test/java/io/arex/inst/runtime/util/TypeUtilTest.java @@ -1,6 +1,7 @@ package io.arex.inst.runtime.util; import io.arex.agent.bootstrap.internal.Pair; +import io.arex.agent.bootstrap.model.ParameterizedTypeImpl; import io.arex.agent.bootstrap.util.CollectionUtil; import io.arex.agent.bootstrap.util.StringUtil; import java.lang.reflect.Field; @@ -22,7 +23,6 @@ import org.junit.jupiter.params.provider.MethodSource; import org.mockito.MockedStatic; import org.mockito.Mockito; -import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl; import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.params.provider.Arguments.arguments; @@ -251,4 +251,4 @@ void testSerializeObjectToString() { final String arg2Type = TypeUtil.errorSerializeToString(arg2); assertEquals("java.lang.Double", arg2Type); } -} \ No newline at end of file +} diff --git a/arex-instrumentation-foundation/pom.xml b/arex-instrumentation-foundation/pom.xml index 60a538483..fdcf5da09 100644 --- a/arex-instrumentation-foundation/pom.xml +++ b/arex-instrumentation-foundation/pom.xml @@ -44,7 +44,7 @@ com.google.code.gson gson - 2.8.9 + 2.10.1 com.google.guava diff --git a/arex-instrumentation/dynamic/arex-cache/pom.xml b/arex-instrumentation/dynamic/arex-cache/pom.xml index ae3449b6a..a4a5d1a00 100644 --- a/arex-instrumentation/dynamic/arex-cache/pom.xml +++ b/arex-instrumentation/dynamic/arex-cache/pom.xml @@ -28,7 +28,7 @@ com.arextest arex-common - 0.1.4 + ${arex-common.version} provided diff --git a/arex-instrumentation/dynamic/arex-dynamic/pom.xml b/arex-instrumentation/dynamic/arex-dynamic/pom.xml index f5cff8d51..a12a3cd67 100644 --- a/arex-instrumentation/dynamic/arex-dynamic/pom.xml +++ b/arex-instrumentation/dynamic/arex-dynamic/pom.xml @@ -22,7 +22,7 @@ com.arextest arex-common - 0.1.4 + ${arex-common.version} provided diff --git a/arex-instrumentation/pom.xml b/arex-instrumentation/pom.xml index 7fe8e1c18..b3bdaf649 100644 --- a/arex-instrumentation/pom.xml +++ b/arex-instrumentation/pom.xml @@ -14,6 +14,7 @@ 5.3.24 + 0.1.6 diff --git a/pom.xml b/pom.xml index 4087c4d2f..2c4ae1d50 100644 --- a/pom.xml +++ b/pom.xml @@ -223,7 +223,17 @@ org.apache.maven.plugins maven-surefire-plugin - 2.22.2 + 3.1.2 + + + --add-opens java.base/java.lang=ALL-UNNAMED + --add-opens java.base/java.math=ALL-UNNAMED + --add-opens java.base/java.util=ALL-UNNAMED + --add-opens java.base/java.net=ALL-UNNAMED + --add-opens java.base/java.time=ALL-UNNAMED + --add-opens java.xml/com.sun.org.apache.xerces.internal.jaxp.datatype=ALL-UNNAMED + + org.jacoco