[toc]

An overview of the

Aviator is an open source Java expression evaluator, not only supports four operations, ternary operations, logical operations, and its powerful interface to support custom extension functions. In view of this, my original R&D team chose the Google computing engine based on the company’s business scenario and defined a series of custom functions to support our business scenario in order to expand our business requirements.

The source code

features

The data type

  • The Number type: numeric type, two types are supported, corresponding to Java Long and Double respectively, that is, any integer will be converted to Long, and any floating point number will be converted to Double, including values passed in by the user. Scientific notation is not supported, only decimal notation is supported. For example, -1, 100, 2.3, etc.
  • Type String: String, a text String enclosed in single or double quotation marks, such as’ helloWorld ‘. The variable is also converted to String if it is passed in as String or Character.
  • Bool type: The constants true and false, representing true and false values, correspond to the Java Boolean. True and Boolean.False.
  • The Pattern type: Similar to Ruby and Perl regular expressions, the string enclosed in //, such as /\d+/, is internally implemented as java.util.pattern.
  • Variable typesThe value of a variable is passed in by the user, for example, “A” or “b”
  • Nil type==, nil ==, nil ==! =, can also compare >, >=, <, <=. Aviator specifies that n is greater than nil for any type except nil, where nil==nil returns true. Variable values passed in by the user that are null are treated as nil, and nil is printed as null.

Operation type

Arithmetic operator

Aviator supports common arithmetic operators, including the five binary operators + – * / % and the unary operator “-“. Where – * / % and unary “-” only work on Number types. “+” can be used not only for the Number type, but also for adding strings, or strings with other objects. Aviator states that any type added to String yields String.

Logical operator

The logical operators supported by Avaitor include the unary negation operator “!” , as well as the “&”, logic and logic or the “| |”. The operands of logical operators can only be Boolean. Relational operators Aviator support relational operators include “<” “< =” “> =” “>” and “= =” and “! = “. Short circuit is implemented && and | | rules. Relational operators can compare relationships between Number, String, Pattern, Boolean, variable, and nil. Different types cannot compare with each other except nil. Aviator dictates that any object is bigger than nil except for nil.

An operator

Aviator support all Java operators, including “&” “|” “^” ~ “” “> > “” < <” “> > >”.

Matching operator

The matching operator “=~” is used to match String and Pattern. Its left operand must be String and its right operand must be Pattern. After the match is successful, the group of Pattern will be stored in the variable $num, where num is the group index.

Ternary operator

Aviator does not provide an if else statement, but does provide the ternary operator “? : “of the form bool? Exp1: exp2. Where bool must be a Boolean expression, exp1 and exp2 can be any valid Aviator expression, and exp1 and exp2 are not required to return the same result type.

Extension features

Digital extension

1, multiple numbers: sum

Summing multiple numbers, ignoring null values and treating them as zeros, provides compatibility.

Sample code:

/ * * *@description: Sums multiple numbers (any number that is empty is treated as a 0) *@Date : 2021/4/11 9:43 AM
 * @Author: Shi Dongdong -Seig Heil */
public class SumTest {
    @Test
    public void test(a){
        Map<String,Object> evn = new HashMap<String,Object>(){{
            put("x".2);
            put("y".4);
            put("z".8);
        }};
        System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("sum(x,y,z,h)").env(evn).build())); }}Copy the code

Output:

14
Copy the code

2. Obtain the maximum value of multiple digits: Max

Get the maximum value for multiple numbers, ignore null values and treat them as 0, providing compatibility.

Sample code:

/ * * *@description: Maximizes multiple digits (if any of them is empty, it is treated as 0) *@Date : 2021/4/11 9:43 AM
 * @Author: Shi Dongdong -Seig Heil */
public class MaxTest {
    @Test
    public void test(a){
        Map<String,Object> evn = new HashMap<String,Object>(){{
            put("x".2);
            put("y".4);
            put("z".8);
        }};
        System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("max(x,y,z,h)").env(evn).build())); }}Copy the code

Output:

8
Copy the code

3. Obtain the maximum value of multiple digits: min

Get minimum values for multiple numbers, ignore null values and treat them as 0, providing compatibility.

Sample code:

/ * * *@description: Minimizes multiple digits (if any of them is empty, it is treated as 0) *@Date : 2021/4/11 9:43 AM
 * @Author: Shi Dongdong -Seig Heil */
public class MinTest {
    @Test
    public void test(a){
        Map<String,Object> evn = new HashMap<String,Object>(){{
            put("x".2);
            put("y".4);
            put("z".8);
        }};
        System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("min(x,y,z,h)").env(evn).build())); }}Copy the code

Output:

2
Copy the code

4. Round up: ceil

Take up the whole

Sample code:

/ * * *@description: Round up *@Date : 2021/4/11 9:43 AM
 * @Author: Shi Dongdong -Seig Heil */
public class CeilTest {

    @Test
    public void test(a){

        System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("The ceil (1.2)").env(Collections.emptyMap()).build()));

        System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("The ceil (1.6)").env(Collections.emptyMap()).build()));

        System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("ceil(201)").env(Collections.emptyMap()).build()));

        System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("ceil(196)").env(Collections.emptyMap()).build())); }}Copy the code

Output:

2.0
2.0
201.0
196.0
Copy the code

5, round down: floor

Take up the whole

Sample code:

/ * * *@description: Round down *@Date : 2021/4/11 9:43 AM
 * @Author: Shi Dongdong -Seig Heil */
public class FloorTest {

    @Test
    public void test(a){

        System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("The floor (1.2)").env(Collections.emptyMap()).build()));

        System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("The floor (1.6)").env(Collections.emptyMap()).build()));

        System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("floor(201)").env(Collections.emptyMap()).build()));

        System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("floor(196)").env(Collections.emptyMap()).build())); }}Copy the code

Output:

1.0
1.0
201.0
196.0
Copy the code

6, round: round

rounded

Sample code:

/ * * *@description: Rounded *@Date : 2021/4/11 9:43 AM
 * @Author: Shi Dongdong -Seig Heil */
public class RoundTest {

    @Test
    public void test(a){

        System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("Round (1.2)").env(Collections.emptyMap()).build()));

        System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("Round (1.6)").env(Collections.emptyMap()).build()));

        System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("round(201)").env(Collections.emptyMap()).build()));

        System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("round(196)").env(Collections.emptyMap()).build())); }}Copy the code

Output:

1, 2, 201, 196Copy the code

7, precision processing: scale

Precision processing, specific parameters that view org. Suze from the aviator. The function. The number, Scale

Sample code:

/ * * *@description: Number rounding method and precision carry processing *@Date : 2021/4/11 9:43 AM
 * @Author: Shi Dongdong -Seig Heil */
public class ScaleTest {

    @Test
    public void test(a){
        Map<String,Object> evn = new HashMap<String,Object>(){{
            put("x".15.344);
        }};
        System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("Scale (x, 0, 0)").env(evn).build()));
        System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("Scale (x, 0, 1)").env(evn).build()));
        System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("Scale (x, 0, 2)").env(evn).build()));
        System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("The scale (x, - 2, 1)").env(evn).build()));
        System.out.println(AviatorExecutor.executeBigDecimal(AviatorContext.builder().expression("The scale (x, - 2, 2)").env(evn).build())); }}Copy the code

Output:

15, 16, 15, 100, 0Copy the code

Set extension

1. Determine whether a string is in a string interval set: in(Finder,delimiter,values)

Determine whether a string is in a string interval collection. Finder represents the search item, delimiter delimiter, and values is the delimiter delimiter string.

Sample code:

/ * * *@description: Determines whether a string is in a set of string intervals@Date : 2021/4/11 9:43 AM
 * @Author: Shi Dongdong -Seig Heil */
public class InTest {
    @Test
    public void test(a){
        Map<String,Object> evn = new HashMap<String,Object>(){{
            put("x".15);
        }};
        String expression = "In (x, ', ', '15,34,22')"; AviatorContext ctx = AviatorContext.builder().expression(expression).env(evn).build(); System.out.println(AviatorExecutor.executeBoolean(ctx)); }}Copy the code

Output:

true
Copy the code

2. Determine whether a string is notin a string interval set: notin(finder,delimiter,values)

Determine whether a string is not in a string interval collection. Finder represents the search item, delimiter delimiter, and values is the delimiter delimiter string.

Sample code:

/ * * *@description: Determines whether a string is in a set of string intervals@Date : 2021/4/11 9:43 AM
 * @Author: Shi Dongdong -Seig Heil */
public class InTest {
    @Test
    public void test(a){
        Map<String,Object> evn = new HashMap<String,Object>(){{
            put("x".15);
        }};
        String expression = "Notin (x, ', ', '15,34,22')"; AviatorContext ctx = AviatorContext.builder().expression(expression).env(evn).build(); System.out.println(AviatorExecutor.executeBoolean(ctx)); }}Copy the code

Output:

false
Copy the code

The generic function

Extended custom functions based on the requirements of daily business scenarios.

1. Date: days.diff(current,destination)

The difference between the two dates is date

Sample code:

/ * * *@description: Indicates the difference between two dates. The parameter type is date *@Date : 2021/4/11 10:19 AM
 * @Author: Shi Dongdong -Seig Heil */
public class DiffDaysTest {

    @SneakyThrows
    @Test
    public void test(a){
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Map<String,Object> evn = new HashMap<String,Object>(){{
            put("current",simpleDateFormat.parse("2021-04-11"));
            put("destination",simpleDateFormat.parse("2020-04-11"));
        }};
        String expression = "days.diff(current,destination)"; AviatorContext ctx = AviatorContext.builder().expression(expression).env(evn).build(); System.out.println( AviatorExecutor.executeBigDecimal(ctx)); }}Copy the code

Output:

365
Copy the code

2, get birthday age: age(date)

Calculate the age based on the date of birth. The date of birth is a character string

Sample code:

/ * * *@description: Calculate the age based on the date of birth. The date of birth is a character string *@Date : 2021/4/11 10:19 AM
 * @Author: Shi Dongdong -Seig Heil */
public class AgeTest {

    @SneakyThrows
    @Test
    public void test(a){
        Map<String,Object> evn = new HashMap<String,Object>(){{
            put("birth"."19880808");
        }};
        String expression = "age(birth)";
        AviatorContext ctx = AviatorContext.builder().expression(expression).env(evn).build();
        System.out.println("age:"+ AviatorExecutor.execute(ctx)); }}Copy the code

Output:

32
Copy the code

3, Summation of string numbers: string.numbers. Sum

Summation of numbers in a string

Sample code:

/ * * *@description: Intercepts the sum of numbers in a string *@Date : 2021/4/11 10:19 AM
 * @Author: Shi Dongdong -Seig Heil */
public class StringNumbersSumTest {

    @SneakyThrows
    @Test
    public void test(a){
        String str = "Borrowing amount of insurance premium: RMB (first year: RMB 5,600.00; Second year: 1110.00 YUAN; Third year: 1000.00 YUAN)";
        Map<String,Object> evn = new HashMap<String,Object>(){{
            put("str",str);
        }};
        String expression = "String. Numbers. Sum (STR, '-', ': ',' yuan ')";
        AviatorContext ctx = AviatorContext.builder().expression(expression).env(evn).cached(false).build(); System.out.println(AviatorExecutor.execute(ctx)); }}Copy the code

Output:

7710.00
Copy the code

4, numeral to uppercase amount: chinese.number.upper(num)

Summation of numbers in a string

Sample code:

/ * * *@description: Uppercase amount *@Date : 2021/4/11 10:19 AM
 * @Author: Shi Dongdong -Seig Heil */
public class ChineseNumberUpperTest {

    @SneakyThrows
    @Test
    public void test(a){
        BigDecimal num = new BigDecimal("11111.01");
        Map<String,Object> evn = new HashMap<String,Object>(){{
            put("num",num);
        }};
        String expression = "chinese.number.upper(num)"; AviatorContext ctx = AviatorContext.builder().expression(expression).env(evn).build(); System.out.println(AviatorExecutor.execute(ctx)); }}Copy the code

Output:

Eleven thousand eleven hundred and eleven centsCopy the code

The object function

When null, set a default value

If NVL (value,defaultValue) is null, set a defaultValue: NVL (value,defaultValue)

The difference between the two dates is date

Sample code:

/ * * *@description: Calculate the age based on the date of birth. The date of birth is a character string *@Date : 2021/4/11 10:19 AM
 * @Author: Shi Dongdong -Seig Heil */
public class NvlTest {

    @SneakyThrows
    @Test
    public void test(a){
        String expression = "nvl(a,0)"; AviatorContext ctx = AviatorContext.builder().expression(expression).env(Collections.emptyMap()).build(); System.out.println(AviatorExecutor.executeBigDecimal(ctx)); }}Copy the code

Output:

0
Copy the code

2, string toNumber: objects.tonumber (value,defaultValue)

String toNumber, if the string is empty, use the defaultValue as the return value, objects.tonumber (value,defaultValue)

Sample code:

/ * * *@description: objects.toNumber(x,y)
 * @Date : 2021/4/11 10:19 AM
 * @Author: Shi Dongdong -Seig Heil */
public class ToNumberTest {

    @SneakyThrows
    @Test
    public void test(a){
        String expression = "objects.toNumber('1',0)"; AviatorContext ctx = AviatorContext.builder().expression(expression).env(Collections.emptyMap()).build(); System.out.println(AviatorExecutor.executeBigDecimal(ctx)); }}Copy the code

Output:

1
Copy the code

Objects.tostring (value,defaultValue)

Number toString, if number is empty,defaultValue is used as the return value, objects.tostring (value,defaultValue)

Sample code:

/ * * *@descriptionObjects.tostring (value,defaultValue) * if the number is empty, the defaultValue is used as the return value@Date : 2021/4/11 10:19 AM
 * @Author: Shi Dongdong -Seig Heil */
public class ToStringTest {

    @SneakyThrows
    @Test
    public void test(a){
        String expression = "objects.toString(1,'0')"; AviatorContext ctx = AviatorContext.builder().expression(expression).env(Collections.emptyMap()).build(); System.out.println(AviatorExecutor.executeBigDecimal(ctx)); }}Copy the code

Output:

1
Copy the code

Advanced features

Sample code:

/ * * *@description: Based on Aviator test class *@Date : 2018/9/7 下午6:00
 * @Author: Shi Dongdong -Seig Heil([email protected]) */
@Slf4j
public class AviatorObjectTest {

    @Test
    public void object_instance(a){
        Teacher teacher = new Teacher(){{
            setName("im");
            setScore(20);
        }};

        Student student = new Student(){{
            setName("Jack");
            setScore(22);
        }};
        Map<String,Object> env = new HashMap<String,Object>(){{
            put("teacher",teacher);
            put("student",student);
        }};

        Object value = AviatorExecutor.execute(AviatorContext.builder().env(env).expression("student.name").build());
        System.out.println(value);
    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class Colleague {
        private String name;
        private double score;
    }

    @Data
    @NoArgsConstructor
    public class Student extends Colleague {

        public Student(String name, double score) {
            super(name, score); }}@Data
    @NoArgsConstructor
    public class Teacher extends Colleague {}}Copy the code

Output:

Jack
Copy the code

Further reading

CSDN introduction to nuggets introduction Aviator source address Aviator API related documents