001/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*- 002 * 003 * Copyright © 2025 microBean™. 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 006 * the License. You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 011 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 012 * specific language governing permissions and limitations under the License. 013 */ 014package org.microbean.clientproxy.bytebuddy; 015 016import java.lang.invoke.MethodHandles; 017import java.lang.invoke.MethodHandles.Lookup; 018 019import java.util.Objects; 020 021import net.bytebuddy.dynamic.DynamicType; 022 023import net.bytebuddy.dynamic.loading.ClassLoadingStrategy; 024 025import net.bytebuddy.pool.TypePool; 026 027import org.microbean.construct.Domain; 028 029import org.microbean.reference.AbstractClientProxier; 030import org.microbean.reference.ProxySpecification; 031 032/** 033 * An {@link AbstractClientProxier} that uses <a href="https://bytebuddy.net/#/">Byte Buddy</a> to {@linkplain 034 * #generate(ProxySpecification) generate} {@linkplain org.microbean.reference.ClientProxy client proxies}. 035 * 036 * @author <a href="https://about.me/lairdnelson" target="_top">Laird Nelson</a> 037 * 038 * @see BBClientProxyClassGenerator 039 */ 040public final class BBClientProxier extends AbstractClientProxier<DynamicType.Unloaded<?>> { 041 042 private final TypeDefinitions tds; 043 044 private final BBClientProxyClassGenerator g; 045 046 private static final Lookup lookup = MethodHandles.lookup(); // or instance variable? 047 048 /** 049 * Creates a new {@link BBClientProxier}. 050 * 051 * @param domain a {@link Domain}; must not be {@code null} 052 * 053 * @exception NullPointerException if any argument is {@code null} 054 * 055 * @see TypeElementTypePool#TypeElementTypePool(Domain) 056 * 057 * @see #BBClientProxier(Domain, TypePool) 058 */ 059 public BBClientProxier(final Domain domain) { 060 this(domain, new TypeElementTypePool(domain)); 061 } 062 063 /** 064 * Creates a new {@link BBClientProxier}. 065 * 066 * @param domain a {@link Domain}; must not be {@code null} 067 * 068 * @param typePool a {@link TypePool}; must not be {@code null} 069 * 070 * @exception NullPointerException if any argument is {@code null} 071 * 072 * @see TypeDefinitions#TypeDefinitions(TypePool) 073 * 074 * @see BBClientProxyClassGenerator#BBClientProxyClassGenerator(TypePool) 075 * 076 * @see #BBClientProxier(Domain, TypeDefinitions, BBClientProxyClassGenerator) 077 */ 078 public BBClientProxier(final Domain domain, 079 final TypePool typePool) { 080 this(domain, new TypeDefinitions(typePool), new BBClientProxyClassGenerator(typePool)); 081 } 082 083 /** 084 * Creates a new {@link BBClientProxier}. 085 * 086 * @param domain a {@link Domain}; must not be {@code null} 087 * 088 * @param tds a {@link TypeDefinitions}; must not be {@code null} 089 * 090 * @param g a {@link BBClientProxyClassGenerator}; must not be {@code null} 091 * 092 * @exception NullPointerException if any argument is {@code null} 093 */ 094 public BBClientProxier(final Domain domain, 095 final TypeDefinitions tds, 096 final BBClientProxyClassGenerator g) { 097 super(domain); 098 this.tds = Objects.requireNonNull(tds, "tds"); 099 this.g = Objects.requireNonNull(g, "g"); 100 } 101 102 @Override // AbstractClientProxier<DynamicType.Unloaded<?>> 103 protected final DynamicType.Unloaded<?> generate(final ProxySpecification ps) { 104 return 105 this.g.generate(ps.name(), 106 this.tds.typeDescription(ps.superclass()), 107 ps.interfaces().stream().map(this.tds::typeDescriptionGeneric).toList()); 108 } 109 110 @Override // AbstractClientProxier<DynamicType.Unloaded<?>> 111 protected final Class<?> clientProxyClass(final DynamicType.Unloaded<?> dtu, final ClassLoader cl) 112 throws ClassNotFoundException { 113 // getTypeName() invoked on a TypeDescription will be its binary name (required by Class#forName(String)): 114 // https://javadoc.io/static/net.bytebuddy/byte-buddy/1.17.3/net/bytebuddy/description/type/TypeDefinition.html#getTypeName-- 115 final String binaryName = dtu.getTypeDescription().getSuperClass().asErasure().getTypeName(); 116 final Class<?> superclass = Class.forName(binaryName, false, cl); 117 return dtu.load(superclass.getClassLoader(), ClassLoadingStrategy.UsingLookup.of(lookup(superclass))).getLoaded(); 118 } 119 120 @Override // AbstractClientProxier<DynamicType.Unloaded<?>> 121 protected final Lookup lookup(final Class<?> c) { 122 return lookup.in(c); 123 } 124 125}