java—如何在jaxb集合解组中使用setter

r6vfmomb  于 2021-06-30  发布在  Java
关注(0)|答案(1)|浏览(338)

我不想将xml反序列化到我的pojo中,但是发生了一些错误。。。
我的pojo课程:

@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、 在我的real bussiness对象中,我在getter中从db实体收集id,并且不能在getter中返回collection。
谢谢!

dpiehjr4

dpiehjr41#

----上次编辑-----

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检查集合是否为null,如果为null(它将第一次调用setter将其初始化为空),您可以在日志中看到这一点。
但是,之后,它将使用其内部逻辑来填充集合(set),通过使用现有的setter初始化其类型(newset)*,并使用set.add(xyz);加(1),然后加(5)。
调用的jaxb逻辑位于类中:

public abstract class Lister<BeanT,PropT,ItemT,PackT> {

//StartPack正在调用以初始化集合集,使其为空

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;
}

//正确的方法是,这将在之后(在任何实体逻辑之前)调用,以执行addtopack(1),addtopack(5),<---现在您的集合有[1,5]

public void addToPack(T collection, Object o) {
    collection.add(o);
}

然后,您可以在日志中看到,它调用getcitiesids(),您将神奇地看到它有[1,5]
这就是jaxb处理集合的方式。所有其他元素,它们的适当设置器被称为。
看,jaxb不调用setter方法
你需要想出一种不同的方法来做,而不是依赖于getter/setter。它完成了从xml文件中解包对象的工作,其余的逻辑可以用外部方法编写。

相关问题