1

I am using the @JsonView annotation to output a simplified version of a complex object in Spring MVC.

The View:

public class UserView {
    public interface Summary {}
}

The entity class:

public class User implements Serializable {

    private static final long serialVersionUID = 1L;

    @Column(name = "name", length = 255)
    @JsonView(UserView.Summary.class)
    private String name;

The resource method:

@GetMapping(value = "users", produces = {MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_UTF8_VALUE})
@JsonView(UserView.Summary.class)
public List<User> getAllUsers() {
    return userRepository.findAllBy();
}

This works perfect when outputting JSON:

[
    {"name": "User 1"},
    {"name": "User 2"}
]

But when the "Content-Type" is set to XML, the following output is returned:

<List>
    <item>
        <name>User 1</name>
    </item>
    <item>
        <name>User 2</name>
    </item>
</List>

I'd like to have <Users> instead of <List> and <User> instead of <item>, but I couldn't find a way of changing these generic names. I've tried annotations like @XmlRootElement(name="user") or @XmlElementWrapper(name="users"), but no luck.

kioleanu
  • 920
  • 1
  • 6
  • 17
  • Could you please provide feedback to the answers ? Thank you. – s7vr Mar 29 '20 at 11:34
  • Hi @SagarVeeram, yes, sorry. I've tried both answers and they both work. I'm going to accept the first one that was provided. Thank you so much for both your contributions! – kioleanu Mar 29 '20 at 12:19
  • @viorel In my case, the xml output is unaffected by JsonView, but json renders perfectly. How did you make yours work could you please share. – bitsobits Nov 11 '20 at 09:52

2 Answers2

1

Using @XmlElementWrapper is generally a good way to do that. But this only works when the list is inside an entity.

I'd recommend to not return List<User> but instead a Users Entity (notice the plural) with the attribute users. We can even omit the @XmlElementWrapper here since the Entity itself is the element wrapper.

@XmlRootElement
public class Users implements Serializable {

    private static final long serialVersionUID = 1337L;

    @XmlElement(name = "User")
    private List<User> users = new ArrayList<>();

    public List<User> getUsers() {
        return users;
    }

    public void setUsers(List<User> users) {
        this.users = users;
    }
}

Output

<Users>
    <User>
        <name>User 1</name>
    </User>
    <User>
        <name>User 2</name>
    </User>
</Users>
jdickel
  • 1,437
  • 1
  • 11
  • 21
1

Collections at the root level support is limited for xml mapper ( see here and here (answers are little dated but you should get the idea ) but collections as pojo property are fully supported. So for customization it is better to create a wrapper.

Also note @JsonView(UserView.Summary.class) to the wrapper property for spring to pick it up.

Something like

@JacksonXmlRootElement(localName = "Users")
public class CollectionWrapper {

    @JacksonXmlElementWrapper(useWrapping = false)
    @JacksonXmlProperty(localName = "User")
    @JsonView(UserView.Summary.class)
    private List<User> users;

    public CollectionWrapper(List<User> users) {
        this.users = users;
    }

}

Resource

@GetMapping(value = "users", produces = {MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_UTF8_VALUE})
@JsonView(UserView.Summary.class)
public CollectionWrapper getAllUsers() {
    return new CollectionWrapper(userRepository.findAllBy());
}

Output

<Users>
    <User>
        <name>User 1</name>
    </User>
    <User>
        <name>User 2</name>
    </User>
</Users>
s7vr
  • 73,656
  • 11
  • 106
  • 127