4

So, in our project, we are using a @JsonView to exclude the attributes that we don't want at each request from being serialiazed/called. The problem is that this is very crude, and we need to create a new View or annotate on the Model every time we need something different, following this example: very nice guy with a blog. We believe that this is not really optimal, and a pretty boilerplate-y way to do it, so we're looking to change that logic: instead of the server responding only what it wants, we want to request the server to respond only what the client wants, to move that responsability from the server. Instead of doing a simple $.get, i'd pass on the parameters of that $.get the attributes that i want at the moment (i.e. only name and picture, sometimes full-information for editing and etc). I know that this is possible, but i haven't been able to find any ways for doing this using Spring. We're using Spring 4.2 and Jackson 2.6.1 and consuming the REST with AngularJS, so this would really help. Any thoughts on how to do this, or any guidance? Really thanks for the help!

GET request:

{
   username,
   picture
}

And receive a json response:

{  
   "id":1,
   "username":"john",
   "picture":"/john.png"
}

Something along these lines.

Yuri-M-Dias
  • 610
  • 1
  • 11
  • 25
  • This sounds like it could be a use for Filters (http://wiki.fasterxml.com/JacksonFeatureJsonFilter) but I haven't used them, so can't give a proper answer. – araqnid Oct 23 '15 at 00:46
  • @araqnid Yes, i am using these filters. But i need to define what i give to the view on the own model classes(on the hibernate/ORM mapping), and then i need to specify a controller that gives these views back. I want to invert that logic, and request for each information individually, and not have to define it on the server. – Yuri-M-Dias Oct 23 '15 at 01:08

3 Answers3

2

Your question looks very similar to:

Spring Rest Controller Return Specific Fields

Just pass fields you are interested in, and return composed map according to that fields.

Community
  • 1
  • 1
androberz
  • 744
  • 10
  • 25
1

If the serialization/deserialization strategy doesn`t work, then you should consider using a builder. It will be pretty straight forward to develop what you want, but no magic. Some alternatives: https://github.com/ralfstx/minimal-json , http://www.javabeat.net/java-json-api-jsr-353/ , https://github.com/Homyk/JsonBuilder/wiki/JsonBuilder-WIKI .

Homyk
  • 364
  • 2
  • 7
  • That's not exactly different from just filtering out the fields that i don't want to give, since that i'd still need to build each request individually. I'm using some generic types, so that isn't a...pretty way of solving it. Plus, the serialization and deserialization is working as intended, i just want to filter out the fields that i don't want to receive for each request. Nor the boilerplate of having to set the views for each object, which are cumbersome and give even more headache.... – Yuri-M-Dias Oct 22 '15 at 10:21
  • It will give you the ability to build the logic for returning the fields specified in the request as opposed to specified on the server using spring. This logic can be extracted into a method I believe and not duplicated. – Homyk Oct 23 '15 at 15:56
1

I also needed similar implementation and did this using Jackson. I used custom serializer and java reflection. No change in model classes is needed.

// my sample object
public class A {

    private int _1;
    private int _2;
    private int _3;

    public A(int _1, int _2, int _3) {
        this._1 = _1;
        this._2 = _2;
        this._3 = _3;
    }
    .. getters .. setters
}

Custom serializer for my class.

public class ASerializer extends JsonSerializer<A> {

    private final List<String> properties;

    public ASerializer(String... properties) {
        this.properties = Arrays.asList(properties);
    }

    @Override
    public Class<A> handledType() {
        return A.class;
    }

    @Override
    public void serialize(A a, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {

        jgen.writeStartObject();
        /* wanted property list is provided through constructor of serializer */
        for (String property : this.properties) {
            try {
                /* field values are accessed by reflection */
                Field field = a.getClass().getDeclaredField(property);
                field.setAccessible(true);
                Object value = field.get(a);
                jgen.writeObjectField(property, value);
            } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException ex) {
                Logger.getLogger(ASerializer.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

        jgen.writeEndObject();
    }

}

Usage:

public class App {

    public static void main(String... args) throws JsonProcessingException, IOException {

        ObjectMapper objectMapper = new ObjectMapper();
        SimpleModule module = new SimpleModule();

        /* initialize object */
        A a = new A(1, 2, 3);
        /* initialize a new serializer object with wanted properties and add to module */
        module.addSerializer(new ASerializer(new String[]{"_1", "_2"}));

        /* if you want to flush cached serializers */
        DefaultSerializerProvider dsp = (DefaultSerializerProvider) objectMapper.getSerializerProvider();
        dsp.flushCachedSerializers();

        objectMapper.registerModule(module);
        System.out.println(objectMapper.writeValueAsString(a));

    }

}

Outputs:

{"_1":1,"_2":2}
Ghokun
  • 3,345
  • 3
  • 26
  • 30