如何在 JAXB 集合解组中使用 setter
How to use setters in JAXB collections unmarshalling
我不想将 XML 反序列化到我的 POJO,但是出了点问题...
我的 POJO class:
@Builder
@ToString
@AllArgsConstructor
@NoArgsConstructor
@XmlRootElement(name="taxi")
@XmlAccessorType(XmlAccessType.PROPERTY)
@XmlType(propOrder = {"id", "name", "phone", "citiesId"})
public class TaxiEntity {
@Getter @Setter
private Integer id;
@Getter @Setter
private String name;
@Getter @Setter
private String phone;
@Singular("city")
private Set<Integer> citiesId = new HashSet<>();
@XmlElementWrapper(name="cities_id")
@XmlElement(name="city_id")
public void setCitiesId(Set<Integer> citiesId) {
System.out.println("setCitiesId()");
this.citiesId = citiesId;
}
public Set<Integer> getCitiesId() {
System.out.println("getCitiesId()");
return new HashSet<>(citiesId);
}
}
编组示例:
JAXBContext context = JAXBContext.newInstance(TaxiEntity.class);
TaxiEntity entity = TaxiEntity.builder().
id(5).
name("my city").
phone("12345678").
city(1).
city(5).
build();
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(entity, new File("entity.xml"));
XML 输出:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<taxi>
<id>5</id>
<name>my city</name>
<phone>12345678</phone>
<cities_id>
<city_id>1</city_id>
<city_id>5</city_id>
</cities_id>
</taxi>
解组示例:
JAXBContext context = JAXBContext.newInstance(TaxiEntity.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
TaxiEntity entity = (TaxiEntity) unmarshaller.unmarshal(new File("entity.xml"));
System.out.println(entity);
控制台输出:
getCitiesId()
getCitiesId()
TaxiEntity(id=5, name=my city, phone=12345678, citiesId=[])
Process finished with exit code 0
如您所见,citiesId 是空的。
发生这种情况是因为 JAXB 解组调用 getter (在我的例子中是字段的副本)
并尝试将值设置到集合的副本中。
如何让它创建一个集合并通过 setter?
进行设置
P.S。在我的真实业务对象中,我从数据库实体中收集了 getter 中的 ID,并且无法在 getter.
中收集 return
谢谢!
----上次编辑-----
import java.io.File;
import java.util.Set;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import lombok.Builder;
import lombok.Singular;
import lombok.ToString;
@Builder
@ToString
@XmlRootElement(name = "taxi")
@XmlType(name="taxi", propOrder = { "id", "name", "phone", "citiesId" })
public class TaxiEntity {
private Integer id;
private String name;
private String phone;
@Singular("city")
private Set<Integer> citiesId;
public TaxiEntity() {
}
public TaxiEntity(Integer id, String name, String phone, Set<Integer> citiesId) {
System.out.println("Hello");
this.id = id;
this.name = name;
this.phone = phone;
this.citiesId = citiesId;
}
@XmlElementWrapper(name = "cities_id")
@XmlElement(name = "city_id")
public void setCitiesId(Set<Integer> citiesId) {
System.out.println("I should be calling during deserialization" + citiesId);
this.citiesId = citiesId;
}
@XmlElement
public void setId(Integer id) {
this.id = id;
}
@XmlElement
public void setName(String name) {
this.name = name;
}
@XmlElement
public void setPhone(String phone) {
this.phone = phone;
}
public Integer getId() {
return id;
}
public String getName() {
return name;
}
public String getPhone() {
return phone;
}
public Set<Integer> getCitiesId() {
System.out.println("Calling getter " + this.citiesId);
return citiesId;
}
public static void main(String[] args) {
try {
JAXBContext context = JAXBContext.newInstance(TaxiEntity.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
Unmarshaller unmarshaller = context.createUnmarshaller();
TaxiEntity entity = TaxiEntity.builder().id(5).name("my city").phone("12345678").city(1).city(5).build();
marshaller.marshal(entity, new File("C:/whee/entity.xml"));
System.out.println("Unmarshalling now ------");
TaxiEntity taxEntityWithSettersGetters = (TaxiEntity) unmarshaller.unmarshal(new File("C:/whee/entity.xml"));
System.out.println(taxEntityWithSettersGetters);
} catch (Exception e) {
e.printStackTrace();
}
}
打印输出:
Hello
Calling getter [1, 5]
Unmarshalling now ------
Calling getter null
I should be calling during deserialization[]
Calling getter [1, 5]
TaxiEntity(id=5, name=my city, phone=12345678, citiesId=[1, 5])
在解组期间,JAXB 检查您的集合是否为空,如果是(它将首次调用 setter 将其初始化为空),您可以在日志中看到。
但是,之后,它将使用其内部逻辑来填充集合 (SET),使用您拥有的 Setter 初始化其类型 (New Set)*,并使用 Set.add (xyz);添加 (1),然后添加 (5)。
调用的 JAXB 逻辑位于 class:
public abstract class Lister<BeanT,PropT,ItemT,PackT> {
//startPacking正在调用初始化集合Set所以它是空的
public T startPacking(BeanT bean, Accessor<BeanT, T> acc) throws AccessorException {
T collection = acc.get(bean);
if(collection==null) {
collection = ClassFactory.create(implClass);
if(!acc.isAdapted())
acc.set(bean,collection);
}
collection.clear();
return collection;
}
//正确的方法,这会在之后调用(在您的任何 TaxiEntity 逻辑之前),以执行 addToPack(1)、addToPack(5),<--- 现在您的 Set 有 [1,5]
public void addToPack(T collection, Object o) {
collection.add(o);
}
然后,你在日志中看到,它调用了 getCitiesIds(),你会神奇地看到它有 [1,5]
这是 JAXB 处理集合的方式。所有其他元素,它们适当的 Setter 被调用。
看,JAXB does not call Setter method
你需要想出不同的方法,而不是依赖于 getter/setter。它完成了从 XML 文件中解组对象的工作,其余逻辑可以用外部方法编写。
我不想将 XML 反序列化到我的 POJO,但是出了点问题...
我的 POJO class:
@Builder
@ToString
@AllArgsConstructor
@NoArgsConstructor
@XmlRootElement(name="taxi")
@XmlAccessorType(XmlAccessType.PROPERTY)
@XmlType(propOrder = {"id", "name", "phone", "citiesId"})
public class TaxiEntity {
@Getter @Setter
private Integer id;
@Getter @Setter
private String name;
@Getter @Setter
private String phone;
@Singular("city")
private Set<Integer> citiesId = new HashSet<>();
@XmlElementWrapper(name="cities_id")
@XmlElement(name="city_id")
public void setCitiesId(Set<Integer> citiesId) {
System.out.println("setCitiesId()");
this.citiesId = citiesId;
}
public Set<Integer> getCitiesId() {
System.out.println("getCitiesId()");
return new HashSet<>(citiesId);
}
}
编组示例:
JAXBContext context = JAXBContext.newInstance(TaxiEntity.class);
TaxiEntity entity = TaxiEntity.builder().
id(5).
name("my city").
phone("12345678").
city(1).
city(5).
build();
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(entity, new File("entity.xml"));
XML 输出:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<taxi>
<id>5</id>
<name>my city</name>
<phone>12345678</phone>
<cities_id>
<city_id>1</city_id>
<city_id>5</city_id>
</cities_id>
</taxi>
解组示例:
JAXBContext context = JAXBContext.newInstance(TaxiEntity.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
TaxiEntity entity = (TaxiEntity) unmarshaller.unmarshal(new File("entity.xml"));
System.out.println(entity);
控制台输出:
getCitiesId()
getCitiesId()
TaxiEntity(id=5, name=my city, phone=12345678, citiesId=[])
Process finished with exit code 0
如您所见,citiesId 是空的。 发生这种情况是因为 JAXB 解组调用 getter (在我的例子中是字段的副本) 并尝试将值设置到集合的副本中。 如何让它创建一个集合并通过 setter?
进行设置P.S。在我的真实业务对象中,我从数据库实体中收集了 getter 中的 ID,并且无法在 getter.
中收集 return谢谢!
----上次编辑-----
import java.io.File;
import java.util.Set;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import lombok.Builder;
import lombok.Singular;
import lombok.ToString;
@Builder
@ToString
@XmlRootElement(name = "taxi")
@XmlType(name="taxi", propOrder = { "id", "name", "phone", "citiesId" })
public class TaxiEntity {
private Integer id;
private String name;
private String phone;
@Singular("city")
private Set<Integer> citiesId;
public TaxiEntity() {
}
public TaxiEntity(Integer id, String name, String phone, Set<Integer> citiesId) {
System.out.println("Hello");
this.id = id;
this.name = name;
this.phone = phone;
this.citiesId = citiesId;
}
@XmlElementWrapper(name = "cities_id")
@XmlElement(name = "city_id")
public void setCitiesId(Set<Integer> citiesId) {
System.out.println("I should be calling during deserialization" + citiesId);
this.citiesId = citiesId;
}
@XmlElement
public void setId(Integer id) {
this.id = id;
}
@XmlElement
public void setName(String name) {
this.name = name;
}
@XmlElement
public void setPhone(String phone) {
this.phone = phone;
}
public Integer getId() {
return id;
}
public String getName() {
return name;
}
public String getPhone() {
return phone;
}
public Set<Integer> getCitiesId() {
System.out.println("Calling getter " + this.citiesId);
return citiesId;
}
public static void main(String[] args) {
try {
JAXBContext context = JAXBContext.newInstance(TaxiEntity.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
Unmarshaller unmarshaller = context.createUnmarshaller();
TaxiEntity entity = TaxiEntity.builder().id(5).name("my city").phone("12345678").city(1).city(5).build();
marshaller.marshal(entity, new File("C:/whee/entity.xml"));
System.out.println("Unmarshalling now ------");
TaxiEntity taxEntityWithSettersGetters = (TaxiEntity) unmarshaller.unmarshal(new File("C:/whee/entity.xml"));
System.out.println(taxEntityWithSettersGetters);
} catch (Exception e) {
e.printStackTrace();
}
}
打印输出:
Hello
Calling getter [1, 5]
Unmarshalling now ------
Calling getter null
I should be calling during deserialization[]
Calling getter [1, 5]
TaxiEntity(id=5, name=my city, phone=12345678, citiesId=[1, 5])
在解组期间,JAXB 检查您的集合是否为空,如果是(它将首次调用 setter 将其初始化为空),您可以在日志中看到。
但是,之后,它将使用其内部逻辑来填充集合 (SET),使用您拥有的 Setter 初始化其类型 (New Set)*,并使用 Set.add (xyz);添加 (1),然后添加 (5)。
调用的 JAXB 逻辑位于 class:
public abstract class Lister<BeanT,PropT,ItemT,PackT> {
//startPacking正在调用初始化集合Set所以它是空的
public T startPacking(BeanT bean, Accessor<BeanT, T> acc) throws AccessorException {
T collection = acc.get(bean);
if(collection==null) {
collection = ClassFactory.create(implClass);
if(!acc.isAdapted())
acc.set(bean,collection);
}
collection.clear();
return collection;
}
//正确的方法,这会在之后调用(在您的任何 TaxiEntity 逻辑之前),以执行 addToPack(1)、addToPack(5),<--- 现在您的 Set 有 [1,5]
public void addToPack(T collection, Object o) {
collection.add(o);
}
然后,你在日志中看到,它调用了 getCitiesIds(),你会神奇地看到它有 [1,5]
这是 JAXB 处理集合的方式。所有其他元素,它们适当的 Setter 被调用。
看,JAXB does not call Setter method
你需要想出不同的方法,而不是依赖于 getter/setter。它完成了从 XML 文件中解组对象的工作,其余逻辑可以用外部方法编写。