Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

how to implements like jdk reflect method.invoke(object,object[]) #1750

Open
newShiJ opened this issue Jan 14, 2025 · 3 comments
Open

how to implements like jdk reflect method.invoke(object,object[]) #1750

newShiJ opened this issue Jan 14, 2025 · 3 comments
Assignees
Labels
Milestone

Comments

@newShiJ
Copy link

newShiJ commented Jan 14, 2025

i want to use byte-buddy to implements a Invoker can be used like jdk reflect method.invoke

I want to make Object[] -> arg0,arg1,arg2,arg3... dynamic bind to a Method

maybe I use a bad way , maybe you can give me some examples

this is a interface Invoker

	public interface Invoker {
		Object invoke(Object target, Object... args);
	}

this is invokerCreate method this is a method

       private Invoker createInvoker() {
               //  getMethod() return java.lang.reflect.Method 
		MethodCall.WithoutSpecifiedTarget withoutSpecifiedTarget = MethodCall.invoke(getMethod());
		MethodCall methodCall;
		// method is static or not
                if(!isStatic){
			methodCall = withoutSpecifiedTarget.onArgument(0);
		} else {
			methodCall = withoutSpecifiedTarget;
		}

		// 参数数量对齐
		Type[] types = getParamTypes();
		if(types.length > 0){
			int[] indexes = new int[types.length];
			for (int i = 0; i < types.length; i++) {
				indexes[i] = i + 1;
			}
			methodCall = methodCall.withArgument(indexes);
		}


		Implementation.Composable composable;
          
                // I have some question on this my interface(Invoker) is (Object,Object[])
                // but the target method ( result of getMethod() ) params is dynamic how can I make Object[] to (arg0,arg1,gar2,arg3...)  like this
                // I need a new Assigner or use other way
       
		// 有需要传递参数那就添加参数类型转换器
		// isVoid is said the method return type is void or not
                if(!isStatic || !isVoid){
			Assigner assigner = new CusPrimitiveTypeAwareAssigner(ReferenceTypeAwareAssigner.INSTANCE);
			composable = methodCall.withAssigner(assigner, Assigner.Typing.DYNAMIC);
		} else {
			composable = methodCall;
		}

		Implementation implementation;
		if(isVoid){
			implementation = composable.andThen(FixedValue.nullValue());
		} else {
			implementation = composable;
		}


		DynamicType.Unloaded<Invoker> invokerUnloaded = new ByteBuddy()
			.subclass(Invoker.class)
			.method(named("invoke"))
			.intercept(implementation)
			.make();
		DynamicType.Loaded<Invoker> load = invokerUnloaded.load(this.getClass().getClassLoader());
		try {
			Invoker instance = load.getLoaded().newInstance();
			this.invokerClassBytes = invokerUnloaded.getBytes();
			return instance;
		} catch (Exception e) {
			throw new HutoolException(e);
		}
	}

this is CusPrimitiveTypeAwareAssigner code just ignore void

@HashCodeAndEqualsPlugin.Enhance
public class CusPrimitiveTypeAwareAssigner implements Assigner {
	/**
	 * Another assigner that is aware of assigning reference types. This assigner is queried for assigning
	 * non-primitive types or for assigning a boxed type to another non-primitive type.
	 */
	private final Assigner referenceTypeAwareAssigner;

	/**
	 * Creates a new assigner with the given delegate.
	 *
	 * @param referenceTypeAwareAssigner A chained assigner that is queried for assignments not involving primitive
	 *                                   types.
	 */
	public CusPrimitiveTypeAwareAssigner(Assigner referenceTypeAwareAssigner) {
		this.referenceTypeAwareAssigner = referenceTypeAwareAssigner;
	}

	/**
	 * {@inheritDoc}
	 */
	public StackManipulation assign(TypeDescription.Generic source, TypeDescription.Generic target, Assigner.Typing typing) {
		// void类型不进行转换
		if(source.represents(void.class) || target.represents(void.class)){
			return referenceTypeAwareAssigner.assign(source, target, typing);
		}
		if (source.isPrimitive() && target.isPrimitive()) {
			return PrimitiveWideningDelegate.forPrimitive(source).widenTo(target);
		} else if (source.isPrimitive() /* && !target.isPrimitive() */) {
			return PrimitiveBoxingDelegate.forPrimitive(source).assignBoxedTo(target, referenceTypeAwareAssigner, typing);
		} else if (/* !source.isPrimitive() && */ target.isPrimitive()) {
			return PrimitiveUnboxingDelegate.forReferenceType(source).assignUnboxedTo(target, referenceTypeAwareAssigner, typing);
		} else /* !source.isPrimitive() && !target.isPrimitive()) */ {
			return referenceTypeAwareAssigner.assign(source, target, typing);
		}
	}
}
@raphw
Copy link
Owner

raphw commented Jan 14, 2025

You will need to wrap the arguments into an array explicitly. Varargs are an instruction to the Java compiler, not to the runtime, so it will not work to just assign.

MethodCall can already assign an array of all arguments using withArgumentArray. Is this what you are looking for?

@raphw raphw self-assigned this Jan 14, 2025
@raphw raphw added the question label Jan 14, 2025
@raphw raphw added this to the 1.15.11 milestone Jan 14, 2025
@newShiJ
Copy link
Author

newShiJ commented Jan 14, 2025

thank you I will try it

@newShiJ
Copy link
Author

newShiJ commented Jan 14, 2025

thank you my code success

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants