使用接口的 JaxB 编组 [英] JaxB marhsalling using interfaces

查看:25
本文介绍了使用接口的 JaxB 编组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下课程,我希望能够基于接口动态生成 xml,并更改实现...这可能...我尝试过但运气不佳...

I have the following class, i want to be able to produce xml dynamically based ona an interface, with changing implementations... is that possible... i have tried with little luck...

@xmlRootElement
public class Vehicles {
   private String id;

   private List<VehicleType> types;


   .... various setters and getters...
   ... with annotated getters...

}

public interface VehicleType {
   public String getName();
}

public Car implements VehicleType {

    private String name;
    private String wheels;

    ...various constructors...

    @XmlElement
    public String getName() {
      return name;
    }

    @XmlElement
    public String getWheels() {
      return wheels;
    }

 }

public Motorbike implements VehicleType {

    private String name;
    private String exhaust;

    ...various constructors...

    @XmlElement
    public String getName() {
      return name;
    }

    @XmlElement
    public String getExhaust() {
      return exhaust;
    }

 }

我希望 Vehicles 的编组产生以下输出:

I want the marshlling of Vehicles to produce the following output:

<vehicles>
   <types>
     <car>
        ..car specific elements
     </car>
     <motorbike>
        .. mototrbike specific elements
     <motorbike>
   </types>
</vehicles> 

车辆类不知道实现,或者存在哪些实现..它只知道接口,在这里我真的用作标记接口......允许我在运行时填充具有不同实现的列表...

The vehicles class cannot know about the implementations, or which ones exist.. it only knows about the interface, which here im using as a marker interface really.. to allow me to populate a list with different implementations at runtime...

无论如何我可以让 jaxb 将输出呈现为 xml 而不让父级真正了解​​实现?

Is there anyway i can get jaxb be to render the output as xml with out the parent really knowing about the implementations?

推荐答案

注意:我是EclipseLink JAXB (MOXy) 领导和成员 JAXB (JSR-222) 专家组.

Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.

以下内容不适用于 JAXB 参考实现,但适用于 EclipseLink JAXB (MOXy).

The following will not work with the JAXB reference implementation but will work with EclipseLink JAXB (MOXy).

Java 模型

下面是一个表示为接口的简单领域模型.我们将使用 @XmlType 注释来指定一个工厂类来创建这些接口的具体实现.这将需要满足解组(参见:http://blog.bdoughan.com/2011/06/jaxb-and-factory-methods.html).

Below is a simple domain model represented as interfaces. We will use the @XmlType annotation to specify a factory class to create concrete impls of these interfaces. This will be required to satisfy unmarshalling (see: http://blog.bdoughan.com/2011/06/jaxb-and-factory-methods.html).

客户

import javax.xml.bind.annotation.*;

@XmlRootElement
@XmlType(
    propOrder={"name", "address"},
    factoryClass=Factory.class, 
    factoryMethod="createCustomer")
public interface Customer {

    String getName();
    void setName(String name);

    Address getAddress();
    void setAddress(Address address);

}

地址

import javax.xml.bind.annotation.XmlType;

@XmlType(factoryClass=Factory.class, factoryMethod="createAddress")
public interface Address {

    String getStreet();
    void setStreet(String street);

}

工厂

下面是返回接口具体实现的工厂方法.这些是将在解组操作期间构建的实现.为了避免需要真正的类,我将利用 Proxy 对象.

Below is the factory method that returns concrete impls of the interfaces. These are the impls that will be built during an unmarshal operation. To prevent requiring real classes I will leverage Proxy objects.

import java.lang.reflect.*;
import java.util.*;

public class Factory {

    public Customer createCustomer() {
        return createInstance(Customer.class);    }

    public Address createAddress() {
        return createInstance(Address.class);
    }

    private <T> T createInstance(Class<T> anInterface) {
        return (T) Proxy.newProxyInstance(anInterface.getClassLoader(), new Class[] {anInterface}, new InterfaceInvocationHandler());
    }

    private static class InterfaceInvocationHandler implements InvocationHandler {

        private Map<String, Object> values = new HashMap<String, Object>();

        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            String methodName = method.getName();
            if(methodName.startsWith("get")) {
                return values.get(methodName.substring(3));
            } else {
                values.put(methodName.substring(3), args[0]);
                return null;
            }
        }

    }
}

jaxb.properties

要使此演示正常运行,您需要将 MOXy 指定为您的 JAXB 提供程序.这是通过带有以下条目的 jaxb.properties 文件完成的(请参阅:http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html)

To get this demo to work you will need to specify MOXy as your JAXB provider. This is done via a jaxb.properties file with the following entry (see: http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html)

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory

演示代码

在下面的演示代码中,我们传递了要编组的接口的任意实现.

In the demo code below we pass an arbitrary implementation of the interfaces to be marshalled.

演示

import javax.xml.bind.*;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Customer.class);

        AddressImpl address = new AddressImpl();
        address.setStreet("123 A Street");

        CustomerImpl customer = new CustomerImpl();
        customer.setName("Jane Doe");
        customer.setAddress(address);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(customer, System.out);
    }

}

输出

以下是运行演示代码的输出:

Below is the output from running the demo code:

<?xml version="1.0" encoding="UTF-8"?>
<customer>
   <name>Jane Doe</name>
   <address>
      <street>123 A Street</street>
   </address>
</customer>

这篇关于使用接口的 JaxB 编组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆