Skip to content

建议:在输入引用赋值顺序错误时给出更明显的提示 #275

Closed

Description

@jerrylususu

引用赋值需要请求中先出现原始值,然后才能被引用,如果顺序相反则引用无法成功。但是在使用 Request 表对输入进行校验时,引用赋值出现的位置(Request 表中)和用户实际使用的位置(POST 请求体)并不相同,在用户请求中因为顺序错误导致引用赋值失败时,给出的错误提示不够明显,导致排错十分困难。希望能给出更明显的提示。

问题场景:APIJSONBoot 示例项目中,有 User, Privacy 两表,其中用户注册时,请求会和 Request 表中对应项 (method=POST, tag=register)进行校验,校验规则简化如下,即 user.id 依赖于 privacy.id 。

简化后的依赖关系

{
  "User": {
    "UPDATE": {"id@": "Privacy/id"}
  },
  "Privacy": {}
}

在实际发起请求的时候,Requestbody 中需要 Privacy 在上,User 在下,如果顺序反过来,用户注册本身不会成功(数据库中无写入操作),但是请求显示正常完成(code=200)。

错误请求例(method=POST, addr=/post)

{
    "User": {
        "name": "test"
    },
    "Privacy": {
        "phone": "13323332338",
        "_password": "testpwd"
    },
    "verify": "9816",
    "tag": "register"
}

此情况下返回值(返回200,但 sql.execute 为0)

{
    "ok": true,
    "code": 200,
    "msg": "success",
    "sql:generate|cache|execute|maxExecute": "0|0|0|200",
    "depth:count|max": "1|5",
    "time:start|duration|end": "1627506120546|7|1627506120553"
}

Activity

  1. jerrylususu commented on Jul 28, 2021

    @jerrylususu
    ContributorAuthor

    这一问题在使用 /register 端点的时候同样存在,但因为一部分处理操作包在了方法体内部(例如 parseResponse(requestObject)),使得找出问题原因更加困难。

    以相同输入,POST /register 得到的返回值(实际用户注册是失败的)

    {
        "ok": true,
        "code": 200,
        "msg": "success"
    }

    如果输入顺序正常,正常的返回

    {
        "privacy": {
            "ok": true,
            "code": 200,
            "msg": "success",
            "count": 1,
            "id": 1627508021086
        },
        "user": {
            "ok": true,
            "code": 200,
            "msg": "success",
            "count": 1,
            "id": 1627508021086
        },
        "verify": "6533",
        "ok": true,
        "code": 200,
        "msg": "success"
    }
  2. TommyLemon commented on Jul 31, 2021

    @TommyLemon
    Member

    原因:引用赋值查不到对应被引用的值时,只是终止处理当期对象。

    规范是必须按照顺序来,但是 Request 表中配置的 json 类型 structure 会被 MySQL 强制自动按 ASCII 编码排序,只能提供文档说明顺序。

    如果要直接从代码上保证,应该对 AbstractObjectParser. onParse 385 和 395 行两个 if 中加上判断
    method == POST || method == PUT 时 throw UnsupportedException("引用赋值 " + path + "/" + key + ": " + targetPath + " 解析失败,POST 和 PUT 接口必须保证每个对象执行都成功!")

    https://github.com/Tencent/APIJSON/blob/3ccd9674ce572e36907dd961ae9386e31abc2483/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java

    image

    这个影响不大,暂时没时间去修改和测试,你可以提个 PR,合并后会把你加入贡献者名单,开源要大家一起共建才会更美好~
    https://github.com/Tencent/APIJSON/blob/master/CONTRIBUTING.md
    image

  3. henriquejsza commented on Aug 30, 2026

    @henriquejsza
    Contributor

    I reproduced this against the core parser path on the current APIJSONORM master (c96950f7) with a DB-free harness. I did not retest the demo project's outer /register endpoint. When User/id@ is parsed before Privacy/id and the target value is not yet available:

    • for POST and PUT, the User table object does not throw; it is invalidated and parse() returns null, so no SQL is generated or executed;
    • the complete parseResponse still returns code: 200, msg: success, with zero generated and executed SQL statements;
    • GET also returns success, while an unresolved reference in a non-table object during POST is silently discarded.

    In the current code, unresolved references are handled in the target == null branch of AbstractObjectParser.onParse; the old targetPath.equals(target) branch is now commented out, and the current branch distinguishes table-field references from non-table-object references. Before making a change, could you please confirm two scope details?

    1. When the object's effective method is POST or PUT, should the exception guard run before the current isTable branch, covering every unresolved string reference (closest to your original suggestion), or only table-field references that invalidate the table object?
    2. By UnsupportedException in your original comment, did you mean UnsupportedOperationException, which exists in the current codebase?

    Once confirmed, I would scope the change to this reference-resolution branch and add DB-free behavioral tests covering the agreed cases: unresolved POST/PUT references fail, while GET and successfully resolved references retain their current behavior. The tests would assert behavior and exception type rather than any exact error message text.

    I haven't started implementing this, I'll wait for your confirmation before opening a PR.

  4. TommyLemon commented on Aug 31, 2026

    @TommyLemon
    Member

    I reproduced this against the core parser path on the current APIJSONORM master (c96950f7) with a DB-free harness. I did not retest the demo project's outer /register endpoint. When User/id@ is parsed before Privacy/id and the target value is not yet available:

    • for POST and PUT, the User table object does not throw; it is invalidated and parse() returns null, so no SQL is generated or executed;
    • the complete parseResponse still returns code: 200, msg: success, with zero generated and executed SQL statements;
    • GET also returns success, while an unresolved reference in a non-table object during POST is silently discarded.

    In the current code, unresolved references are handled in the target == null branch of AbstractObjectParser.onParse; the old targetPath.equals(target) branch is now commented out, and the current branch distinguishes table-field references from non-table-object references. Before making a change, could you please confirm two scope details?

    1. When the object's effective method is POST or PUT, should the exception guard run before the current isTable branch, covering every unresolved string reference (closest to your original suggestion), or only table-field references that invalidate the table object?
    2. By UnsupportedException in your original comment, did you mean UnsupportedOperationException, which exists in the current codebase?

    Once confirmed, I would scope the change to this reference-resolution branch and add DB-free behavioral tests covering the agreed cases: unresolved POST/PUT references fail, while GET and successfully resolved references retain their current behavior. The tests would assert behavior and exception type rather than any exact error message text.

    I haven't started implementing this, I'll wait for your confirmation before opening a PR.

    @henriquejsza Thank you for your feedback
    1.Yes, the exception should be thrown and abort all next operations, in case the wrong request will continue to be resolved and result in unexpected behaviors.

    2.Yes, it should be UnsupportedOperationException.

    Looking forward to your PR~

  5. added a commit that references this issue on Sep 1, 2026
    ef5c519
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions