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

Add support for @JsonView #479

Closed
brentryan opened this issue Mar 5, 2014 · 29 comments
Closed

Add support for @JsonView #479

brentryan opened this issue Mar 5, 2014 · 29 comments
Milestone

Comments

@brentryan
Copy link

In java, many REST services are written using Jersey/dropwizard frameworks and which rely on the Jackson Json library for serialization. With this Jackson library they allow us to define a "JsonView" which acts as a subset of a model that might be exposed via an api (http://wiki.fasterxml.com/JacksonJsonViews).

For example if I have a resource annotated with the following...

@JsonView(View.Public.class)
@ApiOperation(value = "bla bla bal.", notes = "And bla bla bla.",
        response = SomeType.class)
Response getSomeResource() {}

Where the class SomeType looks like this:

class SomeType {
  @JsonView(View.Public.class)
   private String publicProperty;
  @JsonView(View.Internal.class)
   private String internalProperty;
}

I want the swagger docs to only include the property "publicProperty" since it was annotated with the @JSONVIEW(View.Public.class). This dropwizard/jersey resource renders the correct response, but swagger still generates api docs that include both properties.

Is it possible to fix this or is there a swagger change coming that might fix this? I've heard that in the most recent SNAPSHOT of swagger that there's support for "@ApiModelProperty(hidden=true)", but I'd rather not have to duplicate annotating my models like this especially since I think the @JSONVIEW is more flexible.

Thanks,
Brent

@saadmufti
Copy link

+1

@fehguy fehguy added the Feature label Mar 30, 2014
@amandabouman
Copy link

Is there any consideration of this? Or any sort of workaround to make it at all possible? We have multiple views per class and would like to be able to customize the view by endpoint (i.e., we can't hide properties across the board because some properties are shown in some services and not in others).

@ryanlchandler
Copy link

+1

@fehguy fehguy modified the milestone: v1.5.0 Sep 19, 2014
@txfan
Copy link

txfan commented Sep 20, 2014

+1

1 similar comment
@sseide
Copy link

sseide commented Sep 23, 2014

+1

@fehguy
Copy link
Contributor

fehguy commented Sep 26, 2014

1.5.0 will use pure jackson and therefore the @JSONVIEW annotation.

@fehguy fehguy modified the milestones: v1.5.0-M1, v1.5.0 Dec 20, 2014
@fehguy
Copy link
Contributor

fehguy commented Dec 20, 2014

I'd love to see some samples committed to the develop_2.0 branch to cover @JSONVIEW use cases.

@fehguy fehguy added the P3 label Dec 23, 2014
@fehguy fehguy self-assigned this Jan 28, 2015
@fehguy fehguy modified the milestones: v1.5.0-M2, v1.5.0-M1 Feb 1, 2015
@fehguy
Copy link
Contributor

fehguy commented Mar 13, 2015

I know this has gone unanswered for a long time, and I hate to do this, but that functionality just doesn't fit in with swagger. I suggest using filters to attain a similar result, which gives you even more control since the determination is dynamic.

https://github.com/swagger-api/swagger-core/blob/develop_2.0/modules/swagger-core/src/main/java/com/wordnik/swagger/core/filter/SwaggerSpecFilter.java

@fehguy fehguy closed this as completed Mar 13, 2015
@brentryan
Copy link
Author

fyi, the filters do not solve the problem here and suck to implement.

@batcer
Copy link

batcer commented Sep 4, 2015

fehguy, your link gives 404

@gustavolira
Copy link

+1

1 similar comment
@john24318
Copy link

john24318 commented Aug 2, 2016

+1

@sebastienvermeille
Copy link

Hm it is still not resolved in my opinion. This api implicit model only supports manual setted parameters... that means we have to write it :

in jsonviews + in swagger doc

If jsonviews was supported we only had to write into jsonviews.
Please support it

@takumahuwa
Copy link

+1

4 similar comments
@salletchen
Copy link

+1

@aint
Copy link

aint commented Dec 8, 2016

+1

@monoc44
Copy link

monoc44 commented Dec 27, 2016

+1

@prajotNaik
Copy link

+1

@manuelhuber
Copy link

+1

1 similar comment
@jpomykala
Copy link

+1

@monoc44
Copy link

monoc44 commented Jan 7, 2017

@fehguy Thanks for your comment. I don't think SwaggerSpecFilter can be of any help as the limitation resides in the OAI syntax itself.

Taking this example (pseudo code):

@GET(/serviceA)
@JsonView(ViewA.class)
public MyModel methodA() {...}

@GET(/serviceB)
@JsonView(ViewB.class)
public MyModel methodB() {...}

=> parsing these two resources will translate into the following OAI JSON file:

paths: {
   /serviceA:
     get ->  responses: { 200-> $ref: #/definitions/MyModel }
   /serviceB: {
     get ->  responses: { 200-> $ref: #/definitions/MyModel }
},
definitions: {
  MyModel:
      type: object,
      required: [
        propertyForServiceA,
        propertyNotForServiceB
      ]
}

Sadly, method SwaggerSpecFilter#isPropertyAllowed() is invoked only once, either after scanning serviceA or serviceB.

Would it be difficult to instead generate a 'contextualized' definition model which could have then different properties (hidden or not), like:

definitions: {
  MyModel-serviceA.get:
      type: object,
      required: [
        propertyForServiceA,
        propertyNotForServiceB
      ]
  MyModel-serviceB.get:
      type: object,
      required: [
        propertyForServiceB
      ]
}

@barthik
Copy link

barthik commented Feb 2, 2017

+1

@brock-bouchard
Copy link

I also just ran into this! Another idea might be to change the property definition to allow for a views field that holds the views to which the property applies?

@brock-bouchard
Copy link

Another alternative to using JSON views that will get you a more precise swagger definition is to leverage Java 8's "mixin" capability with default interface methods. For example one can define a base Representation class and PropertyBag interface as such:

public interface PropertyBag {

    <T> T get(String key);

    <T> void set(String key, T value);
}

public class Representation implements PropertyBag {

    private Map<String, Object> properties;

    public Representation() {
        this.properties = new HashMap();
    }

    public <T> T get(String key) {
        return (T) this.properties.get(key);
    }

    public <T> void set(String key, T value) {
        this.properties.put(key, value);
    }
}

public interface Creatable extends PropertyBag {

    @ApiModelProperty(
        value = "The time in UTC when the resource was created in the ISO 8601 format "
        + "yyyy-MM-dd'T'HH:mm:ssZ.",
        required = true
        )
    default DateTime getCreatedAt() {
        return this.<DateTime>get("createdAt");
    }

    default void setCreatedAt(DateTime createdAt) {
        this.<DateTime>set("createdAt", createdAt);
    }
}

You can then make "mixins" of common properties...

public interface DisplayOrderable extends PropertyBag {

    @ApiModelProperty(
        value = "The display order of this entity.",
        required = true)
    default Integer getDisplayOrder() {
        return this.<Integer>get("displayOrder");
    }

    default void setDisplayOrder(Integer displayOrder) {
        this.<Integer>set("displayOrder", displayOrder);
    }
}

... and subclasses of the base Representation class as such:

@ApiModel(...)
public class MyEntityRead extends Representation implements Creatable, DisplayOrderable {}

@ApiModel(...)
public class MyEntityCreate extends Representation implements DisplayOrderable {}

Full @JsonView support would be ideal, but this approach lets you define precise models for different situations whilst cutting down on code duplication.

@arcana261
Copy link

+1

@Diom
Copy link

Diom commented Dec 14, 2017

+1

Yeah, this feature would be much appreciated.

@DaBlick
Copy link

DaBlick commented Apr 20, 2018

+1

Strictly speaking, the appropriate JsonView is dynamically specified. For our purposes, we don't need that generality.

What would work just fine for us is to have a new @ApiJsonView annotation that contains the JsonView class and to have the Swagger object-graph walker just do the same test against that that Jackson does.

That change doesn't sound very hard.

@webron
Copy link
Contributor

webron commented Apr 21, 2018

Support has been added via #2681.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests