Skip to content

@JsonView annotation ignored for sub-resources #37145

@jonjanisch

Description

@jonjanisch

code-with-quarkus.zip

Describe the bug

We want to use @JsonView to to selectively hide/show fields for different scenarios.

It works for the simple scenario of adding it to a top-level Resource. But the same code fails if the endpoint is in a sub-resource.

Example

Basic User class where we want to hide the password field in the JSON response except for Private.

public class User {

    private String name;

    // hide the password except for Private view
    @JsonView(Views.Private.class)
    private String password;

    // getters/setters
}

The Views are identical to https://quarkus.io/guides/resteasy-reactive#jsonview-support

public class Views {
    public static class Public {}
    public static class Private extends Public {}
}

Create a simple endpoint at the top-level and it works fine.

@GET
@JsonView(Views.Public.class)
public User hello() {
    User user = new User();
    user.setName("John");
    user.setPassword("password");
    return user;
}
http://localhost:8080/hello
{"name":"John"}

Bug Scenario - using @JsonView in Sub-Resource

Now create another class BugResource with the same code and in GreetingResource add a method to return the sub-resource:

@Path("/bug")
public BugResource getBugResource() {
    return resourceContext.getResource(BugResource.class);
}
@ApplicationScoped
@Unremovable
public class BugResource {

    @GET
    @JsonView(Views.Public.class)
    public User hello() {
        User user = new User();
        user.setName("John");
        user.setPassword("password");
        return user;
    }
}
http://localhost:8080/hello/bug
{"name":"John","password":"password"}

Temporary workaround

Our current workaround is to inject ObjectMapper and manually serialize to a String but it gets pretty ugly as we add @JsonView to more endpoints:

@Inject
ObjectMapper objectMapper;
    
// endpoint must now return a String instead of User
public String bug() throws JsonProcessingException {
        User user = new User();
        user.setName("John");
        user.setPassword("password");
        return objectMapper.writerWithView(Views.Public.class)
                .writeValueAsString(user);
}

Expected behavior

@JsonView annotation on endpoints should work regardless if endpoint is top-level resource or sub-resource.

Actual behavior

@JsonView annotation does not work in sub-resources.

How to Reproduce?

  1. Generate code-with-quarkus project using Quarkus CLI
  2. Add quarkus-resteasy-reactive-jackson dependency to pom.xml
  3. Modify GreetingResource to return a sub-resource:
@Path("/bug")
public BugResource getBugResource() {
    return resourceContext.getResource(BugResource.class);
}
  1. In the sub-resource, add a simple @GET endpoint with a @JsonView annotation.
    @GET
    @JsonView(Views.Public.class)
    public User hello() {
        User user = new User();
        user.setName("John");
        user.setPassword("password");
        return user;
    }
  1. Add User.java and Views.java
public class User {

   private String name;
   @JsonView(Views.Private.class)
   private String password;

   // getters and setters
}

Same as documentation:

public class Views {
    public static class Public {}
    public static class Private extends Public {}
}

Open browser: http://localhost:8080/hello/bug

Output of uname -a or ver

No response

Output of java -version

No response

Quarkus version or git rev

3.5.1

Build tool (ie. output of mvnw --version or gradlew --version)

No response

Additional information

Bug has existed since at least 2.16.6.Final. I was hoping the upgrade to 3.5.1 would fix it.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions