We have an XML that needs to be converted to an object and vice versa. Something like Xstream does. Until now we were using Xstream to marshall and unmarshall the object/xml.
However the problem is that an object that corresponds to XML in xstream, needs to have all the tags as attributes; else if XML contains any extra tags which are not present in object; it bombs.
Or, we need to have custom convertors written to make sure that the operation goes as desired. I was also suggested that common digester allows Xpath parsing from XML to an object.
I am wondering what is the best approach; as long as:
I just want to convert XML to Object and vice versa.
Have the ability to silently ignore any fields in XML that map not be present in mapping object.
What do you suggest?
You need to use a custom MapperWrapper as documented here http://pvoss.wordpress.com/2009/01/08/xstream/
XStream xstream = new XStream() {
#Override
protected MapperWrapper wrapMapper(MapperWrapper next) {
return new MapperWrapper(next) {
#Override
public boolean shouldSerializeMember(Class definedIn,
String fieldName) {
if (definedIn == Object.class) {
return false;
}
return super.shouldSerializeMember(definedIn, fieldName);
}
};
}
};
The only thing it does is tell XStream to ignore all fields that it does not know to deal with.
You might want to take a look at this question...
What is the best way to convert a java object to xml with open source apis
These are some of the libraries that it lists...
http://simple.sourceforge.net/
http://x-stream.github.io/
http://xmlbeans.apache.org/
http://www.rgagnon.com/javadetails/java-0470.html
I would suggest using http://simple.sourceforge.net/ I uses annotations to map attributes and elements and has a "non strict" mode which enables you to read from the XML document ignoring all attributes and elements not present in the Java object.
Related
I am using a Web service and it returns a String value. But in my output, that value is in XML format:
String point = request.getParameter("point");
try {
String latLonListCityNames = proxy.latLonListCityNames(new BigInteger(point));
request.setAttribute("point", latLonListCityNames);
System.out.println(latLonListCityNames);
} catch (RemoteException e) {
e.printStackTrace();
}
I expect the output to be for example "Oklahoma", but the actual output is:
<?xml version='1.0' ?>
<dwml version='1.0' xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://graphical.weather.gov/xml/DWMLgen/schema/DWML.xsd">
<latLonList>
<cityNameList>
Oklahoma
</cityNameList>
</dwml>
The responses of web-services are commonly (not always) in XML. If you need to extract the data from xml string response to your desired format, say, Java Objects (POJO), you need a converter i.e. marshaling and Un-marshaling of data.
Simple solution
Use JAXB.
What is JAXB? From wiki
Java Architecture for XML Binding (JAXB) is a software framework that allows Java developers to map Java classes to XML representations. JAXB provides two main features: the ability to marshal Java objects into XML and the inverse, i.e. to unmarshal XML back into Java objects.
How does it fit into my use-case?
Create a simple POJO for the type of response you are expecting. And then use JAXB convertor to convert them for you.
Eg. If you are expecting a list of cityName in response, you can create your POJO like below..
CityModel.java
public Class CityModel {
private List<String> cityName;
// if more field required, add here.
}
Sample XML response should be..
<ListOfCities>
<CityName>My City</CityName>
<CityName>Your City</CityName>
<CityName>So Pity</CityName>
</ListOfCities>
Then, pass this xml response string to JAXB binding for Equivalent Class type. i.e. CityModel.
How to do all this? Can You Share some good example?
Read this tutorial to get started.
I have problem with the response type names, they are not well described, how can I map them with different name that I want?
You might need to look at links below, they key part is investigate more about #XmlRootElement, #XmlAttribute, #XmlElement, etc annotations for custom configurations.
Few more important links that can help later on?
Convert Soap XML response to Object
convert xml to java object using jaxb (unmarshal)
Using JAXB for XML With Java
JAXB Unmarshalling Example: Converting XML into Object
I am looking for a mechanism to deserialise a JSON representation of a map with polymorphic values out of the following string {"name": "your doubles", "values": [25.0, 15.0]} and into an instance of HashMap<String, Serializable>. As I cannot pass individual value types to the deserialiser (even though I know them) for every element of type Serializable I want to keep the original JSON string representation to deserialise it into a concrete type separately. I could use fasterxml or GSON or any other library that can do the job in a sensible manner.
I would have the same question for XML serialisation.
So for the above example I would like to generate a map, which values equal "\"your doubles\"" and "[25.0, 15.0]". Effectively, I need a custom deserializer that preserves the raw data whenever it finds a node that needs to be deserialized into a Serializable.
There is a straightforward solution to the problem, here is using Gson:
Gson gson = builder
.registerTypeAdapter(Serializable.class, new SerializableDeserializer())
.create();
private static class SerializableDeserializer implements JsonDeserializer<Serializable> {
#Override public Serializable deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
return json.toString();
}
}
However, if I am not mistaken this solution actually parses the node under the Serializable and then serialises it back. So if the value is large I will end up parsing it twice.
Additionally, I failed to implement this same solution for XML using the fasterxml XML parser. The problem there is that, as mentioned above, it actually parses the node and then serialises is back, but into JSON.
Any better JSON options?
Any XML solution?
Have an XML document that I want to convert to a Java bean. I want to tag the missing fields in my bean to a hashMap because these field name keeps varying. Is there a way to do this?
For example, my XML looks like
<employee>
<firstname>stack</firstname>
<lastname>alpha</lastname>
<phone1>999-999-9999</phone1>
</employee>
My java bean look like
#XstreamAlias("employee")
public class Employee {
private String firstname;
private String lastname;
private map<String, String> unknownfields;
}
When I load the XML to my java bean, it should look like
firstname="stack", lastname="alpha", unknownfields=[{"phone1","999-999-9999"}]
Know this is a bad design, but wanted to check whether this could be implemented using xstream.
Implement your own Converter. Take a look at JavaBeanConverter for reference implementation because you want to be as close to that a possible.
The only place you would need to handle things differently is this (within the unmarshal method)
if (propertyExistsInClass) {
Class<?> type = determineType(reader, result, propertyName);
Object value = context.convertAnother(result, type);
beanProvider.writeProperty(result, propertyName, value);
seenProperties.add(new FastField(resultType, propertyName));
} else {
throw new MissingFieldException(resultType.getName(), propertyName);
}
Where, from the else block, it throws the MissingFieldException, you should populate your Map. The XML element name is easily available here, but you need to tweak for the value. The clue to get the value is in the if block just above:
Object value = context.convertAnother(result, type);
The only problem is you dont have a Java type to convert the value into. String maybe?
I would inherit JavaBeanConverter and just override the unmarshal method, but suit your needs.
Using Jersey and Jackson to create a REST interface, how do I get List fields to be serialized as a list when there are 0 or 1 elements in them. For example:
#XmlRootElement(name="foo")
public class Foo {
#XmlElement
public List<Bar> getBars() {
return this.bars;
}
}
#Path("foo")
public FooResource {
#GET
public Foo getFoo() {
return theFoo;
}
}
When bars has no elements, the result serializes as null and when it contains a single element, it serializes as that element, not an array containing a single element. Is there a way to get these to always serialize as an array?
For reference, I'm using Jersey 1.10 and Jackson 1.9.2.
I am pretty sure that you are not actually using Jackson ("POJO" variant of JSON serialization), since Jackson would not convert single-element arrays or lists to anything else. So you are probably using one of legacy output methods (like jettison); meaning that if you configure system to use POJO mapping it should just work.
I wrote a blog post ages ago about forcing Jersey to serialize single element arrays correctly, not sure if it's out-dated now (its from mid-2010!), but it might be of use.
Note the blog comment from Brill Pappin on the blog demonstrating a different approach which means upgrading the Jettison library that you are using.
In short you can write a custom JaxbContextResolver that looks a little like:
#Provider
#Component
public class JAXBContextResolver implements ContextResolver {
private JAXBContext context;
public JAXBContextResolver() throws Exception {
MappedBuilder builder = JSONConfiguration.mapped();
builder.arrays("invite");
builder.rootUnwrapping(true);
this.context = new JSONJAXBContext(builder.build(), Payload.class);
}
public JAXBContext getContext(Class objectType) {
return (Payload.class.equals(objectType)) ? context : null;
}
}
For clarity, my payload class looked a little like
#XmlRootElement(name = "response")
#XmlAccessorType(XmlAccessType.FIELD)
public class Payload {
#XmlElement(name = "invite")
List invites;
... etc.
Regarding stopping Jackson serializing bean properties as null, see my previous answer here, about using annotations to change that behaviour.
I managed to solve JSON array "bug" in recent Jersey json library (v1.14 Sep 2012). Secret ingredient is JSONConfiguration and ContextResolver magic. See my following post it has a full code example, customized ContextResolver and rest Application class might be somewhat fuzzy logic in first look.
How to serialize Java primitives using Jersey REST
Primitives and zero or single-element List array are properly serialized to JSON document.
Yes, we also faced the same issue. Jackson cannot serialize list with 0 or single element to json array. So we tried to use Json's ObjectMapper to convert POJO object to String. It will serialize java List to json array irrespective of number of elements in List (0 or 1 or > 0). The code would look like :
request = new ObjectMapper().writeValueAsString(pojo);
where request is of type Object. This will not affect response. You can give a try.
Given the XML example:
<fooRoot>
<bar>
<lol>LOLOLOLOL</lol>
</bar>
<noob>
<boon>
<thisIsIt></thisIsIt>
</boon>
</noob>
</fooRoot>
Which should be mapped to:
class MyFoo {
String lol;
String thisIsIt;
Object somethingUnrelated;
}
Constraints:
XML should not be transformed, it is provided as a parsed org.w3c.dom.Document object.
Class does not and will not map 1:1 to the XML.
I'm only interested to map specific paths of the XML to specific fields of the object.
My dream solution would look like:
#XmlMapped
class MyFoo {
#XmlElement("/fooRoot/bar/lol")
String lol;
#XmlElement("/noob/boon/thisIsIt")
String thisIsIt;
#XmlIgnore
Object somethingUnrelated;
}
Does anything likewise exists? What I've found either required a strict 1:1 mapping (e.g. JMX, JAXB) or manual iteration over all fields (e.g. SAX, Commons Digester.)
JiBX binding definitions come the nearest to what I'm lokking for. However, this tool is ment to marshall/unmarshall complete hierarchy of Java objects. I only would like to extract parts of an XML document into an existing Java bean at runtime.
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB 2 (JSR-222) expert group.
You can do this with MOXy:
#XmlRootElement(name="fooRoot")
class MyFoo {
#XmlPath("bar/lol/text()")
String lol;
#XmlElement("noob/boon/thisIsIt/text()")
String thisIsIt;
#XmlTransient
Object somethingUnrelated;
}
For More Information
http://blog.bdoughan.com/2010/07/xpath-based-mapping.html
http://blog.bdoughan.com/2010/09/xpath-based-mapping-geocode-example.html
http://blog.bdoughan.com/2011/03/map-to-element-based-on-attribute-value.html
http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html
Try XStream. It's super easy. Hope it helps! I don't have time now for a full example :)
One option could be write a custom annotation which will take the XPath expression as input and do the bindings.