JAXB unmarshal to concrete class without using xsi:type in xml but using actual concrete class name

时间:2017-08-30 20:11:40

标签: java xml jaxb

I wonder if someone can help me with a JAXB problem.

If I have an abstract class with 2 concrete implementations: For example (I have left out most of the markup/xml for brevity):

Map

Is there a way to have the xml below unmarshall correctly to the appropriate concrete class

Do

rather than the following:

abstract class Credential
{
    public abstract CredentialDLL Map();
}
class SNMP : Credential
{
    public override CredentialDLL Map()
    {
        return new SNMPMapper().Map(this);
    }
}

class HTTP : Credential
{
    public override CredentialDLL Map()
    {
        return new HTTPMapper().Map(this);
    }
}

// Simplified do method, it is now a one liner
CredentialDLL Do(Credential input)
{
    return input.Map();
}

The reason I need this is to be backward compatible with our already published API.

Thanks in advance.

2 个答案:

答案 0 :(得分:2)

我刚才在俄语社区回答了类似的问题。可能你正在寻找类似的东西:

df = speed_df.merge(temp_df, how='outer', on='ts')
df = df.rename(columns=dict(val_x='speed', val_y='temp'))
df = df.sort_values('ts')
df.fillna(method='ffill')

一些简单的例子:

@XmlElements({
      @XmlElement(name = "car", type = Car.class),
      @XmlElement(name = "van", type = Van.class)
})
public List<Vehicle> getVehicles() {
      return vehicles;
}

输出将是:

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.*;
import java.io.StringReader;
import java.util.List;

public class Test {

    public static void main(String... args) throws JAXBException {
        String xmldata = "<request><car></car><van></van></request>";
        StringReader reader = new StringReader(xmldata);

        JAXBContext jaxbContext = JAXBContext.newInstance(Request.class);
        Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();

        Request request = (Request) unmarshaller.unmarshal(reader);

        for (Vehicle object : request.getVehicles()) {
            System.out.println(object.getClass());
        }
    }
}

@XmlRootElement(name = "request")
class Request {
    private List<Vehicle> vehicles;

    @XmlElements({
            @XmlElement(name = "car", type = Car.class),
            @XmlElement(name = "van", type = Van.class)
    })
    public List<Vehicle> getVehicles() {
        return vehicles;
    }

    public void setVehicles(List<Vehicle> vehicles) {
        this.vehicles = vehicles;
    }
}

abstract class Vehicle {
}

class Van extends Vehicle {
}

class Car extends Vehicle {
}

<强> UPD

评论后更新。对于单个条目,无论如何都可以删除class Car class Van

List

希望这会有所帮助。

答案 1 :(得分:1)

You can use annotations and annotate the concrete implementations. In this case @XmlType() above Car or Van. This way you will keep your xml generic.