convert JAXBElement<String> value to java string - jaxb

I have a pojo class where return type of variable is JAXBElement<String>. I want to store it in a String. Can someone explain how to do it?
File file = new File("C:/Users/Admin/Desktop/JubulaXMLFiles/DemoWithDrools_1.0.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(Content.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
Content e=(Content) jaxbUnmarshaller.unmarshal(file);
String retrivedValue = (String)e.getProject().getName().toString();
System.out.println(retrivedValue);
Output is like javax.xml.bind.JAXBElement#5a99da. But I want to retrieve the string value in retrivedValue.

If getProject() returns the type JAXBElement<String> then getName() returns the name of the XML tag. To get the value of that element you need to call getValue().
Find below a small snippet
QName qualifiedName = new QName("", "project");
JAXBElement<String> project = new JAXBElement<>(qualifiedName,
String.class, null, "funnyCoding");
System.out.printf("getName() - %s%n", project.getName());
System.out.printf("getValue() - %s%n", project.getValue());
output
getName() - project
getValue() - funnyCoding

Related

Search through XMLs with Java 8

I need to create a tool in java 8 to search through a list of .xml files that are all in the same folder. Each file contains information of this type:
<id>135719887</id>
<FactValue>
<name>FACT.DOCUMENT.TOTAL_DUE_AMOUNT</name>
<valueString>832.15</valueString>
</FactValue>
<FactValue>
<name>FACT.DOCUMENT.AUTO_PAY</name>
<valueString>false</valueString>
</FactValue>
<FactValue>
<name>FACT.DOCUMENT.CREDIT_CARD_EXPIRED</name>
<valueString>false</valueString>
</FactValue>
<FactValue>
<name>FACT.DOCUMENT.HAS_SEDONA_CHARGES</name>
<valueString>true</valueString>
</FactValue>
what required is a tool which can extract from a single or multiple search/query, the FACT code and its value in the following way:
id type value
---------- -------------------- -------
135719887 TOTAL_DUE_AMOUNT 832.15
135719887 AUTO_PAY false
135719887 CREDIT_CARD_EXPIRED false
135719887 HAS_SEDONA_CHARGES true
The queries would be, for instance:
Which Ids have the CREDIT_CARD_EXPIRED = false, AND, AUTO_PAY = true
Which Ids have the CREDIT_CARD_EXPIRED = true, OR, AUTO_PAY = false
What is the value of TOTAL_DUE_AMOUNT fact of the Id xxxxxxxxx
I am interested in a couple of things:
1- What data structure to use
2- How to iterate all the files
Performance is not as importat as flexibility.
Thanks in advance
Let's suppose that FooDto is the POJO class for your XML content, then you can do something like:
public static void main(String[] args) throws Exception {
JAXBContext jaxbContext = JAXBContext.newInstance(FooDto.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
FooDto fooDto1 = (FooDto) jaxbUnmarshaller.unmarshal(getInput("/Foo1.xml"));
FooDto fooDto2 = (FooDto) jaxbUnmarshaller.unmarshal(getInput("/Foo2.xml"));
List<String> ids = Stream.of(fooDto1, fooDto2)
.filter(Main::creditCardIsNotExpired)
.map(FooDto::getId)
.collect(Collectors.toList());
}
private static boolean creditCardIsNotExpired(FooDto foo) {
return Arrays.stream(foo.getFactValue())
.anyMatch(fact -> fact.getName().equals("FACT.DOCUMENT.CREDIT_CARD_EXPIRED")
&& fact.getValueString().equals("false"));
}
This example gives you all ids for CREDIT_CARD_EXPIRED == false.
Use a DTO, which can be generated from the XML using IDE plugins or other tools.
Read files in a loop and create a collection of DTOs then apply your filters.

Can marshalling and unmarshalling behave differently?

With this object for example :
public class Person {
#XmlAttribute
private String name = null;
#XmlElement
private Address address = null;
// getters and setters
}
XML file :
<person name="blabla">
<address>...</address>
</person>
What can I do if I want to load a complete Person object (name + address) when umarshalling but only saving its name when marshalling ? (i.e. not saving the address)
The easiest would be to make a copy and remove unnecessary data.
Another (much more complicated option) option would be to defined different mappings. This is possible with MOXy:
Map<String, Object> tenantOneProps = new HashMap<String, Object>();
ArrayList tenantOneBindings = new ArrayList();
tenantOneBindings.add("examples/virtual/base-bindings.xml");
tenantOneBindings.add("examples/virtual/binding-tenant1.xml");
tenantOneProps.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, tenantOneBindings);
JAXBContext tentantOneContext = JAXBContext.newInstance(new Class[] {Customer.class, Address.class}, tenantOneProps);
Map<String, Object> tenantTwoProps= new HashMap<String, Object>();
ArrayList tenantTwoBindings = new ArrayList();
tenantTwoBindings.add("examples/virtual/base-bindings.xml");
tenantTwoBindings.add("examples/virtual/binding-tenant2.xml");
tenantTwoProps.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, tenantTwoBindings);
JAXBContext tentantTwoContext = JAXBContext.newInstance(new Class[] {Customer.class, Address.class}, tenantTwoProps);
Here you define two sets of mappings - base plus either tenant1 or tenant2. Thus you create two contexts. You can unmarshal with one and marshal with another.

An invalid second ':' was found in the element type or attribute name

class foo
{
public static List parse(String input_xml)
{
try {
// JAXB context created.
JAXBContext jaxbContext = JAXBContext.newInstance(Root.class);
ByteArrayInputStream input = new ByteArrayInputStream(input_xml.getBytes());
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
// Error comes while unmarshalling the input
Root root = (Root) jaxbUnmarshaller.unmarshal(input);
HashMap<String,String> map1 = new HashMap<String,String>();
//... Code to retrieve values from "root" and put it in list
}
}
public static void main(String[] args)
{
String input= "<?xml version=\"1.0\"?>"
+"<root>"
+"<attribs R:SSB:12 = \"ABC\"/>" +
"</root>";
List list = parse(input);
}
}
"attribs" can contains multiple "attributes-value" pairs, hence i need to "UNMARSHAL" it using Jaxb.
I tried using QName , but its throwing error.
Question : While parsing , I am getting this error : "An invalid second ':' was found in the element type or attribute name." .... But i couldn't find any help .... attribute name and values are dynamic in my case.
Thanks for any help!!!*/
The problem is that you are trying to feed JAXB with invalid XML:
<attribs R:SSB:12 = "ABC">
Colon symbol has special meaning in XML: it separates namespace and attribute (or tag) name under that namespace. That's why attribute (or tag) can only contain one colon.
If your attribute names are coming from elsewhere, you have to escape colons to make them valid XML attributes. Try replacing colons with dash symbol (-), for example:
<attribs R-SSB-12="ABC">
The extra : is causing problems as by default JAXB expects the portion behind the : is the namespace prefix. You can solve this by forcing JAXB to use a parser that is not namespace aware.
This can easily be done with a SAX parser and leveraging JAXB's UnmarshallerHandler as the ContentHandler.
Full Example
java xml annotation get field with namespace, <aaa:bbb>value</aaa:bbb>

Passing XMl to the Jaxb Unmarshaller in form of String

I have a Customer class and also an related xml file to it .
File file = new File("D:\\TestingData\\customer.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(Customer.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
Customer data = (Customer) jaxbUnmarshaller.unmarshal(file);
I need to place the customer.xml file in an external location . (D:\TestingData\customer.xml)
My question is that can i supply the xml file as part of String to the unmarshall Method ??
can i supply the xml file as part of String
Yes, you just need to wrap it in a StringReader.
String xml = "<foo><bar>Hello World</bar></foo>";
StringReader reader = new StringReader(xml);
Foo foo = (Foo) unmarshaller.unnmarshal(reader);

How flexible is JAXB?

I am considering using JAXB for XML parsing but I'm having a couple of issues so far that lead me to believe that it might not be flexible enough for what I want.
I'll be parsing XML that is provided by third parties to conform to an XSD that I'll publish. So I want to be flexible enough to handle files that don't have namespaces or specify an old version of the namespace and may in fact contain invalid elements.
Is this sort of flexibility possible with JAXB? At the moment it fails to parse if the namespace is not provided.
How flexible is JAXB?
Very
So I want to be flexible enough to handle files that don't have
namespaces or specify an old version of the namespace and may in fact
contain invalid elements.
NamespaceFilter
Below is a SAX XmlFilter that can be used to apply a missing namespace.
import org.xml.sax.*;
import org.xml.sax.helpers.XMLFilterImpl;
public class NamespaceFilter extends XMLFilterImpl {
private static final String NAMESPACE = "http://www.example.com/customer";
#Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
super.endElement(NAMESPACE, localName, qName);
}
#Override
public void startElement(String uri, String localName, String qName,
Attributes atts) throws SAXException {
super.startElement(NAMESPACE, localName, qName, atts);
}
}
Demo
Below is an example of how you can apply the SAX XMLFilter with JAXB.
import javax.xml.bind.*;
import javax.xml.parsers.*;
import org.xml.sax.*;
public class Demo {
public static void main(String[] args) throws Exception {
// Create the JAXBContext
JAXBContext jc = JAXBContext.newInstance(Customer.class);
// Create the XMLFilter
XMLFilter filter = new NamespaceFilter();
// Set the parent XMLReader on the XMLFilter
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp = spf.newSAXParser();
XMLReader xr = sp.getXMLReader();
filter.setParent(xr);
// Set UnmarshallerHandler as ContentHandler on XMLFilter
Unmarshaller unmarshaller = jc.createUnmarshaller();
UnmarshallerHandler unmarshallerHandler = unmarshaller
.getUnmarshallerHandler();
filter.setContentHandler(unmarshallerHandler);
// Parse the XML
InputSource xml = new InputSource("src/blog/namespace/sax/input.xml");
filter.parse(xml);
Customer customer = (Customer) unmarshallerHandler.getResult();
}
}
For More Information
http://blog.bdoughan.com/2012/11/applying-namespace-during-jaxb-unmarshal.html

Resources