Codegen Module

Codegen module allows to build classes and methods in runtime without the overhead of reflection.

  • It dynamically creates classes needed for runtime query processing (storing the results of computation, intermediate tuples, compound keys, etc.)
  • It implements basic relational algebra operations for individual items: aggregate functions, projections, predicates, ordering, group-by, etc.
  • Since I/O overhead is already minimal due to the Eventloop module, bytecode generation ensures that business logic (such as innermost loops processing millions of items) is also as fast as possible.
  • Easy to use API that encapsulates most of the complexity involved in working with bytecode.

You can add the Codegen module to your project by inserting dependency in pom.xml:

<dependency>
    <groupId>io.datakernel</groupId>
    <artifactId>datakernel-codegen</artifactId>
    <version>3.0.0</version>
</dependency>

Examples

Note: To run the examples, you need to clone DataKernel from GitHub:
$ git clone https://github.com/softindex/datakernel
And import it as a Maven project. Check out branch v3.0. Before running the examples, build the project.
These examples are located at datakernel -> examples -> core -> codegen

Codegen Expressions Example

An example of the implementation of sayHello() method:

public final class CodegenExpressionsExample {
	public static void main(String[] args) throws InstantiationException, IllegalAccessException {
		Class<Example> example = ClassBuilder
				// context class loader is used because without it maven runner is not happy with our codegen
				.create(DefiningClassLoader.create(getSystemClassLoader()), Example.class)
				.withMethod("sayHello", call(staticField(System.class, "out"), "println", value("Hello world")))
				.build();
		Example instance = example.newInstance();

		instance.sayHello();
	}

	public interface Example {
		void sayHello();
	}
}

Dynamic Class Creation Example

In this example a class, which implements Person, is dynamically created:

public static void main(String[] args) throws IllegalAccessException, InstantiationException {
	// Construct a Class that implements Person interface
	Class<Person> personClass = ClassBuilder.create(DefiningClassLoader.create(Thread.currentThread().getContextClassLoader()), Person.class)
			// declare fields
			.withField("id", int.class)
			.withField("name", String.class)
			// setter for both fields - a sequence of actions
			.withMethod("setIdAndName", sequence(
					set(property(self(), "id"), arg(0)),
					set(property(self(), "name"), arg(1))))
			.withMethod("getId", property(self(), "id"))
			.withMethod("getName", property(self(), "name"))
			// compareTo, equals, hashCode and toString methods implementations follow the standard convention
			.withMethod("int compareTo(Person)", compareToImpl("id", "name"))
			.withMethod("equals", equalsImpl("id", "name"))
			.withMethod("hashOfPojo", hash(property(arg(0), "id"), property(arg(0), "name")))
			.withMethod("hash", hash(property(self(), "id"), property(self(), "name")))
			.withMethod("toString", ExpressionToString.create()
					.withQuotes("{", "}", ", ")
					.with("id: ", property(self(), "id"))
					.with("name: ", property(self(), "name")))
			.build();

	// Instantiate two objects of dynamically defined class
	Person jack = personClass.newInstance();
	Person martha = personClass.newInstance();

	jack.setIdAndName(5, "Jack");
	martha.setIdAndName(jack.getId() * 2, "Martha");

	System.out.println("First person: " + jack);
	System.out.println("Second person: " + martha);

	System.out.println("jack.equals(martha) ? : " + jack.equals(martha));

	// Compare dynamically created hashing implementation with the conventional one
	ExamplePojo examplePojo = new ExamplePojo(5, "Jack");
	System.out.println(examplePojo);
	System.out.println("jack.hash(examplePojo)  = " + jack.hashOfPojo(examplePojo));
	System.out.println("jack.hash()             = " + jack.hash());
	System.out.println("examplePojo.hashCode()  = " + examplePojo.hashCode());
}