Generate code that implements JSR 308 runtime validation "instanceof @MyAnotations"

JSR 308 suggests adding type annotations to Java. Once ratified, programmers will be able to add annotations wherever the Java type is allowed. This includes not only decoration of methods / fields / local / parameters, but also constructor calls, throw types and the most interesting instance checks. The Checker Framework uses JSR 308 to implement type classifiers, such as @NonNull for object types, or @Regex for strings.

Now all that Checkers does is a static analysis of your code. These are all compile-time checks. It's great. But what I want to have is a mechanism that can perform checks at runtime. You can declare:

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

I can also write:

 if (x instanceof @Regex String) ... 

but this is no different from x instanceof String , execution checking is not performed. I need an annotation processor compiler time compiler or a runtime runtime manipulator that allows me to run arbitrary code on instanceof checks and returns a boolean value. Is this possible with Java?

+4
source share
2 answers

Yes, you can. But this is neither trivial nor supported by the available annotation API handlers. The available annotation API is limited for creating new classes and does not allow modifying existing bytecodes (even in JDK 8). You can use special compiler classes at the annotation processor level, which allows you to use many more options. But you will have to use the internal compiler API and rewrite it for each available compiler (JDT and JavaC). You can take a look at the Lombok project ( http://projectlombok.org/ ), which is very similar. Unfortunately, Lombok is not yet compatible with annotations of the new JDK8 type.

+4
source

For your regex example, the solution is very simple. I also give some information about cases where the solution is not so simple.

How to implement a run-time test depends on whether the type system is a calculation of the properties of the data itself or the properties of the origin (data source). Here is the text in the " " Runtime Checks and Type Clarification " Framework Checker Guide :

Some type systems support a run-time test that the Framework can use to refine types within a conditional expression, for example, if, after assert is approved, etc.

Regardless of whether the type system supports such a test at runtime, whether the type system is a calculation of the properties of the data itself or the property of origin (data source). Example A data property about whether a string is a regular expression. An example of property of origin is units: there is no way to look at the representation of a number and determine whether it should represent kilometers or miles.

1) For data properties , your easiest option is to avoid test instances and instead use the tests that come with the Framework Checker, such as isRegex .

For example, instead of

  if (x instanceof @Regex String) ... 

records

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

and you're done.

If you really want to use instanceof instead of isRegex , you will need to hack the compiler to convert each source code to x instanceof @Regex String to RegexUtil.isRegex(x) . You can also do this by overwriting the byte code.

2) For properties near the origin , implementation efforts are much greater. You will need to add a bit of evidence to the representation of each database in your program (including both objects and primitives) and change each operation (in your own program and in libraries) so that in addition to working with data this also matches the origin bit . A tool that already does this, on which you can build, is DynComp , which is distributed as part of the Daikon invariant detector .

+2
source

Source: https://habr.com/ru/post/1436010/


All Articles