Coder Social home page Coder Social logo

koresproxy's Introduction

KoresProxy

KoresProxy is a Proxy generator written on top of Kores.

Using KoresProxy

A basic Proxy example:
public class MyClass {
  public int getNumber() {
    return 10;
  }
}

MyClass instance = KoresProxy.newProxyInstance(this.getClass().getClassLoader(), MyClass.class, (instance0, method, args, proxyData) -> {
  if (method.getName().equals("getNumber"))
    return 5;

  return null;
});

Assert.assertEquals("getNumber", 5, instance.getNumber());
Delegate to another instance
public class MyClass {
  public int getNumber() {
    return 10;
  }
}

MyClass origin = new MyClass();
MyClass instance = KoresProxy.newProxyInstance(this.getClass().getClassLoader(), MyClass.class, (instance0, method, args, proxyData) -> {
  if (method.getName().equals("getNumber"))
    return 5;

  return method.resolveOrFail(origin.getClass()).bindTo(origin).invokeWithArguments(args);
});

Assert.assertEquals("getNumber", 5, instance.getNumber());
Assert.assertEquals("hash", origin.hashCode(), instance.hashCode());
Class with constructors
public class ClassWithConstructor {
 private final String name;

 public ClassWithConstructor(String name) {
   this.name = name;
 }

 public String getName() {
   return this.name;
 }
}

ClassWithConstructor cwcOrigin2 = new ClassWithConstructor("Origin 2");
ClassWithConstructor cwc = KoresProxy.newProxyInstance(this.getClass().getClassLoader(), ClassWithConstructor.class, (instance0, method, args, proxyData) -> {
 return method.resolveOrFail(cwcOrigin2.getClass()).bindTo(cwcOrigin2).invokeWithArguments(args);
}, new Class[] { String.class }, new Object[]{ cwcOrigin2.getName() });

Assert.assertEquals("getName", "Origin 2", cwc.getName());

Limitations

  • KoresProxy only handles public, protected and package-private (for package private, see below) methods.
  • KoresProxy only handles non-final methods.
  • KoresProxy only generate proxies to classes that have accessible constructors.

KoresProxy compared to Java Proxies

KoresProxy support Super-classes and Interfaces inheritance, Java Proxies only supports Interfaces inheritance.

Since 2.1, KoresProxy uses MethodInfo to provide method information and delegation instead of Java methods.

Java 9+

In Java 9 (or superior) KoresProxy works in a different way, instead of trying to inject classes in the ProxyData.classLoader using private inaccessible methods, it only injects when the defineClass method is public and if the method is not public, it creates a new class loader (CodeClassLoader) and loads the class with it. If the ProxyData.classLoader is a CodeClassLoader, it will use the instance instead of creating a new one. Also, KoresProxy does not override package-private methods in Java 9 nor defines the class in the same package as the target super class. You can disable this behavior using the option described below.

VM options

Specify them using -D or defining using the System.setProperty(String, String).

  • koresproxy.saveproxies

    • Description: Save proxies generated classes and disassembled code in gen/.
    • Values: true|false
    • Default: false
  • koresproxy.ignore_module_rules

    • Description: Ignore rules that applies to Java 9+, see the Java 9+ section above.
    • Values: true|false
    • Default: false

Known issues

Custom

ClassFormatError Invalid start_pc ...

  • java.lang.ClassFormatError: Invalid start_pc * in LocalVariableTable in class file *

This happens when a Custom adds a return statement out-side a flow or inside a flow that is always reached without invoking env.setInvokeHandler(false);, example:

public class MyCustomGen implements CustomHandlerGenerator {
    @Override
    public CodeSource gen(Method target, MethodDeclaration methodDeclaration, GenEnv env) {
        return CodeSource.fromPart(Factories.returnValue(target.getReturnType(),
            InvocationFactory.invokeSpecial(
                        target.getDeclaringClass(), Access.SUPER, target.getName(), methodDeclaration.getTypeSpec(),
                        methodDeclaration.getParameters().stream()
                            .map(ConversionsKt::toVariableAccess)
                            .collect(Collectors.toList())
                )
        ));
    }
}

This code will cause class proxy to fail to load with class format error, to solve that, you should add:

env.setInvokeHandler(false);
env.setMayProceed(false);

Before the return.

Why this happens?

This happens because without env.setInvokeHandler(false) KoresProxy will append invocation to InvocationHandler after the code generated by your CustomHandlerGenerator, resulting in dead code. CodeAPI-BytecodeWriter optimizers will remove this dead code, but optimizers does not update LocalVariableTable, meaning that local variable entries will point to a label that does not exists anymore in the bytecode, resulting in verifier throwing exception.

The env.setMayProceed(false); will only prevent others Custom to be run, this is necessary to ensure that no other Custom will add code after your (resulting in dead code too).

koresproxy's People

Contributors

jonathanxd avatar

Stargazers

 avatar  avatar  avatar

Watchers

 avatar  avatar

koresproxy's Issues

Proxy a proxy class

Support proxy a KoresProxy proxy class.

Currently KoresProxy generated proxy class fails to be proxied because of proxy generated parameters not being provided to proxy super class through constructs. Instead it enforces that you provide both InvocationHandler and ProxyData manually, which is designed to be automatically provided through proxing logic.

Motivation

This would allow generate delegation to dummy proxies.

Support direct invocation

Proposal

Currently, CodeProxy back calls to a InvocationHandler that handle or resolves another method to invoke at runtime, in cases where the invocation has a static pure resolution, we can generate a direct invocation to the method that would be resolved at runtime during proxy compile time/generation time.

Example

For example, the following InvocationHandler can be easily converted to a direct invocation:

InvocationHandler ih = (instance, method, args, proxyData) -> {
    return method.resolveOrFail(target.getClass()).bindTo(target).invokeWithArguments(args);
}

This InvocationHandler resolves the method in the class of target, it always delegate the call to target, so direct invocation is possible, and may look like that:

public class $Proxy$CodeProxy_$0 implements MyItf {
  ...
  private final Object local$target;

  public $Proxy$CodeProxy_$0(InvocationHandler $InvocationHandler$CodeProxy, Object local$target) {
    ...
    this.local$target = local$target;
  }
  ...
  public void call() {
    this.local$target.call();
  }
}

InvocationHandler still required to construct the proxy instance, but will only be called in the case that method implementation is not generated at proxy compile-time.

Alternative to InvokeSuper which result could be handled

Currently, InvokeSuper is a CustomGen that appends an instance check against InvokeSuper, that in case of match, invokes super method. However, this does not allow we to control the result of super invocation without other Custom.

Invocation of super methods

Introduce something like a MethodInfo.invokeSuper which invokes super method and return the result.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.