java 我如何使抽象类与 JAXB 一起工作
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10267743/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do i make an abstract class work with JAXB
提问by wyche5000
Dear fellow java coders, I have used an example from http://www.vogella.com/articles/JAXB/article.html
亲爱的 Java 编码人员,我使用了http://www.vogella.com/articles/JAXB/article.html 中的示例
for JAXB XML usage for my 3 classes, UserStorage, User, and UserTest
对于我的 3 个类 UserStorage、User 和 UserTest 的 JAXB XML 使用
it works fine, but it's just the unmarchialing of
它工作正常,但它只是 unmarchial
JAXBContext context = JAXBContext.newInstance(UserStorage.class);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
the User class is ABSTRACT!, so it throws an
Exception in thread "main" javax.xml.bind.UnmarshalException: Unable to create an instance of platform.User - with linked exception: [java.lang.InstantiationException] at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.handleEvent(UnmarshallingContext.java:648) at com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:236) at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.createInstance(UnmarshallingContext.java:615) at com.sun.xml.internal.bind.v2.runtime.unmarshaller.StructureLoader.startElement(StructureLoader.java:170) at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext._startElement(UnmarshallingContext.java:487) at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.startElement(UnmarshallingContext.java:465) at com.sun.xml.internal.bind.v2.runtime.unmarshaller.SAXConnector.startElement(SAXConnector.java:135) at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.startElement(AbstractSAXParser.java:501) at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.scanStartElement(XMLNSDocumentScannerImpl.java:400) at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:2756) at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:648) at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:140) at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:511) at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:808) at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:737) at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:119) at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1205) at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:522) at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:200) at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:173) at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:137) at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:194) at platform.UserTest.main(UserTest.java:77) Caused by: java.lang.InstantiationException at sun.reflect.InstantiationExceptionConstructorAccessorImpl.newInstance(InstantiationExceptionConstructorAccessorImpl.java:30) at java.lang.reflect.Constructor.newInstance(Constructor.java:513) at com.sun.xml.internal.bind.v2.ClassFactory.create0(ClassFactory.java:112) at com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl.createInstance(ClassBeanInfoImpl.java:231) at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.createInstance(UnmarshallingContext.java:609) ... 20 more
线程“main”中的异常 javax.xml.bind.UnmarshalException:无法创建 platform.User 的实例 - 带有链接异常:[java.lang.InstantiationException] 在 com.sun.xml.internal.bind.v2.runtime。 unmarshaller.UnmarshallingContext.handleEvent(UnmarshallingContext.java:648) at com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:236) at com.sun.xml.internal.bind。 v2.runtime.unmarshaller.UnmarshallingContext.createInstance(UnmarshallingContext.java:615) 在 com.sun.xml.internal.bind.v2.runtime.unmarshaller.StructureLoader.startElement(StructureLoader.java:170) 在 com.sun.xml。 internal.bind.v2.runtime.unmarshaller.UnmarshallingContext._startElement(UnmarshallingContext.java:487) 在 com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext。startElement(UnmarshallingContext.java:465) at com.sun.xml.internal.bind.v2.runtime.unmarshaller.SAXConnector.startElement(SAXConnector.java:135) at com.sun.org.apache.xerces.internal.parsers。 AbstractSAXParser.startElement(AbstractSAXParser.java:501) 在 com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.scanStartElement(XMLNSDocumentScannerImpl.java:400) 在 com.sun.org.apache.xerces.internal.impl。 XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:2756) at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:648) at com.sun.org.apache.xerces.internal。 impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:140) 在 com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl。scanDocument(XMLDocumentFragmentScannerImpl.java:511) at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:808) at com.sun.org.apache.xerces.internal.parsers.XML11Configuration。 com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:119) 上的 parse(XML11Configuration.java:737) com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser。位于 com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:522) 在 com.sun.xml.internal.bind.v2.runtime 的解析(AbstractSAXParser.java:1205)。 unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:200) 在 com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:173) 在 javax.xml.Abbind.unmarshal(UnmarshallerImpl.java:173)unmarshal(AbstractUnmarshallerImpl.java:137) at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:194) at platform.UserTest.main(UserTest.java:77) 由:java.lang.InstantiationException at sun .reflect.InstantiationExceptionConstructorAccessorImpl.newInstance(InstantiationExceptionConstructorAccessorImpl.java:30) at java.lang.reflect.Constructor.newInstance(Constructor.java:513) at com.sun.xml.internal.bind.v2.ClassFactory.create0(ClassFactory.java) :112) 在 com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl.createInstance(ClassBeanInfoImpl.java:231) 在 com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.createInstance(UnmarshallingContext .java:609) ... 20 多个AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:194) at platform.UserTest.main(UserTest.java:77) 引起:java.lang.InstantiationException at sun.reflect.InstantiationExceptionConstructorAccessorImpl.newInstance(InstantiationExceptionConstructorAccessorImpl.java.lang:30) .reflect.Constructor.newInstance(Constructor.java:513) 在 com.sun.xml.internal.bind.v2.ClassFactory.create0(ClassFactory.java:112) 在 com.sun.xml.internal.bind.v2.runtime .ClassBeanInfoImpl.createInstance(ClassBeanInfoImpl.java:231) 在 com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.createInstance(UnmarshallingContext.java:609) ... 20 更多AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:194) at platform.UserTest.main(UserTest.java:77) 引起:java.lang.InstantiationException at sun.reflect.InstantiationExceptionConstructorAccessorImpl.newInstance(InstantiationExceptionConstructorAccessorImpl.java.lang:30) .reflect.Constructor.newInstance(Constructor.java:513) 在 com.sun.xml.internal.bind.v2.ClassFactory.create0(ClassFactory.java:112) 在 com.sun.xml.internal.bind.v2.runtime .ClassBeanInfoImpl.createInstance(ClassBeanInfoImpl.java:231) 在 com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.createInstance(UnmarshallingContext.java:609) ... 20 更多InstantiationExceptionConstructorAccessorImpl.newInstance(InstantiationExceptionConstructorAccessorImpl.java:30) at java.lang.reflect.Constructor.newInstance(Constructor.java:513) at com.sun.xml.internal.bind.v2.ClassFactory.create0(ClassFactory.java:112)在 com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl.createInstance(ClassBeanInfoImpl.java:231) 在 com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.createInstance(UnmarshallingContext.java: 609)……还有20个InstantiationExceptionConstructorAccessorImpl.newInstance(InstantiationExceptionConstructorAccessorImpl.java:30) at java.lang.reflect.Constructor.newInstance(Constructor.java:513) at com.sun.xml.internal.bind.v2.ClassFactory.create0(ClassFactory.java:112)在 com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl.createInstance(ClassBeanInfoImpl.java:231) 在 com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.createInstance(UnmarshallingContext.java: 609)……还有20个createInstance(ClassBeanInfoImpl.java:231) at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.createInstance(UnmarshallingContext.java:609) ... 20 更多createInstance(ClassBeanInfoImpl.java:231) at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.createInstance(UnmarshallingContext.java:609) ... 20 更多
Is there any solution for this, so i could bind the User class to the XML, as i can save the XML file with user details, but it's when i want to retrieve it, it conplains that User class is abstract, I have an admin, broker, shareholder sub classes, but so far, in my user test class, i have created only 4 admins to test on, thanks and hope you can help.
有什么解决方案,所以我可以将 User 类绑定到 XML,因为我可以保存带有用户详细信息的 XML 文件,但是当我想检索它时,它抱怨 User 类是抽象的,我有一个管理员,经纪人,股东子类,但到目前为止,在我的用户测试类中,我只创建了 4 个管理员来测试,谢谢,希望你能帮忙。
import platform.UserStorage;
import platform.User;
public class UserTest {
private static final String USER_XML = "user2.xml";
public static void main(String[] args) throws JAXBException, IOException {
ArrayList<User> userList = new ArrayList<User>();
// create test users
User user1 = new Admin();
user1.setName("Dave");
user1.setPass("1234");
user1.setDeleted(true);
user1.setBan(false);
userList.add(user1);
User user2 = new Admin();
user2.setName("James");
user2.setPass("1234");
user2.setDeleted(true);
user2.setBan(false);
userList.add(user2);
User user3 = new Admin();
user3.setName("Mike");
user3.setPass("1234");
user3.setDeleted(true);
user3.setBan(false);
userList.add(user3);
// create bookstore, assigning book
UserStorage userstore = new UserStorage();
userstore.setListName("Test List");
userstore.setUserList(userList);
// create JAXB context and instantiate marshaller
JAXBContext context = JAXBContext.newInstance(UserStorage.class);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
m.marshal(userstore, System.out);
Writer w = null;
try {
w = new FileWriter(USER_XML);
m.marshal(userstore, w);
} finally {
try {
w.close();
} catch (Exception e) {
}
}
// get variables from our xml file, created before
System.out.println();
System.out.println("Output from our XML File: ");
Unmarshaller um = context.createUnmarshaller();
UserStorage userstore2 = (UserStorage) um.unmarshal(new FileReader(
USER_XML));
for (int i = 0; i < userstore2.getUsersList().toArray().length; i++) {
System.out.println("User " + (i + 1) + ": "
+ userstore2.getUsersList().get(i).getName() + " Pass "
+ userstore2.getUsersList().get(i).getPass());
}} }
package platform;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
//If you want you can define the order in which the fields are written
//Optional
/**
* @author dinesh.kaushish, james.wyche //updated XML properties.
*
*/
@XmlRootElement(name = "user")
@XmlType(propOrder = { "name", "pass", "deleted", "ban" })
..
..
public abstract class User implements UserInterface {
private String name;
private String pass;
private boolean deleted;
private boolean ban;
/**
* @ author dinesh.kaushish
* @param String username
* return void
*/
public void setName(String name)
{
this.name = name;
}
// If you like the variable name, e.g. "name", you can easily change this
// name for your XML-Output:
/**
* @author dinesh.kaushish
* @param null
* @return String user;
*/
@XmlElement(name = "user")
public String getName()
{
return this.name;
}
/**
* @author dinesh.kaushish
* @param String pwd
* @return void
*/
public void setPass(String pass)
{
this.pass=pass;
}
/**
* @author dinesh.kaushish
* @param void
* @return String password
*/
@XmlElement(name = "pass")
public String getPass()
{
return pass;
}
/**
* @author dinesh.kaushish
* @param dFlag
* @return void
*/
public void setDeleted(boolean deleted)
{
this.deleted = deleted;
}
/**
* @author dinesh.kaushish
* @return boolean isDeleted
*/
@XmlElement(name = "deleted")
public boolean getDeleted()
{
return deleted;
}
/**
* @author dinesh.kaushish
* @param bFlag
*/
public void setBan(boolean ban)
{
this.ban = ban;
}
/**
* @author dinesh.kaushish
* @return Boolean isBanned
*/
@XmlElement(name = "ban")
public Boolean getBan()
{
return ban;
}
public abstract void addUser();
public abstract void removeUser();
public abstract void verifyUser();
public abstract void passReset();
public abstract void faultReport();
public abstract void RequestsForAccess();
public abstract void UpdateDetails();
public abstract void BanUser();
public abstract void ChangePermissions();
}
package platform;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.HashMap;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.XMLEvent;
import java.util.ArrayList;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
/**
* @author michael.wambeek, james.wyche //added JAXB support.
*
*/
//This statement means that class "Bookstore.java" is the root-element of our example
@XmlRootElement(namespace = "platform")
public class UserStorage {
// XmLElementWrapper generates a wrapper element around XML representation
@XmlElementWrapper(name = "userList")
// XmlElement sets the name of the entities
@XmlElement(name = "user")
private ArrayList<User> userList;
private String listName = "";
// private static UserStorage instance; // end of james.wyche JAXB codes.
// 私有静态 UserStorage 实例;// james.wyche JAXB 代码的结尾。
public UserStorage(){
}
/**
* @author michael.wambeek
*
* Searches for a username and returns the password.
*
* @param username The username to search for
* @return The password of the correct username or null
* @throws Exception
*/
public String findUser(String username) throws Exception{
return search(username);
}
public boolean storeUser(String username, String password, UserType type){
return true;
}
/**
* @author james.wyche
* @param userList
*/
public void setUserList(ArrayList<User> userList) {
this.userList = userList;
}
/**
*
* @return UserList
*/
public ArrayList<User> getUsersList() {
return userList;
}
回答by Sean
Why this is failing is because Jaxb will attempt to create an instance of User. which is abstract and therefore the failure.
失败的原因是因为 Jaxb 将尝试创建 User 的实例。这是抽象的,因此是失败的。
On your abstract class add the annotations
在您的抽象类上添加注释
@XmlTransient //Prevents the mapping of a JavaBean property/type to XML representation
@XmlSeeAlso({Admin.class, <other class>}) //Instructs JAXB to also bind other classes when binding this class
see the javadoc for each(XmlTransient, XmlSeeAlso)
请参阅每个(XmlTransient,XmlSeeAlso)的 javadoc
What this will do is prevent jaxb from trying to initialize your abstract class.
这将阻止 jaxb 尝试初始化您的抽象类。
The only downside to this method I found is there will be extra namespace information added to the xml that gets created.
我发现这种方法的唯一缺点是会在创建的 xml 中添加额外的命名空间信息。
回答by Noam
You need to add a XmlSeeAlsoannotation to the User class with the attributes Admin and all the other concrete classes that subclass the User class.
您需要将XmlSeeAlso注释添加到具有属性 Admin 的 User 类和所有其他继承User 类的具体类。
@XmlSeeAlso({Admin.class})
PS, don't forget to add the Xml tag @XmlRootElement to the Admin class.
PS,不要忘记在Admin类中添加Xml标签@XmlRootElement。
回答by Jan
That cannot work, because JAXB has to create new instances (objects) of your classes when unmarshalling the xml. And if a tag from the xml is bound to an abstract class, it just cannot instantiate an object from that class. You either have to make the User class non-abstract or bind the xml tag to a concrete sub-class of User.
这是行不通的,因为 JAXB 在解组 xml 时必须创建类的新实例(对象)。如果来自 xml 的标签绑定到一个抽象类,它就不能从该类实例化一个对象。您要么必须使 User 类成为非抽象类,要么将 xml 标记绑定到 User 的具体子类。
回答by Claus Radloff
You have to specify the concrete
type of each element:
您必须指定concrete
每个元素的类型:
<user xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Admin">
...
</user>