JAXB from XML string to Java object, what is going wrong? - java

I want to create from XML some objects, but when I'm trying I get this error:
[26/07/12 16:20:03:763 CEST] ERROR sitemap.SitemapXMLServlet:
javax.xml.bind.UnmarshalException: unexpected element (uri:"http://www.sitemaps.org/schemas/sitemap/0.9", local:"urlset"). Expected elements are <{}url>
javax.xml.bind.UnmarshalException: unexpected element (uri:"http://www.sitemaps.org/schemas/sitemap/0.9", local:"urlset"). Expected elements are <{}url>
I can't find the problem, and I don't understand why it is getting wrong. This is what I tried:
XML File
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>http://LINK/shop/hoofdcategorie</loc>
<lastmod>2012-07-26</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>
http://LINK/shop/hoofdcategorie/subcategorie
</loc>
<lastmod>2012-07-26</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
</urlset>
Method what unmarshal the XML to an Object
public void getXML() {
final JAXBContext context = JAXBContext.newInstance(SitemapXML.class);
final Unmarshaller unmarshaller = context.createUnmarshaller();
String xml = URLReader.readUrlHttpClient("http://LINK/shop/sitemap.xml");
final UrlSet urlSet = (UrlSet) unmarshaller.unmarshal(new StreamSource(new StringReader(xml)));
}
UrlSet Class
#XmlRootElement(name = "urlset")
public class UrlSet {
#XmlAttribute
String xmlns;
#XmlElement(name = "url")
ArrayList<SitemapXML> sitemaps;
public ArrayList<SitemapXML> getSitemaps() {
return sitemaps;
}
public void setSitemaps(ArrayList<SitemapXML> sitemaps) {
this.sitemaps = sitemaps;
}
#XmlAttribute
public String getXmlns() {
return xmlns;
}
public void setXmlns(String xmlns) {
this.xmlns = xmlns;
}
}
SitemapXML class what I mapping to url
#XmlRootElement(name = "url")
public class SitemapXML {
String loc;
Date lastmod;
String changefreq;
Double priority;
public String getLoc() {
return loc;
}
public void setLoc(String loc) {
this.loc = loc;
}
public Date getLastmod() {
return lastmod;
}
public void setLastmod(Date lastmod) {
this.lastmod = lastmod;
}
public String getChangefreq() {
return changefreq;
}
public void setChangefreq(String changefreq) {
this.changefreq = changefreq;
}
public Double getPriority() {
return priority;
}
public void setPriority(Double priority) {
this.priority = priority;
}
}

your xml uses a namespace, but your annotations don't mention the namespaces. you can specify the namespace in the XmlRootElement annotation or add an XmlSchema annotation at the package level.

You should add a package-info class with the the #XmlSchema annotation to specify the namespace qualification.
package-info
Below is a sample package-info class with the necessary #XmlSchema annotation. You will need to change the package to match your domain objects.
#XmlSchema(
namespace = "http://www.sitemaps.org/schemas/sitemap/0.9",
elementFormDefault = XmlNsForm.QUALIFIED)
package com.example.foo;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
For More Information
http://blog.bdoughan.com/2010/08/jaxb-namespaces.html

Related

Attribute to a JAXB Element

I'm using JAXB for creating xml. I want to set attribute 'lang' on elements PrimaryValue and AlternativeSpelling.
<AgencyOrUnit>
<PrimaryValue lang="el">ΓΑΔΑ</PrimaryValue>
<AlternativeSpelling lang="en">Athens General Police Directorate</AlternativeSpelling>
</AgencyOrUnit>
Here's my code:
#XmlRootElement(name = "OwnerReference")
#XmlType(propOrder = { "primaryValue", "alternativeSpelling"})
public class AgencyOrUnit {
private String PrimaryValue;
private String AlternativeSpelling;
public String getPrimaryValue() {
return PrimaryValue;
}
public void setPrimaryValue(String PrimaryValue){
this.PrimaryValue = PrimaryValue;
}
public String getAlternativeSpelling() {
return AlternativeSpelling;
}
public void setAlternativeSpelling(String AlternativeSpelling){
this.AlternativeSpelling = AlternativeSpelling;
}
}
Here's process of marshalling:
AgencyOrUnit agencyOrUnit = new AgencyOrUnit();
agencyOrUnit.setPrimaryValue("ΓΑΔΑ");
agencyOrUnit.setAlternativeSpelling("General Police");
The problem is that I don't know how to set property with value on elements primaryValue and alternativeSpelling?
You can use annotations #XmlValue & #XmlAttribute but you need to create a new class to hold both lang and the original value string. Something like this:
#Setter
#AllArgsConstructor
public class LocaleString {
private String lang;
private String value;
#XmlAttribute
public String getLang() {
return lang;
}
#XmlValue
public String getValue() {
return value;
}
}
Then modify your AgencyOrUnit accordingly:
#XmlRootElement(name = "OwnerReference")
#XmlType(propOrder = { "primaryValue", "alternativeSpelling"})
#Getter #Setter
public class AgencyOrUnit {
private LocaleString PrimaryValue;
private LocaleString AlternativeSpelling;
}
Test it:
#Test
void test() throws JAXBException {
AgencyOrUnit agencyOrUnit = new AgencyOrUnit();
agencyOrUnit.setPrimaryValue(new LocaleString("el", "ΓΑΔΑ"));
agencyOrUnit.setAlternativeSpelling(new LocaleString("en", "General Police"));
JAXBContext ctx = JAXBContext.newInstance(AgencyOrUnit.class);
Marshaller marshaller = ctx.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(agencyOrUnit, System.out);
}
and you should see this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<OwnerReference>
<primaryValue lang="el">ΓΑΔΑ</primaryValue>
<alternativeSpelling lang="en">General Police</alternativeSpelling>
</OwnerReference>

XML to Java JaxB

My attempt to convert an XML to Java using JAXB not working as expected. There are multiple other similar questions around it but none of the suggested solutions I looked into seem to help me.
Below is my bean
#XmlRootElement(name = "ListingResponse", namespace = "http://www.random.com")
#XmlType(propOrder = {"success", "listingId", "description"})
public class ListingResponse {
private String success;
private String listingId;
private String description;
public String getSuccess() {
return success;
}
#XmlElement(name = "Success")
public void setSuccess(String success) {
this.success = success;
}
public String getListingId() {
return listingId;
}
#XmlElement(name = "ListingId")
public void setListingId(String listingId) {
this.listingId = listingId;
}
public String getDescription() {
return description;
}
#XmlElement(name = "Description")
public void setDescription(String description) {
this.description = description;
}
Below is my attempt to do the unmarshaling
ListingResponse response = null;
try {
JAXBContext jaxbContext = JAXBContext.newInstance(ListingResponse.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
response = (ListingResponse) jaxbUnmarshaller.unmarshal(new File("response.xml"));
} catch (JAXBException e) {
e.printStackTrace();
}
And finally my response.xml content
<ListingResponse xmlns="http://www.random.com" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Success>true</Success>
<Description>ListingId 123 created.</Description>
<ListingId>123</ListingId>
</ListingResponse>
There are not exceptions being thrown.
'response' is NOT null.
I have tried adding #XmlAccessorType(XmlAccessType.FIELD / PROPERTY)
with #XMLEelement annotation on the fields/ set methods but that didn't seem to help either.
However, response is always 'empty' with none of the fields initialized.
Can you guys spot the issue here?
Currently you only have specified the correct namespace qualification for the root element. You need to use the package level #XmlSchema annotation to map the namespace qualification for your model.
package-info.java
#XmlSchema(
namespace = "http://www.random.com",
elementFormDefault = XmlNsForm.QUALIFIED)
package example;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
For More Information
http://blog.bdoughan.com/2010/08/jaxb-namespaces.html

JAXB how to dynamically generate a schema to use it for validation immediately?

I've spent a long time trying to figure out how to validate a XML file, and I've got it working with a pre-generated XSD schema. However, I wish to dynamically generate a schema without creating a file, based on the annotation class I have specified, I've tried to not specify any parameters to SchemaFactory, but then it seems to just create an empty schema (see comments below).
Here are the two classes I use for my JAXB reading and writing of a XML file.
This is the code for the class XMLTranslationWrapper:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(namespace = "my.package.namespace")
public class XMLTranslationWrapper {
#XmlElementWrapper(name = "TRANSLATIONS")
#XmlElement(name = "TRANSL")
public ArrayList<XMLTranslationNode> translations;
public XMLTranslationWrapper(){
translations = new ArrayList<XMLTranslationNode>();
}
public void setTranslations(ArrayList<XMLTranslationNode> translations){
this.translations = translations;
}
public XMLTranslationNode getTranslation(String code){
for(XMLTranslationNode transl : translations){
if(transl.getCode().equals(code))
return transl;
}
return null;
}
public void addTranslation(XMLTranslationNode translation){
this.translations.add(translation);
}
}
This is the code for the class XMLTranslationNode:
#XmlAccessorType(XmlAccessType.PROPERTY)
#XmlRootElement(name = "TRANSL")
#XmlType(propOrder = { "severity", "translation" })
public class XMLTranslationNode {
private String severity;
private String code;
private String translation;
#XmlElement(name="SEVERITY")
public String getSeverity(){
return this.severity;
}
public void setSeverity(String severity){
this.severity = severity;
}
#XmlAttribute(name="CODE")
public String getCode(){
return this.code;
}
public void setCode(String code){
this.code = code;
}
#XmlElement(name="TRANSLATION")
public String getTranslation(){
return this.translation;
}
public void setTranslation(String translation){
this.translation = translation;
}
}
This is the code I used to generate the pre-generated XSD schema:
public class generateSchema {
public static void main(String[] args) {
JAXBContext jaxbContext;
try {
jaxbContext = JAXBContext.newInstance(XMLTranslationWrapper.class);
SchemaOutputResolver sor = new MySchemaOutputResolver();
jaxbContext.generateSchema(sor);
} catch (JAXBException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
static class MySchemaOutputResolver extends SchemaOutputResolver {
public Result createOutput(String namespaceURI, String suggestedFileName) throws IOException {
File file = new File(suggestedFileName);
StreamResult result = new StreamResult(file);
System.out.println(file.toURI().toURL().toString());
result.setSystemId(file.toURI().toURL().toString());
return result;
}
}
}
Finally here is a sample XML which can be used to test the code:
<?xml version="1.0" encoding="US-ASCII" standalone="yes"?>
<ns2:xmlTranslationWrapper xmlns:ns2="my.package.namespace">
<TRANSLATIONS>
<TRANSL CODE="123">
<SEVERITY>Information</SEVERITY>
<TRANSLATION>ABC</TRANSLATION>
</TRANSL>
</TRANSLATIONS>
</ns2:xmlTranslationWrapper>
How can I dynamically generate my XSD schema without creating a file equivalent to using a pre-generated XSD schema?
As promised. The idea is simple:
First generate your schema into a DOM result
The parse it from the generated DOM
And, finally, use for validation
I don't think you can do it much better than that. JAXB's schemagen internal structures do not seem to be compatible with javax.xml.validation.Schema. So creating DOM and then parsing it back is the easiest way.
Code example:
public class DynamicSchemaTest {
#XmlRootElement
public static class A {
#XmlAttribute(required = true)
public String name;
public A() {
}
public A(String name) {
this.name = name;
}
}
#Test(expected = MarshalException.class)
public void generatesAndUsesSchema() throws JAXBException, IOException,
SAXException {
final JAXBContext context = JAXBContext.newInstance(A.class);
final DOMResult result = new DOMResult();
result.setSystemId("schema.xsd");
context.generateSchema(new SchemaOutputResolver() {
#Override
public Result createOutput(String namespaceUri,
String suggestedFileName) {
return result;
}
});
#SuppressWarnings("deprecation")
final SchemaFactory schemaFactory = SchemaFactory
.newInstance(WellKnownNamespace.XML_SCHEMA);
final Schema schema = schemaFactory.newSchema(new DOMSource(result
.getNode()));
final Marshaller marshaller = context.createMarshaller();
marshaller.setSchema(schema);
// Works
marshaller.marshal(new A("works"), System.out);
// Fails
marshaller.marshal(new A(null), System.out);
}
}

Getting incorrect values while converting an XML into a Java Object

I m trying to convert XML file into Java Object using Jaxb unmarshalling.
public static void main(String[] args) {
String input = "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">"+
" <key>1</key>" +
"<income>100.335</income>" +
"</project>" ;
NexusClient c1 = new NexusClient();
c1.getObject(input);
}
/*********/
public boolean getObject(String input) {
InputSource inputSource = new InputSource(new StringReader(input));
System.out.println(inputSource);
try {
JAXBContext jaxbContext = JAXBContext
.newInstance(mavenEntity.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
mavenEntity mavenObject = (mavenEntity) jaxbUnmarshaller
.unmarshal(inputSource);
System.out.println("Success"+mavenObject.getIncome());
} catch (JAXBException e) {
System.out.println("Unable to parse the XML Context");
e.printStackTrace();
return false;
}
return true;
}
I m facing an issue while trying to extract "Income" tag information. I couldn't extract correct values using Jaxb. My pojo class is :
#XmlRootElement(name = "project", namespace = "http://maven.apache.org/POM/4.0.0")
#XmlAccessorType(XmlAccessType.FIELD)
public class mavenEntity {
#XmlElement(name = "key", type = String.class)
private String key;
#XmlElement(name = "income", type = String.class)
private String income;
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getIncome() {
return income;
}
public void setIncome(String income) {
this.income = income;
}
}
I m getting Null as output for any tag in XML. I guess there is some problem with my name space in XML Annotation. But I really don't understand what it is. Before posting this, I did some groundwork by referring to few links similar to this But still my result is incorrect. Can some one help me out.
The namespace qualification in your model does not match the document. Instead of specifying the namespace on #XmlRootElement and all instances of #XmlElement you can specify the namespace qualification at the package level using #XmlSchema.
package-info.java
#XmlSchema(
namespace = "http://maven.apache.org/POM/4.0.0",
elementFormDefault = XmlNsForm.QUALIFIED)
package org.example.foo;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
mavenEntity.java
I have removed the unnecessary annotations from this class (see: http://blog.bdoughan.com/2012/07/jaxb-no-annotations-required.html).
package org.example.foo;
import javax.xml.bind.annotation.XmlSchema;
#XmlRootElement(name = "project")
#XmlAccessorType(XmlAccessType.FIELD)
public class mavenEntity {
private String key;
private String income;
}
For More Information
http://blog.bdoughan.com/2010/08/jaxb-namespaces.html
You will need to add namespace to your #XmlElement annotated fields too
#XmlElement(name = "key", namespace = "http://maven.apache.org/POM/4.0.0")
private String key;
#XmlElement(name = "income", namespace = "http://maven.apache.org/POM/4.0.0")
private String income;
That's because your root element has a particular namespace. Since the nested elements don't have namespace prefix, they are using the root's. I guess this is required by JAXB.
Some alternatives and/or explanations here and here.

JAXB : How to add attributes to an inner element

I have the below XML that I want to read. Using JAXB on java 1.6, how do I annotate for the attribute regex ? Can I have the field to be of type boolean ?
<?xml version="1.0" encoding="utf-8"?>
<authStore>
<authList>
<auth>
<resource>res1</resource>
<privilege regex = "true">PRIV_FILE_.+?_READ</privilege>
</auth>
<auth>
<resource>res2</resource>
<privilege>PRIV_FILE_READ</privilege>
</auth>
</authStore>
UPDATE : Is it possible to make the attribute optional ? If yes, when I unmarshal, will I get regex field to be false when a privilege element does not have the optional attribute regex ?
UDPATE2 : I don't want to define separate classes for resource and privilege. Also, I don't want to use MOXy. Pls. suggest solution for sun/oracle JDK 1.6 JAXB only.
UPDATE3 : My current object model is something like this
// AuthStore.java
#XmlRootElement
public class AuthStore {
#XmlElementWrapper(name = "authList")
#XmlElement(name = "auth")
private ArrayList<Auth> authList;
public void setAuthList(ArrayList<Auth> authList) {
this.authList = authList;
}
public ArrayList<Auth> getAuthsList() {
return authList;
}
}
// Auth.java
#XmlRootElement(name = "auth")
#XmlType(propOrder = { "resource", "privilege" })
public class Auth
{
private String resource;
private String privilege;
#XmlElement(name = "resource")
public String getResource()
{
return resource;
}
public void setResource(String resource)
{
this.resource = resource;
}
#XmlElement(name = "privilege")
public String getPrivilege()
{
return privilege;
}
public void setPrivilege(String author)
{
this.privilege = author;
}
}
Because privilege contains an attribute (It's actually complex type), you must create a class to hold both the value and the attribute:
import java.io.InputStream;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlValue;
#XmlRootElement(name = "authStore")
#XmlAccessorType(XmlAccesssType.FIELD)
public class AuthStore {
public static void main(String []args) throws Exception {
InputStream inputStream = AuthStore.class.getResourceAsStream("test.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(AuthStore.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
AuthStore authStore = (AuthStore)unmarshaller.unmarshal(inputStream);
System.out.println(authStore.getAuthList().get(0).getResource());
System.out.println(authStore.getAuthList().get(0).getPrivilege().getRegex());
System.out.println(authStore.getAuthList().get(0).getPrivilege().getValue());
}
#XmlElementWrapper(name = "authList")
#XmlElement(name = "auth")
private List<Auth> authList;
public List<Auth> getAuthList() {
return authList;
}
#XmlAccessorType(XmlAccesssType.FIELD)
public static class Auth {
#XmlElement(name = "resource")
private String resource;
#XmlElement(name = "privilege")
private Privilege privilege;
public String getResource() {
return resource;
}
public Privilege getPrivilege() {
return privilege;
}
#XmlAccessorType(XmlAccesssType.FIELD)
public static class Privilege {
#XmlAttribute(name = "regex")
private Boolean regex;
#XmlValue
private String value;
public Boolean getRegex() {
return regex;
}
public String getValue() {
return value;
}
}
}
}

Categories