Runtime Proxy Generator

This utility library helps to generate runtime proxies using inheritance mechanism.

License

License

GroupId

GroupId

com.github.vladislavsevruk
ArtifactId

ArtifactId

runtime-proxy-generator
Last Version

Last Version

1.0.3
Release Date

Release Date

Type

Type

pom.sha512
Description

Description

Runtime Proxy Generator
This utility library helps to generate runtime proxies using inheritance mechanism.
Project URL

Project URL

https://github.com/VladislavSevruk/RuntimeProxyGenerator
Source Code Management

Source Code Management

https://github.com/VladislavSevruk/RuntimeProxyGenerator/tree/master

Download runtime-proxy-generator

Dependencies

compile (2)

Group / Artifact Type Version
com.github.vladislavsevruk : type-string-representation-resolver jar 1.0.1
com.github.vladislavsevruk : java-class-generator jar 1.0.1

runtime (2)

Group / Artifact Type Version
org.apache.logging.log4j : log4j-api jar 2.13.0
org.apache.logging.log4j : log4j-core jar 2.13.0

Project Modules

There are no modules declared in this project.

Build Status Quality Gate Status Code Coverage Maven Central

Runtime Proxy Generator

This utility library helps to generate runtime proxies for non-final classes to inject additional actions or override method logic using inheritance mechanism.

Table of contents

Getting started

To add library to your project perform next steps:

Maven

Add the following dependency to your pom.xml:

<dependency>
      <groupId>com.github.vladislavsevruk</groupId>
      <artifactId>runtime-proxy-generator</artifactId>
      <version>1.0.2</version>
</dependency>

Gradle

Add the following dependency to your build.gradle:

implementation 'com.github.vladislavsevruk:runtime-proxy-generator:1.0.2'

Usage

Implement ProxySourceCodeGenerator

First of all you need to implement ProxySourceCodeGenerator interface to provide source code of proxy class to generate. Library has BaseProxySourceCodeGenerator as base implementation with common logic of this interface (like generating constructors that match target type) so you can extend this class and override necessary methods for generating certain class members:

public class SimpleProxySourceGenerator extends BaseProxySourceCodeGenerator {

    // overriding generators for proxy methods
    @Override
    protected Collection<ClassElementGenerator> getMethodsDeclaration(Class<?> clazz) {
        return Collections.singletonList(new DelegateProxyMethodGenerator(clazz));
    }
}

public class DelegateProxyMethodGenerator extends AbstractProxyMethodGenerator {

    public DelegateProxyMethodGenerator(Class<?> delegatedClass) {
        super(delegatedClass);
    }

    // simply delegate call to superclass
    @Override
    protected String getProxyMethodBodyContent(JavaClassGeneratorConfig config, Method originalMethod,
            String delegateCall) {
        return String.format("%s%s;", getReturnKeyWordIfRequired(originalMethod), delegateCall);
    }
}

You may also find AbstractProxyMethodGenerator useful if all overridden methods should have common logic. You can simply implement its getProxyMethodBodyContent method to generate all methods of proxy class with similar behavior:

public class LoggingProxyMethodGenerator extends AbstractProxyMethodGenerator {

    public LoggingProxyMethodGenerator(Class<?> delegatedClass) {
        super(delegatedClass);
    }

    // add debug logging before method call
    @Override
    protected String getProxyMethodBodyContent(JavaClassGeneratorConfig config, Method originalMethod,
            String delegateCall) {
        StringBuilder stringBuilder = new StringBuilder("logger.debug(\"Calling '")
                .append(originalMethod.getName()).append("' method.\");\n");
        return doubleIndents(stringBuilder, config).append(getReturnKeyWordIfRequired(originalMethod))
                .append(delegateCall).append(";").toString();
    }
}

public class LoggingProxySourceGenerator extends BaseProxySourceCodeGenerator {

    // overriding generators for imports
    @Override
    protected Collection<ClassImportGenerator> getImportsDeclaration(Class<?> clazz) {
        return Collections.singletonList((config, schemaObject) -> Arrays
                .asList("import org.apache.logging.log4j.LogManager;\n",
                        "import org.apache.logging.log4j.Logger;\n"));
    }

    // overriding generators for fields
    protected Collection<ClassElementGenerator> getFieldsDeclaration(Class<?> clazz) {
        return Collections.singletonList((config, schemaObject) -> String.format(
                        "%sprivate static final Logger logger = LogManager.getLogger(%s.class);%n%n",
                        config.getIndent().value(), schemaObject.getName()));
    }

    // overriding generators for proxy methods
    @Override
    protected Collection<ClassElementGenerator> getMethodsDeclaration(Class<?> clazz) {
        return Collections.singletonList(new LoggingProxyMethodGenerator(clazz));
    }
}

NOTE: AbstractProxyMethodGenerator generates source code that doesn't override static, final or methods from java.lang.Object class.

Generate proxy class instance

To generate new proxy instance you need to use ProxyFactory class:

class Cake {

    Cake() {
    }

    ...
}

ProxyFactory<Cake> proxyFactory = new ProxyFactory<>(Cake.class, new LoggingProxySourceGenerator());
// result is proxy class instance that extends 'Cake' class
Cake cake = proxyFactory.newInstance();

Please note that proxy class cannot be generated for final classes:

final class Cake {

    Cake() {
    }

    ...
}

ProxyFactory<Cake> proxyFactory = new ProxyFactory<>(Cake.class, new LoggingProxySourceGenerator());
// result is 'Cake' class instance
Cake cake = proxyFactory.newInstance();

and for classes without any non-private constructor:

class Cake {

    // the only constructor of class
    private Cake() {
    }

    ...
}

ProxyFactory<Cake> proxyFactory = new ProxyFactory<>(Cake.class, new LoggingProxySourceGenerator());
// 'IllegalArgumentException' is thrown as there is no any public constructor matching received parameters
Cake cake = proxyFactory.newInstance();

License

This project is licensed under the MIT License, you can read the full text here.

Versions

Version
1.0.3
1.0.2
1.0.1
1.0.0