Does the platform provide many expressions, but they don't meet your scenario needs? How should we add new expressions to satisfy project requirements?

I. Scenarios for Extending Expressions

When needing to perform NULL validation on a specific parameter within a List-type field of input parameters, and finding that the platform's built-in functions cannot support configuration for this scenario, you can leverage the platform's relevant mechanisms to extend built-in functions.

Common code scenarios are as follows:

java
package pro.shushi.pamirs.demo.core.action;

......Imported classes

@Model.model(PetShopProxy.MODEL_MODEL)
@Component
public class PetShopProxyAction extends DataStatusBehavior<PetShopProxy> {

    @Override
    protected PetShopProxy fetchData(PetShopProxy data) {
        return data.queryById();
    }
    @Validation(ruleWithTips = {
        @Validation.Rule(value = "!IS_BLANK(data.code)", error = "Encoding is a required field"),
        @Validation.Rule(value = "LEN(data.name) < 128", error = "Name is too long, cannot exceed 128 characters"),
    })
    @Action(displayName = "Enable")
    @Action.Advanced(invisible="!(activeRecord.code !== undefined && !IS_BLANK(activeRecord.code))")
    public PetShopProxy dataStatusEnable(PetShopProxy data){
        data = super.dataStatusEnable(data);
        data.updateById();
        return data;
    }

    ......Other code

}

II. Creating a Custom Expression Function

A function for validating input parameters. When the input is a collection object, if a specific field of any single object in the collection is null, the function returns false.

Example:

Create a CustomCollectionFunctions class

java
package xxx.xxx.xxx;

import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Component;
import pro.shushi.pamirs.meta.annotation.Fun;
import pro.shushi.pamirs.meta.annotation.Function;
import pro.shushi.pamirs.meta.common.constants.NamespaceConstants;
import pro.shushi.pamirs.meta.util.FieldUtils;

import java.util.List;

import static pro.shushi.pamirs.meta.enmu.FunctionCategoryEnum.COLLECTION;
import static pro.shushi.pamirs.meta.enmu.FunctionLanguageEnum.JAVA;
import static pro.shushi.pamirs.meta.enmu.FunctionOpenEnum.LOCAL;
import static pro.shushi.pamirs.meta.enmu.FunctionSceneEnum.EXPRESSION;

/**
 * Custom built-in functions
 */
@Fun(NamespaceConstants.expression)
@Component
public class CustomCollectionFunctions {

    /**
     * LIST_FIELD_NULL is our custom expression, which must not repeat existing expressions!!!
     *
     * @param list
     * @param field
     * @return
     */
    @Function.Advanced(
        displayName = "Verify if the integrated parameter is null", language = JAVA,
        builtin = true, category = COLLECTION
    )
    @Function.fun("LIST_FIELD_NULL")
    @Function(name = "LIST_FIELD_NULL", scene = {EXPRESSION}, openLevel = LOCAL,
              summary = "Function example: LIST_FIELD_NULL(list,field). Function description: Pass an object collection to verify if the collection's field is null"
             )
    public Boolean listFieldNull(List list, String field) {
        if (null == list) {
            return false;
        }
        if (CollectionUtils.isEmpty(list)) {
            return false;
        }
        for (Object data : list) {
            Object value = FieldUtils.getFieldValue(data, field);
            if (value == null) {
                return false;
            }
        }
        return true;
    }

}

III. Registering the Custom Expression Class to the Platform's Whitelist

Example:

Create the CustomFaasScriptAllowListApi class, where the @Order priority must be higher than the platform's default priority to take effect.

java
package xxx.xxx.xxx;

import org.apache.commons.collections4.SetUtils;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import pro.shushi.pamirs.framework.faas.fun.builtin.*;
import pro.shushi.pamirs.framework.faas.spi.api.guard.FaasScriptAllowListApi;
import pro.shushi.pamirs.meta.common.constants.NamespaceConstants;
import pro.shushi.pamirs.meta.common.spi.SPI;

import java.util.Set;

/**
 * Custom implementation of SPI for function whitelist and blacklist allowing expression calls
 */
@Order(1) // Increase the priority of the custom class here
@Component
@SPI.Service
public class CustomFaasScriptAllowListApi implements FaasScriptAllowListApi {

    // Whitelist
    public static final Set<String> DEFAULT_SET = SetUtils.hashSet(

        // Whitelist, directly replicate the default implementation: pro.shushi.pamirs.framework.faas.spi.service.DefaultFaasScriptAllowListApi
        CollectionFunctions.class.getName(),
        ContextFunctions.class.getName(),
        DateFunctions.class.getName(),
        LogicFunctions.class.getName(),
        MapFunctions.class.getName(),
        MathFunctions.class.getName(),
        ObjectFunctions.class.getName(),
        RegexFunctions.class.getName(),
        TextFunctions.class.getName(),

        // Add your own whitelist classes below
        CustomCollectionFunctions.class.getName()

    );

    @Override
    public Set<String> classWhiteList() {
        return DEFAULT_SET;
    }

    @Override
    public Set<String> namespaceWhiteList() {
        return SetUtils.hashSet(NamespaceConstants.expression);
    }

}

IV. Using Custom Expressions

Example:

Demo usage scenario:

java
/**
     * Note: The [field] parameter of the custom function is a text, so quotes must be added to indicate the parameter is text; otherwise, data cannot be parsed. The same applies to other scenarios.
     *
     * @param data
     * @return
     */
@Action.Advanced(name = FunctionConstants.create, managed = true)
@Action(displayName = "Confirm", summary = "Create", bindingType = ViewTypeEnum.FORM)
@Function(name = FunctionConstants.create)
@Function.fun(FunctionConstants.create)
@Validation(ruleWithTips = {
    @Validation.Rule(value = "LIST_FIELD_NULL(data.itemAttributes,'itemId')", error = "Field cannot be empty"),
})
public DemoItem create(DemoItem data) {
return demoItemService.create(data);
}

Conclusion: You can leverage the platform's mechanisms to establish a set of expressions tailored to your specific scenario requirements.