Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to create any compile time functions in Java?

Tags:

java

gwt

I am looking to create some functions in Java that would be called at compile time - and be entirely excluded from the runtime (i.e. compiled class files). These functions could write to variables which could have different values for different releases of the software. What's the beast way to do this? These could be "final" variables.

This is, by the way, a GWT project and the functions should be able to write to both client and server sides.

Consider this simple example:

final int x = 10;
final int y = x/100;
final int z = y + x - 500;

Here are three "final" variables x, y, and z defined where the values of y and z are dependent on x which is a constant! That means that values of y and z also never actually change in the program. But because they have to be defined as a function of x - their values will be calculated at runtime - which is unnecessary usage of resources at runtime. A compile time function would hardcode the value of y and z and speed up the runtime by a little bit! Obviously, this is a simple example but my real use case has plenty of complex time consuming calculations to be done, which slows down my application. Calculating this at compile time would be really nice and would avoid errors caused by manually hardcoding the numbers if you quickly need multiple releases of the applications with different values of the variables.

Additionally, consider this example:

final String value = getMyValue("argument");

final String getMyValue(String variable){
    return variable + "Lol!";
}

Would you expect the value of "value" to be calculated at compile time? On both client and server side?

like image 376
EternallyCurious Avatar asked May 28 '13 14:05

EternallyCurious


2 Answers

For GWT client side code you can use deferred binding to generate Java code at compile time. You create a subclass of com.google.gwt.core.ext.Generator. Google uses deferred binding for i.e. localization, etc. I used it to implement a simple XML mapper for GWT, but that's closed source.

For example you create an interface com.foo.Constants:

public interface Constants {
  int getY();
  int getZ();
}

And create a Generator for your constants:

public class ConstantsGenerator extends Generator {
  private static final String PACKAGE_NAME = "com.foo";
  private static final String SIMPLE_CLASS_NAME = "GeneratedConstants";
  private static final String CLASS_NAME = PACKAGE_NAME + "." + SIMPLE_CLASS_NAME;

  @Override
  public String generate(TreeLogger logger, GeneratorContext context,
    String typeName) throws UnableToCompleteException {
    // Get a SourceWriter to create the class GeneratedConstants.
    // If it returns null, then this class was already created during this compilation
    // step and we only return the name of class.
    final SourceWriter sourceWriter = getSourceWriter(logger, context);
    if(sourceWriter != null) {
      // Otherwise create the new class ...
      generateConstantsClass(sourceWriter, logger);
    }

    return CLASS_NAME;
  }

  private SourceWriter getSourceWriter(TreeLogger logger, GeneratorContext context) {
    final ClassSourceFileComposerFactory composer = 
      new ClassSourceFileComposerFactory(PACKAGE_NAME, SIMPLE_CLASS_NAME);

    // The generated class implements com.foo.Constants
    composer.addImplementedInterface("com.foo.Constants");

    // Add some imports, if needed
    // composer.addImport("java.util.Map");

    final PrintWriter printWriter = context.tryCreate(logger, PACKAGE_NAME, SIMPLE_CLASS_NAME);
    if(printWriter == null)
      return null;
    else {
      final SourceWriter sw = composer.createSourceWriter(context, printWriter);
      return sw;
    }
  }

  private void generateConstantsClass(SourceWriter sourceWriter, TreeLogger logger) {
    final int y = calculateY();  // Do here the heavy calculation for y.
    final int z = calculateZ();  // Do here the heavy calculation for z.

    // Create the source code for the two Methods getY() and getZ().
    sourceWriter.println(String.format("public int getY() { return %d; }", y));
    sourceWriter.println(String.format("public int getZ() { return %d; }", z));

    sourceWriter.commit(logger);
  }
}

Then you have to configure your GWT module XML file:

<generate-with class="com.foo.ConstantsGenerator">
  <when-type-assignable class="com.foo.Constants" />
</generate-with>

Then in your GWT client code you can create an instance of your generated class like this:

public Constants getConstants() {
  return (Constants) GWT.create(Constants.class);
}

But this only works for client side code. And it is maybe a little bit too much overhead to only precalculate some values.

It would be easier to include a code generation step into your build scripts. Then you can use your generated classes both in server and client code.

But for precalculated values this could still be too much overhead. You can avoid to generate code at all if you only generate a simple file (like a properties file) with your precalculated values and load it at runtime.

On server side this should be no problem. For client side, you can generate your GWT hostpage with JSP and include your precalculated values as a JavaScript dicationary. In GWT code it is then easy to get access to those values.

like image 156
vanje Avatar answered Oct 03 '22 20:10

vanje


You are looking for compile time meta programming. That means that during compilation phase your source or abstract syntax tree is preprocessed or modified in a certain way.

If you look at C++, there is template meta programming.

As for Java I am not aware of a direct means to accomplish this.

So the next cousin would be Scala: They call it macros, and it allows you to modify the abstract syntax tree at compile time. For example, I use this to remove code completely, based on boolean conditions.

Given the compatibility, you could write your complex calculations in Scala, and use it from Java.

like image 36
Beryllium Avatar answered Oct 03 '22 22:10

Beryllium