gregwhitaker / catnap

Partial JSON response framework for RESTful web services
Apache License 2.0
55 stars 15 forks source link

Filtering gets stuck at DefaultModelBuilder throws StackOverflowError #15

Open miguelsatcom opened 6 years ago

miguelsatcom commented 6 years ago

Hello

I'm having some problem while using catnap with Springboot it seems that the DefaultModelBuilder is getting stuck while filtering the object, it goes into an endless loop while and eventually throws an exeption

This is the JSON I get if i make the request without filtering { "status": 200, "result": { "id": 1, "email": "miguel.soares@email.com", "username": "miguel", "enabled": true, "roles": [ { "createdAt": 1516725487432, "updatedAt": 1516725487432, "id": 3, "name": "ROLE_USER" } ] } }

When trying to get only the result like so curl -X GET 'http://localhost:8081/api/users/1?fields=result'

I get this: { "timestamp": 1516784320900, "status": 500, "error": "Internal Server Error", "exception": "java.lang.StackOverflowError", "message": "No message available", "path": "/api/users/1" }

The Java output are endless lines of this: at com.github.gregwhitaker.catnap.core.model.builder.DefaultModelBuilder.filterObject(DefaultModelBuilder.java:140) ~[catnap-core-2.2.1.jar:na] at com.github.gregwhitaker.catnap.core.model.builder.DefaultModelBuilder.buildObject(DefaultModelBuilder.java:104) ~[catnap-core-2.2.1.jar:na] at com.github.gregwhitaker.catnap.core.model.builder.DefaultModelBuilder.buildList(DefaultModelBuilder.java:70) ~[catnap-core-2.2.1.jar:na] at com.github.gregwhitaker.catnap.core.model.builder.DefaultModelBuilder.filterObject(DefaultModelBuilder.java:140) ~[catnap-core-2.2.1.jar:na]

I also find it interesting that it does work if i for example request the username inside the result like ?fields=result(username)

gregwhitaker commented 6 years ago

Thanks for reporting an issue. I'll take a look at this.

Gunju-Ko commented 6 years ago

@miguelsatcom Is there any circular reference in your DTO ? When catnap is enabled by fields query parameter, annotation like @JsonIgnore on field will be ignored. That could be a reason for your problem. I think, there is a circular reference between User class and Role class

miguelsatcom commented 6 years ago

@Gunju-Ko I don't think that is the problem. If i make ?fields=result(username) than it works, shouldn't I get the same error if the circular reference was the problem?

gregwhitaker commented 6 years ago

@Gunju-Ko Is it possible to post your DTOs in a gist? It would be helpful to diagnose the issue. The fields in catnap are evaluated lazily so if you have a circular dependency it will only creep up on you and blow up if you happen to select that field.

Gunju-Ko commented 6 years ago

@gregwhitaker Hi Please understand that I'm not good at english

Here is example DTOs that caused the stackoverflow bug There is a circular reference between Role and User

    @Data
    public class Member {
        private long id;

        private String email;

        private String userName;

        private boolean enabled;

        private List<Role> roles;
    }
    @Data
    public class Role {
        private long id;

        private Date createdAt;

        private Date updatedAt;

        @JsonIgnore
        private Member member;
    }

If request has a fields parameter and the fields parameter contains roles, than a bug occurs

2018-03-03 12 28 28

Below is a bug message

    at com.github.gregwhitaker.catnap.core.model.builder.DefaultModelBuilder.filterObject(DefaultModelBuilder.java:144)
    at com.github.gregwhitaker.catnap.core.model.builder.DefaultModelBuilder.buildObject(DefaultModelBuilder.java:104)
    at com.github.gregwhitaker.catnap.core.model.builder.DefaultModelBuilder.buildList(DefaultModelBuilder.java:70)
    at com.github.gregwhitaker.catnap.core.model.builder.DefaultModelBuilder.filterObject(DefaultModelBuilder.java:140)
    at com.github.gregwhitaker.catnap.core.model.builder.DefaultModelBuilder.buildObject(DefaultModelBuilder.java:104)

If the fields parameter does not contain roles, or if it is sent without the fields parameter, then problem does not occur.

2018-03-03 12 28 40 2018-03-03 12 28 51

You can solve this problem by adding @JsonIgnore on getter method

    @Data
    public class Role {
        private long id;

        private Date createdAt;

        private Date updatedAt;

        private Member member;

        @JsonIgnore
        public Member getMember() {
            return member;
        }
    }
2018-03-03 12 45 05

I apologize for the lack of explanation because I'm not good at english