Jackson根据通用类型设置元素名称

时间:2018-09-22 01:16:25

标签: java xml generics jackson

是否可以使用jackson根据泛型的类设置元素的名称?

鉴于以下情况:

public class Room<T> {
    private int roomId;
    private String roomName;
    private T roomDetails;
//constructor getters, setters
}

public class Livingroom {
    private boolean hasCouch;
    private int numOfSeats;
//constructor getters, setters
}

public class Bathroom{
    private boolean hasShower;
    private boolean hasSink;
//constructor getters, setters
}

如果我使用杰克逊序列化房间对象(将客厅设置为通用对象),则它看起来像这样:

public void jackson() throws JsonProcessingException {
    Livingroom livingroom = new Livingroom();
    livingroom.setHasCouch(true);
    livingroom.setNumOfSeats(5);

    Room<Livingroom> room = new Room<>();
    room.setRoomDetails(livingroom);
    room.setRoomId(10);
    room.setRoomName("MyRoom");
    XmlMapper xmlMapper = new XmlMapper();
    String xml = xmlMapper.writeValueAsString(room);
    System.out.println(xml);
}

结果是:

<Room>
    <roomId>10</roomId>
    <roomName>MyRoom</roomName>
    <roomDetails>
        <hasCouch>true</hasCouch>
        <numOfSeats>5</numOfSeats>
    </roomDetails>
</Room>

但是我希望看到的结果是:

<Room>
    <roomId>10</roomId>
    <roomName>MyRoom</roomName>
    <Livingroom>
        <hasCouch>true</hasCouch>
        <numOfSeats>5</numOfSeats>
    </Livingroom>
</Room>

反之亦然,浴室或所有其他可能的房间。是否可以让jackson在运行时从泛型的实际类派生元素名称?

1 个答案:

答案 0 :(得分:0)

是的,您可以使用自定义序列化器根据通用类型设置元素名称。

请记住,杰克逊使用get方法来命名序列化json / xml的属性,这就是为什么要在序列化xml上获取元素roomDetails的原因。

@JsonGetter@JsonProperty这样的注释期望一个恒定值,因此在这种情况下不能使用它们,因为我们只能在运行时确定类型。

解决方案:

Room类,带有@JsonSerialize注释:

@JsonSerialize(using = RoomSerializer.class)
public class Room<T> {
    private int roomId;
    private String roomName;
    private T roomDetails;

    public int getRoomId() {
        return roomId;
    }

    public void setRoomId(int roomId) {
        this.roomId = roomId;
    }

    public String getRoomName() {
        return roomName;
    }

    public void setRoomName(String roomName) {
        this.roomName = roomName;
    }

    public T getRoomDetails() {
        return roomDetails;
    }

    public void setRoomDetails(T roomDetails) {
        this.roomDetails = roomDetails;
    }
}

BathroomLivingroom之类的类别保持不变。

RoomSerializer实现:

public class RoomSerializer extends StdSerializer<Room> {

    public RoomSerializer() {
        this(null);
    }

    public RoomSerializer(Class<Room> t) {
        super(t);
    }

    @Override
    public void serialize(Room value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
        jgen.writeStartObject();
        jgen.writeNumberField("roomId", value.getRoomId());
        jgen.writeStringField("roomName", value.getRoomName());

        // Here we determine the field name depending on the type
        String roomDetailsFieldName = value.getRoomDetails().getClass().getSimpleName();
        jgen.writeObjectField(roomDetailsFieldName, value.getRoomDetails());

        jgen.writeEndObject();
    }
}

通过您的示例,您将获得想要的东西:

<Room>
    <roomId>10</roomId>
    <roomName>MyRoom</roomName>
    <Livingroom>
        <hasCouch>true</hasCouch>
        <numOfSeats>5</numOfSeats>
    </Livingroom>
</Room>