Backend Development 9 min read

Custom Verify Class for JsonPath Validation with Groovy Operator Overloading

This article introduces a Groovy‑based Verify utility that overloads arithmetic and comparison operators to simplify JsonPath response validation, eliminating manual type conversions and enabling expressive syntax for front‑end test cases.

FunTester
FunTester
FunTester
Custom Verify Class for JsonPath Validation with Groovy Operator Overloading

When using the JsonPath utility class for API response validation, the native JsonPath API returns values as objects, requiring extra conversion code.

This limitation is inconvenient for front‑end users who write test cases with textual markup; a more natural syntax using operators like >, +, /, = would be helpful.

Combining this need with Groovy operator overloading techniques, a custom Verify class was created to provide overloaded operators for JsonPath verification.

Code

package com.fun.utils

import com.alibaba.fastjson.JSON
import com.alibaba.fastjson.JSONArray
import com.alibaba.fastjson.JSONException
import com.alibaba.fastjson.JSONObject
import com.fun.frame.SourceCode
import org.slf4j.Logger
import org.slf4j.LoggerFactory

/**
 * 操作符重写类,用于匹配JSonpath验证语法,基本重载的方法以及各种比较方法,每个方法重载三次,参数为double,String,verify
 * 数字统一采用double类型,无法操作的String对象的方法返回empty
 */
class Verify extends SourceCode implements Comparable {
    public static Logger logger = LoggerFactory.getLogger(Verify.class)

    /**
     * 验证文本
     */
    String extra

    /**
     * 验证数字格式
     */
    double num

    /**
     * 构造方法,暂时写着,尽量使用jsonutil创造verify对象
     * @param json
     * @param path
     */
    private Verify(JSONObject json, String path) {
        this(JsonUtil.getInstance(json).getString(path))
        if (isNumber()) num = changeStringToDouble(extra)
    }

    private Verify(String value) {
        extra = value
        logger.info("构建verify对象:{}",extra)
        if (isNumber()) num = changeStringToDouble(extra)
    }

    /**
     * 获取实例方法
     * @param json
     * @param path
     * @return
     */
    static Verify getInstance(JSONObject json, String path) {
        new Verify(json, path)
    }

    static Verify getInstance(String str) {
        new Verify(str)
    }

    /**
     * 加法重载
     * @param i
     * @return
     */
    def plus(double i) { isNumber() ? num + i : extra + i.toString() }

    /**
     * 加法重载,string类型
     * @param s
     * @return
     */
    def plus(String s) { isNumber() && isNumber(s) ? num + changeStringToDouble(s) : extra + s }

    /**
     * 加法重载,verify类型
     * @param s
     * @return
     */
    def plus(Verify v) { isNumber() && v.isNumber() ? this + (v.num) : extra + v.extra }

    /**
     * 减法重载
     * @param i
     * @return
     */
    def minus(double i) { isNumber() ? num - i : extra - i.toString() }

    /**
     * 加法重载,string类型
     * @param s
     * @return
     */
    def minus(String s) { extra - s }

    def minus(Verify v) { if (isNumber() && v.isNumber()) this - v.num
        extra - v.extra }

    /**
     * extra * i 这里会去强转double为int,调用intvalue()方法
     * @param i
     * @return
     */
    def multiply(double i) { if (isNumber()) num * i
        extra * i }

    def multiply(String s) { isNumber() ? isNumber(s) ? num * changeStringToDouble(s) : s * num : isNumber(s) ? extra * changeStringToDouble(s) : EMPTY }

    def multiply(Verify v) { this * v.extra }

    /**
     * 除法重载
     * @param i
     * @return
     */
    def div(int i) { if (isNumber()) num / i }

    def div(String s) { if (isNumber() && isNumber(s)) num / changeStringToDouble(s) }

    def div(Verify v) { if (isNumber() && v.isNumber()) num / v.num }

    def mod(int i) { if (isNumber()) (int) (num % i * 10000) * 1.0 / 10000 }

    /**
     * 直接取值,用于数组类型
     * @param i
     * @return
     */
    def getAt(int i) { try { JSONArray.parseArray(extra)[i] } catch (JSONException e) { i >= extra.length() ? EMPTY : extra[i] } }

    /**
     * 直接取值,用户json类型
     * @param i
     * @return
     */
    def getAt(String s) { try { JSON.parseObject(extra)[s] } catch (JSONException e) { extra.indexOf(s) } }

    /**
     * if (a implements Comparable) { a.compareTo(b) == 0 } else { a.equals(b) }
     * @param a
     * @return
     */
    boolean equals(Verify verify) { extra == verify.extra }

    boolean equals(Number n) { num == n.doubleValue() }

    boolean equals(String s) { extra == s }

    @Override
    boolean equals(Object o) { extra == o.toString() }

    /**
     * a <=> b  a.compareTo(b)
     * a>b      a.compareTo(b) > 0
     * a>=b     a.compareTo(b) >= 0
     * a<b      a.compareTo(b) < 0
     * a<=b     a.compareTo(b) <= 0
     * @param o
     * @return
     */
    @Override
    int compareTo(Object o) { if (isNumber() && (o instanceof Number || isNumber(o.toString()))) { return num.compareTo(o.toString() as Double) } else { extra.length().compareTo(o.toString().length()) } }

    /**
     * 类型转换,用于as关键字
     * @param tClass
     * @return
     */
    def
T asType(Class
tClass) { logger.info("强转类型:{}", tClass.toString())
        if (tClass == Integer) num.intValue()
        else if (tClass == Double) num
        else if (tClass == Long) num.longValue()
        else if (tClass == String) extra
        else if (tClass == Verify) new Verify(extra)
        else if (tClass == Boolean) changeStringToBoolean(extra) }

    /**
     * 用户正则匹配
     * @param regex
     * @return
     */
    def regex(String regex) { extra ==~ regex }

    /**
     * 是否是数字
     * @return
     */
    def isNumber() { isNumber(extra) }

    /**
     * 是否为boolean类型
     * @return
     */
    def isBoolean() { extra ==~ ("false|true") }

    @Override
    String toString() { extra }
}

Demo Code

package com.fun.ztest.groovy

import com.fun.frame.httpclient.FanLibrary
import com.fun.utils.Verify

class Ft extends FanLibrary {
    public static void main(String[] args) {
        def instance1 = Verify.getInstance("fdsafds")
        def instance2 = Verify.getInstance("fdsa")
        def instance3 = Verify.getInstance("0.2365")
        def instance4 = Verify.getInstance("5.0")
        def instance5 = Verify.getInstance("5")
        println instance1 + instance2
        println instance1 - instance2
        println instance1 * instance2 as boolean
        println instance3 > instance4
        println instance3 * instance4
        println instance1 * instance4
        println instance5 == instance4
        println instance5 / instance4

        println instance4 as Integer

        testOver()
    }
}

Console Output

INFO-> 当前用户:fv,IP:10.60.192.21,工作目录:/Users/fv/Documents/workspace/fun/,系统编码格式:UTF-8,系统Mac OS X版本:10.15.6
INFO-> 构建verify对象:fdsafds
INFO-> 构建verify对象:fdsa
INFO-> 构建verify对象:0.2365
INFO-> 构建verify对象:5.0
INFO-> 构建verify对象:5
fdsafdsfdsa
fds
false
false
1.1824999999999999
fdsafdsfdsafdsfdsafdsfdsafdsfdsafds
true
1.0
INFO-> 强转类型:class java.lang.Integer
5

Process finished with exit code 0
BackendTestingJsonPathGroovyoperator overloadingVerification
FunTester
Written by

FunTester

10k followers, 1k articles | completely useless

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.