Hello! I'm having problems with parsing my XML code. I'm using DOM (org.w3c.dom and javax.xml.parsers packages). I want to dynamically construct objects from XML documents, but I'm new to DOM and have very little experience with it. I've tried to filter out DOM-generated noise, I've tried putting the arguments to the <define/> tag both as attributes and as children; both of them have thrown me a NullPointerException. I'm extremely confused as to why this doesn't work, as it should work in my theory (might just be wishful thinking...). Below is my code.
Resources.java
ResourceTest.java
test.xml
Resources.java
import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Field; import java.net.URL; import java.util.HashMap; import java.util.Map; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.xml.sax.SAXException; @SuppressWarnings("unchecked") public class Resources { private final Document document; private final DocumentBuilder builder; private final DocumentBuilderFactory builderFactory; private final Map<String, Class<?>> classMap = new HashMap<>(); private final Map<String, Resource> resources = new HashMap<>(); public final DecoderGroup decoderGroup = new DecoderGroup(); public Resources(InputStream inputStream) throws ResourceException { try { this.builderFactory = DocumentBuilderFactory.newInstance(); this.builder = this.builderFactory.newDocumentBuilder(); this.document = this.builder.parse(inputStream); if(!this.document.getFirstChild().getNodeName().equals("resources")) { throw new ResourceException("Invalid top-level tag."); } } catch(ParserConfigurationException | SAXException | IOException exception) { throw new ResourceException(exception); } } public Resources(URL url) throws IOException, ResourceException { this(url.openStream()); } public <E extends Resource> E getResource(String name) throws ResourceException { if(this.resources.containsKey(name)) return (E) this.resources.get(name); else throw new ResourceException("Resource not loaded!"); } public void loadResources(boolean silent) throws ResourceException { if(silent) { new Thread() { public void run() { try { loadResources(false); } catch(ResourceException exception) { exception.printStackTrace(); throw new RuntimeException(exception); } } }.start(); } else { if(this.document.getFirstChild().hasChildNodes()) { for(Node i : ResourceUtils.toList(this.document.getFirstChild().getChildNodes())) { if(i.getNodeName().equals("#text") || i.getNodeValue() == null || i.getNodeValue().equals("null")) { continue; } else if(i.getNodeName().equals("define")) { } else if(this.classMap.containsKey(i.getNodeName())) { String name = null; for(Node j : ResourceUtils.toList(i.getAttributes())) { if(j.getNodeName().equals("name")) { name = j.getNodeValue(); break; } } this.resources.put(name, this.loadResource(i)); } else { throw new ResourceException("Uknown error!"); } } } } } public Resource loadResource(Node rootNode) throws ResourceException { try { Class<?> resourceClass = this.classMap.get(rootNode.getNodeValue()); Resource resource; resource = (Resource) resourceClass.newInstance(); if(rootNode.hasChildNodes()) { for(Node node : ResourceUtils.toList(rootNode.getChildNodes())) { Field field = resourceClass.getField(node.getNodeName()); if(!this.decoderGroup.containsKey(field.getType())) { if(node.hasChildNodes()) { field.set(resource, loadResource(node)); } else { throw new ResourceException("Unable to parse node."); } } field.set(resource, this.decoderGroup.get(field.getType()).decode(node.getNodeValue())); } } return resource; } catch(IllegalAccessException | InstantiationException | NoSuchFieldException exception) { exception.printStackTrace(); throw new ResourceException(exception); } } }
ResourceTest.java
import java.io.FileInputStream; public class ResourceTest implements Resource { public String yay; public static void main(String[] args) throws Exception { Resources resources = new Resources(new FileInputStream("test.xml")); resources.loadResources(false); ResourceTest resourceTest = (ResourceTest) resources.getResource("test"); System.out.println(resourceTest.yay); } }
test.xml
<resources> <define name="ResourceTest" class="org.angl.resource.ResourceTest" /> <ResourceTest name="test"> <yay>"YAY!"</yay> </ResourceTest> </resources>