diff --git a/.github/workflows/mvn-release-prepare-perform.yaml b/.github/workflows/mvn-release-prepare-perform.yaml index c858555..3a93fc1 100644 --- a/.github/workflows/mvn-release-prepare-perform.yaml +++ b/.github/workflows/mvn-release-prepare-perform.yaml @@ -24,24 +24,24 @@ 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' gpg-passphrase: 'GPG_PASSPHRASE' gpg-private-key: '${{ secrets.GPG_PRIVATE_KEY }}' - java-version: '23' - mvn-toolchain-id: 'Temurin 23' + java-version: '25' + mvn-toolchain-id: 'Temurin 25' mvn-toolchain-vendor: 'openjdk' # see ../../pom.xml - server-id: 'sonatype-oss-repository-hosting' # see https://github.com/microbean/microbean-parent/blob/master/pom.xml#L38 - server-password: 'SONATYPE_OSSRH_PASSWORD' - server-username: 'SONATYPE_OSSRH_USERNAME' + server-id: 'central.sonatype.com' + server-password: 'CENTRAL_SONATYPE_COM_PASSWORD' + server-username: 'CENTRAL_SONATYPE_COM_USERNAME' - id: 'setup-askpass' name: 'Step: Set Up GIT_ASKPASS' run: | @@ -58,6 +58,8 @@ jobs: - id: 'mvn-release-prepare' name: 'Step: Maven Release: Prepare, Perform and Publish Site' env: + CENTRAL_SONATYPE_COM_PASSWORD: '${{ secrets.CENTRAL_SONATYPE_COM_PASSWORD }}' + CENTRAL_SONATYPE_COM_USERNAME: '${{ secrets.CENTRAL_SONATYPE_COM_USERNAME }}' DRY_RUN: '${{ inputs.dryRun }}' GIT_ASKPASS: '${{ runner.temp }}/.askpass' GPG_PASSPHRASE: '${{ secrets.GPG_PASSPHRASE }}' @@ -65,9 +67,6 @@ jobs: MVN_TRANSFER_LOGGING: ${{ inputs.mvnTransferLogging && '' || '--no-transfer-progress' }} PUSH_TOKEN : '${{ secrets.PUSH_TOKEN }}' # critical; see ${GIT_ASKPASS} file SCM_GIT_HTTPS_URL: 'scm:git:${{ github.server_url }}/${{ github.repository }}.git' - SONATYPE_OSSRH_PASSWORD: '${{ secrets.SONATYPE_OSSRH_PASSWORD }}' - SONATYPE_OSSRH_STAGING_PROFILE_ID: '${{ vars.SONATYPE_OSSRH_STAGING_PROFILE_ID }}' - SONATYPE_OSSRH_USERNAME: '${{ secrets.SONATYPE_OSSRH_USERNAME }}' shell: 'bash -e {0}' run: > git config --global user.email 'ci@microbean.org' @@ -75,12 +74,12 @@ jobs: git config --global user.name 'microbean' echo "::group::Running mvn prepare" - + ./mvnw --batch-mode ${MVN_DEBUG} --errors ${MVN_TRANSFER_LOGGING} release:prepare -DdryRun="${DRY_RUN}" -Darguments="${MVN_TRANSFER_LOGGING}" -Dscm.url="${SCM_GIT_HTTPS_URL}" - + scm_tag="$(grep '^scm.tag=' release.properties | cut -f 2 -d =)" echo "Prepared ${scm_tag}" >> "${GITHUB_STEP_SUMMARY}" @@ -90,37 +89,13 @@ jobs: echo "::endgroup::" echo "::group::Running mvn perform" - - set +e - { ./mvnw --batch-mode ${MVN_DEBUG} --errors ${MVN_TRANSFER_LOGGING} release:perform - -Darguments="${MVN_TRANSFER_LOGGING} -Dscmpublish.dryRun=${DRY_RUN} -Dscmpublish.pubScmUrl=${SCM_GIT_HTTPS_URL} -DskipTests -DstagingProfileId=${SONATYPE_OSSRH_STAGING_PROFILE_ID}" + -Darguments="${MVN_TRANSFER_LOGGING} -Dscmpublish.dryRun=${DRY_RUN} -Dscmpublish.pubScmUrl=${SCM_GIT_HTTPS_URL} -DskipTests -DautoPublish=true -DwaitUntil=published -DwaitMaxTime=3600" -DdryRun="${DRY_RUN}" -Dgoals="process-classes,post-site,scm-publish:publish-scm,deploy" -Dscm.url="${SCM_GIT_HTTPS_URL}" - | - tee /dev/fd/3 - | - grep --invert-match --silent 'Java class com.sonatype.nexus.staging.api.dto.StagingProfileRepositoryDTO' || cat > /dev/null - ; - } - 3>&1 - exit_codes=(${PIPESTATUS[@]}) + echo "Released ${scm_tag} successfully" >> "${GITHUB_STEP_SUMMARY}"; echo "::endgroup::" - - set -e - - if [ "${exit_codes[2]}" -ne 0 ] ; then - # grep "failed" (found com.sonatype.nexus.staging.api.dto.StagingProfileRepositoryDTO) and mvn failed - echo "Released ${scm_tag} successfully, but verify that the staging repository was successfully released" >> "${GITHUB_STEP_SUMMARY}"; - # Treat this as a successful run - exit 0; - elif [ "${exit_codes[0]}" -eq 0 ] ; then - # mvn succeeded and grep "succeeded" (did not find com.sonatype.nexus.staging.api.dto.StagingProfileRepositoryDTO) - echo "Released ${scm_tag} successfully" >> "${GITHUB_STEP_SUMMARY}"; - fi - - exit "${exit_codes[0]}" 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..c652895 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 3c55857..d8e8472 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ Client Proxy: Byte Buddy as a Maven dependency: org.microbean microbean-clientproxy-bytebuddy - 0.0.1 + 0.0.2 ``` 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 7c5979f..7e62158 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.1 + 6.0.1 pom import @@ -135,33 +130,51 @@ net.bytebuddy byte-buddy - 1.17.3 + 1.18.3 + + + + org.microbean + microbean-assign + 0.0.11 org.microbean microbean-bean - 0.0.16 + 0.0.22 org.microbean microbean-construct - 0.0.10 + 0.0.18 + + + + org.microbean + microbean-producer + 0.0.3 + + + + org.microbean + microbean-proxy + 0.0.5 org.microbean microbean-reference - 0.0.2 + 0.0.5 org.microbean microbean-scopelet - 0.0.7 + 0.0.11 - + @@ -173,6 +186,12 @@ compile + + org.microbean + microbean-assign + compile + + org.microbean microbean-bean @@ -185,6 +204,12 @@ compile + + org.microbean + microbean-proxy + compile + + org.microbean microbean-reference @@ -205,12 +230,18 @@ test + + org.microbean + microbean-producer + test + + org.microbean microbean-scopelet test - + @@ -218,11 +249,11 @@ maven-antrun-plugin - 3.1.0 + 3.2.0 maven-assembly-plugin - 3.7.1 + 3.8.0 maven-checkstyle-plugin @@ -332,13 +363,13 @@ com.puppycrawl.tools checkstyle - 10.12.6 + 12.3.0 maven-clean-plugin - 3.4.0 + 3.5.0 @@ -353,49 +384,42 @@ maven-compiler-plugin - 3.13.0 + 3.14.1 -Xlint:all -parameters - - - org.codehaus.plexus - plexus-java - 1.3.0 - - maven-dependency-plugin - 3.8.1 + 3.9.0 maven-deploy-plugin - 3.1.3 + 3.1.4 maven-enforcer-plugin - 3.5.0 + 3.6.2 maven-gpg-plugin - 3.2.7 + 3.2.8 maven-install-plugin - 3.1.3 + 3.1.4 maven-jar-plugin - 3.4.2 + 3.5.0 maven-javadoc-plugin - 3.11.2 + 3.12.0 true @@ -423,20 +447,19 @@ maven-project-info-reports-plugin - 3.8.0 + 3.9.0 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 @@ -448,7 +471,7 @@ maven-source-plugin - 3.3.1 + 3.4.0 attach-sources @@ -460,7 +483,7 @@ maven-surefire-plugin - 3.5.2 + 3.5.4 -XX:StartFlightRecording=duration=10s,filename=${project.build.directory}/recording.jfr @@ -472,35 +495,25 @@ com.github.spotbugs spotbugs-maven-plugin - 4.8.6.6 + 4.9.8.2 org.codehaus.mojo versions-maven-plugin - 2.18.0 + 2.20.1 io.smallrye jandex-maven-plugin - 3.2.3 + 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 @@ -521,7 +534,7 @@ 23 - 3.9.9 + 3.9.12 @@ -546,8 +559,8 @@ - org.sonatype.plugins - nexus-staging-maven-plugin + org.sonatype.central + central-publishing-maven-plugin diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 6959a7b..de403a9 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -13,7 +13,7 @@ */ /** - * Provides packages related to implementing {@linkplain org.microbean.reference.ClientProxy client proxies} + * Provides packages related to implementing {@linkplain org.microbean.proxy.Proxy client proxies} * using Byte Buddy. * * @author Laird Nelson @@ -23,9 +23,10 @@ exports org.microbean.clientproxy.bytebuddy; requires transitive net.bytebuddy; - + requires org.microbean.assign; requires transitive org.microbean.bean; - requires transitive org.microbean.construct; + requires org.microbean.construct; + requires transitive org.microbean.proxy; requires transitive org.microbean.reference; } diff --git a/src/main/java/org/microbean/clientproxy/bytebuddy/BBClientProxier.java b/src/main/java/org/microbean/clientproxy/bytebuddy/BBClientProxier.java index b5e97b7..157c668 100644 --- a/src/main/java/org/microbean/clientproxy/bytebuddy/BBClientProxier.java +++ b/src/main/java/org/microbean/clientproxy/bytebuddy/BBClientProxier.java @@ -16,35 +16,49 @@ import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles.Lookup; +import java.util.Map; import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; + +import java.util.function.Supplier; + import net.bytebuddy.dynamic.DynamicType; import net.bytebuddy.dynamic.loading.ClassLoadingStrategy; import net.bytebuddy.pool.TypePool; +import org.microbean.bean.Id; + import org.microbean.construct.Domain; -import org.microbean.reference.AbstractClientProxier; -import org.microbean.reference.ProxySpecification; +import org.microbean.proxy.AbstractToolkitProxier; +import org.microbean.proxy.Proxy; +import org.microbean.proxy.ProxySpecification; + +import org.microbean.reference.ClientProxier; +import org.microbean.reference.ReferenceException; + +import static java.lang.invoke.MethodType.methodType; /** - * An {@link AbstractClientProxier} that uses Byte Buddy to {@linkplain - * #generate(ProxySpecification) generate} {@linkplain org.microbean.reference.ClientProxy client proxies}. + * An {@link AbstractToolkitProxier} and {@link ClientProxier} that uses Byte + * Buddy to {@linkplain #generate(ProxySpecification) generate} {@linkplain org.microbean.proxy.Proxy client + * proxies}. * * @author Laird Nelson * * @see BBClientProxyClassGenerator */ -public final class BBClientProxier extends AbstractClientProxier> { +public final class BBClientProxier extends AbstractToolkitProxier> implements ClientProxier { + private static final Map clientProxyInstances = new ConcurrentHashMap<>(); + private final TypeDefinitions tds; private final BBClientProxyClassGenerator g; - private static final Lookup lookup = MethodHandles.lookup(); // or instance variable? - /** * Creates a new {@link BBClientProxier}. * @@ -94,11 +108,16 @@ public BBClientProxier(final Domain domain, public BBClientProxier(final Domain domain, final TypeDefinitions tds, final BBClientProxyClassGenerator g) { - super(domain); + super(domain, MethodHandles.lookup()); this.tds = Objects.requireNonNull(tds, "tds"); this.g = Objects.requireNonNull(g, "g"); } + @Override // ClientProxier + public R clientProxy(final Id id, final Supplier instanceSupplier) { + return this.proxy(new ProxySpecification(this.domain(), id), instanceSupplier).$cast(); + } + @Override // AbstractClientProxier> protected final DynamicType.Unloaded generate(final ProxySpecification ps) { return @@ -107,8 +126,28 @@ protected final DynamicType.Unloaded generate(final ProxySpecification ps) { ps.interfaces().stream().map(this.tds::typeDescriptionGeneric).toList()); } + @Override // AbstractToolkitProxier> + @SuppressWarnings("unchecked") + public final Proxy proxy(final ProxySpecification ps, final Supplier instanceSupplier) { + return (Proxy)clientProxyInstances.computeIfAbsent(ps, ps0 -> { + try { + final Class proxyClass = this.proxyClass(ps); + this.getClass().getModule().addReads(proxyClass.getModule()); + return + this.lookup(proxyClass).findConstructor(proxyClass, methodType(void.class, Supplier.class)) + .asType(methodType(Object.class, Supplier.class)) + .invokeExact(instanceSupplier); + } catch (final RuntimeException | Error e) { + throw e; + } catch (final Throwable e) { + throw new ReferenceException(e.getMessage(), e); + } + }); + } + + @Override // AbstractClientProxier> - protected final Class clientProxyClass(final DynamicType.Unloaded dtu, final ClassLoader cl) + protected final Class proxyClass(final DynamicType.Unloaded dtu, final ClassLoader cl) throws ClassNotFoundException { // getTypeName() invoked on a TypeDescription will be its binary name (required by Class#forName(String)): // https://javadoc.io/static/net.bytebuddy/byte-buddy/1.17.3/net/bytebuddy/description/type/TypeDefinition.html#getTypeName-- @@ -117,9 +156,4 @@ protected final Class clientProxyClass(final DynamicType.Unloaded dtu, fin return dtu.load(superclass.getClassLoader(), ClassLoadingStrategy.UsingLookup.of(lookup(superclass))).getLoaded(); } - @Override // AbstractClientProxier> - protected final Lookup lookup(final Class c) { - return lookup.in(c); - } - } diff --git a/src/main/java/org/microbean/clientproxy/bytebuddy/BBClientProxyClassGenerator.java b/src/main/java/org/microbean/clientproxy/bytebuddy/BBClientProxyClassGenerator.java index 6da1046..0959e55 100644 --- a/src/main/java/org/microbean/clientproxy/bytebuddy/BBClientProxyClassGenerator.java +++ b/src/main/java/org/microbean/clientproxy/bytebuddy/BBClientProxyClassGenerator.java @@ -15,7 +15,6 @@ import java.util.Collection; import java.util.List; -import java.util.Objects; import net.bytebuddy.ByteBuddy; @@ -44,6 +43,8 @@ import net.bytebuddy.pool.TypePool; +import static java.util.Objects.requireNonNull; + import static net.bytebuddy.description.modifier.Ownership.STATIC; import static net.bytebuddy.description.modifier.SyntheticState.SYNTHETIC; import static net.bytebuddy.description.modifier.Visibility.PRIVATE; @@ -76,8 +77,8 @@ import static net.bytebuddy.matcher.ElementMatchers.takesNoArguments; /** - * An class generator that uses Byte Buddy to {@linkplain #generate(String, - * TypeDefinition, Collection) generate} {@linkplain org.microbean.reference.ClientProxy client proxy} classes. + * A class generator that uses Byte Buddy to {@linkplain #generate(String, + * TypeDefinition, Collection) generate} {@linkplain org.microbean.proxy.Proxy client proxy} classes. * * @author Laird Nelson */ @@ -94,13 +95,13 @@ public final class BBClientProxyClassGenerator { */ public BBClientProxyClassGenerator(final TypePool typePool) { super(); - this.typePool = Objects.requireNonNull(typePool, "typePool"); + this.typePool = requireNonNull(typePool, "typePool"); } /** * Creates and returns a new {@link DynamicType.Unloaded} representing a client proxy class. * - * @param name the name of the client proxy class; must not be {@code null}; must be a valid Java class binary * name * @@ -117,9 +118,9 @@ public final DynamicType.Unloaded generate(final String name, final TypeDefinition superclass, final Collection interfaces) { - // ClientProxy - final TypeDescription.Generic clientProxyType = - parameterizedType(this.typeDescription("org.microbean.reference.ClientProxy"), + // Proxy + final TypeDescription.Generic proxyType = + parameterizedType(this.typeDescription("org.microbean.proxy.Proxy"), List.of(superclass)) .build(); @@ -129,12 +130,12 @@ public final DynamicType.Unloaded generate(final String name, List.of(TypeDescription.Generic.Builder.of(superclass.asGenericType()).asWildcardUpperBound())) .build(); - // public final class Name extends Superclass implements ClientProxy, Interfaces { /* ... */ } + // public /* synthetic */ final class Name extends Superclass implements Proxy, Interfaces { /* ... */ } DynamicType.Builder builder = new ByteBuddy() .subclass(superclass, NO_CONSTRUCTORS) .merge(List.of(PUBLIC, SYNTHETIC, TypeManifestation.FINAL)) .name(name) - .implement(clientProxyType) + .implement(proxyType) .implement(interfaces) // private final Supplier $proxiedSupplier; @@ -157,7 +158,7 @@ public final DynamicType.Unloaded generate(final String name, .with("proxiedSupplier")) .andThen(FieldAccessor.ofField("$proxiedSupplier").setsArgumentAt(0))) - // @Override // ClientProxy + // @Override // Proxy // public final Superclass $proxied() { // return this.$proxiedSupplier.get(); // } @@ -166,12 +167,12 @@ public final DynamicType.Unloaded generate(final String name, .onField("$proxiedSupplier") .withAssigner(Assigner.DEFAULT, Assigner.Typing.DYNAMIC)) - // @Override // ClientProxy + // @Override // Proxy // public final Superclass $cast() { - // return ClientProxy.super.$cast(); + // return Proxy.super.$cast(); // } .defineMethod("$cast", superclass, PUBLIC, SYNTHETIC, MethodManifestation.FINAL) - .intercept(DefaultMethodCall.prioritize(clientProxyType.asErasure())) + .intercept(DefaultMethodCall.prioritize(proxyType.asErasure())) // Existing/inherited methods; remember that they form a stack, so the last .method() call below should be the // most specific. See https://bytebuddy.net/#members for details. @@ -183,7 +184,7 @@ public final DynamicType.Unloaded generate(final String name, .method(isBusinessMethod() .and(not(isJavaDeclaredMethod() .and(isPackagePrivate() - .or(hasOnePackagePrivateParameter()))))) + .or(hasOneOrMorePackagePrivateParameters()))))) .intercept(invokeSelf() .onMethodCall(invoke(named("$proxied"))) .withAllArguments()) @@ -231,7 +232,7 @@ public final DynamicType.Unloaded generate(final String name, */ - private static final ElementMatcher hasOnePackagePrivateParameter() { + private static final ElementMatcher hasOneOrMorePackagePrivateParameters() { return m -> { for (final ParameterDescription pd : m.getParameters()) { if (isPackagePrivate().matches(pd.getType())) { @@ -249,16 +250,11 @@ private static final ElementMatcher.Junction isBusinessMethod } private static final ElementMatcher.Junction isJavaDeclaredMethod() { - return isDeclaredBy(typeNameStartsWith("java.")); + return isDeclaredBy(t -> t.getTypeName().startsWith("java.")); } private final TypeDescription typeDescription(final String canonicalName) { return this.typePool.describe(canonicalName).resolve(); } - private static final ElementMatcher typeNameStartsWith(final String prefix) { - Objects.requireNonNull(prefix, "prefix"); - return t -> t.getTypeName().startsWith(prefix); - } - } diff --git a/src/main/java/org/microbean/clientproxy/bytebuddy/TypeDefinitions.java b/src/main/java/org/microbean/clientproxy/bytebuddy/TypeDefinitions.java index 03ff775..294dd8a 100644 --- a/src/main/java/org/microbean/clientproxy/bytebuddy/TypeDefinitions.java +++ b/src/main/java/org/microbean/clientproxy/bytebuddy/TypeDefinitions.java @@ -220,7 +220,7 @@ yield parameterizedType(td, } private static final boolean generic(final TypeElement te) { - // Assumes t is thread safe, e.g. supplied via org.microbean.construct.Domain or similar + // Assumes te is thread safe, e.g. supplied via org.microbean.construct.Domain or similar return switch (te.getKind()) { case CLASS, CONSTRUCTOR, ENUM, INTERFACE, METHOD, RECORD -> !te.getTypeParameters().isEmpty(); default -> false; diff --git a/src/main/java/org/microbean/clientproxy/bytebuddy/TypeElementTypePool.java b/src/main/java/org/microbean/clientproxy/bytebuddy/TypeElementTypePool.java index 92e727c..6f2f46d 100644 --- a/src/main/java/org/microbean/clientproxy/bytebuddy/TypeElementTypePool.java +++ b/src/main/java/org/microbean/clientproxy/bytebuddy/TypeElementTypePool.java @@ -17,12 +17,14 @@ import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.Objects; +import java.util.Set; import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.ModuleElement; import javax.lang.model.element.NestingKind; +import javax.lang.model.element.PackageElement; import javax.lang.model.element.RecordComponentElement; import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; @@ -46,6 +48,8 @@ import org.microbean.construct.vm.Signatures; import org.microbean.construct.vm.TypeDescriptors; +import static java.util.Objects.requireNonNull; + /** * A {@link TypePool.Default} that produces {@link net.bytebuddy.description.type.TypeDescription}s from {@code * javax.lang.model.*} constructs. @@ -122,7 +126,7 @@ public TypeElementTypePool(final ClassFileVersion classFileVersion, super(cacheProvider == null ? new TypePool.CacheProvider.Simple() : cacheProvider, ClassFileLocator.NoOp.INSTANCE, // no locator TypePool.Default.ReaderMode.FAST); // irrelevant; doesn't read class files - this.domain = Objects.requireNonNull(domain, "domain"); + this.domain = requireNonNull(domain, "domain"); this.classFileVersion = classFileVersion == null ? ClassFileVersion.ofThisVm() : classFileVersion; } @@ -187,7 +191,7 @@ protected final Resolution doDescribe(final String binaryName) { // Note that we deliberately and I believe properly do not use the two-argument form of // domain#typeElement(ModuleElement, CharSequence), since inferring the ModuleElement representing the caller here // is all but impossible (except for StackWalker). - + // If binaryName is the binary name of a top-level class, this will work just fine because a top level class' binary // and canonical names are the same, and canonical names are what domain#typeElement(CharSequence) accepts. TypeElement e = this.domain.typeElement(binaryName); @@ -275,6 +279,7 @@ private TypeDescription(final Domain domain, final TypeElement e) { typeVariableAnnotationTokens(e), typeVariableBoundsAnnotationTokens(e), annotationTokens(e), + moduleToken(domain, e), fieldTokens(domain, e), methodTokens(domain, e), recordComponentTokens(domain, e), @@ -406,6 +411,28 @@ private static final List methodTokens(final Domain domain, final E return Collections.unmodifiableList(l); } + private static final ModuleToken moduleToken(final Domain domain, Element e) { + while (e != null && e.getKind() != ElementKind.MODULE) { + e = e.getEnclosingElement(); + } + if (e == null) { + return null; + } + final ModuleElement m = (ModuleElement)e; + // TODO: implement + final String name = domain.toString(m.getQualifiedName()); + final Set packages = Set.copyOf(m.getEnclosedElements() + .stream() + .map(p -> domain.toString(((PackageElement)p).getQualifiedName())) + .toList()); + final int modifiers = 0; // TODO: not sure what modifiers are expected; looks like maybe just open + final String version = null; // ModuleElement does not expose this information + final String mainClass = null; // ModuleElement does not expose this information + + // XXX FIXME TODO: finish implementing + return null; + } + private static final List recordComponentTokens(final Domain domain, final Element e) { final ArrayList l = new ArrayList<>(); for (final Element ee : e.getEnclosedElements()) { diff --git a/src/main/java/org/microbean/clientproxy/bytebuddy/package-info.java b/src/main/java/org/microbean/clientproxy/bytebuddy/package-info.java index e0658d0..320bafa 100644 --- a/src/main/java/org/microbean/clientproxy/bytebuddy/package-info.java +++ b/src/main/java/org/microbean/clientproxy/bytebuddy/package-info.java @@ -13,7 +13,7 @@ */ /** - * Provides classes and interfaces related to implementing {@linkplain org.microbean.reference.ClientProxy client + * Provides classes and interfaces related to implementing {@linkplain org.microbean.proxy.Proxy client * proxies} using Byte Buddy. * * @author Laird Nelson diff --git a/src/test/java/org/microbean/clientproxy/bytebuddy/TestBBClientProxier.java b/src/test/java/org/microbean/clientproxy/bytebuddy/TestBBClientProxier.java index fdc061f..90bcc02 100644 --- a/src/test/java/org/microbean/clientproxy/bytebuddy/TestBBClientProxier.java +++ b/src/test/java/org/microbean/clientproxy/bytebuddy/TestBBClientProxier.java @@ -24,37 +24,43 @@ import java.util.Objects; import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; + import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.microbean.attributes.Attributes; -import org.microbean.bean.AttributedType; +import org.microbean.assign.AttributedType; +import org.microbean.assign.Selectable; +import org.microbean.assign.Selectables; + import org.microbean.bean.Bean; +import org.microbean.bean.BeanQualifiersMatcher; import org.microbean.bean.BeanTypeList; +import org.microbean.bean.BeanTypeMatcher; import org.microbean.bean.BeanTypes; +import org.microbean.bean.Beans; import org.microbean.bean.Constant; import org.microbean.bean.Id; -import org.microbean.bean.Request; -import org.microbean.bean.Selectable; import org.microbean.bean.IdMatcher; -import org.microbean.bean.BeanTypeMatcher; -import org.microbean.bean.InterceptorBindingsMatcher; -import org.microbean.bean.BeanQualifiersMatcher; -import org.microbean.bean.Reducer; -import org.microbean.bean.RankedReducer; -import org.microbean.bean.Reducible; +import org.microbean.bean.Qualifiers; import org.microbean.construct.DefaultDomain; import org.microbean.construct.Domain; -import org.microbean.reference.ClientProxy; -import org.microbean.reference.DefaultRequest; +import org.microbean.producer.InterceptorBindingsMatcher; + +import org.microbean.proxy.Proxy; + +import org.microbean.reference.Instances; +import org.microbean.reference.Request; import org.microbean.scopelet.MapBackedScopelet; import org.microbean.scopelet.NoneScopelet; import org.microbean.scopelet.ScopedInstances; import org.microbean.scopelet.Scopelet; +import org.microbean.scopelet.Scopes; import org.microbean.scopelet.SingletonScopelet; import static java.lang.constant.ConstantDescs.BSM_INVOKE; @@ -66,24 +72,20 @@ import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.microbean.assign.Qualifiers.anyQualifier; -import static org.microbean.assign.Qualifiers.anyAndDefaultQualifiers; -import static org.microbean.assign.Qualifiers.defaultQualifier; -import static org.microbean.assign.Qualifiers.defaultQualifiers; -import static org.microbean.assign.Qualifiers.qualifier; - -import static org.microbean.bean.Beans.cachingSelectableOf; - -import static org.microbean.scopelet.Scopelet.APPLICATION_ID; -import static org.microbean.scopelet.Scopelet.NONE_ID; -import static org.microbean.scopelet.Scopelet.SCOPE; -import static org.microbean.scopelet.Scopelet.SINGLETON_ID; +import static org.microbean.bean.Selectables.ambiguityReducing; +import static org.microbean.bean.Selectables.typesafeFiltering; final class TestBBClientProxier { private Domain domain; - private Request r; + private Qualifiers qualifiers; + + private Request r; + + private Instances instances; + + private Bean gorpBean; private TestBBClientProxier() { super(); @@ -93,44 +95,111 @@ private TestBBClientProxier() { final void setup() { this.domain = new DefaultDomain(); - // Rule: your parent scope goes on the Any qualifier - final Attributes anyQualifierWithSingletonParentScope = Attributes.of("Any", qualifier(), SINGLETON_ID); final BeanTypes beanTypes = new BeanTypes(domain); + + this.qualifiers = new Qualifiers(); + + final Scopes scopes = new Scopes(qualifiers); + + // TODO: all this scopelet tunneling stuff is a specific instance of a general case that is already handle-able. If + // you conceive of a Factory that can "create" (cache and return) all kinds of objects, and can use this tunneling + // mechanism to look it up, then you don't need a Scopelet type. + + // Rule: your parent scope goes on the Any qualifier. All beans have the Any qualifier (normally) so this is a + // convenient way to "tunnel" a qualifier/scope without screwing up typesafe resolution and without requiring + // something stupid like BeanAttributes in CDI. You just add meta-annotations. + final Attributes anyQualifierWithSingletonParentScope = Attributes.of("Any", qualifiers.qualifier(), scopes.singleton()); + + final Bean domainBean = + new Bean<>(new Id(beanTypes.beanTypes(domain.declaredType(DefaultDomain.class.getCanonicalName())), + List.of(anyQualifierWithSingletonParentScope, qualifiers.defaultQualifier())), + c -> domain); + + final Bean beanTypesBean = + new Bean<>(new Id(beanTypes.beanTypes(domain.declaredType(BeanTypes.class.getCanonicalName())), + List.of(anyQualifierWithSingletonParentScope, qualifiers.defaultQualifier())), + c -> beanTypes); + + // TODO: we should do this for all the matchers, too, e.g. BeanTypeMatcher, BeanQualifiersMatcher, + // EventTypesMatcher, etc. etc. + // + // BBClientProxier too + // + // Then all these handcrafted beans could say what they need as dependencies and assign them + + final Attributes application = + Attributes.of("Application", + scopes.normal(), + Map.of(), + Map.of("Application", + List.of(qualifiers.qualifier(), + scopes.scope(), + scopes.singleton()))); + + // Set up scopes. final Bean applicationAndSingletonScopeletBean = new Bean<>(new Id(beanTypes.beanTypes(domain.declaredType(SingletonScopelet.class.getCanonicalName())), - // Rule: APPLICATION_ID and SINGLETON_ID function here as qualifiers - List.of(anyQualifierWithSingletonParentScope, APPLICATION_ID, SINGLETON_ID)), - new SingletonScopelet(domain)); + // Rule: application and scopes.singleton() function here as qualifiers + List.of(anyQualifierWithSingletonParentScope, application, scopes.singleton())), + new SingletonScopelet()); + final Bean noneScopeletBean = new Bean<>(new Id(beanTypes.beanTypes(domain.declaredType(NoneScopelet.class.getCanonicalName())), // Rule: NONE_ID functions here as a qualifier - List.of(anyQualifierWithSingletonParentScope, NONE_ID)), - new NoneScopelet(domain)); - - final Selectable> selectable = - cachingSelectableOf(List.of(noneScopeletBean, - applicationAndSingletonScopeletBean, - new Bean<>(new Id(new BeanTypes(domain).beanTypes(domain.declaredType(Gorp.class.getCanonicalName())), - List.of(Attributes.of("Any", qualifier(), APPLICATION_ID), defaultQualifier())), - r -> new Gorp())), - new IdMatcher(new BeanQualifiersMatcher(), - new InterceptorBindingsMatcher(), - new BeanTypeMatcher(domain)), - Map.of()); + List.of(anyQualifierWithSingletonParentScope, scopes.none())), + new NoneScopelet()); + + // Set up the user-supplied bean. Note that it is in application scope. + this.gorpBean = + new Bean<>(new Id(new BeanTypes(domain).beanTypes(domain.declaredType(Gorp.class.getCanonicalName())), + List.of(Attributes.of("Any", qualifiers.qualifier(), application), qualifiers.defaultQualifier())), + c -> new Gorp()); + + // In a production version of all this we need to allow for supplying a preinitialized selection cache. We will + // supply an empty one. + final Map>> selectionCache = new ConcurrentHashMap<>(); + + // See https://jakarta.ee/specifications/cdi/4.1/jakarta-cdi-spec-4.1#unsatisfied_and_ambig_dependencies + Selectable> selectable = + ScopedInstances.selectableOf(domain, + Selectables.>caching(ambiguityReducing(typesafeFiltering(List.of(domainBean, + beanTypesBean, + noneScopeletBean, + applicationAndSingletonScopeletBean, + this.gorpBean), + new IdMatcher(new BeanTypeMatcher(domain), + new BeanQualifiersMatcher(qualifiers), + new InterceptorBindingsMatcher())), + org.microbean.bean.Ranked::alternate, + org.microbean.bean.Ranked::rank + ), + selectionCache::computeIfAbsent)); + + this.instances = new ScopedInstances(domain, qualifiers, scopes); this.r = - new DefaultRequest(selectable, - ScopedInstances.reducible(domain, selectable), - new ScopedInstances(domain), - new BBClientProxier(domain)); + new Request(this.domain, + selectable, + this.instances, + new BBClientProxier(domain)); + } + + private static final boolean alternate(final Bean b) { + final Id id = b.id(); + return false; + } + + @Test + final void testGorpIsProxiable() { + assertTrue(this.instances.proxiable(this.gorpBean.id())); } @Test final void testClientProxySunnyDay() { - final Gorp g = this.r.reference(new AttributedType(this.domain.declaredType(Gorp.class.getCanonicalName()), defaultQualifiers())); - assertTrue(g instanceof ClientProxy, String.valueOf(g)); + final Gorp g = this.r.reference(new AttributedType(this.domain.declaredType(Gorp.class.getCanonicalName()), qualifiers.defaultQualifiers())); + assertTrue(g instanceof Proxy, String.valueOf(g)); assertTrue(g.getClass().isSynthetic()); @SuppressWarnings("unchecked") - final Gorp proxied = ((ClientProxy)g).$proxied(); + final Gorp proxied = ((Proxy)g).$proxied(); assertNotSame(g, proxied); assertSame(Gorp.class, proxied.getClass()); assertEquals("bar", g.bar()); @@ -148,7 +217,7 @@ static class Gorp implements Frobber { super(); } - @Override + @Override // Frobber public String frob() { return "frob"; } diff --git a/src/test/java/org/microbean/clientproxy/bytebuddy/TestBBClientProxyClassGenerator.java b/src/test/java/org/microbean/clientproxy/bytebuddy/TestBBClientProxyClassGenerator.java index def9bbf..6928ca3 100644 --- a/src/test/java/org/microbean/clientproxy/bytebuddy/TestBBClientProxyClassGenerator.java +++ b/src/test/java/org/microbean/clientproxy/bytebuddy/TestBBClientProxyClassGenerator.java @@ -37,7 +37,7 @@ import org.microbean.construct.DefaultDomain; import org.microbean.construct.Domain; -import org.microbean.reference.ClientProxy; +import org.microbean.proxy.Proxy; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals; @@ -78,13 +78,13 @@ final void testGenerateSunnyDay() throws IOException, IllegalAccessException, In final Class cls = dtl.getLoaded(); assertEquals(proxyClassName, cls.getName()); - assertTrue(ClientProxy.class.isAssignableFrom(cls)); + assertTrue(Proxy.class.isAssignableFrom(cls)); assertTrue(Gorp.class.isAssignableFrom(cls)); assertTrue(Cloneable.class.isAssignableFrom(cls)); final Constructor c = cls.getDeclaredConstructor(Supplier.class); @SuppressWarnings("unchecked") - final ClientProxy cp = (ClientProxy)c.newInstance(s); + final Proxy cp = (Proxy)c.newInstance(s); assertTrue(cp instanceof Gorp); assertTrue(cp instanceof Cloneable);