Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to dynamically remove fields from a json response?

I'm using spring to create a restful api, so far so good, my question is how to model the fields that go to the response dynamically?

Thats the controller that i'm using:

@Controller

public class AlbumController {

@Autowired
private MusicService musicService;

@RequestMapping(value = "/albums", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public Collection<Resource<Album>> getAllAlbums() {

    Collection<Album> albums = musicService.getAllAlbums();
    List<Resource<Album>> resources = new ArrayList<Resource<Album>>();
    for (Album album : albums) {
        resources.add(this.getAlbumResource(album));
    }
    return resources;

}

@RequestMapping(value = "/album/{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public Resource<Album> getAlbum(@PathVariable(value = "id") String id) {

    Album album = musicService.getAlbum(id);
    return getAlbumResource(album);

}

private Resource<Album> getAlbumResource(Album album) {

    Resource<Album> resource = new Resource<Album>(album);


    // Link to Album
    resource.add(linkTo(methodOn(AlbumController.class).getAlbum(album.getId())).withSelfRel());
    // Link to Artist
    resource.add(linkTo(methodOn(ArtistController.class).getArtist(album.getArtist().getId())).withRel("artist"));
    // Option to purchase Album
    if (album.getStockLevel() > 0) {
        resource.add(linkTo(methodOn(AlbumController.class).purchaseAlbum(album.getId())).withRel("album.purchase"));
    }

    return resource;

}

@RequestMapping(value = "/album/purchase/{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public Resource<Album> purchaseAlbum(@PathVariable(value = "id") String id) {

    Album a = musicService.getAlbum(id);
    a.setStockLevel(a.getStockLevel() - 1);
    Resource<Album> resource = new Resource<Album>(a);
    resource.add(linkTo(methodOn(AlbumController.class).getAlbum(id)).withSelfRel());
    return resource;

}
}

And the model:

public class Album {

private final String id;
private final String title;
private final Artist artist;
private int stockLevel;

public Album(final String id, final String title, final Artist artist, int stockLevel) {
    this.id = id;
    this.title = title;
    this.artist = artist;
    this.stockLevel = stockLevel;
}

public String getId() {
    return id;
}

public String getTitle() {
    return title;
}

public Artist getArtist() {
    return artist;
}

public int getStockLevel() {
    return stockLevel;
}

public void setStockLevel(int stockLevel) {
    this.stockLevel = stockLevel;
}
}
like image 792
danillosl Avatar asked Apr 24 '15 04:04

danillosl


People also ask

How do I remove a field from a JSON file?

var json = { 'name': John Doe, 'nickname': Johnny } var key = "name"; delete json[key];

How do you ignore a field in JSON response?

The Jackson @JsonIgnore annotation can be used to ignore a certain property or field of a Java object. The property can be ignored both when reading JSON into Java objects and when writing Java objects into JSON.

How do I remove a property from a JSON object?

Using the Delete operator The Delete operator is the easiest way to delete the object property. if we want to delete multiple properties which are in the object, we need to use this operator multiple times. In the following example, we have created a JSON Object with keys and values.

How do I remove a key from a JSON file?

How do you remove a key value pair from a JSON object? JsonObject::remove() removes a key-value pair from the object pointed by the JsonObject . If the JsonObject is null, this function does nothing.


1 Answers

I'm struggling with this requirement, too.

The following code is a workaround using the JsonViews already mentioned by @beerbajay in the comment to your question:

http://wiki.fasterxml.com/JacksonJsonViews

I'm using Spring Boot 1.2.3.

Views.java

package demo;

public class Views {

    static interface Public {}

    static interface Internal extends Public {}
}

Album.java

package demo;

import com.fasterxml.jackson.annotation.JsonView;

public class Album {

    @JsonView(Views.Public.class)
    private String id;

    @JsonView(Views.Public.class)
    private String title;

    @JsonView(Views.Public.class)
    private String artist;

    @JsonView(Views.Internal.class)
    private String secret;

    public Album(String id, String title, String artist, String secret) {
        this.id = id;
        this.title = title;
        this.artist = artist;
        this.secret = secret;
    }

}

AlbumController.java

package demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;

@RestController
public class AlbumController {

    @Autowired
    ObjectMapper mapper;

    @RequestMapping(value = "/album", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
    public String getAlbum() throws JsonProcessingException {
        Album foo = new Album("1", "foo", "John Doe", "secretProperty");

        // replace the following value with runtime logic of your choice,
        // e.g. role of a user
        boolean forInternal = false;

        ObjectWriter viewWriter;
        if (forInternal) {
            viewWriter = mapper.writerWithView(Views.Internal.class);
        } else {
            viewWriter = mapper.writerWithView(Views.Public.class);
        }

        return viewWriter.writeValueAsString(foo);
    }
}

So the key is to use jackson's ObjectMapper and ObjectWriter to generate a string of the json representation of your object.

Feels kind of ugly to me, but works. Certainly the question remains how this scales when defining more than one RequestMapping.

like image 137
Thomas Traude Avatar answered Oct 28 '22 23:10

Thomas Traude