I am using SimpleXml 2.6.1 in my android app. Eventhough the documentation (http://simple.sourceforge.net/download/stream/doc/javadoc/index.html?org/simpleframework/xml/Order.html) says the order of the elements in the xml are same as the way they have defined in the class file, I am always getting the order to be random in the xml. If I add few more variables, the order of the elements again changes.
Adding #Order notation works, but since the class is complex with 100s of variables, I do not want to add order. Is this a known bug for android versions? It works fine in java console programs.
p.s: I opened the .class file disassembled and found the variables declared in the same order as java file, so I don't think it's a class file issue.
import org.simpleframework.xml.Element;
import org.simpleframework.xml.Order;
#Order(elements = {"name", "isTrue"})
public class SimpleXml {
public static final String NAME = "$NAME$";
public static final String IS_TRUE = "$IS_TRUE$";
#Element
private String name;
#Element
private Boolean isTrue;
...
Since there is no answer, I'll try to save precious time to anyone who gets here.
I found no cause, and since I don't have time to analyze Simple libraries, I came up with a "workaroud". It's more of an advice, actually - don't use it for (marshaling)creating xml if you have a large xml definition and the order matters(a rule more than an exception). The order is mostly used for marshaling anyway so just save yourself some time and do it manually.
The template:
<document>
<name>$NAME$</name>
<isTrue>$IS_TRUE$</isTrue>
</document>
The class:
import org.apache.commons.io.IOUtils;
import java.io.IOException;
import java.io.InputStream;
/**
* User: ksaric
*/
public class SimpleXml {
public static final String NAME = "$NAME$";
public static final String IS_TRUE = "$IS_TRUE$";
private String name;
private Boolean isTrue;
public SimpleXml() {
}
public Boolean getTrue() {
return isTrue;
}
public void setTrue(Boolean aTrue) {
isTrue = aTrue;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public String toString() {
String template = null;
try {
template = getTemplate();
} catch (IOException e) {
e.printStackTrace();
}
/* GUAVA - checkNotNull() */
if (null == template) return null;
template = template.replace(NAME, getName());
/* OR CONVERT IN THE GETTER METHOD */
template = template.replace(IS_TRUE, getTrue().toString());
return template;
}
/* SINGLETON? Performance(IO) loss... */
public String getTemplate() throws IOException {
InputStream templateStream = getClass().getResourceAsStream("/template.xml");
/* APACHE IO COMMONS */
/*
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-io</artifactId>
<version>1.3.2</version>
</dependency>
*/
final String stringTemplate = IOUtils.toString(templateStream);
return stringTemplate;
}
}
The test:
import org.junit.Test;
import static junit.framework.Assert.*;
/**
* User: ksaric
*/
public class SimpleXmlTest {
#Test
public void test() throws Exception {
//Before
/* Use standard instantiation, factory method recommended for immutability */
SimpleXml simpleXml = new SimpleXml();
simpleXml.setName("This is a name");
simpleXml.setTrue(false);
//When
String result = simpleXml.toString();
//Then
assertNotNull(result);
System.out.println(result);
}
}
Not really an answer, but save yourself some time and don't use Simple(which is a great library) on Android...
Simple Xml doesn't preserve Order on Android. Based on pfh's answer, here is my recommendation:
I would prefer to use JAXB in the case where you want the order to be preserved than manual string/template parsing. JAXB is slightly complex to use than SimpleXml but comes with similar set of annotations based xml serialization and deserialization.
Related
My applications needs to convert data between Java and XML.
When converting the data, I need to distinguish whether or not the value was present, the value was set explicitly to null or the value had a value.
XML example:
<person><name>Bob</name></person> <-- element 'name' contains value "Bob"
<person><name nil="true"/></person> <-- element 'name' was set explicitly to 'nil'/null
<person></person> <-- element 'name' is missing
As Java types like 'String' only knows two states (null or not null), I tried to use Java Optionals to solve this.
A mapping between XML and Java Optionals could look like this:
<person></person> <=> Optional<String> name = null;
<person><name>Bob</name></person> <=> Optional<String> name = Optional.of("Bob");
<person><name nil="true"/></person> <=> Optional<String> name = Optional.empty();
I tried to use JAXB for the marshalling and unmarshalling. The idea was that the setter of a field only gets invoked when a value needs to be set explicitly to an value. That means that a value is absent implicitly.
I had a look on other stackoverflow questions like the following, but all of them were incomplete handling the behaviour I need to achieve:
How to generate JaxB-Classes with java.util.Optional?
Using generic #XmlJavaTypeAdapter to unmarshal wrapped in Guava's Optional
Using Guava's Optional with #XmlAttribute
I've been struggling with this problem for two days now. I tried to use the XMLAdapter and GenericAdapter, tried several ways how to annotate the fields and getter/setter with #XmlElement, tried to use #XmlAnyElment with and without lax, but all of them only led to a partial success. Either the nil value was not handeld correctly, the lists were not printed out correctly, ...
I think every Java webservice with a properly implemented patch operation should have had this problem. (not talking about the "json patch approach" (RFC 6902))
Is there a common way to solve my problem?
The following code is able to distinguish empty name from null name. To make the solution work, I created a PersonList element to contain all of the person elements. Each Person contains a Name that will have isNil() return true if the element was explicitly set to null by the XML:
Person.java:
import java.util.Optional;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
#XmlType(propOrder = {"name"})
#XmlRootElement(name = "person")
public class Person {
private Optional<Name> optionalName;
public Person() {
optionalName = Optional.<Name>empty();
}
public Optional<Name> getOptionalName() {
return optionalName;
}
public Name getName() {
return (optionalName.isPresent()) ? (optionalName.get()) : (null);
}
#XmlElement(name = "name", required = false)
public void setName(Name name) {
optionalName = Optional.ofNullable(name);
}
#Override
public String toString() {
return String.format("Person(optionalName.isPresent() = %s, name = %s)",
Boolean.toString(optionalName.isPresent()),
((getName() == null) ? ("null") : (getName().toString())));
}
}
Name.java:
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlValue;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "name")
public class Name {
#XmlAttribute(name = "nil")
private boolean nil;
#XmlValue
private String value;
public Name() {
nil = false;
value = null;
}
public boolean isNil() {
return nil;
}
public void setNil(boolean torf) {
this.nil = torf;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
#Override
public String toString() {
return String.format("Name(nil = %s, value = %s)",
Boolean.toString(nil),
(value == null) ? ("null"):("\""+getValue()+"\""));
}
}
PersonList.java:
import java.util.Iterator;
import java.util.List;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name = "PersonList")
public class PersonList {
private List<Person> persons;
public PersonList() {
persons = null;
}
#XmlElement(name = "person")
public List<Person> getPersons() {
return persons;
}
public void setPersons(List<Person> persons) {
this.persons = persons;
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder("PersonList(persons = ");
if(persons == null) {
sb.append("null");
}
else {
sb.append("[");
Iterator<Person> iterator = persons.iterator();
while(iterator.hasNext()) {
sb.append(iterator.next().toString());
if(iterator.hasNext()) {
sb.append(", ");
}
}
sb.append("]");
}
sb.append(")");
return sb.toString();
}
}
Main class to demonstrate the solution:
import java.io.ByteArrayInputStream;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
public class XmlOptional {
public static final int STATUS_OKAY = 0;
public static final int STATUS_ERROR = -1;
public static final String XML_DATA = "<PersonList>" +
"<person><name>Bob</name></person>" +
"<person><name nil=\"true\" /></person>" +
"<person></person>" +
"</PersonList>";
private XmlOptional() {
}
private static PersonList loadXml() {
try {
ByteArrayInputStream bais = new ByteArrayInputStream(XML_DATA.getBytes());
JAXBContext context = JAXBContext.newInstance(PersonList.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
PersonList personList = (PersonList)unmarshaller.unmarshal(bais);
return personList;
}
catch(Exception e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
int status = STATUS_OKAY;
try {
PersonList personList = loadXml();
System.out.format("Xml contained: %s%n", personList);
}
catch (Throwable thrown) {
status = STATUS_ERROR;
thrown.printStackTrace();
}
finally {
System.exit(status);
}
}
}
Sample output:
Xml contained: PersonList(persons = [Person(optionalName.isPresent() = true, name = Name(nil = false, value = "Bob")), Person(optionalName.isPresent() = true, name = Name(nil = true, value = "")), Person(optionalName.isPresent() = false, name = null)])
Since I was not able to solve the problem completely by solely using and configuring JAXB properly, I decided to solve it as follows:
(The main goal was to write a subsystem to communicate with an external system based on XML)
As a starting point, I used the XSD schema provided by the target system to communicate with and generated the corresponding (XML)Java classes using JAXB and the XSD file. All the fields in those generated classes were of type JAXBElement<>, in order to be able to hold the 3 states needed (absent, null, someValue).
On the business model side, I used Java classes with Optional<> field types in order to hold the 3 states.
For the mapping, I wrote a mapper which uses reflection to recursively map from JAXB to Java and vice versa. When mapping from Java to JAXB, the mapper used the ObjectFactory to create the JAXBElement objects. (Mapper itself just had about 300 lines of code).
The fields were mapped based on the matching field names.
The most ugly and challenging part was, that the XSD schema file needed to be altered, in order to make JAXB generated classes that uses JAXBElement field types. Therefore I had to manually add the attribute minOccurs="0" nillable="true" to the XML elements, if not already set.
With that solution above, I finally managed to map the XML to Java and vice versa considering the 3 states needed, easily.
Of course, this solution has its drawbacks.
One is the manual modification of the XSD file. Usually bad practice to alter the XSD file provided by the external system, which acts as an interface contract.
For my requirements at the time, the solution worked perfectly. Even changes to the interface contract of the external system could be implemented very easily.
You can use some validation in your java class like #NotNull, #Size and so on. Or you can put default value , to be sure , that it will be not null. After that you can create DTOs (Data transfer object) with the recommended Xml annotations and mapped it with the ModelMapper.
I'm new to Java and have used the long piece of code provided in
GWT: Dealing with incoming JSON string
to read the json similar to the layout of the original posting person raised.
My layout is as follows:
{
"messagedata": [
{
"msgkey": "12552",
"reference": "201708010001",
"bic": "PARABLULLEISI",
"securityid": "BE0003735496",
"safekeepingacc": "7744085P"
},
{
"msgkey": "12553",
"reference": "000081676368",
"bic": "PARABLULLEISX",
"securityid": "CNE00000BQ0",
"safekeepingacc": "1053542760H"
}
]
}
But the final line of code (jsonString.stringValue()) only ever reads the first block of JSON data i.e. msgkey or bic from the first section.
How would i get data from other sections i.e. if there were 3 sections each containing msgkey, bic, reference etc
More importantly if i know the msgkey value as in the sample JSON how can I get the other associated values for that section when the msgkey value changes?
I've used the library com.google.gwt.json.client.*
Thanks
Martin
You can use JsInterop and JSON.parse in GWT 2.8 + elemental2.
import com.google.gwt.core.client.EntryPoint;
import elemental2.core.Global;
import elemental2.dom.DomGlobal;
import java.util.stream.Stream;
import jsinterop.annotations.*;
import jsinterop.base.Js;
class JsInteropExample implements EntryPoint {
#JsType(isNative = true, namespace = JsPackage.GLOBAL, name = "Object")
static class Message {
public Data[] messagedata;
}
#JsType(isNative = true, namespace = JsPackage.GLOBAL, name = "Object")
static class Data {
public String msgkey;
public String reference;
public String bic;
public String securityid;
public String safekeepingacc;
}
#Override public void onModuleLoad() {
Message msg = Js.cast(Global.JSON.parse("{\"messagedata\": […]}"));
Stream.of(msg.messagedata).forEach(d -> DomGlobal.console.log(d.msgkey));
}
}
I totally agree with Ignacio, JsInterop is the way, that is why I was asking about GWT version.
JsInterop will automatically map getter and setter to the right property as you can see below.
It also allow you to add java overlay methods to your native objects, which I personally find very convenient and clean.
In order to have this code working you need to make sure to have elemental2 and jsinterop imported in your gwt.xml files.
import com.google.gwt.core.client.EntryPoint;
import elemental2.core.Global;
import elemental2.dom.DomGlobal;
import java.util.stream.Stream;
import jsinterop.annotations.*;
import jsinterop.base.Js;
class JsInteropExample implements EntryPoint {
#JsType(isNative = true, namespace = JsPackage.GLOBAL, name = "Object")
static abstract class Message {
#JsProperty
public abstract Data[] getMessagedata();
#JsOverlay
public void logObject(){
Stream.of(getMessagedata).forEach(d -> DomGlobal.console.log(d.msgkey));
}
}
#JsType(isNative = true, namespace = JsPackage.GLOBAL, name = "Object")
static class Data {
public String msgkey;
public String reference;
public String bic;
public String securityid;
public String safekeepingacc;
}
#Override public void onModuleLoad() {
Message msg = Js.cast(Global.JSON.parse("{\"messagedata\": […]}"));
Stream.of(msg.messagedata).forEach(d -> DomGlobal.console.log(d.msgkey));
}
}
If you want to avoid using elemental2 you can decode the Json by using:
#JsMethod(namespace="JSON")
static native DivData parse(String json);
I have properties file app.properties and it has 50 different properties.
I am accessing those in my java class using
Properties prop = new Properties();
prop.load("app.properties");
System.out.prinltn(prop.getProperty("APPNAME"));
Actually, I want to get rid of accessing property like prop.getProperty("APPNAME"). Is there any best way in java to access properties.
I can declare all variables as static in java class.
static String appName = prop.getProperty("APPNAME");
Any other best way available?
I can suggest two approaches:
1. Define a utility method which will take String as parameter and return value from properties.
For Example:
public static String GetValue(String key) {
return properties.getProperty(key);
}
And now you can use this function on callers
String value = GetValue("key"); // properties.getProperty("key");
Define above method and in addition create one class Called Constants(or something suitable). Define all your Keys here as Static final variable.
public class Constants
{
public static final String KEY = "key";
public static final String KEY2 = "key2";
}
and now make call for getting value using these variable instead of string:
String value = GetValue(KEY); //GetValue("key");
If you do only option 1, your code is becoming more readable. But I will recommend 2nd option, which is making your code readable as well as maintainable.
You can easily do following operation :
Update property name
No need to worry about mistyping key etc.
You may use "resourceBundle" package as
First import the resourceBundle API:
import java.util.ResourceBundle;
Create an instance of your property file:
private static ResourceBundle resource = ResourceBundle.getBundle("app");
Now you can get the value of the property:
String appName = resource.getString("APPNAME");
IMO, your approach of using static variables to hold the values is the best. The following structure was what I was using in a project for the same functionality.
package snippet;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;
public class Constants {
public static final String APPNAME;
public static final String VERSION;
public static final int DEFAULT_TIMEOUT;
static {
Properties p = new Properties();
try {
p.load(new FileInputStream("constants.properties"));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
APPNAME = p.getProperty("APPNAME");
VERSION = p.getProperty("VERSION");
DEFAULT_TIMEOUT = Integer.parseInt(p.getProperty("DEFAULT_TIMEOUT"));
}
}
Of course, there were checks for NumberFormatException etc.
probably a stupid question, but I'm stuck.
I try do parse a huge xml document retrieved from a REST service.
What I'm interested in are both the abstract parts.
<article article-type="research-article">
<front>
<article-meta>
<abstract></abstract>
<abstract abstract-type="summary"></abstract>
</article-meta>
</front>
</article>
In my front class, I do the following:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement
public class Front {
#XmlElementWrapper(name = "article-meta")
#XmlElement(name="abstract")
private List<AuthorSummary> authorSummaries = new ArrayList<AuthorSummary>();
/** Getter and Setter **/
}
Sadly, I only the get the first abstract, but there the content as well. You can see my AuthorSummary Class below.
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement
public class AuthorSummary {
#XmlElement(name = "title")
private String title;
#XmlElement(name = "p")
private String content;
#XmlAttribute(name = "abstract-type")
private String abstractType;
/** Getter and Setter **/
}
So, I'm stuck and would be very glad for any hints.
Thank you very much
I have a solution, but it is not using jaxb or even data binding at all. So if you are stuck to data binding I will delete my answer. Otherwise, I like you point to data projection (Disclosure: I am affiliated with that project) instead of data binding:
public class ReadElementsWithSameName {
public interface Article {
#XBRead("./#article-type")
String getType();
#XBRead("./front/article-meta/abstract")
List<String> getAllAbstracts();
#XBRead("./front/article-meta/abstract[#abstract-type='summary']")
String getSummary();
}
// Configure the underlying document builder to not load the (nonexisting) DTD
private static final XMLFactoriesConfig nonValidatingConfig = new DefaultXMLFactoriesConfig() {
#Override
public DocumentBuilderFactory createDocumentBuilderFactory() {
DocumentBuilderFactory factory = super.createDocumentBuilderFactory();
try {
factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
} catch (ParserConfigurationException e) {
throw new RuntimeException(e);
}
return factory;
}
};
public static void main(String... args) throws IOException {
List<Article> articles = new XBProjector(nonValidatingConfig).io().url("res://data.xml").evalXPath("/article").asListOf(Article.class);
for (Article article:articles) {
System.out.println(article.getType());
System.out.println(article.getSummary());
System.out.println(article.getAllAbstracts());
}
}
}
Instead of reflecting the XML structure with java classes, just define the Java API as a "projection interface" with the accessors (and setters) you like to have. Afterwards, let the projection framework take care of reading and writing your changes to the DOM.
I have a POJO which has a field:
public class Media {
private Asset asset;
}
Everything works perfectly when parsing a json response into this asset POJO. but however there is a slight difference with the key this asset comes with. It can either be:
#JsonProperty("cover_asset")
or
#JsonProperty("asset")
Is there a way to annotate the POJO to recognize this case and de-serialize into the same field. Its not possible for both of them to appear in the same response.
Well, as only deserialization is your concern, #JsonAlias introduced in 2.9 is perfect for this situation. You can do something like this:
#JsonAlias({"cover_asset", "asset"})
private Asset asset;
#JsonAlias docs:
Annotation that can be used to define one or more alternative names
for a property, accepted during deserialization as alternative to the
official name. Alias information is also exposed during POJO
introspection, but has no effect during serialization where primary
name is always used.
Note: Make sure you update all related dependencies(annotations, core, databind) if you are using them. Updating just annotations without others threw me runtime error.
More succinctly, I would suggest using two separate #JsonSetter annotations for this. Here's a working example. This means that your java class will only have one getter method to use for the property instead of two. You can also make the setter you don't want exposed to clients of Media private and treat one of the json keys in a special manner.
import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSetter;
import com.fasterxml.jackson.databind.ObjectMapper;
#SuppressWarnings("unused")
public class Media {
private Asset asset;
#JsonGetter("asset")
public Asset getAsset() {
return asset;
}
#JsonSetter("asset")
public void setAsset(Asset asset) {
this.asset = asset;
}
#JsonSetter("cover_asset")
private void setMediaAsset(Asset asset) {
if (this.asset == null) {
setAsset(asset);
}
}
private static class Asset {
#JsonProperty("foo")
private String foo;
}
public static void main(String[] args) throws Exception {
String withAsset = "{'asset': {'foo':'bar'}}";
String withCoverAsset = "{'cover_asset': {'foo':'bar'}}";
ObjectMapper mapper = new ObjectMapper();
Media mediaFromAsset = mapper.readValue(withAsset.replace('\'','"'), Media.class);
Media mediaFromCoverAsset = mapper.readValue(withCoverAsset.replace('\'','"'), Media.class);
System.out.println(mediaFromAsset.asset.foo.equals(mediaFromCoverAsset.asset.foo));
}
}
Great answer By Vikas with JsonAlias.
Just adding that you can also benefit from both of the worlds (JsonProperty&Alias) [Since jackson 2.9]:
#JsonProperty("cover_asset")
#JsonAlias({"asset", "cover_asset","amazing_asset"})
private Asset asset;
Reference.
I'd propose to use getters/setters, for both property names, which are referring to the same POJO field.
public class Media {
private Asset asset;
#JsonProperty("cover_asset")
public Asset getCoverAsset() {
return asset;
}
public void setCoverAsset(Asset asset) {
this.asset= asset;
}
#JsonProperty("asset")
public Asset getAsset() {
return asset;
}
public void setAsset(Asset asset) {
this.asset= asset;
}
}
See also my answer to possible duplicate question:
Different names of JSON property during serialization and deserialization