I am getting a XML response and it keeps on changing very frequently (nodes keep on increasing or reducing). After each updation in response xml my code breaks as my mapped Java class does not have all fileds.
Is there any way to avoid my code breaking if any changes occurs in response XML.
Any help will be appreciated.
Thanks.
Use JAXB.unmarshal() to simply create Java objects from XML.
By default it is very liberal.
Quoting from the javadoc:
In addition, the unmarshal methods have the following characteristic:
Schema validation is not performed on the input XML. The processing will try to continue even if there are errors in the XML, as much as possible. Only as the last resort, this method fails with DataBindingException.
So what JAXB.unmarshal() does is it tries to "transfer" as much data from XML to Java as possible, and it doesn't care if there is no Java field for an XML element or attribute, and it also doesn't care if there is a Java field for which there is no XML element or attribute.
Example
Let's try to unmarshal the following XML to an instance of java.awt.Point:
<p hi="Yo">
<y>123</y>
<peach>weor</peach>
</p>
The Java code:
String s = "<p hi=\"Yo\"><y>123</y><peach>weor</peach></p>";
Point p = JAXB.unmarshal(new StringReader(s), Point.class);
System.out.println(p); // Prints "java.awt.Point[x=0,y=123]"
We told JAXB.unmarshal() to parse a java.awt.Point instance. The input XML contains an element <y> which can be matched with Point.y so an int was parsed and set to Point.y. No XML data was found for Point.x so it was not touched. There were no match for the attribute hi and the XML element <peach>, so they were simply not used for anything.
We got absolutely no Exception here, and the most that was possible was parsed and transferred from XML to Java.
To cope with unknown fields, you can add a List<Object> property annotated #XmlAnyElement(lax=true)
#XmlAnyElement(lax = true)
private List<Object> anything;
Any elements in the input that do not correspond to explicit properties of the class will be swept up into this list. If the element is known to the JAXBContext you'll get the unmarshalled form (the #XmlRootElement annotated class or a JAXBElement<Foo>), if the element is not known to the context you'll get an org.w3c.dom.Element.
Full details in Blaise's blog.
For nodes that get removed you should be fine as long as you use types that can be null (Integer rather than int, Boolean rather than boolean, etc).
Related
I use javax and some XmlAdapters to generate XML. In the adapter I return an empty string as symbol for the presence of the value and null for absence.
The resulting XML looks like:
<ex:Example></ex:Example>
, which is correct and validates to my XSD (fixed="" minOccurs="0").
What I want is a self enclosed tag like:
<ex:Example/>
I have only found solutions for the opposite problem.
Is there a way to configure the Marshaller or JAXBContext to output XML to my taste?
First let me say that using Struts2 + Freemarker is a real blast.
Yet there's something is driving me crazy, because I cannot understand why it happens. I ask here as maybe someone else has an idea to share about it.
I've got an action, with a property.
Say
private String myText;
Then I've got a setter and a getter:
public void setMyText(String myText)
{
this.myText = myText;
}
public String getMyText()
{
if (myText == null)
myText = "(empty)";
return this.myText;
}
The result (in struts.xml) is a freemarker result.
So in my Freemarker template there's a line like the following:
<p>The text is: ${myText}</p>
Now consider I'm calling the action without any text parameter: say the url is
http:localhost:8080/myapp/myaction
As the getter provides a default value, when the action is processed and the result passed to my template, the property is set to the default; so I get (html on the browser side)
<p>The text is: (empty)</p>
If I call my action with the parameter set, instead (I mean with something like:
http:localhost:8080/myapp/myaction?myText=hallo
) things go wrong. Freemarker fires the following exception:
Exception occurred during processing request: For "${...}" content:
Expected a string or something automatically convertible to string
(number, date or boolean), but this has evaluated to a
sequence+extended_hash (String[] wrapped into f.e.b.ArrayModel)
It seems that "myText" is found twice...
What am I doing wrong? Or, at least, is there anyone that can explain to me why it happens?
P.S.: it's really found twice; the following is a way to workaround the problem:
<#if myText?is_sequence>${myText[0]}<#else>${myText}</#if>
Yet it seems to me not viable to wrap every variable in that way.
P.P.S.: a further hint: in the freemarker template there's a call to another action some lines before. Something like:
<#s.action var="innerAction" name="getTable" namespace="/foo" />
If I comment the line above, everything works fine.
The myText could be a variable from the freemarker context, but if you want to use action property
<p>The text is: ${action.myText}</p>
Note, that action prefix is not required to access action properties. A property resolution method is applied when resolving freemarker variables:
Property Resoloution:
Your action properties are automatically resolved - just like in a
velocity view.
for example ${name} will result in stack.findValue("name"), which
generally results in action.getName() being executed.
A search process is used to resolve the variable, searching the
following scopes in order, until a value is found :
freemarker variables
value stack
request attributes
session attributes
servlet context attributes
And later you can read what objects are accessible from the context.
Objects in the Context:
The following variables exist in the FreeMarker views
req - the current HttpServletRequest
res - the current HttpServletResponse
stack - the current OgnlValueStack
ognl - the OgnlTool instance
This class contains useful methods to execute OGNL expressions against arbitary objects, and a method to generate a select list using
the <s:select> pattern. (i.e. taking the name of the list property, a
listKey and listValue)
struts - an instance of StrutsBeanWrapper
action - the current Struts action
exception - optional the Exception instance, if the view is a JSP exception or Servlet exception view
The error might be caused by searches from the value stack and returning something that you didn't expect depending on the structure of the stack at the moment of execution.
Adding a prefix to the variable to point out the exact location of the property should fix the redundancy in the code when searching in the value stack.
My team has recently inherited a codebase that utilizes XStream 1.4.7 to load and save XML for configuration settings which then de-/serializes them from/to custom POCOs. The problem that we're having is that some of the values are getting corrupted during reads or writes. It isn't consistently occurring either which makes it that much more unusual. In most cases, it works perfectly fine with the exact same XML and the exact same POCOs.
A very simplified example (I can't post the exact code and it's quite a bit more complex so I'm going for an easy way to explain what we're seeing) is given the XML:
<monitor>
<autostart>true</autostart>
<name>MYVALUE</name>
</monitor>
Mapped to a POCO:
public class MonitorEntry {
public Boolean autostart;
public String name;
}
Loaded with XStream:
XStream xStream = new XStream(new DomDriver());
xStream.alias("Monitor", MonitorEntry.class);
Monitor monitor = (Monitor)xStream.fromXML(myFile);
The value of name in the Monitor object is read in as arVALUE instead of MYVALUE. The garbage characters at the beginning are what throws things off. Even more strangely, if we change the value of the <autostart> element to false then the XML is mapped correctly and the garbage characters do not appear.
To add to the mystery, on our end we're only seeing the corruption on loading XML to objects, but on one particular customer system they are seeing corruption only when actually saving the XML from objects. In this case, it's exactly the opposite of the above scenario. Given the same POCO with name set to MYVALUE, the actual XML written to the XML file becomes:
<monitor>
<autostart>true</autostart>
<name>arVALUE</name>
</monitor>
Now for a string value such as name it isn't much of a functional issue as it's just a name that is then just spelled wrong but where this becomes a problem is when mapping the XML value to, for example, an enum and the mapping can't find the enum value.
An example being if there is an enum:
public enum Type { VALUE1, VALUE2 };
And the POCO is:
public class MonitorEntry {
public Boolean autostart;
public String name;
public Type type;
}
With the XML:
<monitor>
<autostart>true</autostart>
<name>MYNAME</name>
<type>VALUE2</type>
</monitor>
But the XML value is being read by XStream as erLUE2 then the XStream mapping won't be able to match the correct enum value and throws an exception such as:
No enum const class com.sample.MonitorEntry$Type.erLUE2
We tried updating to XStream 1.4.8 just to see if perhaps something had been fixed but the behavior persists. The codebase is set to compile to Java 1.6 but we've tried 1.6, 7, and 8 as runtimes just to see if it was a runtime bug or something else environmental.
Has anyone else seen similar issues or have any suggestions on what might cause this? I can further update my post to include more detail if necessary. We've used XStream quite a bit before but never had issues.
Edit: We are not currently using any custom converters in this codebase, only the built-in XStream converters.
I need help to find the approach of how to create xml multiple times while I will be changing only two fields everytime and rest of the fields would be same as now. Please tell me the way to do it in java?
This is the sample xml below:
I would be changing the value of <Id> and <Originator>
<TransactionBlk>
<Id>NIK</Id>
<CorrelationId />
<Originator>NIK</Originator>
<Service>GetIns</Service>
<VersionNbr>1</VersionNbr>
<VersionNbrMin>0</VersionNbrMin>
<MsgNm>Req</MsgNm>
<MsgFormatCd>XML</MsgFormatCd>
</TransactionBlk>
You can crate one class contain all this parameter as class variable, create getter and setter method. Create object of class set value by using setter method.
You can use JAXB API's class to convert your java object into XML format.
The JAXBContext class provides the client's entry point to the JAXB API.
It provides an abstraction for managing the XML/Java binding information
necessary to implement the JAXB binding framework operations: unmarshal,
marshal and validate.
Here is Doc reference for convert your Java object into XML.
Here are tutorial for same Tutorial Link
Sample Code :
#XmlRootElement(name="TransactionBlk_REQ",namespace="http://TransactionBlk.com")
#XmlAccessorType(XmlAccessType.FIELD)
public class TransactionBlk
{
#XmlElement(name = "Id")
private String id;
#XmlElement(name = "Originator")
private String Originator;
//Your getter and setter method.
}
TransactionBlk bean = new TransactionBlk();
//Set your parameter value here
StringWriter responseWriter = new StringWriter();
JAXBContext jaxbContext = JAXBContext.newInstance(TransactionBlk.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.marshal(bean, responseWriter);
String xmlStr = responseWriter!=null?responseWriter.toString():null;
You can use XSLT to transform XML.
If all you're doing is printing a "boilerplate" document with changes in those two values, a, you could use the DPH (Desperate Perl Hacker) approach: simply assemble it as text, pausing to print the values at the appropriate places. To be safe, you should pre-scan the values to make sure they don't contain the <, >, or & characters and escape those if you find them.
For something more complex, or if you want to start learning how to do it "properly", look at the standard XML APIs for Java: DOM (the Document Object Model, an in-memory tree model of a document), SAX (an event-stream view of a document), and JAXP (tools to take an XML document and parse it into DOM or SAX so you can read it, and to take DOM or SAX and write those out as XML syntax). JAXP also provides standard APIs for invoking XPath to search a document and XSLT to apply a stylesheet to a document, so taken together these cover a huge percentage of the basic operations on XML.
You might want to look at some tutorials on using Java to manipulate XML. I'm certainly biased, not least because they published one of my articles, but in my experience IBM's DeveloperWorks website (https://www.ibm.com/developerworks/xml/) has had better-than-average material for learning about XML and other standards.
When I use JAXB, there is something wrong.
I convert entity to a xml String and everything is ok.
But when I convert xml String back to entity, some information is lost (All of them have the same type java.util.Date).
In entity:
public Date flightBaseDate;
In xml:
<flightBaseDate>2013-09-16T00:00:00 08:00</flightBaseDate>
after unmarshalling, getFlightBaseDate() returns null.
I googled.
Following one suggestion, I used # in my entity.
Then it is:
#XmlElement(name = "timestamp", required = true)
public Date flightBaseDate;
I'm sure it will be perfect,
but...throws Exception, like this:
com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
Class has two properties of the same name "flightBaseDate"
this problem is related to the following location:
at public java.lang.String com.wonders.nlia.omms.vo.FlightServiceInfoVo.getFlightBaseDate()
at com.wonders.nlia.omms.vo.FlightServiceInfoVo
this problem is related to the following location:
at public java.lang.String com.wonders.nlia.omms.vo.FlightServiceInfoVo.flightBaseDate
at com.wonders.nlia.omms.vo.FlightServiceInfoVo
Why JAXB could not distinguish between the property and its getMethod?
How to solve it?
Platform:jdk7 win7 eclipse tomcat wtp
My Unmarshalling code is:
JAXBContext context = JAXBContext.newInstance(FlightServiceInfoVo.class);
Unmarshaller unMarshaller = context.createUnmarshaller();
FlightServiceInfoVo flightServiceInfoVo =(FlightServiceInfoVo)unMarshaller.unmarshal(new StringReader(flightServiceInfoVoXml));
flightServiceInfoVoXml is a String.
You can configure JAXB in many different ways. You have chosen Annotations to define the binding (this is allright, do not worry).
I strongle recommend you read about that technique first as there are a lot of pitfalls. Here is a link to a good tutorial. Here is the part in the tutorial which explains why your binding does not work: XmlAccessorType part
As for your specific issue:
In general you have to tell JAXB what and how to bind the java object to it's XML representation. If you do not do anything, then by default all public members of your class are bound (as you can read here).
Additionally you have chosen to annotate the getter method of your public member, which then just pushes the same variable twice to your XML which later causes the exception you see.
To fix your error, either specify a different mapping strategy for your class by putting e.g. (#XmlAccessorType(XmlAccessType.NONE)) before your class declaration or move the annotation from the getter method to the property.
By the way: Having a getter method and a public member variable does not make sense at all. So making your member variable private will also fix your issue with JAXB and be a lot better for your class design.
the exception clearly says that the property name is duplicated, so check you class for a property 'flightBaseDae', it should be unique. remove the duplicate then unmarshall it