简体   繁体   中英

org.primefaces.model.menu.DefaultSubMenu cannot be cast to javax.faces.component.UIComponent

Im trying to upgrade from PrimeFaces 3.5 to PrimeFaces 4.0, the line of code that its fine on version 3.5 is this one:

private MenuModel modelPrincipal;
private Menubar menuBar;

menuBar.getChildren().addAll(modelPrincipal.getContents());

But when I upgrade to version 4.0 I have to change it as follows:

private org.primefaces.model.menu.DefaultMenuModel modelPrincipal;
private Menubar menuBar;
menuBar.getChildren().addAll((Collection<? extends UIComponent>) modelPrincipal.getElements());

and it throws the Exception of title, do you guys know a workaround for it? I couldn't find anything on the documentation of the migration https://github.com/primefaces/primefaces/wiki/Migration-Guide

I also tried:

menuBar.getElements().addAll(modelPrincipal.getElements());

But gives me same Exception

Any help is appreciated

EDIT (Minimal (this is as minimal as I could make the code to make the error appear) Reproducible Example):

This is PrimeFaces 4.0:

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;

import javax.faces.component.UIComponent;

import org.primefaces.component.menubar.Menubar;
import org.primefaces.model.menu.DefaultMenuItem;
import org.primefaces.model.menu.DefaultSubMenu;

public class MenuExampleMB {
    private org.primefaces.model.menu.DefaultMenuModel modelPrincipal;
    private Menubar menuBar;
    private HashMap<String, SubMenuItemObject> menuUrlCodigos;

    public static void main(String[] args) {
        MenuExampleMB menuExampleMB = new MenuExampleMB();
        // MenuList
        List<MenuObject> menuList = new ArrayList<>();
        // SubMenuItemList
        List<SubMenuItemObject> subMenuList = new ArrayList<>();
        // Add 1 item to the SubMenuItemList
        subMenuList.add(new SubMenuItemObject("1", "SubMenu", "an url"));
        // MenuObject
        MenuObject menu1 = new MenuObject("Menu 1");
        // Set the SubMenu list for this MenuObject
        menu1.setlSubmenus(subMenuList);
        menuList.add(menu1);
        // Call method that brings the Exception
        menuExampleMB.loadMenu(menuList);
    }

    public void loadMenu(List<MenuObject> lMenus) {

        menuUrlCodigos = new HashMap<String, SubMenuItemObject>();
        modelPrincipal = new org.primefaces.model.menu.DefaultMenuModel();
        menuBar = new Menubar();
        // Go through the list of MenuObject and create each SubMenu and add them to
        // DefaultMenuModel
        for (MenuObject menu : lMenus) {
            DefaultSubMenu subMenu = new DefaultSubMenu();
            subMenu = agregarSubmenu(menu.getlSubmenus());
            subMenu.setLabel(menu.getTitulo());
            modelPrincipal.addElement(subMenu);
        }
        // This is the one that brings the exception.
        menuBar.getChildren().addAll((Collection<? extends UIComponent>) modelPrincipal.getElements());

    }

    private DefaultSubMenu agregarSubmenu(List<SubMenuItemObject> lSubMenuUsuario) {

        DefaultMenuItem menuItem = null;
        DefaultSubMenu subMenuPadre = new DefaultSubMenu();

        for (SubMenuItemObject subMenuItem : lSubMenuUsuario) {

            // Ask if this submenu has sons
            if (subMenuItem.getlSubmenus().size() > 0) {

                DefaultSubMenu subMenuHijo = new DefaultSubMenu();
                subMenuHijo.setLabel(subMenuItem.getTitulo());

                /*
                 * Invoke this method with recursivity to get all the sons of this menu
                 * 
                 */
                subMenuHijo.getElements().addAll(agregarSubmenu(subMenuItem.getlSubmenus()).getElements());

                // Add sons to the father submenu.
                subMenuPadre.getElements().add(subMenuHijo);

            } else {
                // This submenu doesn't have sons so its created as an unique son of the
                // father submenu.
                menuItem = agregarItem(subMenuItem);
                subMenuPadre.getElements().add(menuItem);
                subMenuPadre.setLabel(subMenuItem.getTitulo());
            }

        }

        return subMenuPadre;
    }

    private DefaultMenuItem agregarItem(SubMenuItemObject pSubMenuItem) {
        DefaultMenuItem menuItem = new DefaultMenuItem();
        menuItem.setValue(pSubMenuItem.getTitulo());
        menuItem.setUrl(pSubMenuItem.getUrl());

        menuUrlCodigos.put(pSubMenuItem.getUrl(), pSubMenuItem);

        return menuItem;
    }

}

class MenuObject {
    private String titulo;
    private List<SubMenuItemObject> lSubmenus = new ArrayList<SubMenuItemObject>();

    public MenuObject(String pTitulo) {
        titulo = pTitulo;
    }

    public String getTitulo() {
        return titulo;
    }

    public void setTitulo(String titulo) {
        this.titulo = titulo;
    }

    public List<SubMenuItemObject> getlSubmenus() {
        return lSubmenus;
    }

    public void setlSubmenus(List<SubMenuItemObject> lSubmenus) {
        this.lSubmenus = lSubmenus;
    }
}

class SubMenuItemObject {
    private String codigo;
    private String titulo;
    private String url;
    private List<String[]> lJerarquia;
    private List<String> lTabs;
    private List<SubMenuItemObject> lSubmenus = new ArrayList<SubMenuItemObject>();

    public SubMenuItemObject(String pCodigo, String pTitulo, String pUrl) {
        codigo = pCodigo;
        titulo = pTitulo;
        url = pUrl;
        lJerarquia = new ArrayList<String[]>();
    }

    public SubMenuItemObject() {

    }

    public String getCodigo() {
        return codigo;
    }

    public void setCodigo(String codigo) {
        this.codigo = codigo;
    }

    public String getTitulo() {
        return titulo;
    }

    public void setTitulo(String titulo) {
        this.titulo = titulo;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public List<SubMenuItemObject> getlSubmenus() {
        return lSubmenus;
    }

    public void setlSubmenus(List<SubMenuItemObject> lSubmenus) {
        this.lSubmenus = lSubmenus;
    }

    public List<String[]> getlJerarquia() {
        return lJerarquia;
    }

    public void setlJerarquia(List<String[]> lJerarquia) {
        this.lJerarquia.clear();
        this.lJerarquia.addAll(lJerarquia);
    }

    public List<String> getlTabs() {
        return lTabs;
    }

    public void setlTabs(List<String> lTabs) {
        this.lTabs = lTabs;
    }
}

The classcast in

 menuBar.getChildren().addAll((Collection<? extends UIComponent>) modelPrincipal.getElements());

is sort of logical since the org.primefaces.model.menu.DefaultMenuItem elements in the model are not in any way a UIComponent (you can see this by following the source up to the base class/interface). Even if you'd not have explicitly casted this it would have failed with the same error but on another line in another class.

Doing the

menuBar.getElements().addAll(modelPrincipal.getElements());

Fails for the same reason. If you'd inspected the code in the getElements() method in the menuBar , you'd have seen

public List getElements() {
    MenuModel model = getModel();
    if (model != null) {
        return model.getElements();
    }
    else {
        return getChildren();
    }
}

You could have even debugged it and seen that the model was null and then the getChildren() would be returned, effectively ending up in the same calls as in your first attempt. But...

You'd also see the getModel() in there, maybe being a hint in where to look for the solution. The menuBar has a setModel(...) to where you can set the model you programmatically created. So the solution for this is

menuBar.setModel(modelPrincipal);

IF you create the menuBar programmatically.

But most often it is added in the xhtml via

<p:menu model="#{menuBean.model}" />

Some additional hints:

  • A search for "primefaces menu model 4.0 3.5" resulted in hits that would have given you help/hints (at least G00gle showed then to me)
  • typing 'menumodel' in the PrimeFaces 7 documentation would have given a hint to the dynamic menu part in the generic menu component, having a full complete example. https://primefaces.github.io/primefaces/7_0/#/components/menu
  • Having an IDE with code completion in java code or xhtml and check the api's would have shown the setModel method or the model attribute.

But I agree, a little more explanation in the migration document would have helped, but at the time (when at least I migrated from 3.5 to 4) this was mentioned in the forums etc... so it was 'actual' at the time

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM