Я пытаюсь выяснить, как сериализовать специализированный List
в XML, используя XmlMapper
(подкласс ObjectMapper
), контролируя при этом имя внешней оболочки каждого элемента.
Желательно, чтобы я делал это с помощью аннотаций, а не путем настройки XmlMapper
(к которому у меня, возможно, нет доступа).
Например, рассмотрим бизнес-объект, который расширяет ArrayList
, например:
static class Photo {
String name;
}
class Album extends ArrayList<Photo> {
}
Я хочу сериализовать эту модель для JSON и XML, например:
JSON:
[
{
"name": "..."
},
{
"name": "..."
}
]
XML:
<Album>
<Photo>
<Name>...</Name>
</Photo>
<Photo>
<Name>...</Name>
</Photo>
<Album>
Я очень близко подошел к тому, чтобы выяснить, как это сделать, и я успешно построил версии вышеупомянутой модели для поддержки любого формата, но я не могу заставить ни одну версию поддерживать оба формата одновременно.
В случае, если непонятно, о чем я спрашиваю, рассмотрите следующий прохождение модульного теста (который представляет собой упрощенное представление моей проблемы), а затем обратитесь к TODO:
public class SpecializedListTest {
@JsonRootName("Photo")
class Photo {
@JsonProperty("name")
String name;
}
@JsonRootName("Album")
class Album1 extends ArrayList<Photo> {}
Album1 getAlbum1() {
Album1 album = new Album1();
Photo photo = new Photo();
photo.name = "Hawaii";
album.add(photo);
album.add(photo);
return album;
}
@Test
public void serializeAlbum1ToJson() throws JsonProcessingException {
Album1 album = getAlbum1();
ObjectMapper mapper = new ObjectMapper();
String actual = mapper.writeValueAsString(album);
String expected = "[{'name':'Hawaii'},{'name':'Hawaii'}]".replace('\'', '"');
assertEquals(expected, actual);
}
@Test
public void serializeAlbum1ToXml() throws JsonProcessingException {
Album1 album = getAlbum1();
ObjectMapper mapper = new XmlMapper();
String actual = mapper.writeValueAsString(album);
// TODO Render as "<Photo>" instead of "<item">.
String expected = "<Album><item><name>Hawaii</name></item><item><name>Hawaii</name></item></Album>";
assertEquals(expected, actual);
}
@JsonRootName("Album")
class Album2 {
@JsonProperty
@JacksonXmlElementWrapper(useWrapping = false)
@JacksonXmlProperty(localName = "Photo")
private final List<Photo> photos = new ArrayList<>();
}
Album2 getAlbum2() {
Album2 album = new Album2();
Photo photo = new Photo();
photo.name = "Hawaii";
album.photos.add(photo);
album.photos.add(photo);
return album;
}
@Test
public void serializeAlbum2ToJson() throws JsonProcessingException {
Album2 album = getAlbum2();
ObjectMapper mapper = new ObjectMapper();
String actual = mapper.writeValueAsString(album);
// TODO Render as list, not object: [{"name":"Hawaii"},{"name":"Hawaii"}]
String expected = "{'photos':[{'name':'Hawaii'},{'name':'Hawaii'}]}".replace('\'', '"');
assertEquals(expected, actual);
}
@Test
public void serializeAlbum2ToXml() throws JsonProcessingException {
Album2 album = getAlbum2();
ObjectMapper mapper = new XmlMapper();
String actual = mapper.writeValueAsString(album);
String expected = "<Album><Photo><name>Hawaii</name></Photo><Photo><name>Hawaii</name></Photo></Album>";
assertEquals(expected, actual);
}
}
Проблема с моделью на основе списка (Album1
) заключается в том, что я не могу контролировать имя внешнего XML-элемента Photo
. По умолчанию <item>
.
Проблема с моделью списка-контейнера (Album2
) заключается в том, что список представлен в виде свойства объекта, и я хочу, чтобы выходные данные представляли собой массив JSON, а не объект.
Я не могу согласиться с различными форматами вывода, потому что я пишу совместимую замену для существующего устаревшего продукта. Я знаю, что, возможно, смогу решить эту проблему с помощью специального сериализатора, но я надеюсь избежать этого.
Есть идеи?