protected void buildConfiguration()

in plugins/convention/src/main/java/org/apache/struts2/convention/PackageBasedActionConfigBuilder.java [681:795]


    protected void buildConfiguration(Set<Class<?>> classes) {
        Map<String, PackageConfig.Builder> packageConfigs = new HashMap<>();

        for (Class<?> actionClass : classes) {
            Actions actionsAnnotation = actionClass.getAnnotation(Actions.class);
            Action actionAnnotation = actionClass.getAnnotation(Action.class);

            // Skip classes that can't be instantiated
            if (cannotInstantiate(actionClass)) {
                LOG.trace("Class [{}] did not pass the instantiation test and will be ignored", actionClass.getName());
                continue;
            }

            if (eagerLoading) {
                // Tell the ObjectFactory about this class
                try {
                    objectFactory.getClassInstance(actionClass.getName());
                } catch (ClassNotFoundException e) {
                    LOG.error("Object Factory was unable to load class [{}]", actionClass.getName(), e);
                    throw new StrutsException("Object Factory was unable to load class " + actionClass.getName(), e);
                }
            }

            // Determine the action package
            String actionPackage = actionClass.getPackage().getName();
            LOG.debug("Processing class [{}] in package [{}]", actionClass.getName(), actionPackage);

            Set<String> allowedMethods = getAllowedMethods(actionClass);

            // Determine the default namespace and action name
            List<String> namespaces = determineActionNamespace(actionClass);
            for (String namespace : namespaces) {
                String defaultActionName = determineActionName(actionClass);
                PackageConfig.Builder defaultPackageConfig = getPackageConfig(packageConfigs, namespace,
                        actionPackage, actionClass, null);

                // Verify that the annotations have no errors and also determine if the default action
                // configuration should still be built or not.
                Map<String, List<Action>> map = getActionAnnotations(actionClass);
                Set<String> actionNames = new HashSet<>();
                boolean hasDefaultMethod = ReflectionTools.containsMethod(actionClass, DEFAULT_METHOD);
                if (!map.containsKey(DEFAULT_METHOD)
                        && hasDefaultMethod
                        && actionAnnotation == null && actionsAnnotation == null
                        && (alwaysMapExecute || map.isEmpty())) {
                    boolean found = false;
                    for (List<Action> actions : map.values()) {
                        for (Action action : actions) {

                            // Check if there are duplicate action names in the annotations.
                            String actionName = action.value().equals(Action.DEFAULT_VALUE) ? defaultActionName : action.value();
                            if (actionNames.contains(actionName)) {
                                throw new ConfigurationException("The action class [" + actionClass +
                                        "] contains two methods with an action name annotation whose value " +
                                        "is the same (they both might be empty as well).");
                            } else {
                                actionNames.add(actionName);
                            }

                            // Check this annotation is the default action
                            if (action.value().equals(Action.DEFAULT_VALUE)) {
                                found = true;
                            }
                        }
                    }

                    // Build the default
                    if (!found) {
                        createActionConfig(defaultPackageConfig, actionClass, defaultActionName, DEFAULT_METHOD, null, allowedMethods);
                    }
                }

                // Build the actions for the annotations
                for (Map.Entry<String, List<Action>> entry : map.entrySet()) {
                    String method = entry.getKey();
                    List<Action> actions = entry.getValue();
                    for (Action action : actions) {
                        PackageConfig.Builder pkgCfg = defaultPackageConfig;
                        if (action.value().contains("/") && !slashesInActionNames) {
                            pkgCfg = getPackageConfig(packageConfigs, namespace, actionPackage,
                                    actionClass, action);
                        }

                        createActionConfig(pkgCfg, actionClass, defaultActionName, method, action, allowedMethods);
                    }
                }

                // some actions will not have any @Action or a default method, like the rest actions
                // where the action mapper is the one that finds the right method at runtime
                if (map.isEmpty() && mapAllMatches && actionAnnotation == null && actionsAnnotation == null) {
                    createActionConfig(defaultPackageConfig, actionClass, defaultActionName, null, actionAnnotation, allowedMethods);
                }

                //if there are @Actions or @Action at the class level, create the mappings for them
                String methodName = hasDefaultMethod ? DEFAULT_METHOD : null;
                if (actionsAnnotation != null) {
                    List<Action> actionAnnotations = checkActionsAnnotation(actionsAnnotation);
                    for (Action actionAnnotation2 : actionAnnotations)
                        createActionConfig(defaultPackageConfig, actionClass, defaultActionName, methodName, actionAnnotation2, allowedMethods);
                } else if (actionAnnotation != null)
                    createActionConfig(defaultPackageConfig, actionClass, defaultActionName, methodName, actionAnnotation, allowedMethods);
            }

            allowlistClasses.addAll(ConfigurationUtil.getAllClassTypes(actionClass));
        }
        providerAllowlist.registerAllowlist(this, allowlistClasses);

        buildIndexActions(packageConfigs);

        // Add the new actions to the configuration
        Set<String> packageNames = packageConfigs.keySet();
        for (String packageName : packageNames) {
            configuration.addPackageConfig(packageName, packageConfigs.get(packageName).build());
        }
    }