Pregunta

JSR 308 proposes to add type annotations to Java. After its ratification, programmers will be able to add an annotation wherever a Java type is currently allowed. That includes not only method/field/local/parameter decorations, but also constructor calls, type casts, and most curiously instanceof checks. The Checker Framework uses JSR 308 to implement type qualifiers like @NonNull on object types, or @Regex on strings.

Now all what Checkers does is to statically analyze your code. That's all compile time checks. That's fine. But what I want to have is a mechanism that can do checks at runtime. You can declare:

@Regex String p1 = "[a-z]+";
@Regex String p1 = "[a-z)+";    // compile time error from annotation processor

I can also write:

if (x instanceof @Regex String) ...

but that is no different from x instanceof String, no runtime check is performed. I need a compile time annotation processor or runtime bytecode manipulator that lets me run arbitrary code on instanceof checks and return a boolean. Is this possible with Java?

¿Fue útil?

Solución

Yes you can. But its not trivial and not supported by annotation processors accessible API. The accessible Annotation Processor API is limited to generate new classes and is not allowed to modify existing bytecodes (even in JDK 8). You could cast to compiler specific classes at annotation processor level, which enables a lot more options. But you would have to use the compilers internal API and rewrite it for each compiler available (JDT and JavaC). You may take a look at project Lombok (http://projectlombok.org/) which does a very similar thing. Sadly Lombok is not yet compatible with JDK8s new type anntotations.

Otros consejos

For your example of regular expressions, the solution is very simple. I also give some information about cases when the solution is not so simple.

How to implement a run-time test depends on whether the type system is computing properties of data itself, or properties of provenance (the source of the data). Here is text from section "Run-time tests and type refinement" of the Checker Framework manual:

Some type systems support a run-time test that the Checker Framework can use to refine types within the scope of a conditional such as if, after an assert statement, etc.

Whether a type system supports such a run-time test depends on whether the type system is computing properties of data itself, or properties of provenance (the source of the data). An example of a property about data is whether a string is a regular expression. An example of a property about provenance is units of measure: there is no way to look at the representation of a number and determine whether it is intended to represent kilometers or miles.

1) For properties of the data, your simplest option is to avoid instanceof tests and instead use the tests that are shipped with the Checker Framework, such as isRegex.

For example, instead of

  if (x instanceof @Regex String) ...

write

  if (RegexUtil.isRegex(x)) ...

and you are done.

If you really want to use instanceof instead of isRegex, then you will need to hack the compiler to convert each source-code occurrence of x instanceof @Regex String into RegexUtil.isRegex(x). You could also do this via byte-code rewriting.

2) For properties about provenance, the implementation effort is much greater. You will have to add a provenance bit to the representation of each datum in your program (including both objects and primitives) and change every operation (in your own program and in libraries) so that in addition to operating on the data, it also appropriately maintains the provenance bit. A tool that already does this, which you might be able to build upon, is DynComp, which is distributed as part of the Daikon invariant detector.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top