xmlet/HtmlFlow

Groovy compilation errors ...

paulbandler opened this issue · 4 comments

I am experimenting using HtmlFlow from Groovy and encountering some challenges finding the groovy statically typed syntax to use. I want the benefit of the static type checking, so include an annotation (@CompileStatic) that tells the compiler to that to check types and resolve method linkage at compile time. There is a rather intricate relationship between groovy 'Closures' and Java Single Abstract Method interfaces that TBH I don't fully understand, but I have been able to find a syntax that seems to be fully accepted by the IDE. Here is such an example of a 'partial':

    static HtmlView<LevelHeaderRowModel> headerView = DynamicHtml.view({ DynamicHtml<LevelHeaderRowModel> view, LevelHeaderRowModel headerModel ->
        view.tr()
                .th().addAttr("width", "26%").addAttr("style", "...").text(headerModel.leftLevelLabel).__()
                .th().addAttr("width", "11%").addAttr("style", "text-right").text(headerModel.leftFieldLabel).__()
                .th().addAttr("width", "5%").text("Count").__()
                .th().addAttr("width", "26%").text(headerModel.rightLevelLabel).__()
                .th().addAttr("width", "11%").attrClass("text-right").text(headerModel.rightFieldLabel).__()
                .th().addAttr("width", "5%").text("Count").__()
                .th().addAttr("width", "4%").attrClass("text-right").__()
                .th().addAttr("width", "12%").attrClass("text-right padding-right-medium").text("Delta").__()
                .__()
    } as BiConsumer<DynamicHtml<LevelHeaderRowModel>, LevelHeaderRowModel>)

Sadly though when I try to run a simplyetest that uses the above, I get groovy compilation errors such as:

...BreakdownRenderer.groovy: 103: [Static type checking] - Cannot find matching method org.xmlet.htmlapifaster.Element#th(). Please check if the declared type is correct and if the method exists.
 @ line 103, column 9.
           view.tr()
           ^

where line 103 is the line above containing the view.tr() expression.

However, if I then remove the @CompileStatic, leaving method resolution to groovy's dynamic runtime resolution, the exact same code works fine.

I appreciate that this is a groovy specific issue, and not really the concern of this library, but I'm raising it here to ask whether others have previously successfully used this library from the groovy language and if so, whether there is any advice available on appropriate syntax / type hints needed to make it work when statically compiled.

I know nothing about Groovy. But, rather than a closure could you define the template as a named function and then pass the function pointer (or method reference) as parameter to DynamicView.view(<template function pointer>)? It will make any difference on your issue?

In Java it would be something like:

static HtmlView<LevelHeaderRowModel> headerView = DynamicHtml.view(::myTemplate)

static void myTemplate(DynamicHtml<LevelHeaderRowModel> view, LevelHeaderRowModel headerModel) {
        view.tr()
                .th().addAttr("width", "26%").addAttr("style", "...").text(headerModel.leftLevelLabel).__()
                .th().addAttr("width", "11%").addAttr("style", "text-right").text(headerModel.leftFieldLabel).__()
                .th().addAttr("width", "5%").text("Count").__()
   ...
}

Thanks for your prompt reply. Unfortunately Groovy 2.x, which I am constrained to using currently, doesn't support method references, so need to use Closures. I will ask in a Groovy forum for suggestions on how to make this work with @CompileStatic.

The above issues are resolved by using Groovy 4, which has fuller support for theJava type system. I suspect that maybe the sophisticated use of Java Generics by htmlflow is problematic for the pre-Groovy 4 static type checker implementation

@paulbandler Great news! Nice "sophisticated use of Java Generics by htmlflow" :-)