Skip to content

Commit

Permalink
Revert "Update proxy bytecode generator from cglib, which requires ru…
Browse files Browse the repository at this point in the history
…ntime '--add-opens ...' and is generally obsolete, with byte-buddy."

This reverts commit e8427a9.
  • Loading branch information
dkocher committed Feb 17, 2025
1 parent e719059 commit 02b790a
Show file tree
Hide file tree
Showing 9 changed files with 77 additions and 84 deletions.
8 changes: 4 additions & 4 deletions rococoa/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,9 @@
<version>5.16.0</version>
</dependency>
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<version>1.17.1</version>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
</dependencies>
</dependencyManagement>
Expand Down Expand Up @@ -205,7 +205,7 @@
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>@{argLine}-Djava.library.path=${project.build.directory}</argLine>
<argLine>@{argLine} --add-opens java.base/java.lang=ALL-UNNAMED -Djava.library.path=${project.build.directory}</argLine>
<systemPropertyVariables>
<jna.library.path>${project.build.directory}</jna.library.path>
</systemPropertyVariables>
Expand Down
4 changes: 2 additions & 2 deletions rococoa/rococoa-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
<artifactId>jna</artifactId>
</dependency>
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
</dependency>
<dependency>
<groupId>org.rococoa</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,11 +158,7 @@ public static ID getClass(String className) {
if (logging.isLoggable(Level.FINEST)) {
logging.finest(String.format("calling objc_getClass(%s)", className));
}
ID classID = foundationLibrary.objc_getClass(className);
if (classID.isNull()) {
throw new RococoaException(new ClassNotFoundException(className));
}
return classID;
return foundationLibrary.objc_getClass(className);
}

public static Selector selector(String selectorName) {
Expand Down
74 changes: 24 additions & 50 deletions rococoa/rococoa-core/src/main/java/org/rococoa/Rococoa.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,18 @@

import java.lang.reflect.Proxy;

import net.bytebuddy.ByteBuddy;
import net.bytebuddy.TypeCache;
import net.bytebuddy.description.modifier.Visibility;
import net.bytebuddy.dynamic.scaffold.subclass.ConstructorStrategy;
import net.bytebuddy.implementation.InvocationHandlerAdapter;
import net.sf.cglib.core.DefaultNamingPolicy;
import net.sf.cglib.core.Predicate;
import net.sf.cglib.proxy.Enhancer;

import org.rococoa.cocoa.CFIndex;
import org.rococoa.internal.*;
import org.rococoa.internal.OCInvocationCallbacks;
import org.rococoa.internal.ObjCObjectInvocationHandler;
import org.rococoa.internal.VarArgsUnpacker;

import java.util.logging.Level;
import java.util.logging.Logger;

import static net.bytebuddy.implementation.FieldAccessor.*;
import static net.bytebuddy.implementation.MethodCall.*;
import static net.bytebuddy.matcher.ElementMatchers.*;

/**
* Static factory for creating Java wrappers for Objective-C instances, and Objective-C
* wrappers for Java instances. <strong>START HERE</strong>.
Expand Down Expand Up @@ -162,55 +159,32 @@ public static <T extends ObjCObject> T proxy(Object javaObject, Class<T> javaTyp
// it to be release'd when the NSObject is finalized
return wrap(proxyID, javaType, false);
}

private static final TypeCache<Class<? extends ObjCObject>> typeCache = new TypeCache<>();
private static final String i15r = "invocationHandler";


/**
* Create a java.lang.reflect.Proxy or cglib proxy of type, which forwards
* invocations to invocationHandler.
* invocations to invococationHandler.
*/
@SuppressWarnings("unchecked")
private static <T extends ObjCObject> T createProxy(final Class<T> type, ObjCObjectInvocationHandler invocationHandler) {
private static <T> T createProxy(final Class<T> type, ObjCObjectInvocationHandler invocationHandler) {
if (type.isInterface()) {
return (T) Proxy.newProxyInstance(
invocationHandler.getClass().getClassLoader(),
new Class[] {type}, invocationHandler);
} else {
ClassLoader classLoader = type.getClassLoader();

Class<?> proxyClass =
typeCache.findOrInsert(classLoader, type, () ->
new ByteBuddy()
.subclass(type, ConstructorStrategy.Default.NO_CONSTRUCTORS)
.name(type.getName() + "$$ByRococoa")
.defineField(i15r, ObjCObjectInvocationHandler.class)
.defineConstructor(Visibility.PUBLIC)
.withParameter(ObjCObjectInvocationHandler.class, i15r)
.intercept(
// Invoke superclass default constructor explicitly
invoke(type.getConstructor())
.andThen(ofField(i15r).setsArgumentAt(0))
)
.method(
isAbstract()
.or(is(ObjCObjectInvocationHandler.OBJECT_EQUALS))
.or(is(ObjCObjectInvocationHandler.OBJECT_TOSTRING))
.or(is(ObjCObjectInvocationHandler.OCOBJECT_ID))
)
.intercept(InvocationHandlerAdapter.toField(i15r))
.make()
.load(classLoader)
.getLoaded()
);

try {
return ((Class<? extends T>) proxyClass)
.getConstructor(ObjCObjectInvocationHandler.class)
.newInstance(invocationHandler);
} catch (ReflectiveOperationException e) {
throw new RococoaException(e);
}
Enhancer e = new Enhancer();
e.setUseCache(true); // make sure that we reuse if we've already defined
e.setNamingPolicy(new DefaultNamingPolicy() {
public String getClassName(String prefix, String source, Object key, Predicate names) {
if (source.equals(net.sf.cglib.proxy.Enhancer.class.getName())) {
return type.getName() + "$$ByRococoa";
}
else {
return super.getClassName(prefix, source, key, names);
}
}});
e.setSuperclass(type);
e.setCallback(invocationHandler);
return (T) e.create();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
package org.rococoa.internal;

import com.sun.jna.Pointer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import org.rococoa.*;
import org.rococoa.cocoa.CFIndex;

Expand All @@ -40,16 +42,16 @@
*
* @author duncan
*/
public class ObjCObjectInvocationHandler implements InvocationHandler {
public class ObjCObjectInvocationHandler implements InvocationHandler, MethodInterceptor {

private static final int FINALIZE_AUTORELEASE_BATCH_SIZE = 1000;

private static final Logger logging = Logger.getLogger("org.rococoa.proxy");

public static final Method OBJECT_TOSTRING;
public static final Method OBJECT_HASHCODE;
public static final Method OBJECT_EQUALS;
public static final Method OCOBJECT_ID;
static final Method OBJECT_TOSTRING;
static final Method OBJECT_HASHCODE;
static final Method OBJECT_EQUALS;
static final Method OCOBJECT_ID;

static {
try {
Expand Down Expand Up @@ -150,6 +152,25 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Exceptio
return invokeCocoa(method, args);
}

/**
* Callback from cglib proxy
*/
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
if (logging.isLoggable(Level.FINEST)) {
logging.finest(String.format("invoking [%s %s].%s(%s)",
javaClassName, ocInstance, method.getName(), new VarArgsUnpacker(args)));
}
if (isSpecialMethod(method)) {
return invokeSpecialMethod(method, args);
}
if (!Modifier.isAbstract(method.getModifiers())) {
// method is not abstract, so a Java override has been provided, which we call
return methodProxy.invokeSuper(proxy, args);
}
// normal case
return invokeCocoa(method, args);
}

private boolean isSpecialMethod(Method method) {
return (OBJECT_TOSTRING.equals(method) ||
OBJECT_EQUALS.equals(method) ||
Expand Down Expand Up @@ -292,23 +313,22 @@ private Object marshall(Object arg) {
}

private String selectorNameFor(Method method) {
StringBuilder selector = new StringBuilder(method.getName());
if (selector.charAt(selector.length()-1) == '_') {
String methodName = method.getName();
if (methodName.endsWith("_")) {
// lets us append _ to allow Java keywords as method names
selector.setLength(selector.length()-1);
methodName = methodName.substring(0, methodName.length() - 1);
}
if (method.getParameterTypes().length > 0) {
for (int i = 0; i < selector.length(); i++) {
if (selector.charAt(i) == '_') {
selector.setCharAt(i, ':');
}
}
selector.append(':');
if (method.getParameterTypes().length == 0) {
return methodName;
}
return selector.toString();
String[] parts = methodName.split("_");
StringBuilder result = new StringBuilder();
for (String part : parts) {
result.append(part).append(":");
}
return result.toString();
}


private boolean shouldInvokeMethodsOnMainThread(AnnotatedElement element) {
return element != null && element.getAnnotation(RunOnMainThread.class) != null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public void test() {
}

@Test
public void testByteBuddyReusesClasses() {
public void testCGLibResusesClasses() {
NSNumberAsClass number = NSNumberAsClass.numberWithInt(42);
NSNumberAsClass number2 = NSNumberAsClass.numberWithInt(42);
assertSame(number.getClass(), number2.getClass());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ public void testToString() {
public void testGeneratedClassName() {
NSString string = NSString.stringWithString("Hello World");
Class<? extends NSString> stringClass = string.getClass();
assertEquals(NSString.class.getPackage().getName(), stringClass.getPackage().getName());
assertEquals(NSString.class.getPackage(), stringClass.getPackage());
assertEquals("NSString$$ByRococoa", stringClass.getSimpleName());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

package org.rococoa.internal;

import com.sun.jna.Native;
import org.junit.Ignore;
import org.junit.Test;
import org.rococoa.ID;
Expand All @@ -35,6 +36,10 @@

public class RococoaObjCObjectByReferenceTest extends RococoaTestCase {

static {
Native.load("rococoa-test", RococoaLibrary.class);
}

private interface TestShunt extends ObjCObject {
NSNumber testNumberFromInt(int value);
void testNSNumberByReference_with(ObjCObjectByReference reference, int value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,18 @@
import com.sun.jna.Native;
import org.junit.After;
import org.junit.Before;
import org.rococoa.Foundation;
import org.rococoa.ID;
import org.rococoa.cocoa.foundation.NSAutoreleasePool;
import org.rococoa.cocoa.foundation.NSObject;
import org.rococoa.internal.RococoaLibrary;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.logging.LogManager;
import java.util.logging.Logger;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

/**
Expand All @@ -41,9 +42,6 @@
* @author duncan
*/
public abstract class RococoaTestCase {
static {
Native.load("rococoa-test", RococoaLibrary.class);
}

// stress our memory management
public static boolean gcAfterTest = true;
Expand Down

0 comments on commit 02b790a

Please sign in to comment.