Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Customizing Vaadin HTML Template

DZone's Guide to

Customizing Vaadin HTML Template

This week, I had an interesting question on Twitter: "How in Vaadin do you add a lang attribute to the html element?" While it’s quite easy to customize individual components on the page, the outer HTML tag is outside our control. In this article, I’ll describe a possible solution to this problem.

· Web Dev Zone
Free Resource

Start coding today to experience the powerful engine that drives data application’s development, brought to you in partnership with Qlik.

This week, I had an interesting question on Twitter: "How in Vaadin do you add alang attribute to the html element?", like this:

<html lang="fr">

While it’s quite easy to customize individual components on the page, the outer HTML tag is outside our control. In this article, I’ll describe a possible solution to this problem. Note that I think this is too specialized for morevaadin.com. However, this should still be my reference site for all things Vaadin.

My first (wrong) thought, was that the html element is generated by the UI widget client-side. It’s not the case—as there’s no such widget. In order to find the answer, I had to understand how the framework works. Here’s a short summary of the sequence when one makes a request to a Vaadin application.

Basically, the Vaadin Servlet delegates to the Vaadin Service. In turn, the service loops over its internal list of Request Handlers until one of them is able to handle the request. By default, the Vaadin Service registers the following handlers:

  1. ConnectorResourceHandler
  2. UnsupportedBrowserHandler: returns a specific message if the browser is not supported by Vaadin
  3. UidlRequestHandler: handles RPC communication between client and server
  4. FileUploadHandler: handles file uploads achieved with the FileUpload component
  5. HeartbeatHandler: handles heartbeat requests
  6. PublishedFileHandler
  7. SessionRequestHandler: delegates in turn to request handlers that have been registered in the session

This is implemented in VaadinService.createRequestHandlers(). However, notice that VaadinService is abstract. There’s a subtle change introduced in the concrete VaadinServletService subclass that is used. It registers a new request handler–theServletBootstrapHandler, in order for Vaadin to run transparently in both a servlet and a portlet context. In this later case, only a fragment :









The servlet bootstrap handler is responsible for generating the initial HTML page at the start of the application, including the desired outer html tag. Next, requests to the application will just update part of the page via AJAX, but the outside HTML won’t change. Thus, this is the class that needs to be updated if one wishes to add a lang attribute. A quick glance at the class makes it very clear that it’s quite hard to extend. Besides, it delegates HTML generation to the JSoup and more precisely to the Document.createShell()static method.

At this point, you have 3 options:

  1. Forget about it, what is it worth anyway?
  2. Rewrite a large portion of the BootstrapHandler and add it before the BootstrapHandler in the handlers sequence
  3. Be lazy and apply Ockham’s razor: just use a simple AOP‘s aspect

In order to be of any use, I chose the latest option. It’s quite straightforward and very concise, you only need the following steps.

Create the aspect itself. Note that I’m using Kotlin to be coherent with the existing project but Java or any other JVM-based language would be the same.

@Aspect
open class UpdateLangAspect {

    @Pointcut("execution(static * org.jsoup.nodes.Document.createShell(..))")
    fun callDocumentCreateShell(): Unit {}

    @AfterReturning(pointcut = "callDocumentCreateShell()", returning = "document")
    fun setLangAttribute(document: Document): Unit {
        document.childNode(0).attr("lang", "fr")
    }
}

As the method to instrument is static, it’s not possible to use simple Spring proxies, but we need AspectJ class instrumentation viaLTW. In order to activate it in Spring Boot, I just have to update the application.properties file:

spring.aop.proxy-target-class=true

Also, one has to tell Aspect’s weaver what needs to be instrumented in the META-INF/aop.xml:

<?xml version="1.0" encoding="UTF-8"?>
<aspectj>
  <aspects>
    <aspect name="ch.frankel.blog.bootvaadinkotlin.UpdateLangAspect" />
  </aspects>
  <weaver options="-XnoInline -Xlint:ignore -verbose -showWeaveInfo">
    <include within="org.jsoup.nodes.Document" />
    <include within="ch.frankel.blog.bootvaadinkotlin.UpdateLangAspect" />
  </weaver>
</aspectj> 

The first section is about the aspect, the second is about what classes need to be instrumented. Note that weaving section needs also to reference the aspect too.

Finally, one has to update the POM so that launching the application through the Spring Boot Maven plugin will also use the aspect.

<plugin>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-maven-plugin</artifactId>
  <configuration>
    <agent>${settings.localRepository}/org/aspectj/aspectjweaver/1.8.8/aspectjweaver-1.8.8.jar</agent>
  </configuration>
</plugin>

For the sake of completeness, the code is available on Github on the manage-lang branch.

At this point, generating the page will display the desired change. Job done!

Create data driven applications in Qlik’s free and easy to use coding environment, brought to you in partnership with Qlik.

Topics:
vaadin

Published at DZone with permission of Nicolas Frankel, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}