Custom static metamodel for deep referencing
I just tried out how we could create a static metamodel that allows deep referencing and I was able to come up with a solution. Making use of a static metamodel is really important as it makes the queries more type safe. Although we can't use it for entity views, queries can benefit from it. If we implement #83 there won't be such a big need for a static metamodel anymore since entity views would be checked at startup time.
The idea is similar to what the JPA static metamodel offers but goes further. It generates "relation" classes that hold instance variables, representing the fields of an entity.
public class Person {
private Integer id;
private String name;
//...
}
// Custom subtype to allow treating path as expression directly
interface ExtendedSingularAttribute<X, Y> extends Expression<Y> {
SingularAttribute<X, Y> attr();
}
@DeepStaticMetamodel(Person.class)
public class Person_ {
public static voltaile ExtendedSingularAttribute<Person, Integer> id;
public static volatile ExtendedSingularAttribute<Person, String> name;
public static final String ID = "id";
public static final String NAME = "name";
}
public class PersonRelation<T, A extends Attribute<?, ?>> implements AttributePath<T, Person> {
private final AttributePath<T, Person> path;
public PersonRelation(AttributePath<T, Person> path) {
this.path = path;
}
public A attr() {
return (A) path.getLast();
}
public AttributePath<T, Integer> id() {
return path.get(Person_.id);
}
public AttributePath<T, String> name() {
return path.get(Person_.name);
}
}
When a person is referenced, a PersonRelation is used instead of a normal singular attribute. This allows for deep referencing like Document_.owner.name
public class Document {
private Integer id;
private Person owner;
}
@DeepStaticMetamodel(Document.class)
public class Document_ {
public static volatile ExtendedSingularAttribute<Document, Integer> id;
public static volatile PersonRelation<Document> owner;
public static final String ID = "id";
public static final String OWNER = "owner";
// Max level for static deep referencing is 5, Maybe introduce annotation for activating deep referencing or configuring per type/attribute?
public static class OWNER_ {
public static final String ID = "owner.id";
public static final String NAME = "owner.name";
}
}
To implement this we can adopt a lot of what other static metamodel generators already have. In the end it is just an annotation processor generating these classes.
It would also be interesting to support generating static metamodels for enums.
package a.b.c;
enum Status {
OK,
FAILED;
}
Would produce
package a.b.c;
interface Status_ {
String OK = "a.b.c.Status.OK";
String FAILED = "a.b.c.Status.FAILED";
}
which is very convenient for uses in @Mapping annotations.
Apart from the generation of the static metamodel we would also have to add support for it in the API which might not be that easy.