JAXB和接口属性

时间:2018-11-02 18:37:17

标签: java jaxb

假设我有以下课程:

import javax.xml.bind.annotation.XmlAnyElement;
import javax.xml.bind.annotation.XmlRootElement;

import core.type.ApplicationType;
import core.type.BaseApplicationType;

@XmlRootElement
public class Application
{
  @XmlAnyElement
  private ApplicationType type;
  private int x = 0;
  private int y = 0;
  private String description = "";

  public Application()
  {
  }

  public Application(ApplicationType type)
  {
    this.type = type;
  }

  /**
   * Get the application's type.
   *
   * @return the type
   */
  public ApplicationType getType()
  {
    return type;
  }

  /**
   * Get the description of this scenario.
   *
   * @return the description
   */
  public String getDescription()
  {
    return description;
  }

  /**
   * Set the scenario description.
   *
   * @param description the description to set
   * @throws Exception if the description is invalid.
   */
  public void setDescription(String description) throws Exception
  {

    if (description != null)
    {
      this.description = description;
    }
    else
    {
      throw new Exception("Invalid application description: '"
              + description + "'");
    }
  }

  /**
   * @param type the type to set
   */
  public void setType(BaseApplicationType type)
  {
    this.type = type;
  }

  /**
   * @return the x
   */
  public int getX()
  {
    return x;
  }

  /**
   * @param x the x to set
   */
  public void setX(int x)
  {
    this.x = x;
  }

  /**
   * @return the y
   */
  public int getY()
  {
    return y;
  }

  /**
   * @param y the y to set
   */
  public void setY(int y)
  {
    this.y = y;
  }
}

具有以下界面:

import core.Configuration;

import java.awt.*;

public interface ApplicationType
{
  /**
   * Get application name.
   *
   * @return This application name. Most likely it's entity ID.
   */
  public String getName();

  /**
   * Get application icon.
   *
   * @param type Type of icon. Useful if it varies by state for example.
   * @return Icon.
   */
  public Image getIcon(int type);

  /**
   * Set the application's icon.
   *
   * @param icon Icon to set.
   */
  public void setIcon(Image icon);

  /**
   * Set the application's name.
   *
   * @param name Name to set.
   */
  public void setName(String name);

  /**
   * Get the application's path
   *
   * @return path
   */
  public String getApplicationPath();

  /**
   * Create the application's folder.
   *
   * @throws Exception on any underlying error.
   */
  public void createAppDirectory() throws Exception;

  /**
   * Set the application's path.
   *
   * @param path Path to set.
   */
  public void setApplicationPath(String path);

  /**
   * Set the server's configuration.
   *
   * @param config New configuration.
   */
  public void setConfiguration(Configuration config);

  /**
   * Get the server's configuration
   *
   * @return Configuration.
   */
  public Configuration getConfiguration();
}

以及以下示例实现:

@XmlRootElement
public class ServerType extends BaseApplicationType
{
  public ServerType()
  {
    setConfiguration(new Configuration());
    setName("Server");
  }
}

这个抽象类:

import java.awt.*;
import java.io.File;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public abstract class BaseApplicationType implements ApplicationType
{
  private String path;
  private String name;
  private Image icon;
  private Configuration config;

  public BaseApplicationType(String path, String name, Image icon)
  {
    this.path = path;
    this.name = name;
    this.icon = icon;
  }

  public BaseApplicationType()
  {
  }

  @Override
  public Image getIcon(int type)
  {
    return icon;
  }

  @Override
  public void setIcon(Image icon)
  {
    this.icon = icon;
  }

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

  @Override
  public final void setName(String name)
  {
    this.name = name;
  }

  @Override
  public String getApplicationPath()
  {
    return path;
  }

  @Override
  public void createAppDirectory() throws Exception
  {
    if (path != null)
    {
      File appDir = new File(path);
      if (appDir.exists())
      {
        throw new Exception("Path already exists: " + path);
      }
      else
      {
        if (!appDir.mkdirs())
        {
          throw new Exception("Error creating path: " + path);
        }
      }
    }
    else
    {
      throw new Exception("Invalid path: " + path);
    }
  }

  @Override
  public void setApplicationPath(String path)
  {
    this.path = path;
  }

  @Override
  public final void setConfiguration(Configuration config)
  {
    this.config = config;
  }

  @Override
  public final Configuration getConfiguration()
  {
    return config;
  }
}

我可以将其整理如下:

@Test
  public void testMarshallingApplication() throws JAXBException
  {
    Collection<? extends ApplicationType> types
            = Lookup.getDefault().lookupAll(ApplicationType.class);
    Class[] classes = new Class[types.size() + 1];
    classes[0] = Application.class;
    Iterator<? extends ApplicationType> it = types.iterator();
    for (int i = 1; i <= types.size(); i++)
    {
      classes[i] = it.next().getClass();
    }

    JAXBContext jaxbContext = JAXBContext.newInstance(classes);
    Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
    // output pretty printed
    jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
    for (ApplicationType type : types)
    {
      Application app = new Application((BaseApplicationType) type);
      File testFile = new File(TestCaseUtils.createTempFile());
      jaxbMarshaller.marshal(app, testFile);
      jaxbMarshaller.marshal(app, TestCaseUtils.originalSystemOut);

      Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
      Application loaded
              = (Application) jaxbUnmarshaller.unmarshal(testFile);

      assertNotNull(loaded);
      assertNotNull(loaded.getType().getConfiguration());
      assertEquals(app.getType().getConfiguration(),
              loaded.getType().getConfiguration());
      assertEquals(app.getDescription(), loaded.getDescription());
      assertEquals(app.getX(), loaded.getX());
      assertEquals(app.getType(), loaded.getType());
    }
  }

它给了我这个输出:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<application>
    <ServerType>
        <configuration>
        </configuration>
        <name>Server</name>
    </ServerType>
    <description></description>
    <x>0</x>
    <y>0</y>
</application>

尝试解组时会给我错误:

java.lang.IllegalArgumentException: Can not set type.ApplicationType field core.application.Application.type to com.sun.org.apache.xerces.internal.dom.ElementNSImpl

我不知道如何将ServerType转换回去。欢迎任何帮助!

发现这确实接近JAXB: Can't unmarshal JAXBElement<?>, getting ElementNSImpl instead,但不完全相同。

0 个答案:

没有答案