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
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 @@