代理模式
静态代理
由程序员创建或由特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。
直白来说,代理类是一个独立的类,通过依赖目标类从而完成代理的实现。
动态代理
静态代理因为其特性所以存在弊端:
因为代理需求增加了类的数量,增加了依赖的复杂度,业务的实现会因此变得复杂。
静态代理是否可以被替换,当然可以,依赖Java的反射机制实现动态代理,实例不仅可以通过直接实现也能动态生成。
JDK代理
JDK代理的实现分为两个部分:
- 将增强服务的逻辑封装到InvocationHandler的实现类InvocationHandlerImpl的invoke方法中
- Proxy类将InvocationHandlerImpl和目标对象的信息作为入参构造出一个代理类
接口
public interface HelloService {
public void sayHello(String name);
}
目标类 targetClass
public class HelloServiceImpl implements HelloService{
@override
public void sayHello(String name){
System.err.println("hello"+ name);
}
}
第一种实现 HelloServiceInvocationHandler实现InvocationHandler封装增强服务信息
public class HelloServiceInvocationHandler implements InvocationHandler {
/**
*
*真实服务对象
*/
private Object target;
/**
*绑定委托对象并返回一个代理类
*
**/
public Object bind(Object target){
this.target = target;
//取得代理对象,可以看到,只有在
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterface(),
this);
//jdk代理需要提供接口
}
@Override
/**
*通过代理对象调用方法首先进入这个方法
* proxy --代理对象
* method -- 被调用方法
* args 方法的参数
*/
public Object invoke(Object proxy ,
Method method,
Object[] args) throw Throwable{
System.err.println("我是jdk动态代理");
Object result = null;
//反射方法前调用
System.err.println("我准备说Hello");
//执行方法,相当于调用 HelloServiceImpl 类的sayHello方法
result = method.invoke(target, args);
//反射方法后调用
System.err.println("我说过hello了");
return result;
}
}
实现代理
public class HelloServiceMain {
public static void main(String[] args) {
HelloServiceInvocationHandler HelloHandler = new HelloServiceInvocationHandler ();
HelloService proxy = (HelloService) HelloHandler.bind(new HelloServiceImpl());
proxy.sayHello("张三");
}
}
第二种实现
public class HelloServiceInvocationHandler implements InvocationHandler {
/**
*
*真实服务对象
*/
private Object target;
public HelloServiceInvocationHandler(Object target){
this.target = target;
}
@Override
/**
*通过代理对象调用方法首先进入这个方法
* proxy --代理对象
* method -- 被调用方法
* args 方法的参数
*/
public Object invoke(Object proxy ,
Method method,
Object[] args) throw Throwable{
System.err.println("我是jdk动态代理");
Object result = null;
//反射方法前调用
System.err.println("我准备说Hello");
//执行方法,相当于调用 HelloServiceImpl 类的sayHello方法
result = method.invoke(target, args);
//反射方法后调用
System.err.println("我说过hello了");
return result;
}
}
public class HelloServiceMain {
public static void main(String[] args) {
// 创建被代理对象
HelloServiceImpl helloservice = new HelloServiceImpl();
// 创建处理器类实现
InvocationHandler myHandler = new HelloServiceInvocationHandler(helloservice);
// 重点! 生成代理类, 其中proxy就是HelloServiceImpl的代理类了
HelloService proxy = (HelloService) Proxy.newProxyInstance(helloservice .getClass().getClassLoader(), helloservice .getClass().getInterfaces(), myHandler);
// 调用代理类的代理的sayHello方法, 在此处就会去调用上述myHandler的invoke方法区执行
proxy.sayHello("张三");
}
}
这两种实现没什么区别,直接看代理对象$Proxy0.class字节码反编译
public final class $Proxy0 extends Proxy implements HelloService {
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m0;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
//代理对象执行目标方法的过程
public final void sayHello(String var1) throws {
try {
super.h.invoke(this, m3, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m3 = Class.forName("com.proxy.HelloService").getMethod("sayHello", Class.forName("java.lang.String"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
如果你对JVM很熟悉,JDK代理的概念会好理解的多,你把增强服务的逻辑写到InvocationHandle实现类的invoke方法中,InvocationHandler接口是Proxy的属性,你创建的代理对象是Proxy的子类,Proxy拿到了目标对象的所有信息,用反射创建一个实现目标对象的所有方法的并且继承自己的实例,再加上你给的InvocationHandle接口实现类的信息给你把增强服务嵌入到代理对象映射了你要执行的目标对象的方法中。
如果把JVM的底层原理学好,这些过程一定可以驾轻就熟。
JDK代理源码
Proxy.newProxyInstance
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
// 如果h为空直接抛出空指针异常,之后所有的单纯的判断null并抛异常,都是此方
Objects.requireNonNull(h);
// 拷贝类实现的所有接口
final Class<?>[] intfs = interfaces.clone();
// 获取当前系统安全接口
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
/*
* Look up or generate the designated proxy class.
译: 查找或生成指定的代理
*/
Class<?> cl = getProxyClass0(loader, intfs);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
if (sm != null) {
// Reflection.getCallerClass返回调用该方法的方法的调用类;loader:接口的类加载器
// 进行包访问权限、类加载器权限等检查
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
/*
* 获取代理类的构造函数对象。
* constructorParams是类常量,作为代理类构造函数的参数类型,常量定义如下:
* private static final Class<?>[] constructorParams = { InvocationHandler.class };
*/
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}
// 根据代理类的构造函数对象来创建需要返回的代理类对象
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException|InstantiationException e) {
throw new InternalError(e.toString(), e);
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString(), t);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString(), e);
}
}
getProxyClass0
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
// 接口数不得超过65535个,这么大,足够使用的了
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
// If the proxy class defined by the given loader implementing
// the given interfaces exists, this will simply return the cached copy;
// otherwise, it will create the proxy class via the ProxyClassFactory
// 译: 如果缓存中有代理类了直接返回,否则将由代理类工厂ProxyClassFactory创建代理类
return proxyClassCache.get(loader, interfaces);
}
proxyClassCache.get(loader, interfaces)
/**
* Look-up the value through the cache. This always evaluates the
* {@code subKeyFactory} function and optionally evaluates
* {@code valueFactory} function if there is no entry in the cache for given
* pair of (key, subKey) or the entry has already been cleared.
*
* @param key possibly null key
* @param parameter parameter used together with key to create sub-key and
* value (should not be null)
* @return the cached value (never null)
* @throws NullPointerException if {@code parameter} passed in or
* {@code sub-key} calculated by
* {@code subKeyFactory} or {@code value}
* calculated by {@code valueFactory} is null.
*/
public V get(K key, P parameter) {
// key:类加载器;parameter:接口数组
// 检查指定类型的对象引用不为空null。当参数为null时,抛出空指针异常。
Objects.requireNonNull(parameter);
// 清除已经被GC回收的弱引用
expungeStaleEntries();
// 将ClassLoader包装成CacheKey, 作为一级缓存的key
Object cacheKey = CacheKey.valueOf(key, refQueue);
// lazily install the 2nd level valuesMap for the particular cacheKey
// 获取得到二级缓存
// lazily install the 2nd level valuesMap for the particular cacheKey
ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
// 没有获取到对应的值
if (valuesMap == null) {
ConcurrentMap<Object, Supplier<V>> oldValuesMap
= map.putIfAbsent(cacheKey,
valuesMap = new ConcurrentHashMap<>());
if (oldValuesMap != null) {
valuesMap = oldValuesMap;
}
}
// create subKey and retrieve the possible Supplier<V> stored by that
// subKey from valuesMap
// 根据代理类实现的接口数组来生成二级缓存key
// create subKey and retrieve the possible Supplier<V> stored by that
// subKey from valuesMap
Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
// 通过subKey获取二级缓存值
Supplier<V> supplier = valuesMap.get(subKey);
Factory factory = null;
// 这个循环提供了轮询机制, 如果条件为假就继续重试直到条件为真为
while (true) {
// supplier might be a Factory or a CacheValue<V> instance
// 在这里supplier可能是一个Factory也可能会是一个CacheValue
// 在这里不作判断, 而是在Supplier实现类的get方法里面进行验证
if (supplier != null) {
// supplier might be a Factory or a CacheValue<V> instance
V value = supplier.get();
if (value != null) {
return value;
}
}
// else no supplier in cache
// or a supplier that returned null (could be a cleared CacheValue
// or a Factory that wasn't successful in installing the CacheValue)
// lazily construct a Factory
// 新建一个Factory实例作为subKey对应的值
if (factory == null) {
factory = new Factory(key, parameter, subKey, valuesMap);
}
// 到这里表明subKey没有对应的值, 就将factory作为subKey的值放入
if (supplier == null) {
// successfully installed Factory
// 到这里表明成功将factory放入缓存
supplier = valuesMap.putIfAbsent(subKey, factory);
if (supplier == null) {
// successfully installed Factory
supplier = factory;
}
// 否则, 可能期间有其他线程修改了值, 那么就不再继续给subKey赋值, 而是取出来直接用
// else retry with winning supplier
// else retry with winning supplier
} else {
// 期间可能其他线程修改了值, 那么就将原先的值替换
if (valuesMap.replace(subKey, supplier, factory)) {
// successfully replaced
// cleared CacheEntry / unsuccessful Factory
// with our Factory
// 成功将factory替换成新的值
supplier = factory;
} else {
// 替换失败, 继续使用原先的值
// retry with current supplier
supplier = valuesMap.get(subKey);
}
}
}
}
ProxyClassFactory.apply()实现代理类创建
private static final class ProxyClassFactory
implements BiFunction<ClassLoader, Class<?>[], Class<?>>
{
// prefix for all proxy class names
// 统一代理类的前缀名都以$Proxy
private static final String proxyClassNamePrefix = "$Proxy";
// next number to use for generation of unique proxy class names
// 使用唯一的编号给作为代理类名的一部分,如$Proxy0,$Proxy1等
private static final AtomicLong nextUniqueNumber = new AtomicLong();
@Override
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
for (Class<?> intf : interfaces) {
/*
* Verify that the class loader resolves the name of this
* interface to the same Class object.
* 验证指定的类加载器(loader)加载接口所得到的Class对象(interfaceClass)是否与intf对象相同
*/
Class<?> interfaceClass = null;
try {
interfaceClass = Class.forName(intf.getName(), false, loader);
} catch (ClassNotFoundException e) {
}
if (interfaceClass != intf) {
throw new IllegalArgumentException(
intf + " is not visible from class loader");
}
/*
* Verify that the Class object actually represents an
* interface.
* 验证该Class对象是不是接口
*/
if (!interfaceClass.isInterface()) {
throw new IllegalArgumentException(
interfaceClass.getName() + " is not an interface");
}
/*
* Verify that this interface is not a duplicate.
* 验证该接口是否重复
*/
if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
throw new IllegalArgumentException(
"repeated interface: " + interfaceClass.getName());
}
}
// 声明代理类所在包
String proxyPkg = null; // package to define proxy class in
int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
/*
* Record the package of a non-public proxy interface so that the
* proxy class will be defined in the same package. Verify that
* all non-public proxy interfaces are in the same package.
* 验证所有非公共的接口在同一个包内;公共的就无需处理
*/
for (Class<?> intf : interfaces) {
int flags = intf.getModifiers();
if (!Modifier.isPublic(flags)) {
accessFlags = Modifier.FINAL;
String name = intf.getName();
int n = name.lastIndexOf('.');
// 截取完整包名
String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
if (proxyPkg == null) {
proxyPkg = pkg;
} else if (!pkg.equals(proxyPkg)) {
throw new IllegalArgumentException(
"non-public interfaces from different packages");
}
}
}
if (proxyPkg == null) {
// if no non-public proxy interfaces, use com.sun.proxy package
/*如果都是public接口,那么生成的代理类就在com.sun.proxy包下如果报java.io.FileNotFoundException: com\sun\proxy\$Proxy0.class
(系统找不到指定的路径。)的错误,就先在你项目中创建com.sun.proxy路径*/
proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
}
/*
* Choose a name for the proxy class to generate.
* nextUniqueNumber 是一个原子类,确保多线程安全,防止类名重复,类似于:$Proxy0,$Proxy1......
*/
long num = nextUniqueNumber.getAndIncrement();
// 代理类的完全限定名,如com.sun.proxy.$Proxy0.calss
String proxyName = proxyPkg + proxyClassNamePrefix + num;
/*
* Generate the specified proxy class.
* 生成类字节码的方法(重点)
*/
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
try {
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
/*
* A ClassFormatError here means that (barring bugs in the
* proxy class generation code) there was some other
* invalid aspect of the arguments supplied to the proxy
* class creation (such as virtual machine limitations
* exceeded).
*/
throw new IllegalArgumentException(e.toString());
}
}
}
代理类创建真正在ProxyGenerator.generateProxyClass()方法中
public static byte[] generateProxyClass(final String name, Class<?>[] interfaces, int accessFlags) {
ProxyGenerator gen = new ProxyGenerator(name, interfaces, accessFlags);
// 真正生成字节码的方法
final byte[] classFile = gen.generateClassFile();
// 如果saveGeneratedFiles为true 则生成字节码文件,所以在开始我们要设置这个参数
// 当然,也可以通过返回的bytes自己输出
if (saveGeneratedFiles) {
java.security.AccessController.doPrivileged( new java.security.PrivilegedAction<Void>() {
public Void run() {
try {
int i = name.lastIndexOf('.');
Path path;
if (i > 0) {
Path dir = Paths.get(name.substring(0, i).replace('.', File.separatorChar));
Files.createDirectories(dir);
path = dir.resolve(name.substring(i+1, name.length()) + ".class");
} else {
path = Paths.get(name + ".class");
}
Files.write(path, classFile);
return null;
} catch (IOException e) {
throw new InternalError( "I/O exception saving generated file: " + e);
}
}
});
}
return classFile;
}
代理类生成的最终方法是ProxyGenerator.generateClassFile()
private byte[] generateClassFile() {
/* ============================================================
* Step 1: Assemble ProxyMethod objects for all methods to generate proxy dispatching code for.
* 步骤1:为所有方法生成代理调度代码,将代理方法对象集合起来。
*/
//增加 hashcode、equals、toString方法
addProxyMethod(hashCodeMethod, Object.class);
addProxyMethod(equalsMethod, Object.class);
addProxyMethod(toStringMethod, Object.class);
// 获得所有接口中的所有方法,并将方法添加到代理方法中
for (Class<?> intf : interfaces) {
for (Method m : intf.getMethods()) {
addProxyMethod(m, intf);
}
}
/*
* 验证方法签名相同的一组方法,返回值类型是否相同;意思就是重写方法要方法签名和返回值一样
*/
for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
checkReturnTypes(sigmethods);
}
/* ============================================================
* Step 2: Assemble FieldInfo and MethodInfo structs for all of fields and methods in the class we are generating.
* 为类中的方法生成字段信息和方法信息
*/
try {
// 生成代理类的构造函数
methods.add(generateConstructor());
for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
for (ProxyMethod pm : sigmethods) {
// add static field for method's Method object
fields.add(new FieldInfo(pm.methodFieldName,
"Ljava/lang/reflect/Method;",
ACC_PRIVATE | ACC_STATIC));
// generate code for proxy method and add it
// 生成代理类的代理方法
methods.add(pm.generateMethod());
}
}
// 为代理类生成静态代码块,对一些字段进行初始化
methods.add(generateStaticInitializer());
} catch (IOException e) {
throw new InternalError("unexpected I/O Exception", e);
}
if (methods.size() > 65535) {
throw new IllegalArgumentException("method limit exceeded");
}
if (fields.size() > 65535) {
throw new IllegalArgumentException("field limit exceeded");
}
/* ============================================================
* Step 3: Write the final class file.
* 步骤3:编写最终类文件
*/
/*
* Make sure that constant pool indexes are reserved for the following items before starting to write the final class file.
* 在开始编写最终类文件之前,确保为下面的项目保留常量池索引。
*/
cp.getClass(dotToSlash(className));
cp.getClass(superclassName);
for (Class<?> intf: interfaces) {
cp.getClass(dotToSlash(intf.getName()));
}
/*
* Disallow new constant pool additions beyond this point, since we are about to write the final constant pool table.
* 设置只读,在这之前不允许在常量池中增加信息,因为要写常量池表
*/
cp.setReadOnly();
ByteArrayOutputStream bout = new ByteArrayOutputStream();
DataOutputStream dout = new DataOutputStream(bout);
try {
// u4 magic;
dout.writeInt(0xCAFEBABE);
// u2 次要版本;
dout.writeShort(CLASSFILE_MINOR_VERSION);
// u2 主版本
dout.writeShort(CLASSFILE_MAJOR_VERSION);
cp.write(dout); // (write constant pool)
// u2 访问标识;
dout.writeShort(accessFlags);
// u2 本类名;
dout.writeShort(cp.getClass(dotToSlash(className)));
// u2 父类名;
dout.writeShort(cp.getClass(superclassName));
// u2 接口;
dout.writeShort(interfaces.length);
// u2 interfaces[interfaces_count];
for (Class<?> intf : interfaces) {
dout.writeShort(cp.getClass(
dotToSlash(intf.getName())));
}
// u2 字段;
dout.writeShort(fields.size());
// field_info fields[fields_count];
for (FieldInfo f : fields) {
f.write(dout);
}
// u2 方法;
dout.writeShort(methods.size());
// method_info methods[methods_count];
for (MethodInfo m : methods) {
m.write(dout);
}
// u2 类文件属性:对于代理类来说没有类文件属性;
dout.writeShort(0); // (no ClassFile attributes for proxy classes)
} catch (IOException e) {
throw new InternalError("unexpected I/O Exception", e);
}
return bout.toByteArray();
}
InvocationHandler#invoke 调用目标方法
当执行代理对象的目标方法时,会执行
// 接口代理方法
public final void sayHello()
throws
{
try
{
this.h.invoke(this, m3, null);
return;
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
回到了invocationHandler的invoke处理逻辑
通过反射调用方法
CGLib代理
动态代理总结
JDK代理的实现:
我们知道普通类通过javac编译生成字节码文件,然后通过类加载将类信息加载进入内存相关运行时数据区继续之后的执行。
动态代理的实现通过
Proxy.newProxyInstance |
Class<?> cl = getProxyClass0(loader, intfs);
proxyClassCache.get(loader, interfaces)
Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
ProxyClassFactory.apply()实现代理类创建
ProxyClassFactory.apply()是创建动态类最重要的步骤,它等效于我们普通类的编译、加载过程。
关键过程 | 功能 |
---|---|
byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags); | 创建动态类字节码二进制流 |
defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length); | 根据字节流加载动态类进入内存 |
可以看到,JDK代理直接动态构建字节流动态类文件并加载。
和静态代理产生明显对比,不需要再通过普通类的方式实现代理,这个动态类同样可以实现和目标类一样的接口,但需要作为Proxy类的子类
CGlib代理
和jdk代理过程相似
enhancer#setSuperClass
enhancer#setCallBack
enhancer.create
enhancer.createHelper
super.create(key) (AbstractClassGenerator#create) 创建Class对象(内存中有了该类元信息存在)
二者的不同(进一步理解二者的特点)
JDK通过接口实现,Cglib通过继承
为什么 JDK 动态代理要基于接口实现?而不是基于继承来实现?
解答:因为 JDK 动态代理生成的对象默认是继承 Proxy ,Java 不支持多继承,所以 JDK 动态代理要基于接口来实现。
CGLib动态代理是通过字节码底层继承目标类
二者的效率
效率问题不是很影响,主要是适用场景的问题。
JDK代理与JVM
通过上面的分析发现涵盖了JVM这几个方面的知识:
- 类文件的组成
- 类的使用过程(类加载)
补充一些知识点
Proxy中有本地方法defineClass0,这和ClassLoader中的defineClass很像
ClassLoader的defineClass是普通类加载进入内存的入口,那么这个Proxy中的defineClass0又怎么样呢
hotspot源码
方法内大多是在条件判断,最终通过调用
和Java普通类的加载殊途同归,参照上面的链接你就会发现都最终调用jvm_define_class_common实现类的加载。
Java_java_lang_reflect_Proxy_defineClass0(JNIEnv *env,
jclass ignore,
jobject loader,
jstring name,
jbyteArray data,
jint offset,
jint length)
{
jbyte *body;
char *utfName;
jclass result = 0;
char buf[128];
if (data == NULL) {
JNU_ThrowNullPointerException(env, 0);
return 0;
}
/* Work around 4153825. malloc crashes on Solaris when passed a
* negative size.
*/
if (length < 0) {
JNU_ThrowArrayIndexOutOfBoundsException(env, 0);
return 0;
}
body = (jbyte *)malloc(length);
if (body == 0) {
JNU_ThrowOutOfMemoryError(env, 0);
return 0;
}
(*env)->GetByteArrayRegion(env, data, offset, length, body);
if ((*env)->ExceptionOccurred(env))
goto free_body;
if (name != NULL) {
jsize len = (*env)->GetStringUTFLength(env, name);
jsize unicode_len = (*env)->GetStringLength(env, name);
if (len >= (jsize)sizeof(buf)) {
utfName = malloc(len + 1);
if (utfName == NULL) {
JNU_ThrowOutOfMemoryError(env, NULL);
goto free_body;
}
} else {
utfName = buf;
}
(*env)->GetStringUTFRegion(env, name, 0, unicode_len, utfName);
VerifyFixClassname(utfName);
} else {
utfName = NULL;
}
result = (*env)->DefineClass(env, utfName, loader, body, length);
if (utfName && utfName != buf)
free(utfName);
free_body:
free(body);
return result;
}