Codegen Module

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

  • Dynamically creates classes needed for runtime query processing (storing the results of computation, intermediate tuples, compound keys etc.)
  • 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 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 Codegen module to your project by inserting dependency in pom.xml:

<dependency>
    <groupId>io.datakernel</groupId>
    <artifactId>datakernel-codegen</artifactId>
    <version>3.0.0-beta1</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. Before running the examples, build the project.

Codegen Expressions Example

An example of 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(self(), "id", arg(0)),
					set(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)", compareTo("id", "name"))
			.withMethod("equals", asEquals("id", "name"))
			.withMethod("hashOfPojo", hashCodeOfArgs(property(arg(0), "id"), property(arg(0), "name")))
			.withMethod("hash", hashCodeOfArgs(property(self(), "id"), property(self(), "name")))
			.withMethod("toString", ((ExpressionToString) asString())
					.withQuotes("{", "}", ", ")
					.withArgument("id: ", property(self(), "id"))
					.withArgument("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());
}