【发布时间】:2023-03-29 23:16:01
【问题描述】:
我正在尝试编写一个小型库,该库将通过反射将 Java 对象转换为 XML。我已经完成了大部分工作,但是在尝试遍历数组时遇到了错误。
这是我用于测试的域对象:
在 Company.java 中:
import java.util.List;
import com.google.common.collect.Lists;
public class Company
{
public Employee employeeArray[];
public Employee[] getEmployeeArray()
{
return employeeArray;
}
public void setEmployeeArray(Employee[] employeeArray)
{
this.employeeArray = employeeArray;
}
}
在 Employee.java 中:
public class Employee
{
public String firstName;
public String lastName;
public Employee() {}
public Employee(String firstName, String lastName)
{
this.firstName = firstName;
this.lastName = lastName;
}
public String getFirstName()
{
return firstName;
}
public void setFirstName(String firstName)
{
this.firstName = firstName;
}
public String getLastName()
{
return lastName;
}
public void setLastName(String lastName)
{
this.lastName = lastName;
}
}
库的核心(ObjectXMLWriter.java):
import java.io.StringWriter;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.List;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import com.falcondev.web.DOMFactory;
import com.google.common.collect.Lists;
public class ObjectXMLWriter
{
private static final Logger logger = Logger.getLogger(ObjectXMLWriter.class);
private String fileLocation;
private Object object;
private boolean shouldOverride;
public ObjectXMLWriter(String fileLocation, Object object) {
this.fileLocation = fileLocation;
this.object = object;
this.shouldOverride = false;
}
public ObjectXMLWriter(String fileLocation, Object object, boolean shouldOverride) {
this(fileLocation, object);
this.shouldOverride = shouldOverride;
}
public String getFileLocation()
{
return fileLocation;
}
public void setFileLocation(String fileLocation)
{
this.fileLocation = fileLocation;
}
public Object getObject()
{
return object;
}
public void setObject(Object object)
{
this.object = object;
}
public boolean isShouldOverride()
{
return shouldOverride;
}
public void setShouldOverride(boolean shouldOverride)
{
this.shouldOverride = shouldOverride;
}
public boolean saveObject() throws Exception {
boolean saveSuccessful = false;
Document document = createDocument();
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
StringWriter stringWriter = new StringWriter();
StreamResult result = new StreamResult(stringWriter);
DOMSource source = new DOMSource(document);
transformer.transform(source, result);
String xmlString = stringWriter.toString();
//print XML
System.out.println("Here's the xml:\n\n" + xmlString);
//TODO save XML file
return saveSuccessful;
}
private Node createNode(Document document, Object object) throws Exception {
Node node = document.createElement(getObjectClassName(object));
logger.trace("NODE: " + node);
if(node != null) {
//create children nodes from object fields
List<Field> fields = Lists.newArrayList(object.getClass().getFields());
for(Field field: fields) {
Object obj = field.get(object);
logger.trace("OBJECT: " + obj);
if(obj == null || !checkInstantiability(obj) || field.getType().isAssignableFrom(List.class) || field.getType().isArray()) {
logger.debug("ATTEMPTING TO CREATE NODE FOR FIELD: " + field.getName());
logger.debug("FIELD TYPE: " + field.getType());
//TODO add types as needed
String fieldValue = "";
if(List.class.isAssignableFrom(field.getType())) { //TODO check if object is iterable instead
//TODO figure out how to iterate through iterable's
}
else if(field.getType().isArray()) {
Object array = field.get(obj); //Fails here
int length = Array.getLength(array);
for (int i = 0; i < length; i++) {
System.out.println(Array.get(array, i));
node.appendChild(createNode(document, Array.get(array, i)));
}
}
else if(field.getType() == Class.class) {
fieldValue = obj.toString().replaceFirst("class ", "");
}
else {
fieldValue = obj.toString();
}
logger.debug("FIELD OBJECT VALUE: '" + fieldValue + "'");
//TODO check for annotation to choose whether to create element or attribute
Element element = document.createElement(field.getName());
element.setTextContent(fieldValue);
node.appendChild(element);
}
else {
logger.debug("ATTEMPTING TO CREATE OBJECT NODE FOR FIELD: " + field.getName());
node.appendChild(createNode(document, obj));
}
}
}
return node;
}
private Document createDocument() throws Exception {
Document document = DOMFactory.create();
if(checkInstantiability(object)) {
Node rootNode = createNode(document, object);
document.appendChild(rootNode);
}
else {
logger.error("CANNOT SAVE UNINSTANTIABLE OBJECT. DOCUMENT MUST HAVE A ROOT NODE");
}
return document;
}
private String getObjectClassName(Object object) {
return object.getClass().getSimpleName().toLowerCase();
}
private boolean checkInstantiability(Object object) {
try
{
object.getClass().newInstance();
}
catch (InstantiationException exception)
{
return false;
}
catch (IllegalAccessException exception)
{
return false;
}
return true;
}
}
以及测试驱动程序(Test.java):
public class Test
{
public static void main(String[] args) throws Exception
{
Employee[] employees = new Employee[3];
employees[0] = new Employee("Tom", "C");
employees[1] = new Employee("Paul", "E");
employees[2] = new Employee("George", "A");
Company company = new Company();
company.setEmployeeArray(employees);
new ObjectXMLWriter("resources/test2.xml", company).saveObject();
}
}
我在运行这段代码时遇到的错误如下:
Exception in thread "main" java.lang.IllegalArgumentException: Can not set [Lcom.falcondev.orm.test.Employee; field com.falcondev.orm.test.Company.employeeArray to [Lcom.falcondev.orm.test.Employee;
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:146)
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:150)
at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:37)
at sun.reflect.UnsafeObjectFieldAccessorImpl.get(UnsafeObjectFieldAccessorImpl.java:18)
at java.lang.reflect.Field.get(Field.java:358)
at com.falcondev.orm.ObjectXMLWriter.createNode(ObjectXMLWriter.java:116)
at com.falcondev.orm.ObjectXMLWriter.createDocument(ObjectXMLWriter.java:149)
at com.falcondev.orm.ObjectXMLWriter.saveObject(ObjectXMLWriter.java:74)
at com.falcondev.orm.test.Test.main(Test.java:37)
我意识到这是相当多的代码要发布。我尝试了以下示例,如本文所示(http://stackoverflow.com/questions/2200399/iterating-over-arrays-by-reflection/2200493#2200493),它工作正常,所以一定有一些细微的差别从简单的例子和我在上面的代码中所做的事情。
有效的简单测试:
public class Test
{
public static void main(String[] args) throws Exception
{
Employee[] employees = new Employee[3];
employees[0] = new Employee("Tom", "C");
employees[1] = new Employee("Paul", "E");
employees[2] = new Employee("George", "A");
Company company = new Company();
company.setEmployeeArray(employees);
Field field = company.getClass().getField("employeeArray");
if (field.getType().isArray()) {
Object array = field.get(company);
int length = Array.getLength(array);
for (int i = 0; i < length; i++) {
System.out.println(Array.get(array, i));
}
}
}
}
至于技术信息,在本示例中,我使用的是:windows 7、eclipse 3.7、jdk 1.6.0_26、log4j 1.2.16、apache commons-lang3-3.0.1 和 google guava 10.0
在过去的几周里,我一直在努力让它发挥作用,因此我们将不胜感激。
编辑:
供日后参考和他人使用,修复问题的相关代码如下:
boolean shouldSaveFieldValue = true;
if(... || field.getType() == String.class) {
..
else if(field.getType().isArray()) {
Object array = field.get(object);
...
shouldSaveFieldValue = false;
}
if(shouldSaveFieldValue) {
...
Element element = document.createElement(field.getName());
element.setTextContent(fieldValue);
node.appendChild(element);
}
}
【问题讨论】:
-
你拥有的列表和数组之间的逻辑区别是什么?
-
@glowcoder 如果您谈论员工列表字段和employeeArray 数组字段。我最初试图让它与列表一起使用,我不小心在 Employee.java 和我的帖子标题中留下了员工列表字段。让它与列表一起工作会很好,但我只能使用数组来处理它。将编辑我的帖子。
-
目前只有十几个开源库可以完成这项工作。与编写自己的代码相比,使用 JAX-B、XML-Beans 或来自 Apache CXF 的 Aegis 可能更快乐。
-
@bmargulies 这些看起来可以工作,但我故意避开其他库。简要查看了 JAX-B,但它看起来有些复杂,我的目标是编写一个简单的库。如果我需要更复杂的库,我肯定会考虑使用您提到的其中一些库,而不是为此编写更多功能。
-
@nickg - 以下示例将帮助您解决 JAXB:wiki.eclipse.org/EclipseLink/Examples/MOXy/GettingStarted
标签: java xml arrays list reflection