docs: public void scanForMenuItems(){
  		Map<String, Map<String, MenuItemExt>> allMenuItems = new PutIfAbsentMap<String, Map<String, MenuItemExt>>(
  				new HashMap<String, Map<String, MenuItemExt>>(), 
  				new MapValueFactory<String, Map<String, MenuItemExt>>(){
  					@Override
  					public Map<String, MenuItemExt> createValue(String key) {
  						return new TreeMap<String, MenuItemExt>();
  					}
  				});
  				//new HashMap<String, Map<String, MenuItemExt>>();	// <menuName, <path, MenuItemExt>>
  		
  		// Get all beans that may have menu items defined
  		Map<String, Object> beans =  appContext.getBeansWithAnnotation(WebMenu.class);
  		beans.putAll(appContext.getBeansWithAnnotation(RequestMapping.class));
  		
  		// Find all menu items 
  		for (Object bean: beans.values()){
  			Class<?> beanClass;
  			if (bean instanceof Advised){		// if EnhancerBySpringCGLIB
  				beanClass = ((Advised)bean).getTargetClass();
  			}else{
  				beanClass = bean.getClass();
  			}
  			
  			// Check class level annotations first
  			RequestMapping classRequestMapping = beanClass.getAnnotation(RequestMapping.class);
  			WebMenu classWebMenu = beanClass.getAnnotation(WebMenu.class);
  			if (true) {//classWebMenu != null && classWebMenu.value().length() != 0){	// not hidden
  				MenuItemExt classMenuItem = new MenuItemExt(classWebMenu, classRequestMapping);
  				
  				String basePath = classMenuItem.path != null ? classMenuItem.path : "";
  				if(classMenuItem.title != null && classMenuItem.title.length() > 0){		// it is also a visible menu item
  					MenuItemExt existing = allMenuItems.get(classMenuItem.menuName).put(basePath, classMenuItem);
  					if (existing != null){
  						log.error("Duplicated web menu item definitions in " + beanClass.getName() 
  								+ ".\n\tExisting: " + existing + "\n\tCurrent: " + classMenuItem);
  					}
  				}
  				
  				// Then look into all the methods
  				for(Method method : beanClass.getMethods()) {
  					RequestMapping methodRequestMapping = method.getAnnotation(RequestMapping.class);
  					WebMenu methodWebMenu = method.getAnnotation(WebMenu.class);
  					if (methodWebMenu != null && methodWebMenu.value().length() != 0){	// not hidden
  						MenuItemExt methodMenuItem = new MenuItemExt(methodWebMenu, methodRequestMapping, classMenuItem);
  						
  						if (methodMenuItem.menuName != null){
  							MenuItemExt existing = allMenuItems.get(methodMenuItem.menuName).put(methodMenuItem.path, methodMenuItem);
  							if (existing != null){
  								log.error("Duplicated web menu item definitions in " + beanClass.getName() + "." + method.toGenericString() 
  										+ ".\n\tExisting: " + existing + "\n\tCurrent: " + methodMenuItem);
  							}
  						}
  					}
  				}
  			}
  		}
  		
  		// construct menu trees
  		menus = new HashMap<String, WebMenuItem>();
  		menuItemPaths = new HashMap<String, Map<String, WebMenuItem>>();
  		
  		for (Map.Entry<String, Map<String, MenuItemExt>> menuItems: allMenuItems.entrySet()){
  			String menuName = menuItems.getKey();
  			Map<String, MenuItemExt> items = menuItems.getValue();
  			WebMenuItem root = new WebMenuItem();
  			root.title = menuName;			// for the root, set its title as menu name
  			root.breadcrumbs = new ArrayList<WebMenuItem>(1);
  			root.breadcrumbs.add(root);		// root is the first in breadcrumbs
  			menus.put(menuName, root);
  			menuItemPaths.put(menuName, new HashMap<String, WebMenuItem>());
  			for (MenuItemExt itemExt: items.values()){
  				String path = itemExt.path;
  				WebMenuItem parent = null;
  				do{
  					path = StringUtils.substringBeforeLast(path, "/");
  					if (path == null || path.indexOf('/') == -1){
  						parent = root;
  						break;
  					}
  					parent = items.get(path);
  				}while (parent == null);
  				parent.addSubItem(itemExt);
  			}
  			
  			// clean up the tree
  			cleanUpMenuTree(root, menuName);
  			log.info("Menu '" + menuName + "' loaded:\n" + root);
  		}
  	}