Java: Type aliases support annotation processing tool (APT)?

497 views Asked by At

I never worked with type aliases, but this concept seems to be a very useful feature adding semantics over same-typed objects and defending from common typos.

Let's say, there is void foo(float volume, float weight). It's ok if it's invoked like this: foo(v, m), but foo(m, v) is not an obvious typo. void process(Iterable<File> javaPath, Iterable<File> classPath) can be another use case. Unfortunately there are no type aliases in Java, and some workarounds are a true overkill:

  • aggregating a single field into a class (boxing a primitive into an object; an object in an object having an extra reference; more complicated serializing/deserializing rules)
  • extending one class from another one (like how do i create some variable type alias in Java - impossible for primitives; classes may be final or have an inaccessible constructor).

So both of them have drawbacks and runtime/performance cost.

As far as I can see, in Java, runtime-based "type aliasing" might be replaced with compile-time checks, like @NotNull and @Nullable are processed. Are there any static type-alias checkers/APT tools featuring support for constructions like void foo(@Volume float volume, @Weight float weight), so that checker could verify such "type safety" at compile time and require passed variables/constants and literals to be annotated (at declaration and call sites respectively)?


This question also has been raised because I'm currently working on a Java-source code processing tool that can use multiple back-ends (currently, JDT only). As long as I want it to be JDT-agnostic, I would like to have business objects for types, methods and fields. Despite, I lose a lot of information coming from JDT AST, the best current approach for my tool is use of strings (it allows to perform some analysis that's enough for the scope of the tool). But methods like void process(String type, String field, String method) are confusing, so I've created Type, Field and Method that represent the domain objects and are JDT-agnostic. They're fine, but I don't expect them to be extended in the future (all of these three types have single private final String name; field + I had to override hashCode/equals and toString). That led me to the idea of type-checking APT once again. As long as it's ok to process raw data, it would be enough to have something like void process(@Type String type, @Field String field, @Method String method) (I still could use a single object).

1

There are 1 answers

9
Adrian Shum On

If your problem is it looks ambiguous when you call foo(v,m) that people may mistakenly wrote foo(m,v) without any warning or visible clue of error, you may use a fluent-builder-like pattern:

(Code not tested, just wrote to demonstrate the idea)

public class MyClass {
    public class FooStub {
        int volume;
        int weight;
        public FooStub withVolume(int v) {
            this.volume = v;
            return this;
        }
        public FooStub withWeight(int w) {
            this.weight = w;
            return this;
        }
        public int run() {   // or call it getResult() or whatever you want
            Assert.notNull(volume);
            Assert.notNull(weight);
            return foo(volume,weight);  // calling method of outer class
        }
    }

    public int foo(int volume, int weight) {   // you even hide this if you want
        return volume * weight;
    }
    public FooStub foo() {
        return new FooStub();
    }

}

By doing so, caller can do

MyClass myObj = ....;
int result = myObj.foo().withVolume(a).withWeight(b).run();
// which is the same as result = myObject.foo(a,b);