Skip to content

Getting started with Dynamic Menu

This guide explains the minimal steps to integrate Dynamic Menu in a new application.

Prepare the Application

A new application created on start.vaadin.com can be used as a starting point for this tutorial. Open the site, select an empty project, choose Spring Boot as the framework, and download the generated archive. Extract it, import it into your IDE of choice, and verify the application starts correctly by running the main class.

Add the AppJars Repository

AppJars artifacts are published to the public AppJars Maven repository. Add it to your pom.xml so that Maven can resolve the AppJars dependencies:

<repositories>
    <repository>
        <id>appjars</id>
        <name>AppJars Public Repository</name>
        <url>https://maven.appjars.com</url>
        <releases>
            <enabled>true</enabled>
        </releases>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
</repositories>

Add the Dependencies

Given that it is a monolithic application, the following dependencies representing the three layers of the appjar must be added:

<dependency>
    <groupId>com.appjars</groupId>
    <artifactId>appjars-dynamic-menu-flow</artifactId>
</dependency>
<dependency>
    <groupId>com.appjars</groupId>
    <artifactId>appjars-dynamic-menu-data-impl</artifactId>
</dependency>
<dependency>
    <groupId>com.appjars</groupId>
    <artifactId>appjars-dynamic-menu-business-impl</artifactId>
</dependency>

After adding them, build the application to confirm that the dependencies are resolved correctly.

Implement the Authority Utils

Dynamic Menu needs to know what roles and authorities exist in the application in order to restrict menu items by role. Provide this information by implementing the DynamicMenuAuthorityUtils interface and registering it as a Spring component:

@Primary
@Component
public class AppDynamicMenuAuthorityUtils implements DynamicMenuAuthorityUtils {

    @Override
    public Set<String> getAvailableAuthorities() {
        return Set.of("ROLE_USER", "ROLE_ADMIN");
    }

    @Override
    public String getAnonymousAuthority() {
        return "ROLE_ANONYMOUS";
    }
}

The import for DynamicMenuAuthorityUtils is com.appjars.dynamicmenu.utils.DynamicMenuAuthorityUtils.

  • getAvailableAuthorities: Returns the full set of roles or authorities defined in the application. These are presented in the menu item editor when configuring visibility restrictions.
  • getAnonymousAuthority: Returns the authority assigned to unauthenticated users.

The @Primary annotation is required. Dynamic Menu ships a default implementation that returns a placeholder set of roles, so without @Primary the application has two candidate beans and startup fails with an ambiguity error.

Modifying the Main Application Class

The following annotation must be added to the main application class to include the Dynamic Menu auto-configuration and its Spring components:

@ComponentScan(basePackageClasses = {DynamicMenuAutoConfiguration.class, AppJarsAutoConfiguration.class, Application.class})
  • @ComponentScan: Instructs Spring to load the beans provided by the appjar as well as the beans of the application itself. AppJarsAutoConfiguration contributes the components shared across appjars, and it is not registered automatically, so naming it here is required.

The imports are com.appjars.dynamicmenu.DynamicMenuAutoConfiguration and com.appjars.AppJarsAutoConfiguration.

Then inject the RouteConfigurer provided by Dynamic Menu and configure the router layout in a @PostConstruct method so that the appjar views share the same layout as the rest of the application:

@Autowired
@Qualifier("DynamicMenuRouteConfigurer")
RouteConfigurer routeConfigurer;

@PostConstruct
public void configure() {
    routeConfigurer.setViewsRouterLayout(MainLayout.class);
}

The import for RouteConfigurer is com.appjars.dynamicmenu.flow.view.util.RouteConfigurer.

Render the Dynamic Menu

The stored menu items are turned into navigation entries by DynamicMenuItemProvider. Build the navigation from it, in the method createNavigation() of MainLayout, so that the drawer reflects what is configured in the database:

private SideNav createNavigation() {
    SideNav nav = new SideNav();

    for (SideNavItem item : DynamicMenuItemProvider.getInstance().getMenuItems()) {
        nav.addItem(item);
    }
    return nav;
}

The import for the provider is com.appjars.dynamicmenu.flow.service.DynamicMenuItemProvider.

getMenuItems() resolves the roles of the logged-in user and returns only the entries that user is allowed to see. Entries of the application's own that are not managed by the appjar, such as a home view, can be added to the same SideNav alongside them.

Note

While no menu item has been created yet, the provider returns a single Menu Items entry pointing at the management view. A fresh installation therefore always offers a way to reach the editor and create the first item, without the application declaring that entry itself.

Configure Application Properties

Add the following properties to application.properties:

spring.jpa.hibernate.ddl-auto=update
spring.jpa.generate-ddl=true
spring.jpa.properties.hibernate.event.merge.entity_copy_observer=allow

The spring.jpa.properties.hibernate.event.merge.entity_copy_observer=allow property is required. Menu items form a tree, so a single merge can reach the same item twice — once as an entry and once through its parent — which Hibernate rejects by default.

Finally, add com.flowingcode and com.appjars to the list of whitelisted packages in application.properties:

vaadin.allowed-packages = com.vaadin,org.vaadin,com.example.application,com.flowingcode,com.appjars

Testing the Application

Start the application by running the main Spring Boot class. After it starts, the navigation drawer shows a single Menu Items entry, because no item has been configured yet. Open it.

Create a new menu item by clicking the New item button. Assign it a label, an optional icon, and an internal route pointing to an existing view in the application. Optionally restrict its visibility to specific roles on the Permissions tab. Once saved, the item appears in the application's navigation drawer.