Bnd globbing capabilities

Hi,

According to the documentation, the $classes macro supports a NAMED;PATTERN query where PATTERN is a glob. Does this glob support any kind of “exclude” option please? In particular, something like **[!$]* so as to exclude any fqn which contains a $ character?

I am trying to exclude nested, inner and anonymous classes here.

Thanks,
Chris

Yes, not very advanced. You can use character classes in a glob, and character classes can be negated.

 [^$]+

This will match foo.bar but not foo$bar.

You should also be able to chain filters and also negate filers with !;

${classes;NAMED;!PATTERN;NAMED;PATERN}

(note I had negated in the wrong place… need to negate the filter input not the filter name)

Thanks, I think both of these solutions would work… if only the names of inner, nested and anonymous classes actually contained a $ character to find! My println debugging has revealed that the class name I am matching against is:

com.foo.bar.MyClass.InnerClass

and not

com.foo.bar.MyClass$InnerClass

A consequence of the query using getClassName().getDottedOnly() here, I believe :cry:.

Cheers,
Chris

Edit: Yes, matching against getClassName().getFQN() would have the behaviour that I seek. So I guess the question becomes “Is this a bug? Or a request for a new feature (pretty) please”?

Hmm, the documentation says:

NAMED PATTERN The class fqn must match the given pattern.

:eyes:

To close the loop here, I added STATIC and INNER query types for the ${classes} macro to enable selection of non-inner or inner classes, respectively.

It is a bad idea to look for a $ in the class name as an indicator that it is an inner (or even nested) class. $ is a completely legitimate character in a Java identifier such as a class name.

I also updated the doc page for the ${classes} macro to be more clear on the form of the name used for each query type.

Thanks for doing this. It turns out that Kotlin will happily generate static anonymous classes, and so my final query now contains:

STATIC;NAMED;!*.[\d]+

Cheers,
Chris

Hmmm. I would like to get one of these class files to look at it and see how it differs from a Java anonymous inner class. It would be better if Bnd could properly recognize these. Could you get one to me?

No problem. I think I’ve just sent you a Google Drive link.

Cheers,
Chris

Thanks! In the example you sent, the member classes did not reference anything from the enclosing scope. So the generated class files are more member classes than inner classes.

When I changed the source code to reference a variable from the enclosing scope, then the generated class is an inner class and is passed the instance of enclosing scope.

         0: new           #32                 // class com/example/Example$execute$localOp$1
         3: dup
         4: aload_0
         5: invokespecial #36                 // Method com/example/Example$execute$localOp$1."<init>":(Lcom/example/Example;)V
  com.example.Example$execute$localOp$1();
    descriptor: (Lcom/example/Example;)V
    flags:
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: aload_1
         2: putfield      #31                 // Field this$0:Lcom/example/Example;

However, the kotlin compiler seems to generate an improper InnerClassesAttribute in this case:

InnerClasses:
     public static final #2; //class com/example/Example$execute$localOp$1

It declares the member class as static which I would say is incorrect.

Looking at some test classes used in the Bnd test cases, there are also some old pre Java 7 anonymous classes also marked static in the InnerClassesAttribute.

So I made a fix to the isInnerClass test to handle these odd cases better. See https://github.com/bndtools/bnd/pull/4565. With this fix, Bnd will properly recognize kotlin’s anonymous and local classes and Bnd will also properly recognize anonymous classes made by older Java compilers.

Thanks for the test code which enabled me to understand how to make the fix.