Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] We look forward to adding support for @JsonView. #1161

Closed
YanzMing opened this issue Sep 4, 2024 · 11 comments · Fixed by #1162
Closed

[Feature] We look forward to adding support for @JsonView. #1161

YanzMing opened this issue Sep 4, 2024 · 11 comments · Fixed by #1162
Labels
status: feedback required feedback required type: feature request Feature Enhancement Request

Comments

@YanzMing
Copy link

YanzMing commented Sep 4, 2024

Adding support for @JSONVIEW(期望添加对 @JSONVIEW 的支持)

Purpose of the requirement(需求目的)

Based on annotations, different documentation information can be generated.

(JsonView is a very convenient and powerful method that allows the use of models without duplicating resources. It determines the response field information by grouping with different views, eliminating the need to create redundant VOs)

As in the following example services A and B:
可以根据注解来生成不同的文档信息

(JsonView是一种非常方便且功能强大的方法,可以不复制资源使用的模型, 通过不同的视图分组来确定响应的字段信息,不需要创建冗余的 VO)

如以下示例服务A与服务B:

@GetMapping("/serviceA")
@JsonView(Entity.ViewA.class)
public Entity methodA() {...}

@GetMapping("/serviceB")
@JsonView(Entity.ViewB.class)
public Entity methodB() {...}

public Entity (){
    @JsonView(ViewA.class)
    private String A;   

    @JsonView(ViewB.class)
    private String B; 
    
    public interface ViewA{}
    public interface ViewB{}
}

The response contents of the above two services are as follows(以上两个服务的响应内容分别为):

RES_A:{
    A:""
}

RES_B:{
    B:""
}

In the current version, the documentation generated for the above two services will describe all fields, for example(当前版本对于以上两个服务所生成的文档会将所有字段进行描述,如):

RES_A:{
    A:"",
    B:""
}

RES_B:{
    A:"",
    B:""
}

What is expected for the documentation generated from the above two services is(对于以上两个服务生成的文档所期望的是):

RES_A:{
    A:""
}

RES_B:{
    B:""
}

When generating documentation, it is hoped to support @JSONVIEW.
在生成文档时希望支持@JSONVIEW,

Source of requirements(需求来源)

swagger-api/swagger-core#2681

swagger-api/swagger-core#479

swagger-api/swagger-core#2662

@YanzMing YanzMing added the type: feature request Feature Enhancement Request label Sep 4, 2024
@tangcent tangcent added the status: acknowledged This issue has been acknowledged and is under review. label Sep 5, 2024
@tangcent
Copy link
Owner

tangcent commented Sep 6, 2024

@YanzMing 你在用的是jackson里的JsonView吗? 方便的话可以尝试配一下这个规则,看看是否符合你的预期:

# Cache the JsonView information at the method level
api.method.parse.before=groovy:```
    def jsonViews = it.annValue("com.fasterxml.jackson.annotation.JsonView")
    //logger.info("method jsonViews:"+jsonViews)
    if (jsonViews) {
        session.set("json-views", jsonViews)
    }
```
api.method.parse.after=groovy:```
    session.remove("json-views")
```

# Check if a field should be ignored based on the active JsonView
field.ignore=groovy:```
    if(it.contextType()!="field"){
        return false
    }
    def jsonViews = session.get("json-views")
    //logger.info("field jsonViews:"+jsonViews)
    if (jsonViews) {
        def fieldViews = it.annValue("com.fasterxml.jackson.annotation.JsonView")
        if (fieldViews) {
            // Return true if none of the field's views are in the active JsonView
            return !fieldViews.any{ fieldView-> jsonViews.any{ jsonView-> jsonView.isExtend(fieldView.name) } }
        } else {
            // If the field has no JsonView annotation, it should be ignored
            return true
        }
    }
    return false
```

@tangcent tangcent added status: feedback required feedback required and removed status: acknowledged This issue has been acknowledged and is under review. labels Sep 6, 2024
@YanzMing
Copy link
Author

YanzMing commented Sep 8, 2024

这个规则生效了, 但是并没有完全生效, 如下:

@RestController
@RequestMapping("test")
public class Test {
   
    @JsonView(Person.A.class)
    @GetMapping("A")
    public Person testA(){
        return Person.builder().id(1L).name("测试01").age(18).wallet(BigDecimal.valueOf(1000)).build();
    }

    @JsonView(Person.A.B.class)
    @GetMapping("B")
    public Person testB(){
        return Person.builder().id(1L).name("测试01").age(18).wallet(BigDecimal.valueOf(1000)).build();
    }

    @JsonView(Person.A.C.class)
    @GetMapping("C")
    public Person testC(){
        return Person.builder().id(1L).name("测试01").age(18).wallet(BigDecimal.valueOf(1000)).build();
    }
   
    @Data
    @Builder
    static class Person{

        @JsonView(A.class)
        private Long id;

        @JsonView(A.B.class)
        private String name;

        @JsonView(A.B.class)
        private Integer age;

        @JsonView(A.C.class)
        private BigDecimal wallet;

        interface A{
            interface B extends A{}
            interface C extends A{}
        }
    }
}

A、B、C三个接口应该生成的相应结果如下:

// testA()
{
    "id": 1L
}

// testB()
{
    "id": 1L,
    "name": "测试01",
    "age": 18
}

// testC()
{
    "id": 1L,
    "wallet": 1000
}

但是,A、B、C三个接口生成的结果是相同的,如下

{
    "id": 1L,
    "wallet": 1000
}

这是不正确的!!!

测试得到,哪一个方法在最后面所生成的结果是对应最后一个方法的 (调整方法的编写顺序,如:testA() 在最后,三个方法结果都是 testA() 的结果响应)

@tangcent
Copy link
Owner

抱歉,漏了: json.cache.disable=true
https://github.com/tangcent/easy-yapi/pull/1162/files#diff-c4538e37e8492c4ab2f8b12f61b888cabe1f699f67db269230feed70fa13efb1R136-R171

@YanzMing
Copy link
Author

是的,它可以了

@YanzMing
Copy link
Author

还存在一个问题, 他在入参中也生效了, 这是不对的, 入参不应该根据Jackson.JsonView来判断是否滤除, 而应该是Validated

@tangcent
Copy link
Owner

试试这样:

# Support for Jackson annotation JsonView
json.cache.disable=true
api.param.parse.before=groovy:session.set("is-param",true)
api.param.parse.after=groovy:session.remove("is-param")

# Cache the JsonView information at the method level
api.method.parse.before=groovy:```
    def jsonViews = it.annValue("com.fasterxml.jackson.annotation.JsonView")
    //logger.info("method jsonViews:"+jsonViews)
    if (jsonViews) {
        session.set("json-views", jsonViews)
    }
```
api.method.parse.after=groovy:```
    session.remove("json-views")
```

# Check if a field should be ignored based on the active JsonView
field.ignore=groovy:```
    if(session.get("is-param")){
        return false
    }
    if(it.contextType()!="field"){
        return false
    }
    def jsonViews = session.get("json-views")
    //logger.info("field jsonViews:"+jsonViews)
    if (jsonViews) {
        def fieldViews = it.annValue("com.fasterxml.jackson.annotation.JsonView")
        if (fieldViews) {
            // Return true if none of the field's views are in the active JsonView
            return !fieldViews.any{ fieldView-> jsonViews.any{ jsonView-> jsonView.isExtend(fieldView.name) } }
        } else {
            // If the field has no JsonView annotation, it should be ignored
            return true
        }
    }
    return false
```

@YanzMing
Copy link
Author

好像导致validation失效了

@YanzMing
Copy link
Author

@Validated
@RestController
@RequestMapping("test")
public class Test {

    @JsonView(Person.A.class)
    @PostMapping("A")
    public Person testA(@RequestBody @Validated(Person.A.class) Person person) {
        return person;
    }

    @JsonView(Person.A.B.class)
    @PostMapping("B")
    public Person testB(@RequestBody Person person) {
        return person;
    }

    @JsonView(Person.A.C.class)
    @PostMapping("C")
    public Person testC(@RequestBody Person person) {
        return person;
    }

    @JsonView(Person.D.class)
    @PostMapping("D")
    public Person testD(@RequestBody Person person) {
        return person;
    }

    @PostMapping("E")
    @JsonView(Person.E.class)
    public Person testE(@RequestBody Person person) {
        return person;
    }
}
@Data
@GroupSequenceProvider(Person.PersonGroupSequenceProvider.class)
public class Person {

    @JsonView(A.class)
    @Null(groups = A.class)
    private Long id;

    @JsonView({A.class, D.class, E.class})
    @NotNull
    private String name;

    @JsonView({A.B.class, D.class})
    @Null
    private Integer age;

    @JsonView({A.C.class, E.class})
    @NotNull(groups = {WhenAge20And30Group.class, WhenAge30And40Group.class})
    private BigDecimal wallet;

    public interface A {
        interface B extends A {}
        interface C extends A {}
    }
    public interface D {}
    public interface E {}
    interface WhenAge20And30Group {}
    interface WhenAge30And40Group {}

    // 组序列
    @GroupSequence({Default.class, WhenAge20And30Group.class, WhenAge30And40Group.class})
    interface Group{}

    static class PersonGroupSequenceProvider implements DefaultGroupSequenceProvider<Person> {
        @Override
        public List<Class<?>> getValidationGroups(Person bean) {
            List<Class<?>> defaultGroupSequence = new ArrayList<>();
            defaultGroupSequence.add(Person.class); 
            if (bean != null) {
                Integer age = bean.getAge();
                if (age >= 20 && age < 30) {
                    defaultGroupSequence.add(Person.WhenAge20And30Group.class);
                } else if (age >= 30 && age < 40) {
                    defaultGroupSequence.add(Person.WhenAge30And40Group.class);
                }
            }
            return defaultGroupSequence;
        }
    }
}

@YanzMing
Copy link
Author

在使用@JSONVIEW的情况下, 如何修改响应类的类名?

    @JsonView(Person.AView.class)
    @PostMapping("A")
    public Person testA(@RequestBody @Validated(Person.A.class) Person person) {
        return person;
    }

如: 一个被@JsonView(Person.AView.class)注解的方法, 在文档中生成响应为Person#AView而不是Person

@tangcent
Copy link
Owner

GroupSequence

这个有点复杂了,难搞 :)

@tangcent
Copy link
Owner

在使用@JSONVIEW的情况下, 如何修改响应类的类名?

    @JsonView(Person.AView.class)
    @PostMapping("A")
    public Person testA(@RequestBody @Validated(Person.A.class) Person person) {
        return person;
    }

如: 一个被@JsonView(Person.AView.class)注解的方法, 在文档中生成响应为Person#AView而不是Person

你的意思是这里注解的Person.AView.class不是一个group class,而是一个POJO class?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: feedback required feedback required type: feature request Feature Enhancement Request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants