4.5.1.3.6. Controller Companions

Controller base classes are located in the gui module of the cuba base project and do not contain references to the implementation of visual component classes (Swing or Vaadin). This allows you to use them in both types of clients.

At the same time concrete controller classes can be created in gui, web or desktop modules, depending on screen specifics and client blocks used in the project. If a controller is common for all client types but additional functionality is required for different client types, it can be implemented in so-called companion classes.

Companion class is located in client module of the corresponding client type (web or desktop) and implements an interface defined in the controller that uses the companion class. A companion class should be defined in the companions element of the screen XML-descriptor. Controller can retrieve a reference to the companion instance using injection or by invoking getCompanion(), and then pass control to the companion instance when appropriate, e.g. for extended initialization of visual components in a way specific to a given client type.

For example, on some screen, you need to initialize a table differently for web and desktop clients. Then in the screen controller located in gui module, define a companion interface and delegate the table initialization to it:

public class CustomerBrowse extends AbstractLookup {

    public interface Companion {
        void initTable(Table<Customer> table);
    }

    @Inject
    protected Table<Customer> table;
    @Inject
    protected Companion companion;

    @Override
    public void init(Map<String, Object> params) {
        if (companion != null) {
            companion.initTable(table);
        }
    }
}

Create companion implementations in web and desktop modules:

public class WebCustomerBrowseCompanion implements CustomerBrowse.Companion {
    @Override
    public void initTable(Table<Customer> table) {
        com.vaadin.ui.Table webTable = (com.vaadin.ui.Table) WebComponentsHelper.unwrap(table);
        // do something specific to Vaadin table
    }
}
public class DesktopCustomerBrowseCompanion implements CustomerBrowse.Companion {
    @Override
    public void initTable(Table<Customer> table) {
        javax.swing.JTable desktopTable = (javax.swing.JTable) DesktopComponentsHelper.unwrap(table);
        // do something specific to Swing table
    }
}

And register the implementation classes in the screen XML descriptor:

<window ...
      class="com.company.sample.gui.customers.CustomerBrowse">
  <companions>
      <web class="com.company.sample.web.customers.WebCustomerBrowseCompanion"/>
      <desktop class="com.company.sample.desktop.customers.DesktopCustomerBrowseCompanion"/>
  </companions>
  <dsContext>...</dsContext>
  <layout>...</layout>
</window>

The companion classes are located in web and desktop modules, therefore you can use WebComponentsHelper.unwrap() and DesktopComponentsHelper.unwrap() to get references to Vaadin and Swing components implementing the table.