From JSON to XML and back in Java - java

Converting XML to JSON is quite straight forward. XML Attributes become String values and XML Elements become JSON objects. Naming conventions are stricter for XML than JSON. The way back is more complicated. If working in Java, is there a way to reliably convert between the formats?

When you are dealing with a bean, two libraries make your life easy:
GSon for JSON
JAXB for XML
Using the bean as authoritative format conversion between JSON and XML simple. Use this example as reference:
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlRootElement;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
#XmlRootElement(name = "Fruit")
public class Fruit {
public final static String XML_FILE = "fruit.xml";
public final static String JSON_FILE = "fruit.json";
public static Fruit fromJson(InputStream in) {
Gson gson = new GsonBuilder().create();
Fruit result = gson.fromJson(new InputStreamReader(in), Fruit.class);
return result;
}
public static Fruit fromXML(InputStream in) throws Exception {
JAXBContext context = JAXBContext.newInstance(Fruit.class);
Unmarshaller um = context.createUnmarshaller();
return (Fruit) um.unmarshal(in);
}
public static void main(String[] args) throws Exception {
Fruit f = new Fruit("Apple", "Red", "Sweet");
Fruit f2 = new Fruit("Durian", "White", "Don't ask");
System.out.println(f.toXML());
System.out.println(f2.toJSON());
f.saveXML(new FileOutputStream(new File(XML_FILE)));
f2.saveJSON(new FileOutputStream(new File(JSON_FILE)));
Fruit f3 = Fruit.fromXML(new FileInputStream(new File(XML_FILE)));
System.out.println(f3.toJSON());
Fruit f4 = Fruit.fromJson(new FileInputStream(new File(JSON_FILE)));
System.out.println(f4.toXML());
}
private String name;
private String color;
private String taste;
public Fruit() {
// Default constructor
}
public Fruit(final String name, final String color, final String taste) {
this.name = name;
this.color = color;
this.taste = taste;
}
/**
* #return the color
*/
public final String getColor() {
return this.color;
}
/**
* #return the name
*/
public final String getName() {
return this.name;
}
/**
* #return the taste
*/
public final String getTaste() {
return this.taste;
}
public void saveJSON(OutputStream out) throws IOException {
GsonBuilder gb = new GsonBuilder();
gb.setPrettyPrinting();
gb.disableHtmlEscaping();
Gson gson = gb.create();
PrintWriter writer = new PrintWriter(out);
gson.toJson(this, writer);
writer.flush();
writer.close();
}
public void saveXML(OutputStream out) throws Exception {
JAXBContext context = JAXBContext.newInstance(Fruit.class);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
m.marshal(this, out);
}
/**
* #param color
* the color to set
*/
public final void setColor(String color) {
this.color = color;
}
/**
* #param name
* the name to set
*/
public final void setName(String name) {
this.name = name;
}
/**
* #param taste
* the taste to set
*/
public final void setTaste(String taste) {
this.taste = taste;
}
public String toJSON() throws IOException {
GsonBuilder gb = new GsonBuilder();
gb.setPrettyPrinting();
gb.disableHtmlEscaping();
Gson gson = gb.create();
return gson.toJson(this, Fruit.class);
}
public String toXML() throws Exception {
ByteArrayOutputStream out = new ByteArrayOutputStream();
JAXBContext context = JAXBContext.newInstance(Fruit.class);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
m.marshal(this, out);
return out.toString();
}
}

Underscore-java can convert xml to json and back. There are methods U.xmlToJson(xml) and U.jsonToXml(json). I am the maintainer of the project.

Related

Unable to set Pojo Object variable with an external value during JaxB MoXY Unmarshalling

I am trying the above approach that you have mentioned for NodeAdaptar, but I am getting null for my element.
Scenario:
I have to set the value of variable defined in my Java Model(POJO) Class with a value, coming externally(not part of the input XML). This value will be used in some calculation post unmarshal.
input XML: its a huge one. I am able to unmarshall it correctly.
POJO Class:
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.bind.annotation.XmlValue;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import org.eclipse.persistence.oxm.annotations.XmlPath;
#XmlRootElement(name="root")
#XmlAccessorType(XmlAccessType.FIELD)
public class MainModelClass {
#XmlPath("abc/def/Result/text()")
#XmlElement(name="Result")
private String result;
#XmlPath("/abc/def/Score/text()")
#XmlElement(name="Score")
private String score;
///This is where I want to populate the external value ///
#XmlElement
#XmlJavaTypeAdapter(PCNDateAdaptar.class)
private PCNDate pcnDateObject;
public PCNDate getPcnDateObject() {
return pcnDateObject;
}
public void setPcnDateObject(PCNDate pcnDateObject) {
this.pcnDateObject = pcnDateObject;
}
public String getResult() {
return result;
}
public void setResult(String result) {
this.result = result;
}
public String getScore() {
return score;
}
public void setScore(String score) {
this.score = score;
}
// Block for overridden toString() //
}
Adaptar Class:
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class PCNDateAdaptar extends XmlAdapter<Integer, PCNDate> {
private PCNDate pcnDateObject;
public void setPcnDateObject(PCNDate pcnDateob) {
this.pcnDateObject = pcnDateob;
}
#Override
public PCNDate unmarshal(Integer v) throws Exception {
if(v == null)
return this.pcnDateObject;
else
return this.pcnDateObject;
}
#Override
public Integer marshal(PCNDate v) throws Exception {
if(v == null)
return null;
else
return null;
}
}
PCNDate.class:
public class PCNDate {
private Integer processControlDate;
public Integer getProcessControlDate() {
return processControlDate;
}
public void setProcessControlDate(Integer pcn) {
this.processControlDate = pcn;
}
}
Unmarshaller Method:
public static <T> T getXMLSnippetObject(String xmlString, Class<T> modelClass, XmlAdapter<?, ?> xmlAdapterObject) throws XMLStreamException, JAXBException {
JAXBContext context = JAXBContext.newInstance(modelClass);
Unmarshaller unmarshaller = context.createUnmarshaller();
unmarshaller.setAdapter(xmlAdapterObject);
InputStream xmlInputStream = IOUtils.toInputStream(xmlString);
XMLInputFactory2 xmlInputFactory = (XMLInputFactory2)XMLInputFactory.newInstance();
xmlInputFactory.setProperty("javax.xml.stream.isCoalescing", true);
xmlInputFactory.setProperty("javax.xml.stream.isNamespaceAware", true);
xmlInputFactory.setProperty("javax.xml.stream.isReplacingEntityReferences", true);
xmlInputFactory.setProperty(XMLInputFactory2.P_AUTO_CLOSE_INPUT, true);
//xmlInputFactory.setProperty(XMLInputFactory2.P_DTD_OVERRIDE, false);
xmlInputFactory.setProperty(XMLInputFactory2.P_REPORT_PROLOG_WHITESPACE, false);
xmlInputFactory.setProperty(XMLInputFactory2.P_PRESERVE_LOCATION,false);
xmlInputFactory.setProperty(XMLInputFactory2.P_INTERN_NS_URIS, true);
XMLStreamReader2 xmlStreamReader = (XMLStreamReader2) xmlInputFactory.createXMLStreamReader(xmlInputStream);
T objectInstance = (T) JAXBIntrospector.getValue(unmarshaller.unmarshal(xmlStreamReader, modelClass));
return objectInstance;
}
Main Calling Class:
public class XMLparsing {
public static void main(String[] args) throws XMLStreamException, JAXBException, IOException {
String xmlString = // Xml String //
MainModelClass modelObj = null;
Integer pcnDate = 20171010;
// PCNDate & PCNDateAdapter are both no-arg-constructor classes for JAXB purpose
PCNDate pcnObj = new PCNDate();
pcnDateObj.setProcessControlDate(pcnDate);
PCNDateAdaptar pcndateAdaptar = new PCNDateAdaptar();
pcndateAdaptar.setPcnDateObject(pcnObj);
modelObj = XmlUtilsStAX.getXMLSnippetObject(xmlString, MainModelClass.class, pcndateAdaptar);
}
Result:
The whole Xml String is getting correctly parsed. Only MainModelClass's pcnDateObject is null, result & score have values. I want pcnDateObject to have 20171010.
I don't know, what I am missing, please help.

Statically defined KeyDeserializer not found but if defined locally everything perfect

I am baffled by how registering a custom KeyDeserializer works.
Here is my code:
Matchday.java
package com.example;
import java.io.Serializable;
import java.util.Objects;
public class Matchday implements Serializable, Comparable<Matchday> {
private static final long serialVersionUID = -8823049187525703664L;
private final int matchdayNumber;
public Matchday(final int matchdayNumber) {
this.matchdayNumber = matchdayNumber;
}
public int getMatchdayNumber() {
return matchdayNumber;
}
#Override
public int compareTo(Matchday o) {
return Integer.compare(matchdayNumber, o.getMatchdayNumber());
}
#Override
public final int hashCode() {
return Objects.hash(matchdayNumber);
}
#Override
public final boolean equals(final Object obj) {
return obj instanceof Matchday && Integer.valueOf(matchdayNumber).equals(((Matchday) obj).matchdayNumber);
}
#Override
public String toString() {
return Integer.toString(matchdayNumber);
}
}
TeamPlayer.java
package com.example;
import java.io.Serializable;
import org.apache.commons.lang3.builder.ToStringBuilder;
public class TeamPlayer implements Serializable {
private static final long serialVersionUID = -6057852081020631549L;
private int id;
private String name;
private String surname;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSurname() {
return surname;
}
public void setSurname(String surname) {
this.surname = surname;
}
#Override
public String toString() {
return new ToStringBuilder(this).append("id", id).append("name", name).append("surname", surname).build()
.toString();
}
}
Now if I define a custom map key deserializer for my class Matchday.java, it works like a charm if I do it like this.
KeyDeserializerTest.java
package com.example;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.SortedMap;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.Version;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.KeyDeserializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
public class KeyDeserializerTest {
public static void main(String[] args) throws IOException {
final ObjectMapper objectMapper = new ObjectMapper();
final SimpleModule mySimpleModule = new SimpleModule("dummy", new Version(0, 0, 0, "dummy", "dummy", "dummy"));
mySimpleModule.addKeyDeserializer(Matchday.class, new KeyDeserializer() {
#Override
public Object deserializeKey(String arg0, DeserializationContext arg1)
throws IOException, JsonProcessingException {
return new Matchday(Integer.valueOf(arg0));
}
});
objectMapper.registerModule(mySimpleModule);
final InputStream inputStream = new ByteArrayInputStream(
"{\"1\":[{\"id\": 1, \"name\": \"Arkadiusz\", \"surname\": \"Malarz\"}]}".getBytes());
SortedMap<Matchday, List<TeamPlayer>> map = objectMapper.readValue(inputStream,
new TypeReference<SortedMap<Matchday, List<TeamPlayer>>>() {
});
System.out.println(map);
}
}
It prints
{1=[com.example.TeamPlayer#3a8624[id=1,name=Arkadiusz,surname=Malarz]]}
But if I define both the object mapper and my deserializer instances as static attributes then I get the following exception!
KeyDeserializerStaticTest.java
package com.example;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.SortedMap;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.Version;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.KeyDeserializer;
import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
public class KeyDeserializerStaticTest {
public static final ObjectMapper OBJECT_MAPPER = createObjectMapper();
private static final KeyDeserializer MATCHDAY_KEY_DESERIALIZER = new KeyDeserializer() {
#Override
public Object deserializeKey(String key, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
return new Matchday(Integer.valueOf(key));
}
};
private static ObjectMapper createObjectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(createSimpleModule());
return objectMapper;
}
private static Module createSimpleModule() {
SimpleModule simpleModule = new SimpleModule("dummy", new Version(0, 0, 0, "dummy", "dummy", "dummy"));
simpleModule.addKeyDeserializer(Matchday.class, MATCHDAY_KEY_DESERIALIZER);
return simpleModule;
}
public static void main(String[] args) throws IOException {
final InputStream inputStream = new ByteArrayInputStream(
"{\"1\":[{\"id\": 1, \"name\": \"Arkadiusz\", \"surname\": \"Malarz\"}]}".getBytes());
SortedMap<Matchday, List<TeamPlayer>> map = OBJECT_MAPPER.readValue(inputStream,
new TypeReference<SortedMap<Matchday, List<TeamPlayer>>>() {
});
System.out.println(map);
}
}
Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: Can not find a (Map) Key deserializer for type [simple type, class com.example.Matchday]
at [Source: java.io.ByteArrayInputStream#bbc1e0; line: 1, column: 1]
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:270)
at com.fasterxml.jackson.databind.DeserializationContext.reportMappingException(DeserializationContext.java:1234)
at com.fasterxml.jackson.databind.deser.DeserializerCache._handleUnknownKeyDeserializer(DeserializerCache.java:585)
at com.fasterxml.jackson.databind.deser.DeserializerCache.findKeyDeserializer(DeserializerCache.java:168)
at com.fasterxml.jackson.databind.DeserializationContext.findKeyDeserializer(DeserializationContext.java:499)
at com.fasterxml.jackson.databind.deser.std.MapDeserializer.createContextual(MapDeserializer.java:247)
at com.fasterxml.jackson.databind.DeserializationContext.handleSecondaryContextualization(DeserializationContext.java:681)
at com.fasterxml.jackson.databind.DeserializationContext.findRootValueDeserializer(DeserializationContext.java:481)
at com.fasterxml.jackson.databind.ObjectMapper._findRootDeserializer(ObjectMapper.java:3899)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3794)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2915)
at com.example.KeyDeserializerStaticTest.main(KeyDeserializerStaticTest.java:43)
What is wrong here? Semantically there is no difference between the above presented main methods. Is this a feature that is somewhere documented or is it simply a bug in Jackson?
The root problem here was the order of initialization of static variables.
It is
public static final ObjectMapper OBJECT_MAPPER = createObjectMapper();
private static final KeyDeserializer MATCHDAY_KEY_DESERIALIZER = new KeyDeserializer() {
#Override
public Object deserializeKey(String key, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
return new Matchday(Integer.valueOf(key));
}
};
while it should be
private static final KeyDeserializer MATCHDAY_KEY_DESERIALIZER = new KeyDeserializer() {
#Override
public Object deserializeKey(String key, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
return new Matchday(Integer.valueOf(key));
}
};
public static final ObjectMapper OBJECT_MAPPER = createObjectMapper();
This was hard to spot because the method addKeyDeserializer(Class<?>, KeyDeserializer) of the class SimpleModule silently adds null references to an internal key deserializers' map. In my opinion it should throw a NullPointerException upon trying adding a key deserializer reference that is null.
The Jackson code for it looks like this.
First addKeKeyDeserializer(Class<?>, KeyDeserializer)
public SimpleModule addKeyDeserializer(Class<?> type, KeyDeserializer deser)
{
if (_keyDeserializers == null) {
_keyDeserializers = new SimpleKeyDeserializers();
}
_keyDeserializers.addDeserializer(type, deser);
return this;
}
there is no check here whether deser is null.
Then it delegates to addDeserializer(Class, KeyDeserializer) of class SimpleKeyDeserializers.
public SimpleKeyDeserializers addDeserializer(Class<?> forClass, KeyDeserializer deser)
{
if (_classMappings == null) {
_classMappings = new HashMap<ClassKey,KeyDeserializer>();
}
_classMappings.put(new ClassKey(forClass), deser);
return this;
}
Here is the null reference also ignored and silently put into _classMappings map.
Here is the issue I posted on GitHub together with the discussion.

Serialization - not working

I create class with methods like a How to serialize an object into a string
and it every say error "java.lang.ClassCastException: java.lang.String cannot be cast to Myclass"
My codes:
1)
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import javax.xml.bind.DatatypeConverter;
public class Serialization {
public static Object fromString(String s) throws IOException,
ClassNotFoundException {
byte[] data = DatatypeConverter.parseBase64Binary(s);
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(
data));
Object o = ois.readObject();
ois.close();
return o;
}
public static String toString(Serializable o) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(o);
oos.close();
return DatatypeConverter.printBase64Binary(baos.toByteArray());
}
}
2) - calling
MyClass hl = (MyClass) Serialization.fromString(items
.getString("data"));
hl.load(); // this is my method from class
3) MyClass - Hologram
public class Hologram implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private Location loc;
private String name;
private String displayname;
public ArmorStand stand;
public Hologram(String name, String displayname, Location loc) {
this.loc = loc;
this.name = name;
this.displayname = displayname;
ArmorStand as = (ArmorStand) loc.getWorld().spawnEntity(loc,
EntityType.ARMOR_STAND);
as.setGravity(false);
as.setCanPickupItems(false);
as.setCustomName(displayname);
as.setCustomNameVisible(true);
as.setVisible(false);
this.stand = as;
HologramManager.holograms.put(name, this);
}
public void move(Location loc) {
this.loc = loc;
stand.teleport(loc);
}
public Location getLocation() {
return this.loc;
}
public void remove() {
stand.remove();
HologramManager.holograms.remove(name);
}
public void removeHologram() {
HologramManager.remove(name);
}
public void changeName(String name) {
HologramManager.holograms.remove(this.name);
this.name = name;
HologramManager.holograms.put(name, this);
}
public void changeDisplayName(String displayName) {
this.displayname = displayName;
stand.setCustomName(displayname);
stand.setCustomNameVisible(true);
}
public void load() {
//todo
}
}
Based on the linked answer, the problem most likely lies in the code you aren't showing us. When you serialize your MyClass object, you are probably doing something like this:
MyClass hl;
String base64String = Serialization.toString(hl.toString());
However you should be calling it like this:
MyClass hl;
String base64String = Serialization.toString(hl);
If you pass a String to the serialization function, you'll get a String back when you call Serialization.fromString(). You want to get an object back that you can cast to a MyClass instance, so pass one of those into Serialization.toString().
The fromString() method in Serilization returns an Object, which you wouldnt be able to cast to the class MyClass. The below line is causing the classCastException
MyClass hl = (MyClass) Serialization.fromString(items
.getString("data"));

Marshalling List<Object> with MOXy

I have read many of Blaise Doughan's StackOverflow answers and blog posts, and I thought I understood his examples for using #XmlAnyElement with Object[]'s.
But the same principles doesn't appear to work with List - as shown with the example below (partly copied from one of his examples, and partly copied from xjc output).
I believe the code below should create JSON:
{"method":"test","status":["value":"500"]}
but instead it is creating the JASON:
{"method":"test","value":["com.mdsh.test.JsonRequestTest$Status#64dbfe37"]}
which is not much use to me.
Can anyone guide me to marshall this small object correctly, please?
package com.mdsh.test;
import static org.junit.Assert.assertEquals;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAnyElement;
import javax.xml.bind.annotation.XmlRootElement;
import org.eclipse.persistence.jaxb.MarshallerProperties;
import org.junit.Test;
import org.jvnet.jaxb2_commons.lang.JAXBToStringStrategy;
import org.jvnet.jaxb2_commons.lang.ToStringStrategy;
import org.jvnet.jaxb2_commons.locator.ObjectLocator;
public class JsonRequestTest
{
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public static class Request
{
String method;
#XmlAnyElement(lax = true)
protected List<Object> any = new Vector<Object>();
public String getMethod()
{
return this.method;
}
public void setMethod(final String value)
{
this.method = value;
}
public List<Object> getAny()
{
if (this.any == null) {
this.any = new Vector<Object>();
}
return this.any;
}
#Override
public String toString()
{
final ToStringStrategy strategy = JAXBToStringStrategy.INSTANCE;
final StringBuilder buffer = new StringBuilder();
append(null, buffer, strategy);
return buffer.toString();
}
public StringBuilder append(final ObjectLocator locator, final StringBuilder buffer, final ToStringStrategy strategy)
{
strategy.appendStart(locator, this, buffer);
appendFields(locator, buffer, strategy);
strategy.appendEnd(locator, this, buffer);
return buffer;
}
public StringBuilder appendFields(final ObjectLocator locator, final StringBuilder buffer, final ToStringStrategy strategy)
{
{
List<Object> theAny;
theAny = (((this.any!= null)&&(!this.any.isEmpty()))?getAny():null);
strategy.appendField(locator, this, "any", buffer, theAny);
}
return buffer;
}
}
public static class Status
{
int value;
public int getValue()
{
return this.value;
}
public void setValue(final int value)
{
this.value = value;
}
}
#Test
public void testListOfObjects() throws JAXBException
{
System.setProperty(JAXBContext.class.getName(), "org.eclipse.persistence.jaxb.JAXBContextFactory");
final Map<String, Object> props = new HashMap<String, Object>();
props.put(MarshallerProperties.MEDIA_TYPE, "application/json");
props.put(MarshallerProperties.JSON_INCLUDE_ROOT, false);
final JAXBContext ctx = JAXBContext.newInstance(
new Class<?>[] { Request.class },
props);
final Marshaller m = ctx.createMarshaller();
final StringWriter writer = new StringWriter();
final Request req = new Request();
req.setMethod("test");
final Status stat = new Status();
stat.setValue(500);
req.getAny().add(stat);
m.marshal(req, writer);
assertEquals("{\"method\":\"test\",\"status\":[\"value\":\"500\"]}",
writer.toString());
}
}

Attempting to parse XML using SAX, but none of my JUnit tests work?

So I'm attempting to run various tests to check that my XML parsing is correct. Unfortunately none of them pass which I assume is due to the fact my XML file isn't being stored correctly to the ArrayList. I'd appreciate any help!
VideoFile.java:
package server;
public class VideoFile {
private int id;
private String title;
private String filename;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getFilename() {
return filename;
}
public void setFilename(String filename) {
this.filename = filename;
}
}
XMLReader.java:
package server;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class XMLReader extends DefaultHandler {
//List to hold VideoFiles object
private List<VideoFile> videoList = null;
private VideoFile emp = null;
//getter method for employee list
public List<VideoFile> getList() {
return videoList;
}
boolean bTitle = false;
boolean bFilename = false;
#Override
public void startElement(String uri, String localName, String qName, Attributes attributes)
throws SAXException {
if (qName.equalsIgnoreCase("video")) {
//create a new VideoFile and put it in Map
String id = attributes.getValue("id");
//initialize VideoFile object and set id attribute
emp = new VideoFile();
emp.setId(Integer.parseInt(id));
//initialize list
if (videoList == null)
videoList = new ArrayList<>();
} else if (qName.equalsIgnoreCase("title")) {
//set boolean values for fields, will be used in setting VideoFile variables
bTitle = true;
} else if (qName.equalsIgnoreCase("filename")) {
bFilename = true;
}
}
#Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if (qName.equalsIgnoreCase("video")) {
//add VideoFile object to list
videoList.add(emp);
}
}
#Override
public void characters(char ch[], int start, int length) throws SAXException {
if (bTitle) {
emp.setTitle(new String(ch, start, length));
bTitle = false;
} else if (bFilename) {
emp.setFilename(new String(ch, start, length));
bFilename = false;
}
}
public static void main(String[] args) {
SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
try {
SAXParser saxParser = saxParserFactory.newSAXParser();
XMLReader handler = new XMLReader();
saxParser.parse(new File("videoList.xml"), handler);
//Get VideoFiles list
List<VideoFile> videoList = handler.getList();
//print employee information
for(VideoFile emp : videoList)
System.out.println(emp);
} catch (ParserConfigurationException | SAXException | IOException e) {
e.printStackTrace();
}
}
}
XMLReaderTest.java:
package server;
import static org.junit.Assert.*;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
public class XMLReaderTest {
private XMLReader reader;
private List<VideoFile> videoList;
#Before
public void setUp() throws Exception {
reader = new XMLReader();
videoList = reader.getList();
}
#Test
public void createListOfVideos() {
assertTrue(videoList instanceof List);
}
#Test
public void listContainsVideoFiles() {
assertTrue(videoList.get(0) instanceof VideoFile);
}
#Test
public void videoFileReturnsCorrectFields() {
VideoFile videoFile = videoList.get(0);
assertNotNull(videoFile.getId());
assertNotNull(videoFile.getTitle());
assertNotNull(videoFile.getFilename());
}
#Test
public void videoFileReturnsCorrectData() {
VideoFile videoFile = videoList.get(0);
assertEquals("201202132", videoFile.getId());
assertEquals("Monsters Inc.", videoFile.getTitle());
assertEquals("monstersinc_high.mpg", videoFile.getFilename());
}
}
videoList.xml:
<?xml version="1.0"?>
<videoList version="sample">
<video id="4352524242">
<title>Video 1</title>
<filename>vid1_high.mpg</filename>
</video>
<video id="20120102b7">
<title>Video 2</title>
<filename>vid2-featurehp.mp4</filename>
</video>
<video id="1242102b7">
<title>Vid3</title>
<filename>vid3-featureukFhp.mp4</filename>
</video>
</videoList>
Your tests are failing because your code does not parse the XML and your list of videos is left at null. Your XML document is valid, but the code that parses it isn't being run.
The only code that parses the XML document is in the main method of XMLReader. Because XMLReader isn't the main class (the main class will be a JUnit test runner class), it's main method is ignored.
Move the XML handling code out of the main method and ensure that your test calls it.

Categories

Resources