Swagger-core: @ApiModelProperty(hidden = true) seems not work

Created on 27 Dec 2016  路  8Comments  路  Source: swagger-api/swagger-core

Hi,
I am using 'io.swagger:swagger-jersey2-jaxrs:1.5.10'.
The @ApiModelProperty(hidden = true) seems not hide those properties from 'definitions'!
Could you please have a look? Thanks!

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.collect.Lists;
import io.swagger.annotations.ApiModelProperty;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;

import java.util.List;

@Getter
@Setter
@JsonInclude(JsonInclude.Include.NON_EMPTY)
//@JsonFilter("attributeFilter")
public final class User extends Resource {

    public static final String SCHEMA = "urn:ietf:params:scim:schemas:core:2.0:User";

    @ApiModelProperty(value = "MUST be same as work type email address", required = true)
    private String userName;    // unique user-friendly identifier
    @ApiModelProperty(required = true)
    private Name name;
    @ApiModelProperty(hidden = true)
    private String displayName;
    @ApiModelProperty(hidden = true)
    private String nickName;
    @ApiModelProperty(hidden = true)
    private String profileUrl;
    @ApiModelProperty(hidden = true)
    private String title;
    @ApiModelProperty(hidden = true)
    private String userType;    // used to identify the relationship between the organization and the user
    @ApiModelProperty(hidden = true)
    private String preferredLanguage;
    @ApiModelProperty(hidden = true)
    private String locale;      // https://tools.ietf.org/html/rfc5646
    @ApiModelProperty(hidden = true)
    private String timezone;    // https://tools.ietf.org/html/rfc6557
    @ApiModelProperty("user status")
    private Boolean active;     // active/disabled/suspended
    @ApiModelProperty(hidden = true)
    private String password;
    @ApiModelProperty(required = true)
    private List<Email> emails;
    private List<PhoneNumber> phoneNumbers;
    @ApiModelProperty(hidden = true)
    private List<Im> ims;
    @ApiModelProperty(hidden = true)
    private List<Photo> photos;
    private List<Address> addresses;
    @ApiModelProperty(hidden = true)
    private List<GroupRef> groups;
    @ApiModelProperty(hidden = true)
    private List<Entitlement> entitlements;
    @ApiModelProperty(hidden = true)
    private List<Role> roles;
    @ApiModelProperty(hidden = true)
    private List<X509Certificate> x509Certificates;

    @JsonProperty(EnterpriseUser.SCHEMA)
    private EnterpriseUser enterpriseUser;

    @Builder
    @JsonCreator
    private User(@JsonProperty(value = "schemas", required = true) List<String> schemas,
                 @JsonProperty("id") String id,
                 @JsonProperty("externalId") String externalId,
                 @JsonProperty("meta") Meta meta,
                 @JsonProperty("userName") String userName,
                 @JsonProperty("name") Name name,
                 @JsonProperty("displayName") String displayName,
                 @JsonProperty("nickName") String nickName,
                 @JsonProperty("profileUrl") String profileUrl,
                 @JsonProperty("title") String title,
                 @JsonProperty("userType") String userType,
                 @JsonProperty("preferredLanguage") String preferredLanguage,
                 @JsonProperty("locale") String locale,
                 @JsonProperty("timezone") String timezone,
                 @JsonProperty("active") Boolean active,
                 @JsonProperty("password") String password,
                 @JsonProperty("emails") List<Email> emails,
                 @JsonProperty("phoneNumbers") List<PhoneNumber> phoneNumbers,
                 @JsonProperty("ims") List<Im> ims,
                 @JsonProperty("photos") List<Photo> photos,
                 @JsonProperty("addresses") List<Address> addresses,
                 @JsonProperty("groups") List<GroupRef> groups,
                 @JsonProperty("entitlements") List<Entitlement> entitlements,
                 @JsonProperty("roles") List<Role> roles,
                 @JsonProperty("x509Certificates") List<X509Certificate> x509Certificates,
                 @JsonProperty(EnterpriseUser.SCHEMA) EnterpriseUser enterpriseUser) {
        super(schemas == null ? Lists.newArrayList(SCHEMA) : schemas, id, externalId, meta);
        this.userName = userName;
        this.name = name;
        this.displayName = displayName;
        this.nickName = nickName;
        this.profileUrl = profileUrl;
        this.title = title;
        this.userType = userType;
        this.preferredLanguage = preferredLanguage;
        this.locale = locale;
        this.timezone = timezone;
        this.active = active;
        this.password = password;
        this.emails = emails;
        this.phoneNumbers = phoneNumbers;
        this.ims = ims;
        this.photos = photos;
        this.addresses = addresses;
        this.groups = groups;
        this.entitlements = entitlements;
        this.roles = roles;
        this.x509Certificates = x509Certificates;

        setEnterpriseUser(enterpriseUser);
    }

    public void setEnterpriseUser(EnterpriseUser enterpriseUser) {
        if (enterpriseUser != null) {
            this.enterpriseUser = enterpriseUser;
            addSchema(EnterpriseUser.SCHEMA);
        }
    }

}
@Api(tags = "User")
@Produces({MediaType.APPLICATION_JSON, SCIMConstants.SCIM_CONTENT_TYPE})
@Consumes({MediaType.APPLICATION_JSON, SCIMConstants.SCIM_CONTENT_TYPE})
@Path("/Users")
public class UserEndpoint extends ResourceEndpoint<User> {

    @Inject
    UserService userService;
    @Inject
    UserPatchService userPatchService;

    @ApiOperation(value = "get an user by id", response = User.class)
    @ApiResponses({
        @ApiResponse(code = 401, message = "authorization failure", response = ErrorResponse.class),
        @ApiResponse(code = 403, message = "license limit", response = ErrorResponse.class),
        @ApiResponse(code = 404, message = "not found", response = ErrorResponse.class),
        @ApiResponse(code = 429, message = "too many requests", response = ErrorResponse.class),
        @ApiResponse(code = 500, message = "internal server error", response = ErrorResponse.class)
    })
    @GET
    @Path("/{id}")
    public Response getUserById(@ApiParam("user id") @PathParam("id") String id) {
        User user = userService.getById(id);
        return buildResponseWithLocation(user);
    }

}

Most helpful comment

Hidden parameter also does not seem to work on scala case classes.

All 8 comments

This is an interesting case. IIRC, it would work if you set it either on the setter or the getter (don't recall which) - however, you're using Lombok so... annotating the setter/getter is a bit messy.

At least for testing, can you try adding the setter and getter explicitly and set the hidden on them?

Hi @webron, it's working when annotating @ApiModelProperty(hidden = true) on getter.
Looking over the source codes of io.swagger.jackson.ModelResolver#resolve(com.fasterxml.jackson.databind.JavaType, io.swagger.converter.ModelConverterContext, java.util.Iterator<io.swagger.converter.ModelConverter>) and io.swagger.jackson.ModelResolver#ignore, it doesn't handle the @ApiModelProperty(hidden = true) on field.

Thanks for checking. Okay, so at least there's a workaround for now, but we'll keep this open as a bug. If you have time, consider submitting a PR.

Hi @webron, I was trying to fix this issue, and digging a bit more deeply into Jackson.
Found, the metadata of fields are removed in com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector#_removeUnwantedProperties.
Since I used the Lombok, which will generate getter and setter methods. As a result, Jackson will ignore the metadata of field, and then use getter instead on its priority order...
But another case is the description defined by @ApiModelProperty(value = "MUST be same as work type email address", required = true), it's captured by Swagger. That means the annotations on field are handled by Swagger someway.
What's your suggestion on handling 'hidden' flag annotated on field when the getter/setter also exist?
Thanks.

+1 馃憤

Hidden parameter also does not seem to work on scala case classes.

We had the same issue.
The fix was easy - setters were missing.

Fixed by #2251

Was this page helpful?
0 / 5 - 0 ratings