From 9851b6c54d06f744cdd4fabe1bcbd16de2e054b8 Mon Sep 17 00:00:00 2001 From: Laird Nelson Date: Fri, 19 Dec 2025 21:39:00 -0800 Subject: [PATCH] Uptakes microbean-assign 0.0.11 and microbean-bean 0.0.22 Signed-off-by: Laird Nelson --- .../mvn-release-prepare-perform.yaml | 4 +- .github/workflows/mvn-verify.yaml | 8 +- .mvn/wrapper/maven-wrapper.properties | 25 +- README.md | 2 +- mvnw | 50 ++- mvnw.cmd | 56 +++- pom.xml | 79 ++--- .../microbean/proxy/AbstractProxier.java.bak | 300 ------------------ .../proxy/AbstractReflectiveProxier.java | 139 +------- .../proxy/AbstractToolkitProxier.java | 6 +- src/main/java/org/microbean/proxy/Proxy.java | 2 - .../microbean/proxy/ProxySpecification.java | 22 +- 12 files changed, 157 insertions(+), 536 deletions(-) delete mode 100644 src/main/java/org/microbean/proxy/AbstractProxier.java.bak diff --git a/.github/workflows/mvn-release-prepare-perform.yaml b/.github/workflows/mvn-release-prepare-perform.yaml index c858555..4cfc38c 100644 --- a/.github/workflows/mvn-release-prepare-perform.yaml +++ b/.github/workflows/mvn-release-prepare-perform.yaml @@ -24,13 +24,13 @@ jobs: steps: - id: 'checkout' name: 'Step: Check Out Project' - uses: 'actions/checkout@v4' + uses: 'actions/checkout@v6' with: fetch-depth: 1 persist-credentials: false - id: 'setup-java' name: 'Step: Set Up Java and Maven' - uses: 'actions/setup-java@v4' + uses: 'actions/setup-java@v5' with: cache: 'maven' distribution: 'temurin' diff --git a/.github/workflows/mvn-verify.yaml b/.github/workflows/mvn-verify.yaml index a414901..faefc80 100644 --- a/.github/workflows/mvn-verify.yaml +++ b/.github/workflows/mvn-verify.yaml @@ -12,18 +12,18 @@ jobs: steps: - id: 'checkout' name: 'Step: Checkout' - uses: 'actions/checkout@v4' + uses: 'actions/checkout@v6' with: fetch-depth: 1 persist-credentials: false - id: 'setup-java' name: 'Step: Set Up Java and Maven' - uses: 'actions/setup-java@v4' + uses: 'actions/setup-java@v5' with: cache: 'maven' distribution: 'temurin' - java-version: '23' - mvn-toolchain-id: 'Temurin 23' + java-version: '25' + mvn-toolchain-id: 'Temurin 25' mvn-toolchain-vendor: 'openjdk' # see ../../pom.xml - id: 'mvn-verify' name: 'Step: Maven Verify' diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties index bca10a6..2079886 100644 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -1,20 +1,13 @@ -# 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 +# 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. -wrapperVersion=3.3.2 +# 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. +wrapperVersion=3.3.4 distributionType=only-script -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip - +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.12/apache-maven-3.9.12-bin.zip diff --git a/README.md b/README.md index f23c5dd..13b964d 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ dependency: org.microbean microbean-proxy - 0.0.2 + 0.0.4 ``` diff --git a/mvnw b/mvnw index 19529dd..bd8896b 100755 --- a/mvnw +++ b/mvnw @@ -19,7 +19,7 @@ # ---------------------------------------------------------------------------- # ---------------------------------------------------------------------------- -# Apache Maven Wrapper startup batch script, version 3.3.2 +# Apache Maven Wrapper startup batch script, version 3.3.4 # # Optional ENV vars # ----------------- @@ -105,14 +105,17 @@ trim() { printf "%s" "${1}" | tr -d '[:space:]' } +scriptDir="$(dirname "$0")" +scriptName="$(basename "$0")" + # parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties while IFS="=" read -r key value; do case "${key-}" in distributionUrl) distributionUrl=$(trim "${value-}") ;; distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;; esac -done <"${0%/*}/.mvn/wrapper/maven-wrapper.properties" -[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in ${0%/*}/.mvn/wrapper/maven-wrapper.properties" +done <"$scriptDir/.mvn/wrapper/maven-wrapper.properties" +[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" case "${distributionUrl##*/}" in maven-mvnd-*bin.*) @@ -130,7 +133,7 @@ maven-mvnd-*bin.*) distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip" ;; maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;; -*) MVN_CMD="mvn${0##*/mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;; +*) MVN_CMD="mvn${scriptName#mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;; esac # apply MVNW_REPOURL and calculate MAVEN_HOME @@ -227,7 +230,7 @@ if [ -n "${distributionSha256Sum-}" ]; then echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 exit 1 elif command -v sha256sum >/dev/null; then - if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c >/dev/null 2>&1; then + if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c - >/dev/null 2>&1; then distributionSha256Result=true fi elif command -v shasum >/dev/null; then @@ -252,8 +255,41 @@ if command -v unzip >/dev/null; then else tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar" fi -printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/mvnw.url" -mv -- "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME" + +# Find the actual extracted directory name (handles snapshots where filename != directory name) +actualDistributionDir="" + +# First try the expected directory name (for regular distributions) +if [ -d "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" ]; then + if [ -f "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/bin/$MVN_CMD" ]; then + actualDistributionDir="$distributionUrlNameMain" + fi +fi + +# If not found, search for any directory with the Maven executable (for snapshots) +if [ -z "$actualDistributionDir" ]; then + # enable globbing to iterate over items + set +f + for dir in "$TMP_DOWNLOAD_DIR"/*; do + if [ -d "$dir" ]; then + if [ -f "$dir/bin/$MVN_CMD" ]; then + actualDistributionDir="$(basename "$dir")" + break + fi + fi + done + set -f +fi + +if [ -z "$actualDistributionDir" ]; then + verbose "Contents of $TMP_DOWNLOAD_DIR:" + verbose "$(ls -la "$TMP_DOWNLOAD_DIR")" + die "Could not find Maven distribution directory in extracted archive" +fi + +verbose "Found extracted Maven distribution directory: $actualDistributionDir" +printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$actualDistributionDir/mvnw.url" +mv -- "$TMP_DOWNLOAD_DIR/$actualDistributionDir" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME" clean || : exec_maven "$@" diff --git a/mvnw.cmd b/mvnw.cmd index b150b91..5761d94 100644 --- a/mvnw.cmd +++ b/mvnw.cmd @@ -19,7 +19,7 @@ @REM ---------------------------------------------------------------------------- @REM ---------------------------------------------------------------------------- -@REM Apache Maven Wrapper startup batch script, version 3.3.2 +@REM Apache Maven Wrapper startup batch script, version 3.3.4 @REM @REM Optional ENV vars @REM MVNW_REPOURL - repo url base for downloading maven distribution @@ -40,7 +40,7 @@ @SET __MVNW_ARG0_NAME__= @SET MVNW_USERNAME= @SET MVNW_PASSWORD= -@IF NOT "%__MVNW_CMD__%"=="" (%__MVNW_CMD__% %*) +@IF NOT "%__MVNW_CMD__%"=="" ("%__MVNW_CMD__%" %*) @echo Cannot start maven from wrapper >&2 && exit /b 1 @GOTO :EOF : end batch / begin powershell #> @@ -73,16 +73,30 @@ switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) { # apply MVNW_REPOURL and calculate MAVEN_HOME # maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ if ($env:MVNW_REPOURL) { - $MVNW_REPO_PATTERN = if ($USE_MVND) { "/org/apache/maven/" } else { "/maven/mvnd/" } - $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')" + $MVNW_REPO_PATTERN = if ($USE_MVND -eq $False) { "/org/apache/maven/" } else { "/maven/mvnd/" } + $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace "^.*$MVNW_REPO_PATTERN",'')" } $distributionUrlName = $distributionUrl -replace '^.*/','' $distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$','' -$MAVEN_HOME_PARENT = "$HOME/.m2/wrapper/dists/$distributionUrlNameMain" + +$MAVEN_M2_PATH = "$HOME/.m2" if ($env:MAVEN_USER_HOME) { - $MAVEN_HOME_PARENT = "$env:MAVEN_USER_HOME/wrapper/dists/$distributionUrlNameMain" + $MAVEN_M2_PATH = "$env:MAVEN_USER_HOME" +} + +if (-not (Test-Path -Path $MAVEN_M2_PATH)) { + New-Item -Path $MAVEN_M2_PATH -ItemType Directory | Out-Null +} + +$MAVEN_WRAPPER_DISTS = $null +if ((Get-Item $MAVEN_M2_PATH).Target[0] -eq $null) { + $MAVEN_WRAPPER_DISTS = "$MAVEN_M2_PATH/wrapper/dists" +} else { + $MAVEN_WRAPPER_DISTS = (Get-Item $MAVEN_M2_PATH).Target[0] + "/wrapper/dists" } -$MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join '' + +$MAVEN_HOME_PARENT = "$MAVEN_WRAPPER_DISTS/$distributionUrlNameMain" +$MAVEN_HOME_NAME = ([System.Security.Cryptography.SHA256]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join '' $MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME" if (Test-Path -Path "$MAVEN_HOME" -PathType Container) { @@ -134,7 +148,33 @@ if ($distributionSha256Sum) { # unzip and move Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null -Rename-Item -Path "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" -NewName $MAVEN_HOME_NAME | Out-Null + +# Find the actual extracted directory name (handles snapshots where filename != directory name) +$actualDistributionDir = "" + +# First try the expected directory name (for regular distributions) +$expectedPath = Join-Path "$TMP_DOWNLOAD_DIR" "$distributionUrlNameMain" +$expectedMvnPath = Join-Path "$expectedPath" "bin/$MVN_CMD" +if ((Test-Path -Path $expectedPath -PathType Container) -and (Test-Path -Path $expectedMvnPath -PathType Leaf)) { + $actualDistributionDir = $distributionUrlNameMain +} + +# If not found, search for any directory with the Maven executable (for snapshots) +if (!$actualDistributionDir) { + Get-ChildItem -Path "$TMP_DOWNLOAD_DIR" -Directory | ForEach-Object { + $testPath = Join-Path $_.FullName "bin/$MVN_CMD" + if (Test-Path -Path $testPath -PathType Leaf) { + $actualDistributionDir = $_.Name + } + } +} + +if (!$actualDistributionDir) { + Write-Error "Could not find Maven distribution directory in extracted archive" +} + +Write-Verbose "Found extracted Maven distribution directory: $actualDistributionDir" +Rename-Item -Path "$TMP_DOWNLOAD_DIR/$actualDistributionDir" -NewName $MAVEN_HOME_NAME | Out-Null try { Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null } catch { diff --git a/pom.xml b/pom.xml index a4cc04e..c04dda6 100644 --- a/pom.xml +++ b/pom.xml @@ -89,7 +89,6 @@ deployment [maven-release-plugin] [skip ci] v@{project.version} - false @@ -101,12 +100,8 @@ true false - - - true - - https://oss.sonatype.org/ - 10 + + ${project.name} v${project.version} UTF8 @@ -125,7 +120,7 @@ org.junit junit-bom - 5.12.2 + 6.0.1 pom import @@ -135,19 +130,19 @@ org.microbean microbean-attributes - 0.0.2 + 0.0.5 org.microbean microbean-bean - 0.0.18 + 0.0.22 org.microbean microbean-construct - 0.0.10 + 0.0.18 @@ -194,11 +189,11 @@ maven-antrun-plugin - 3.1.0 + 3.2.0 maven-assembly-plugin - 3.7.1 + 3.8.0 maven-checkstyle-plugin @@ -308,13 +303,13 @@ com.puppycrawl.tools checkstyle - 10.23.1 + 12.3.0 maven-clean-plugin - 3.4.1 + 3.5.0 @@ -329,7 +324,7 @@ maven-compiler-plugin - 3.14.0 + 3.14.1 -Xlint:all @@ -339,7 +334,7 @@ maven-dependency-plugin - 3.8.1 + 3.9.0 maven-deploy-plugin @@ -347,12 +342,11 @@ maven-enforcer-plugin - 3.5.0 + 3.6.2 maven-gpg-plugin - - 3.2.7 + 3.2.8 maven-install-plugin @@ -360,11 +354,11 @@ maven-jar-plugin - 3.4.2 + 3.5.0 maven-javadoc-plugin - 3.11.2 + 3.12.0 true @@ -396,16 +390,15 @@ maven-release-plugin - - 3.1.1 + 3.3.1 maven-resources-plugin - 3.3.1 + 3.4.0 maven-scm-plugin - 2.1.0 + 2.2.1 maven-scm-publish-plugin @@ -417,7 +410,7 @@ maven-source-plugin - 3.3.1 + 3.4.0 attach-sources @@ -429,7 +422,7 @@ maven-surefire-plugin - 3.5.3 + 3.5.4 maven-toolchains-plugin @@ -438,35 +431,25 @@ com.github.spotbugs spotbugs-maven-plugin - 4.9.3.0 + 4.9.8.2 org.codehaus.mojo versions-maven-plugin - 2.18.0 + 2.20.1 io.smallrye jandex-maven-plugin - 3.3.0 + 3.5.3 - org.sonatype.plugins - nexus-staging-maven-plugin - 1.6.13 + org.sonatype.central + central-publishing-maven-plugin + 0.9.0 true - - - - com.thoughtworks.xstream - xstream - 1.4.20 - - - sonatype-oss-repository-hosting - ${nexusUrl} - ${autoReleaseAfterClose} + central.sonatype.com @@ -487,7 +470,7 @@ 23 - 3.9.9 + 3.9.12 @@ -512,8 +495,8 @@ - org.sonatype.plugins - nexus-staging-maven-plugin + org.sonatype.central + central-publishing-maven-plugin diff --git a/src/main/java/org/microbean/proxy/AbstractProxier.java.bak b/src/main/java/org/microbean/proxy/AbstractProxier.java.bak deleted file mode 100644 index 73a392f..0000000 --- a/src/main/java/org/microbean/proxy/AbstractProxier.java.bak +++ /dev/null @@ -1,300 +0,0 @@ -/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*- - * - * Copyright © 2025 microBean™. - * - * 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 - * - * 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.microbean.proxy; - -import java.lang.invoke.MethodHandles.Lookup; - -import java.lang.System.Logger; - -import java.util.Objects; - -import java.util.function.Supplier; - -import javax.lang.model.element.TypeElement; - -import org.microbean.construct.Domain; - -import static java.lang.System.getLogger; -import static java.lang.System.Logger.Level.DEBUG; - -/** - * An abstract base class for classes that create {@linkplain Proxy proxies}. - * - *

Implementations will call the methods in this class to help with the common aspects involved with proxy creation - * of all kinds.

- * - * @param the {@link ProxySpecification} type - * - * @param the type of descriptor this implementation uses to represent (normally unloaded) generated classes - * - * @author Laird Nelson - * - * @see #proxyClass(ProxySpecification) - */ -// : the type of descriptor the underlying mechanism uses to represent (normally unloaded) generated classes; -// ByteBuddy uses DynamicType.Unloaded; Red Hat projects use ClassFile or something like it, ReflectiveClientProxier -// uses Class, and so on -public abstract class AbstractProxier { - - - /* - * Static fields. - */ - - - private static final Logger LOGGER = getLogger(AbstractProxier.class.getName()); - - - /* - * Instance fields. - */ - - - private final Domain domain; - - - /* - * Constructors. - */ - - - /** - * Creates a new {@link AbstractProxier}. - * - * @param domain a {@link Domain}; must not be {@code null} - * - * @exception NullPointerException if {@code domain} is {@code null} - */ - protected AbstractProxier(final Domain domain) { - super(); - this.domain = Objects.requireNonNull(domain, "domain"); - } - - - /* - * Instance methods. - */ - - - /** - * Given a {@link TypeElement} that {@linkplain javax.lang.model.element.ElementKind#isDeclaredType() is a declared - * type}, returns a {@link ClassLoader} suitable for eventually transforming it into a {@link Class}. - * - *

The default implementation of this method returns the {@linkplain Thread#getContextClassLoader() context - * classloader}.

- * - * @param e a {@link TypeElement}; must not be {@code null}; must be a {@linkplain - * javax.lang.model.element.ElementKind#isDeclaredType() declared type} - * - * @return a non-{@code null} {@link ClassLoader} - * - * @exception NullPointerException if {@code e} is {@code null} - * - * @exception IllegalArgumentException if {@code e} {@linkplain javax.lang.model.element.ElementKind#isDeclaredType() - * is not a declared type} - */ - protected ClassLoader classLoader(final TypeElement e) { - if (!e.getKind().isDeclaredType()) { - throw new IllegalArgumentException("e: " + e); - } - return Thread.currentThread().getContextClassLoader(); - } - - /** - * Returns the {@link Domain} {@linkplain #AbstractProxier(Domain) supplied at construction time}. - * - * @return a non-{@code null} {@link Domain} - * - * @see #AbstractProxier(Domain) - */ - protected final Domain domain() { - return this.domain; - } - - /** - * Creates a generated class definition from the information present in the supplied {@link ProxySpecification}, and - * returns it for eventual supplying to an inovcation of the {@link #proxyClass(Object, ClassLoader)} method (optional - * operation). - * - *

The default implementation of this method throws an {@link UnsupportedOperationException}.

- * - * @param ps a {@link ProxySpecification}; must not be {@code null} - * - * @return a non-{@code null} generated class definition - * - * @exception NullPointerException if {@code ps} is {@code null} - * - * @exception UnsupportedOperationException if this operation is unsupported - * - * @exception Throwable if creation of the generated class definition fails - * - * @see #proxyClass(Object, ClassLoader) - */ - protected T generate(final PS ps) throws Throwable { - throw new UnsupportedOperationException(); - } - - /** - * Creates a new instance of a {@link Proxy Proxy<R>} that proxies contextual instances supplied by - * the supplied {@code instanceSupplier}, and returns it (optional operation). - * - * @param the type of contextual instance being proxied - * - * @param ps a {@link ProxySpecification}; must not be {@code null} - * - * @param instanceSupplier a {@link Supplier} of contextual instances of the {@code } type; must not be {@code null} - * - * @return a non-{@code null} {@link Proxy Proxy<R>} - * - * @exception NullPointerException if any argument is {@code null} - * - * @exception UnsupportedOperationException if this operation is unsupported - * - * @exception Throwable if instantiation fails - * - * @see #proxyClass(Object, ClassLoader) - * - * @see #instantiate(Class, Supplier) - */ - protected abstract Proxy instantiate(final PS ps, final Supplier instanceSupplier) - throws Throwable; - - /** - * Creates a new instance of the supplied {@code proxyClass} that proxies contextual instances supplied by the - * supplied {@code instanceSupplier} (optional operation). - * - * @param the type of contextual instance being proxied - * - * @param proxyClass a {@link Class} {@linkplain Class#isAssignableFrom(Class) assignable to} {@link Proxy - * Proxy.class} and {@linkplain Proxy#$cast() castable to} the {@code R} type; must not be {@code null} - * - * @param instanceSupplier a {@link Supplier} of contextual instances of the {@code R} type; must not be {@code - * null} - * - * @return a non-{@code null} {@link Proxy Proxy<R>} - * - * @exception NullPointerException if any argument is {@code null} - * - * @exception UnsupportedOperationException if this operation is unsupported - * - * @exception Throwable if instantiation fails - */ - protected abstract Proxy instantiate(final Class proxyClass, final Supplier instanceSupplier) - throws Throwable; - - /** - * Returns a {@link Lookup} suitable for the supplied {@link Class}. - * - * @param c a {@link Class}; must not be {@code null} - * - * @return a {@link Lookup}; never {@code null} - * - * @exception NullPointerException if {@code c} is {@code null} - * - * @see java.lang.invoke.MethodHandles#lookup() - * - * @see Lookup#in(Class) - * - * @see java.lang.invoke.MethodHandles#privateLookupIn(Class, Lookup) - */ - protected abstract Lookup lookup(final Class c); - - /** - * Loads and returns a proxy class corresponding to the supplied {@link ProxySpecification}, using the - * {@link #generate(ProxySpecification)} and {@link #proxyClass(Object, ClassLoader)} methods to assist. - * - * @param ps a {@link ProxySpecification}; must not be {@code null} - * - * @return a {@link Class} {@linkplain Class#isAssignableFrom(Class) assignable to} {@link Proxy Proxy.class} and - * {@linkplain Proxy#$cast() castable to} the {@code R} type; must not be {@code null} - * - * @exception NullPointerException if {@code ps} is {@code null} - * - * @exception ClassNotFoundException if the proxy class could not be loaded - * - * @see #generate(ProxySpecification) - * - * @see #proxyClass(Object, ClassLoader) - * - * @see #classLoader(TypeElement) - */ - protected final Class proxyClass(final PS ps) throws ClassNotFoundException { - final String name = ps.name(); - final ClassLoader cl = this.classLoader((TypeElement)ps.superclass().asElement()); - Class pc; - try { - pc = cl.loadClass(name); - } catch (ClassNotFoundException primaryLoadException) { - try { - pc = this.proxyClass(this.generate(ps), cl); - if (pc == null) { - primaryLoadException = new ClassNotFoundException(name + "; proxyClass(generate(" + ps + "), " + cl + " == null"); - throw primaryLoadException; - } - if (LOGGER.isLoggable(DEBUG)) { - LOGGER.log(DEBUG, "Proxy class generated because it was not initially found", primaryLoadException); - } - } catch (final ClassNotFoundException | RuntimeException generationException) { - try { - // We try again; generation may have failed because of a race condition defining a class in the - // classloader. This will probably fail 99.9% of the time. - pc = cl.loadClass(name); - } catch (final ClassNotFoundException secondaryLoadException) { - generationException.addSuppressed(primaryLoadException); - secondaryLoadException.addSuppressed(generationException); - throw secondaryLoadException; - } catch (final Error e) { - e.addSuppressed(generationException); - throw e; - } catch (final Throwable wtf) { - generationException.addSuppressed(wtf); - throw generationException; - } - } catch (final Error e) { - e.addSuppressed(primaryLoadException); - throw e; - } catch (final Throwable wtf) { - primaryLoadException.addSuppressed(wtf); - throw primaryLoadException; - } - } - return pc; - } - - /** - * Called by the {@link #proxyClass(ProxySpecification)} method, converts the supplied class definition into a {@link - * Class}, using the supplied {@link ClassLoader}, and returns it (optional operation). - * - *

Overrides of this method must not call the {@link #proxyClass(ProxySpecification)} method or undefined behavior - * may result.

- * - * @param t a class definition; must not be {@code null} - * - * @param cl a {@link ClassLoader}; must not be {@code null} - * - * @return a non-{@code null} {@link Class} - * - * @exception NullPointerException if any argument is {@code null} - * - * @exception UnsupportedOperationException if class generation is not supported by this {@link AbstractProxier} - * - * @exception ClassNotFoundException if an invocation of {@link ClassLoader#loadClass(String)} fails - * - * @see #proxyClass(ProxySpecification) - */ - // Turns a T into a Class (loads it) using a ClassLoader. For reflection-based implementations, t may already be a - // Class. - protected abstract Class proxyClass(final T t, final ClassLoader cl) throws ClassNotFoundException; - -} diff --git a/src/main/java/org/microbean/proxy/AbstractReflectiveProxier.java b/src/main/java/org/microbean/proxy/AbstractReflectiveProxier.java index 93dbf67..b2d67b1 100644 --- a/src/main/java/org/microbean/proxy/AbstractReflectiveProxier.java +++ b/src/main/java/org/microbean/proxy/AbstractReflectiveProxier.java @@ -35,8 +35,6 @@ import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; -import java.util.function.Supplier; - import org.microbean.construct.Domain; /** @@ -51,10 +49,6 @@ * @author Laird Nelson * * @see #proxy(ProxySpecification, Supplier) - * - * @see #type(Type) - * - * @see #executableElement(Executable) */ public abstract non-sealed class AbstractReflectiveProxier extends AbstractProxier { @@ -72,7 +66,7 @@ protected AbstractReflectiveProxier(final Domain domain) { } /** - * Returns {@code true} if the supplied {@link Method} is the {@link Object#equals(Object) + * A convenience method that returns {@code true} if the supplied {@link Method} is the {@link Object#equals(Object) * java.lang.Object#equals(java.lang.Object)} method. * * @param m a {@link Method}; must not be {@code null} @@ -82,6 +76,7 @@ protected AbstractReflectiveProxier(final Domain domain) { * * @exception NullPointerException if {@code m} is {@code null} */ + // (Convenience.) protected final boolean equalsMethod(final Method m) { return m.getDeclaringClass() == Object.class && @@ -92,37 +87,8 @@ protected final boolean equalsMethod(final Method m) { } /** - * Returns an {@link ExecutableElement} corresponding to the supplied {@link Executable}. - * - * @param e an {@link Executable}; must not be {@code null} - * - * @return an {@link ExecutableElement} corresponding to the supplied {@link Executable}; never {@code null} - * - * @exception NullPointerException if {@code e} is {@code null} - * - * @exception IllegalArgumentException if somehow {@code e} is neither a {@link Constructor} nor a {@link Method} - */ - protected final ExecutableElement executableElement(final Executable e) { - final Domain domain = domain(); - return switch (e) { - case null -> throw new NullPointerException("e"); - case Constructor c -> - domain.executableElement(domain.typeElement(c.getDeclaringClass().getCanonicalName()), - domain.noType(TypeKind.VOID), - "", - this.types(c.getParameterTypes())); - case Method m -> - domain.executableElement(domain.typeElement(m.getDeclaringClass().getCanonicalName()), - this.type(m.getReturnType()), - m.getName(), - this.types(m.getParameterTypes())); - default -> throw new IllegalArgumentException("e: " + e); - }; - } - - /** - * Returns {@code true} if the supplied {@link Method} is the {@link Object#hashCode() java.lang.Object#hashCode()} - * method. + * A convenience method that returns {@code true} if the supplied {@link Method} is the {@link Object#hashCode() + * java.lang.Object#hashCode()} method. * * @param m a {@link Method}; must not be {@code null} * @@ -131,6 +97,7 @@ protected final ExecutableElement executableElement(final Executable e) { * * @exception NullPointerException if {@code m} is {@code null} */ + // (Convenience.) protected final boolean hashCodeMethod(final Method m) { return m.getDeclaringClass() == Object.class && @@ -139,27 +106,6 @@ protected final boolean hashCodeMethod(final Method m) { m.getName().equals("hashCode"); } - /** - * Returns a {@link Parameterizable} corresponding to the supplied {@link GenericDeclaration}. - * - * @param gd a {@link GenericDeclaration}; must not be {@code null} - * - * @return a {@link Parameterizable} corresponding to the supplied {@link GenericDeclaration}; never {@code null} - * - * @exception NullPointerException if {@code gd} is {@code null} - * - * @exception IllegalArgumentException if {@code gd} is neither a {@link Class} nor an {@link Executable} - */ - protected final Parameterizable parameterizable(final GenericDeclaration gd) { - final Domain domain = this.domain(); - return switch (gd) { - case null -> throw new NullPointerException("gd"); - case Class c -> domain.typeElement(c.getCanonicalName()); - case Executable e -> this.executableElement(e); - default -> throw new IllegalArgumentException("gd: " + gd); - }; - } - /** * Returns a {@link Proxy} appropriate for the supplied specification and {@link Supplier} of instances. * @@ -223,79 +169,4 @@ protected abstract Proxy proxy(final PS ps, final Class[] interfaces, final Supplier instanceSupplier); - /** - * Returns the {@link TypeMirror} corresponding to the supplied {@link Type}. - * - * @param t a {@link Type}; must not be {@code null} - * - * @return the {@link TypeMirror} corresponding to the supplied {@link Type}; never {@code null} - * - * @exception NullPointerException if {@code t} is {@code null} - * - * @exception IllegalArgumentException if {@code t} is not a {@link Class}, {@link GenericArrayType}, {@link - * ParameterizedType}, {@link TypeVariable} or {@link WildcardType} - */ - protected final TypeMirror type(final Type t) { - // TODO: anywhere there is domain.declaredType(), consider passing - // domain.moduleElement(this.getClass().getModule().getName()) as the first argument. Not sure how this works - // exactly but I think it might be necessary. - final Domain domain = this.domain(); - return switch (t) { - case null -> throw new NullPointerException("t"); - case Class c when t == boolean.class -> domain.primitiveType(TypeKind.BOOLEAN); - case Class c when t == byte.class -> domain.primitiveType(TypeKind.BYTE); - case Class c when t == char.class -> domain.primitiveType(TypeKind.CHAR); - case Class c when t == double.class -> domain.primitiveType(TypeKind.DOUBLE); - case Class c when t == float.class -> domain.primitiveType(TypeKind.FLOAT); - case Class c when t == int.class -> domain.primitiveType(TypeKind.INT); - case Class c when t == long.class -> domain.primitiveType(TypeKind.LONG); - case Class c when t == short.class -> domain.primitiveType(TypeKind.SHORT); - case Class c when t == void.class -> domain.noType(TypeKind.VOID); - case Class c when t == Object.class -> domain.javaLangObject().asType(); // cheap and easy optimization - case Class c when c.isArray() -> domain.arrayTypeOf(this.type(c.getComponentType())); - case Class c -> domain.declaredType(c.getCanonicalName()); - case GenericArrayType g -> domain.arrayTypeOf(this.type(g.getGenericComponentType())); - case ParameterizedType pt when pt.getOwnerType() == null -> - domain.declaredType(domain.typeElement(((Class)pt.getRawType()).getCanonicalName()), - this.types(pt.getActualTypeArguments())); - case ParameterizedType pt -> - domain.declaredType((DeclaredType)this.type(pt.getOwnerType()), - domain.typeElement(((Class)pt.getRawType()).getCanonicalName()), - this.types(pt.getActualTypeArguments())); - case TypeVariable tv -> domain.typeVariable(this.parameterizable(tv.getGenericDeclaration()), tv.getName()); - case WildcardType w when w.getLowerBounds().length <= 0 -> domain.wildcardType(this.type(w.getUpperBounds()[0]), null); - case WildcardType w -> domain.wildcardType(null, this.type(w.getLowerBounds()[0])); - default -> throw new IllegalArgumentException("t: " + t); - }; - } - - /** - * Returns an array of {@link TypeMirror}s whose elements correspond to the elements in the supplied {@link Type} array. - * - * @param ts an array of {@link Type}s; must not be {@code null} - * - * @return an array of {@link TypeMirror}s whose elements correspond to the elements in the supplied {@link Type} - * array; never {@code null} - * - * @exception NullPointerException if {@code ts} is {@code null} or contains {@code null} elements - * - * @exception IllegalArgumentException if any element of {@code ts} is deemed illegal by the {@link #type(Type)} - * method - * - * @see #type(Type) - */ - protected final TypeMirror[] types(final Type[] ts) { - if (ts.length <= 0) { - return EMPTY_TYPE_MIRROR_ARRAY; - } else if (ts.length == 1) { - // cheap and easy optimization - return new TypeMirror[] { type(ts[0]) }; - } - final TypeMirror[] rv = new TypeMirror[ts.length]; - for (int i = 0; i < ts.length; i++) { - rv[i] = type(ts[i]); - } - return rv; - } - } diff --git a/src/main/java/org/microbean/proxy/AbstractToolkitProxier.java b/src/main/java/org/microbean/proxy/AbstractToolkitProxier.java index 8f04887..9e960e9 100644 --- a/src/main/java/org/microbean/proxy/AbstractToolkitProxier.java +++ b/src/main/java/org/microbean/proxy/AbstractToolkitProxier.java @@ -18,8 +18,6 @@ import java.lang.System.Logger; -import java.util.Objects; - import java.util.function.Supplier; import org.microbean.construct.Domain; @@ -28,6 +26,8 @@ import static java.lang.System.Logger.Level.DEBUG; +import static java.util.Objects.requireNonNull; + /** * An {@link AbstractProxier} built using some kind of toolkit, such as Byte Buddy and the like. @@ -58,7 +58,7 @@ public abstract non-sealed class AbstractToolkitProxier interfaces; private final List attributes; - + private final String name; @@ -81,17 +82,16 @@ public ProxySpecification(final Domain domain, final Id id) { this.attributes = id.attributes(); final BeanTypeList types = id.types(); final TypeMirror t = types.get(0); // putative superclass - if (t.getKind() != TypeKind.DECLARED || domain.javaLangObject(t) && types.size() == 1) { + if (t.getKind() != DECLARED || domain.javaLangObject(t) && types.size() == 1) { throw new IllegalArgumentException("id: " + id); - } else if (((DeclaredType)t).asElement().getKind() == ElementKind.INTERFACE) { + } else if (((DeclaredType)t).asElement().getKind() == INTERFACE) { this.sc = (DeclaredType)domain.javaLangObject().asType(); this.interfaces = types; } else if (!proxiableBeanType(t)) { throw new IllegalArgumentException("id: " + id); } else { this.sc = (DeclaredType)t; - final int interfaceIndex = types.interfaceIndex(); - this.interfaces = interfaceIndex < 0 ? List.of() : types.subList(interfaceIndex, types.size()); + this.interfaces = types.interfaces(); } this.name = computeName(domain, this.sc, this.interfaces); } @@ -187,7 +187,7 @@ static final String computeName(final Domain domain, final DeclaredType supercla // TODO: there will absolutely be edge cases here and we know this is not complete. - if (superclass.getKind() != TypeKind.DECLARED) { + if (superclass.getKind() != DECLARED) { throw new IllegalArgumentException("superclass: " + superclass); } final DeclaredType proxyClassSibling; @@ -197,7 +197,7 @@ static final String computeName(final Domain domain, final DeclaredType supercla } // Interface-only. There will be at least one and it will be the most specialized. proxyClassSibling = (DeclaredType)interfaces.get(0); - if (proxyClassSibling.getKind() != TypeKind.DECLARED) { + if (proxyClassSibling.getKind() != DECLARED) { throw new IllegalArgumentException("interfaces: " + interfaces); } } else {