Ваша проблема связана с неправильным использованием аннотаций xml. Вы определяете Tuple2
как корневой элемент xml, аннотируя его с помощью @XmlRootElement
, а его поля - как атрибуты xml, аннотируя методы get с помощью @XmlAttribute
. Что означает:
<tuple2 first="first_attributes_vale" second="second_attributes_value" />
Теперь оба поля имеют тип Coords
, который объявлен как другой элемент xml, аннотируя класс Coords
с помощью @XmlRootElement
, а его поля - xml. атрибутов. Когда Coords
будет сериализован в xml, это будет:
<coords x="value" y="value" />
Проблема возникает при сериализации Tuple2
. Его поля должны быть атрибутами xml, но Coords
- это еще один элемент xml. Атрибуты XML не могут содержать вложенные элементы, а только значения.
Решение
В зависимости от того, что вы хотите, вы можете решить это двумя различными способами. Хотя я бы не рекомендовал второй подход, потому что он странный (хотя он и работает) и потребует дополнительных усилий на стороне клиента (см. Пояснения ниже).
Первый подход
Аннотируйте методы getFirst()
и getSecon()
с помощью аннотации @XmlElement
.
package model;
import static javax.xml.bind.annotation.XmlAccessType.NONE;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
@XmlAccessorType(NONE)
public class Tuple2 {
private Coords c1;
private Coords c2;
public Tuple2(Coords c1, Coords c2) {
this.c1 = c1;
this.c2 = c2;
}
public Tuple2() {
c1 = new Coords(0, 0);
c2 = new Coords(0, 0);
}
@XmlElement
public Coords getFirst() {
return this.c1;
}
@XmlElement
public Coords getSecond() {
return this.c2;
}
}
Это даст результат, который выглядит следующим образом:
<tuple2>
<first x="2" y="4"/>
<second x="12" y="12"/>
</tuple2>
Второй подход
Это странный способ его решения. Это работает, но требует дополнительных усилий на стороне клиента, потому что значения Coords
кодируются как строковые значения и требуют анализа на принимающей стороне.
Измените тип возврата getFirst()
и getSecond()
методов для String
и переопределения toString()
метода Coords
.
package model;
import static javax.xml.bind.annotation.XmlAccessType.NONE;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
@XmlAccessorType(NONE)
public class Tuple2 {
private Coords c1;
private Coords c2;
public Tuple2(Coords c1, Coords c2) {
this.c1 = c1;
this.c2 = c2;
}
public Tuple2() {
c1 = new Coords(0, 0);
c2 = new Coords(0, 0);
}
@XmlAttribute
public String getFirst() {
return this.c1.toString();
}
@XmlAttribute
public String getSecond() {
return this.c2.toString();
}
}
Переопределения toString()
метода Coords
:
package model;
import static javax.xml.bind.annotation.XmlAccessType.NONE;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
@XmlAccessorType(NONE)
public class Coords {
@XmlAttribute private int x;
@XmlAttribute private int y;
public Coords(final int x, final int y) {
this.x = x;
this.y = y;
}
public Coords() {
this.x = 0;
this.y = 0;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("Coords [x=");
builder.append(x);
builder.append(", y=");
builder.append(y);
builder.append("]");
return builder.toString();
}
}
Thisвыдаст результат, подобный следующему:
<tuple2 first="Coords [x=2, y=4]" second="Coords [x=12, y=12]"/>
Значения атрибутов first
и second
будут такими, какие возвращает toString()
метод Coords
.