I'm using jaxb, and as I understood, we define for each element and attribute field, and jaxb reconize this attribute, and put it value into this elemnt. My problem that one of my attribute is class:
<div class="hello"> Hi </div>
so I want to define in the class div, the next:
String class;
public String getClass() {
return class;
}
#XmlAttribute
public void setClass(String class) {
this.class = class;
}
But I can't because - Syntax error on token "class", invalid VariableDeclarator
What can I do?
You can use the name property of XmlAttribute to specify a different name for the mapping variable.
String className;
public String getClassName() {
return clazz;
}
#XmlAttribute(name="class")
public void setClassName(String className) {
this.className = className;
}
It is working perfectly fine
import java.io.StringReader;
import java.io.StringWriter;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
public class Test {
public static void main(String[] args) throws Exception {
JAXBContext context = JAXBContext.newInstance(Div.class);
Div div = new Div();
div.setClassName("new-item");
StringWriter sw = new StringWriter();
context.createMarshaller().marshal(div, sw);
System.out.println(sw.toString());
String s = "<div class=\"hello\"> Hi </div>";
Div object = (Div) context.createUnmarshaller().unmarshal(new StringReader(s));
System.out.println(object.getClassName());
}
#XmlType(name = "div")
#XmlRootElement(name = "div")
public static class Div {
private String className;
#XmlAttribute(name = "class")
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
}
}
Related
I'm trying to deserialize this XML into a Parts object:
<Parts>
<Part>
<Name>gearbox</Name>
<Year>1990</Year>
</Part>
<Part>
<Name>wheel</Name>
<Year>2000</Year>
</Part>
</Parts>
Car.java:
package problem.car;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Car {
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({
"Parts"
})
public class Parts {
#JsonProperty("parts")
private List<Part> parts = new ArrayList<>();
#JsonProperty("parts")
public List<Part> getParts() {
return parts;
}
#JsonProperty("parts")
public void setParts(List<Part> parts) {
this.parts = parts;
}
}
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({
"Name",
"Year"
})
public class Part {
#JsonProperty("Name")
private String Name;
#JsonProperty("Year")
private String Year;
#JsonProperty("Name")
public String getName() {
return Name;
}
#JsonProperty("Name")
public void setName(String Name) {
this.Name = Name;
}
#JsonProperty("Year")
public String getYear() {
return Year;
}
#JsonProperty("Year")
public void setYear(String Year) {
this.Year = Year;
}
}
public static void main(String args[]) {
try {
String xml = "<Parts>\n"
+ " <Part>\n"
+ " <Name>gearbox</Name>\n"
+ " <Year>1990</Year>\n"
+ " </Part>\n"
+ " <Part>\n"
+ " <Name>wheel</Name>\n"
+ " <Year>2000</Year>\n"
+ " </Part>\n"
+ "</Parts>";
Parts parts = (Parts) deserialize(Parts.class, xml);
} catch (IOException ex) {
Logger.getLogger(Car.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static final Object deserialize(final Class clazz, final String xml) throws IOException {
ObjectMapper xmlMapper = new XmlMapper();
xmlMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssz"));
Object object;
try {
object = xmlMapper.readValue(xml, clazz);
} catch (com.fasterxml.jackson.databind.exc.InvalidFormatException ex) {
xmlMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd"));
object = xmlMapper.readValue(xml, clazz);
}
return object;
}
}
I don't see anything wrong with my code though so why does it keep giving me the following?
com.fasterxml.jackson.databind.JsonMappingException: No suitable constructor found for type [simple type, class problem.car.Car$Parts]: can not instantiate from JSON object (missing default constructor or creator, or perhaps need to add/enable type information?)
The answer
The Part class is a nested, non-static class.
In order to instantiate it, you must have an instance of the outer class.
Here is an inner class tutorial
I-hate-reading answer
Move the Part and Parts classes to their own java files, named Part.java and Parts.java.
Try writing it in uppercase, just like in class body:
#XmlType(name = "Parts", propOrder = {
"Part"
})
Because jackson deserialization is case sensitive.
Lets suppose that we have XML consnensual with Schema and Java class with some common fields:
<objectFromSchema1>
<element1/>
<commonElement1/>
<commonElement2/>
<element2/>
</objectFromSchema1>
public class X {
private String element1;
private String commonElement1;
private String commonElement2;
private String element2;
}
Is a nice way to unmarschall such kind of XML to Java object ? It means: convert all consensual fields and set null on rest.
The answer is "yes". This is the way JAXB works. Take a look on basic JAXB tutorial, e.g. https://jaxb.java.net/tutorial/
http://docs.oracle.com/javase/tutorial/jaxb/intro/
http://www.vogella.com/tutorials/JAXB/article.html
"YES"
If you have an xsd you also could generate automatically these classes by <artifactId>maven-jaxb2-plugin</artifactId>maven plugin.
An example of your Class
import java.io.Serializable;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "objectFromSchema1", propOrder = {
})
#XmlRootElement(name = "objectFromSchema1")
public class ObjectFromSchema1
implements Serializable
{
private final static long serialVersionUID = 12343L;
protected String element1;
protected String element2;
protected String commonElement1;
protected String commonElement2;
public String getElement1() {
return element1;
}
public void setElement1(String element1) {
this.element1 = element1;
}
public String getElement2() {
return element2;
}
public void setElement2(String element2) {
this.element2 = element2;
}
public String getCommonElement1() {
return commonElement1;
}
public void setCommonElement1(String commonElement1) {
this.commonElement1 = commonElement1;
}
public String getCommonElement2() {
return commonElement2;
}
public void setCommonElement2(String commonElement2) {
this.commonElement2 = commonElement2;
}
}
Main method to use it
public static void main(String[] args) throws JAXBException {
final JAXBContext context = JAXBContext.newInstance(ObjectFromSchema1.class);
final Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
final ObjectFromSchema1 objectFromSchema1 = new ObjectFromSchema1();
objectFromSchema1.setCommonElement1("commonElement1");
objectFromSchema1.setCommonElement2("commonElement2");
objectFromSchema1.setElement1("element1");
objectFromSchema1.setElement2("element2");
m.marshal(objectFromSchema1, System.out);
}
output
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<objectFromSchema1>
<element1>element1</element1>
<element2>element2</element2>
<commonElement1>commonElement1</commonElement1>
<commonElement2>commonElement2</commonElement2>
</objectFromSchema1>
I am getting below exception, i need some help to resolve the issue.
If remove the namespace in the object factory and with out package-info.java class it is working fine.
Exception that is throwing now
Exception in thread "main" com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
There's no ObjectFactory with an #XmlElementDecl for the element {}shipping.
this problem is related to the following location:
at protected javax.xml.bind.JAXBElement com.jverstry.annotations.generics.Market$Detail.shipping
at com.jverstry.annotations.generics.Market$Detail
at protected com.jverstry.annotations.generics.Market$Detail com.jverstry.annotations.generics.Market.detail
at com.jverstry.annotations.generics.Market
ObjectFactory class which is creating the jaxbelement
package com.jverstry.annotations.generics;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.XmlElementDecl;
import javax.xml.bind.annotation.XmlRegistry;
import javax.xml.namespace.QName;
import org.example.customer.Customer;
#XmlRegistry
public class ObjectFactory {
public ObjectFactory() {
}
public Market.Detail.Shipping createShipping() {
return new Market.Detail.Shipping();
}
private final static QName _Shipping_QNAME = new QName("http://www.example.org/customer", "shipping");
#XmlElementDecl(namespace = "http://www.example.org/customer", name = "shipping")
public JAXBElement<Market.Detail.Shipping> createShipping(Market.Detail.Shipping value) {
return new JAXBElement<Market.Detail.Shipping>(_Shipping_QNAME, Market.Detail.Shipping.class, value);
}
}
Class package-info.java, where the name spaces are mentioned for the response xml
#XmlSchema(namespace = "http://www.example.org/customer", elementFormDefault = XmlNsForm.QUALIFIED)
package com.jverstry.annotations.generics;
import javax.xml.bind.annotation.*;
Demo class where marshalling object
package com.jverstry.annotations.generics;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Marshaller;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Market.class);
Market market = new Market();
Market.Detail md = new Market.Detail();
Market.Detail.Shipping mds = new Market.Detail.Shipping();
mds.setAvailable(false);
JAXBElement<Market.Detail.Shipping> shipping = new ObjectFactory().createShipping(mds);
shipping.setNil(true);
md.setShipping(shipping);
market.setDetail(md);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(market, System.out);
}
}
Market class, this is the main root class where jaxbcontext is created
package com.jverstry.annotations.generics;
import java.math.BigDecimal;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.*;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = { "detail" })
#XmlRootElement(name = "Market")
public class Market
{
#XmlElement(required = false)
protected Market.Detail detail;
public Market.Detail getDetail() {
return detail;
}
public void setDetail(Market.Detail detail) {
this.detail = detail;
}
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = { "shipping" })
public static class Detail
{
#XmlElementRef(name = "shipping")
protected JAXBElement<Market.Detail.Shipping> shipping;
public JAXBElement<Market.Detail.Shipping> getShipping() {
return shipping;
}
public void setShipping(JAXBElement<Market.Detail.Shipping> value) {
this.shipping = value;
}
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = { "value" })
public static class Shipping
{
#XmlValue
protected BigDecimal value;
#XmlAttribute(name = "available")
protected Boolean available;
public BigDecimal getValue() {
return value;
}
public void setValue(BigDecimal value) {
this.value = value;
}
public Boolean getAvailable() {
return available;
}
public void setAvailable(Boolean value) {
this.available = value;
}
}
}
}
You need to create the JAXBContext by passing in the ObjectFactory class or the package name of the generated model to ensure the ObjectFactory class is processed.
If you specify the namespace property on the #XmlElementRef annotation things should work.
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;
}
}
}
}
I'm struggling with some JAXB parsing and need some guidance.
Essentially, I'm trying to add attributes to my class variables that I have already declared as Elements using #XmlElement. So far, any attempt to use #XmlAttribute sets the attribute at the class level.
What I"m currently getting is this:
<DataClass newAttribute="test">
<myElement>I wish this element had an attribute</myElement>
<anotherElement>I wish this element had an attribute too</anotherElement>
</DataClass>
I'd like to to do this:
<DataClass>
<myElement thisAtt="this is what I'm talking about">This is better</myElement>
<anotherElement thisAtt="a different attribute here">So is this</anotherElement>
</DataClass>
I've seen other posts add an attribute to a single element using the #XmlValue, but that doesn't work when you have Elements, and won't work on multiple elements.
Does anyone have a thought on how this could be accomplished?
Thanks!
Jason
This will create that XML:
public class JaxbAttributes {
public static void main(String[] args) throws Exception {
Marshaller marshaller =
JAXBContext.newInstance(DataClass.class).createMarshaller();
StringWriter stringWriter = new StringWriter();
DataClass dataClass = new DataClass(
new Foo("this is what I'm talking about", "This is better"),
new Foo("a different attribute here", "So is this"));
marshaller.marshal(dataClass, stringWriter);
System.out.println(stringWriter);
}
#XmlRootElement(name = "DataClass")
#XmlType(propOrder = {"myElement", "anotherElement"})
static class DataClass {
private Foo myElement;
private Foo anotherElement;
DataClass() {}
public DataClass(Foo myElement, Foo anotherElement) {
this.myElement = myElement;
this.anotherElement = anotherElement;
}
public Foo getMyElement() { return myElement; }
public void setMyElement(Foo myElement) { this.myElement = myElement; }
public Foo getAnotherElement() { return anotherElement; }
public void setAnotherElement(Foo anotherElement) { this.anotherElement = anotherElement; }
}
static class Foo {
private String thisAtt;
private String value;
Foo() {}
public Foo(String thisAtt, String value) {
this.thisAtt = thisAtt;
this.value = value;
}
#XmlAttribute
public String getThisAtt() { return thisAtt; }
public void setThisAtt(String thisAtt) { this.thisAtt = thisAtt; }
#XmlValue
public String getValue() { return value; }
public void setValue(String value) { this.value = value; }
}
}
Note: I'm the EclipseLink JAXB (MOXy) lead, and a member of the JAXB 2.X (JSR-222) expert group.
Alternatively you could use the #XmlPath extension in MOXy to handle this use case:
DataClass
The #XmlPath annotation can be used with the standard JAXB annotations:
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import org.eclipse.persistence.oxm.annotations.XmlPath;
#XmlRootElement(name="DataClass")
#XmlType(propOrder={"myElement", "anotherElement"})
public class DataClass {
private String myElement;
private String myElementThisAtt;
private String anotherElement;
private String anotherElementThisAtt;
public String getMyElement() {
return myElement;
}
public void setMyElement(String myElement) {
this.myElement = myElement;
}
#XmlPath("myElement/#thisAtt")
public String getMyElementThisAtt() {
return myElementThisAtt;
}
public void setMyElementThisAtt(String myElementThisAtt) {
this.myElementThisAtt = myElementThisAtt;
}
public String getAnotherElement() {
return anotherElement;
}
public void setAnotherElement(String anotherElement) {
this.anotherElement = anotherElement;
}
#XmlPath("anotherElement/#thisAtt")
public String getAnotherElementThisAtt() {
return anotherElementThisAtt;
}
public void setAnotherElementThisAtt(String anotherElementThisAtt) {
this.anotherElementThisAtt = anotherElementThisAtt;
}
}
Demo
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(DataClass.class);
DataClass dataClass = new DataClass();
dataClass.setMyElement("This is better");
dataClass.setMyElementThisAtt("this is what I'm talking about");
dataClass.setAnotherElement("So is this");
dataClass.setAnotherElementThisAtt("a different attribute here");
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(dataClass, System.out);
}
}
Output
<?xml version="1.0" encoding="UTF-8"?>
<DataClass>
<myElement thisAtt="this is what I'm talking about">This is better</myElement>
<anotherElement thisAtt="a different attribute here">So is this</anotherElement>
</DataClass>
More Information
http://bdoughan.blogspot.com/2010/07/xpath-based-mapping.html
http://bdoughan.blogspot.com/2011/05/specifying-eclipselink-moxy-as-your.html