Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Exclude fields in json Using Jackson and Json-View

I am using json-view to create a dynamic json as per my need ,it is a great library ,I am using this library for a while now . Recently I am facing a problem with my one of the Use cases, let me place my code first

User class

public class User {

    private String name;
    private String emailId;
    private String mobileNo;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmailId() {
        return emailId;
    }

    public void setEmailId(String emailId) {
        this.emailId = emailId;
    }

    public String getMobileNo() {
        return mobileNo;
    }

    public void setMobileNo(String mobileNo) {
        this.mobileNo = mobileNo;
    }

}

ScreenInfoPojo class

public class ScreenInfoPojo {

    private Long id;
    private String name;
    private ScreenInfoPojo parentScreen;
    private User createdBy;
    private User lastUpdatedBy;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public ScreenInfoPojo getParentScreen() {
        return parentScreen;
    }

    public void setParentScreen(ScreenInfoPojo parentScreen) {
        this.parentScreen = parentScreen;
    }



    public User getCreatedBy() {
        return createdBy;
    }

    public void setCreatedBy(User createdBy) {
        this.createdBy = createdBy;
    }

    public User getLastUpdatedBy() {
        return lastUpdatedBy;
    }

    public void setLastUpdatedBy(User lastUpdatedBy) {
        this.lastUpdatedBy = lastUpdatedBy;
    } 

Run code

public class TestMain {
    public static void main(String[] args) throws JsonProcessingException {
        User user=new User();
        user.setName("ABC");
        user.setEmailId("[email protected]");
        user.setMobileNo("123456789");

        ScreenInfoPojo screen1=new ScreenInfoPojo();
        screen1.setId(1l);
        screen1.setName("Screen1");
        screen1.setCreatedBy(user);
        screen1.setLastUpdatedBy(user);

        ScreenInfoPojo screen2=new ScreenInfoPojo();
        screen2.setId(2l);
        screen2.setName("Screen2");
        screen2.setParentScreen(Screen1);
        screen2.setCreatedBy(user);
        screen2.setLastUpdatedBy(user);

        ScreenInfoPojo screen3=new ScreenInfoPojo();
        screen3.setId(3l);
        screen3.setName("Screen3");
        screen3.setParentScreen(Screen2);
        screen3.setCreatedBy(user);
        screen3.setLastUpdatedBy(user);

        ScreenInfoPojo screen4=new ScreenInfoPojo();
        screen4.setId(4l);
        screen4.setName("Screen4");
        screen4.setParentScreen(Screen3);
        screen4.setCreatedBy(user);
        screen4.setLastUpdatedBy(user);

        List<ScreenInfoPojo> screens=new ArrayList<>();
        screens.add(screen1);
        screens.add(screen2);
        screens.add(screen3);
        screens.add(screen4);

        ObjectMapper mapper = new ObjectMapper().registerModule(new JsonViewModule());
        String json = mapper.writeValueAsString(JsonView.with(screens).onClass(ScreenInfoPojo.class, Match.match()
                .exclude("*")
                .include("id","name","createdBy.name","lastUpdatedBy.mobileNo","parentScreen.id")));
        System.out.println("json"+json);
    }    

Result

[{
    "id": 1,
    "name": "Screen1",
    "parentScreen": null,
    "createdBy": {
        "name": "ABC"
    },
    "lastUpdatedBy": {
        "mobileNo": "123456789"
    }
}, {
    "id": 2,
    "name": "Screen2",
    "parentScreen": {
        "id": 1,
        "name": "Screen1",
        "parentScreen": null,
        "createdBy": {},
        "lastUpdatedBy": {}
    },
    "createdBy": {
        "name": "ABC"
    },
    "lastUpdatedBy": {
        "mobileNo": "123456789"
    }
}, {
    "id": 3,
    "name": "Screen3",
    "parentScreen": {
        "id": 2,
        "name": "Screen2",
        "parentScreen": {
            "id": 1,
            "name": "Screen1",
            "parentScreen": null,
            "createdBy": {},
            "lastUpdatedBy": {}
        },
        "createdBy": {},
        "lastUpdatedBy": {}
    },
    "createdBy": {
        "name": "ABC"
    },
    "lastUpdatedBy": {
        "mobileNo": "123456789"
    }
}, {
    "id": 4,
    "name": "Screen4",
    "parentScreen": {
        "id": 3,
        "name": "Screen3",
        "parentScreen": {
            "id": 2,
            "name": "Screen2",
            "parentScreen": {
                "id": 1,
                "name": "Screen1",
                "parentScreen": null,
                "createdBy": {},
                "lastUpdatedBy": {}
            },
            "createdBy": {},
            "lastUpdatedBy": {}
        },
        "createdBy": {},
        "lastUpdatedBy": {}
    },
    "createdBy": {
        "name": "ABC"
    },
    "lastUpdatedBy": {
        "mobileNo": "123456789"
    }
}]

Expected Result

[{
    "id": 1,
    "name": "Screen1",
    "parentScreen": null,
    "createdBy": {
        "name": "ABC"
    },
    "lastUpdatedBy": {
        "mobileNo": "123456789"
    }
}, {
    "id": 2,
    "name": "Screen2",
    "parentScreen": {
        "id": 1
    },
    "createdBy": {
        "name": "ABC"
    },
    "lastUpdatedBy": {
        "mobileNo": "123456789"
    }
}, {
    "id": 3,
    "name": "Screen3",
    "parentScreen": {
        "id": 2
    },
    "createdBy": {
        "name": "ABC"
    },
    "lastUpdatedBy": {
        "mobileNo": "123456789"
    }
}, {
    "id": 4,
    "name": "Screen4",
    "parentScreen": {
        "id": 3
    },
    "createdBy": {
        "name": "ABC"
    },
    "lastUpdatedBy": {
        "mobileNo": "123456789"
    }
}]

Problem

In my use case I have a class ScreenInfoPojo which refers to same class as parentScreen , I am trying to fetch specific field/fields of parent ( "parentScreen.id") instate I am getting all fields that I have defined on child/target Object ("id","name","createdBy.name","lastUpdatedBy.mobileNo","parentScreen.id") and parent response is again recursive ! One thing i observed that It is only happening in case of a class has its own reference , I placed User class reference as two different field createdBy and lastUpdatedBy and tried to fetch "name" and "mobileNo" respectively worked just fine.

Any suggestion to solve this problem will be really helpful !!!!

Thanks

like image 389
Dev Avatar asked May 18 '17 12:05

Dev


1 Answers

Yes. Include clause does not work for reference to the same class.

That you can do?

Compile from source according to github instruction build from source

Update function JsonViewSerializer.JsonWriter.fieldAllowed

find:

        if(match == null) {
            match = this.currentMatch;
        } else {
            prefix = "";
        }

and comment else clause

        if(match == null) {
            match = this.currentMatch;
        } else {
            //prefix = "";
        }

You will get expected result. But. I do not know how it will affect another filters.

To have more control you could add property to JsonView class.

For example:

in JsonView add:

private boolean ignorePathIfClassRegistered = true;

     public boolean isIgnorePathIfClassRegistered() {
            return ignorePathIfClassRegistered;
        }

        public JsonView1<T>  setIgnorePathIfClassRegistered(boolean ignorePathIfClassRegistered) {
            this.ignorePathIfClassRegistered = ignorePathIfClassRegistered;
            return this;
        }

In JsonViewSerializer.JsonWriter.fieldAllowed function rewrite if clause to:

        if(match == null) {
            match = this.currentMatch;
        } else {
            if (result.isIgnorePathIfClassRegistered())
            prefix = "";
        }

And you could use it in your example like:

JsonView<List<ScreenInfoPojo>> viwevedObject = JsonView
        .with(screens)
        .onClass(ScreenInfoPojo.class,
                Match.match()
                        .exclude("*")
                        .include("id","name")
                        .include("createdBy.name")
                        .include("lastUpdatedBy.mobileNo")
                        .include("parentScreen.id"))
        .setIgnorePathIfClassRegistered(false);

ObjectMapper mapper = new ObjectMapper().registerModule(new JsonViewModule());
mapper.configure(SerializationFeature.INDENT_OUTPUT, true);

String json = mapper.writeValueAsString(viwevedObject);
like image 72
Oleg Avatar answered Sep 18 '22 12:09

Oleg