Im using javax.xml.bind.annotation and I need to get the attribute "xmlns:language" (see below xml)
<type xmlns:language="ru" xmlns:type="string">Some text</type>
What annotation should I use?
#XmlRootElement(name = "type")
#XmlAccessorType(XmlAccessType.FIELD)
public class Type {
#XmlValue
protected String value;
#XmlAttribute
protected String language;
}
In the document from your question you are declaring that the prefix language will be associated with the namespace ru.
<type xmlns:language="ru" xmlns:type="string">Some text</type>
I do not believe the above is what you are trying to do. If you are trying to specify the language for your document I would recommend using the xml:lang attribute instead (as suggested by Ian Roberts).
<type xml:lang="ru">Some text</type>
Type
Then you would map to it as follows using the #XmlAttribute annotation:
import javax.xml.bind.annotation.*;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Type {
#XmlValue
protected String value;
#XmlAttribute(name = "lang", namespace = "http://www.w3.org/XML/1998/namespace")
protected String language;
}
Demo
import java.io.StringReader;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Type.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
StringReader xml = new StringReader(
"<type xml:lang='ru' xmlns:type='string'>Some text</type>");
Type type = (Type) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(type, System.out);
}
}
Output
<?xml version="1.0" encoding="UTF-8"?>
<type xml:lang="ru">Some text</type>
Related
I'm trying to convert a Java bean into an xml document and I'm having trouble with some of these more complex interfaces. Here is the setup:
protected Set<Object> field1;
protected Map<Integer, List<Object>> field2;
protected List<String> field3;
protected List<Object> field4;
protected List<Object> field5;
protected List<Object> field6;
protected List<String> field7;
protected List<Object> field8;
In each Object (which is itself a bean) I have the following at the top of each class:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"field1",
"field2",
"field3",
"field4",
"field5",
"field6",
"field7",
"field8"
})
#XmlRootElement(name = "root")
I keep getting an exception for the Map of Integers and Lists when I marshal the whole bean. Is there something that I'm missing?
Suppose you have below three class
Customer class
package comparison;
import java.util.ArrayList;
import java.util.List;
public class Customer {
private long id;
private String name;
private Address address;
private List<phonenumber> phoneNumbers;
public Customer() {
phoneNumbers = new ArrayList<PhoneNumber>();
}
}
Address class
package comparison;
public class Address {
private String city;
private String street;
}
and PhoneNumber class
package comparison;
public class PhoneNumber {
private String type;
private String number;
}
Now adding some dummy data
package comparison;
public class Data {
public static Customer CUSTOMER;
static {
CUSTOMER = new Customer();
CUSTOMER.setId(123);
CUSTOMER.setName("Jane Doe");
Address address = new Address();
address.setStreet("1 A Street");
address.setCity("Any Town");
CUSTOMER.setAddress(address);
PhoneNumber workPhoneNumber = new PhoneNumber();
workPhoneNumber.setType("work");
workPhoneNumber.setNumber("555-WORK");
CUSTOMER.getPhoneNumbers().add(workPhoneNumber);
PhoneNumber cellPhoneNumber = new PhoneNumber();
cellPhoneNumber.setType("cell");
cellPhoneNumber.setNumber("555-CELL");
CUSTOMER.getPhoneNumbers().add(cellPhoneNumber);
}
}
So now you apply marshalling to convert the object to xml
package comparison.jaxb;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Marshaller;
import javax.xml.namespace.QName;
import comparison.Customer;
import static comparison.Data.CUSTOMER;
public class JAXBDemo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Customer.class);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
JAXBElement<Customer> jaxbElement = new JAXBElement<Customer>(new QName("customer"), Customer.class, CUSTOMER);
marshaller.marshal(jaxbElement, System.out);
}
}
A JAXBContext needs to be initialized on the binding metadata before
the marshal operation can occur.
Unlike XStream JAXB does not format
the XML by default, so we will enable this feature.
With no metadata
specified we need to supply JAXB with a root element name (and
namespace).
The code will produce result:
<customer>
<id>123</id>
<address>
<city>Any Town</city>
<street>1 A Street</street>
</address>
<name>Jane Doe</name>
<phoneNumbers>
<number>555-WORK</number>
<type>work</type>
</phoneNumbers>
<phoneNumbers>
<number>555-CELL</number>
<type>cell</type>
</phoneNumbers>
By default JAXB will access public fields and properties. You can configure JAXB to use field access with the following package level annotation.
#XmlAccessorType(XmlAccessType.FIELD)
package comparison;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
You can look at this blogpost for details.
I've a service that returns this XML:
<?xml version="1.0" encoding="UTF-8"?>
<response>
<status>success</status>
<result>
<project>
<id>id1</id>
<owner>owner1</owner>
</project>
<project>
<id>id2</id>
<owner>owner2</owner>
</project>
</result>
or
<?xml version="1.0" encoding="UTF-8"?>
<response>
<status>success</status>
<result>
<user>
<id>id1</id>
<name>name1</name>
</user>
<user>
<id>id2</id>
<name>name2</name>
</user>
</result>
I want to unmarshall the retrieved XML using these classes:
Result:
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Response<T> {
#XmlElement
protected String status;
#XmlElementWrapper(name = "result")
#XmlElement
protected List<T> result;
}
Project:
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Project {
#XmlElement
public String id;
#XmlElement
public String owner;
}
User:
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class User {
#XmlElement
public String id;
#XmlElement
public String name;
}
First not working solution
JAXBContext context = JAXBContext.newInstance(Response.class, Project.class, User.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
StreamSource source = new StreamSource(new File("responseProject.xml"));
Response<Project> responseProject = (Response<Project>)unmarshaller.unmarshal(source);
System.out.println(responseProject.getStatus());
for (Project project:responseProject.getResult()) System.out.println(project);
source = new StreamSource(new File("responseUser.xml"));
Response<User> responseUser = (Response<User>)unmarshaller.unmarshal(source);
System.out.println(responseUser.getStatus());
for (User user:responseUser.getResult()) System.out.println(user);
I get an empty list.
Second not working solution
Inspired by this article http://blog.bdoughan.com/2012/11/creating-generic-list-wrapper-in-jaxb.html I've modified the Response class:
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Response<T> {
#XmlElement
protected String status;
#XmlAnyElement(lax=true)
protected List<T> result;
}
And then tested it with this code:
Response<Project> responseProject = unmarshal(unmarshaller, Project.class, "responseProject.xml");
System.out.println(responseProject.getStatus());
for (Project project:responseProject.getResult()) System.out.println(project);
private static <T> Response<T> unmarshal(Unmarshaller unmarshaller, Class<T> clazz, String xmlLocation) throws JAXBException {
StreamSource xml = new StreamSource(xmlLocation);
#SuppressWarnings("unchecked")
Response<T> wrapper = (Response<T>) unmarshaller.unmarshal(xml, Response.class).getValue();
return wrapper;
}
And I get this exception reading the response list:
Exception in thread "main" java.lang.ClassCastException: com.sun.org.apache.xerces.internal.dom.ElementNSImpl cannot be cast to org.test.Project
Note: I can't modify the original XML. There are more types other than Project and User.
Thanks to Blaise Doughan and his article I've found the solution.
First we need the Wrapper class provided in the article:
#XmlRootElement
public class Wrapper<T> {
private List<T> items;
public Wrapper() {
items = new ArrayList<T>();
}
public Wrapper(List<T> items) {
this.items = items;
}
#XmlAnyElement(lax=true)
public List<T> getItems() {
return items;
}
}
Then I've modified the Response class in order to use it:
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Response<T> {
#XmlElement
protected String status;
#XmlElement
protected Wrapper<T> result;
...
public Response(String status, List<T> result) {
this.status = status;
this.result = new Wrapper<>(result);
}
...
public List<T> getResult() {
return result.getItems();
}
...
}
Finally the unmarshalling code:
JAXBContext context = JAXBContext.newInstance(Response.class, Project.class, User.class, Wrapper.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
StreamSource source = new StreamSource(new File("responseProject.xml"));
Response<Project> responseProject = (Response<Project>)unmarshaller.unmarshal(source);
System.out.println(responseProject.getStatus());
for (Project project:responseProject.getResult()) System.out.println(project);
source = new StreamSource(new File("responseUser.xml"));
Response<User> responseUser = (Response<User>)unmarshaller.unmarshal(source);
System.out.println(responseUser.getStatus());
for (User user:responseUser.getResult()) System.out.println(user);
I've added the Wrapper class to the context class list.
Alternatively you can add this annotation to the Response class:
#XmlSeeAlso({Project.class, User.class})
Using #XmlSeeAlso({Project.class, User.class}) on Response classes has the drawback of generating some garbage information on each entity in the list: xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="userAccount"
<resources>
<links>
<link>
<rel>self</rel>
<uri>http://localhost:8080/salonea-1.0/rest/user-accounts?offset=0&limit=2</uri>
</link>
<link>
<rel>prev</rel>
<uri></uri>
</link>
<link>
<rel>next</rel>
<uri>http://localhost:8080/salonea-1.0/rest/user-accounts?offset=2&limit=2</uri>
</link>
</links>
<collection>
<user-account
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="userAccount">
<accountType>user</accountType>
<activationCode>638f502a0e409348ccc2e36c24907f0</activationCode>
<email>michzio#hotmail.com</email>
<login>michzio</login>
<password>sAmPL3#e</password>
<registrationDate>2015-09-03T17:30:03+02:00</registrationDate>
<userId>1</userId>
</user-account>
<user-account
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="userAccount">
<accountType>user</accountType>
<activationCode>334bc79d142a291894bd71881e38a719</activationCode>
<email>alicja#krainaczarow.com</email>
<login>alicja</login>
<password>zAczka!00</password>
<registrationDate>2015-09-03T17:30:03+02:00</registrationDate>
<userId>2</userId>
</user-account>
</collection>
</resources>
I am using JAXB to parse some xml.
<countries>
<Name language="en">Australia</Name>
<Name language="se">Australien</Name>
</countries>
If I in my class Countries use
#XmlElement(name = "Name", required = true)
protected List<Name> name;
everything works.
However I would like to only get the attribute where language="en"
So I in my Countries class have
protected String name
not a collection.
Is there a good way to solve this with some annotation for example?
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group
Below are two ways you could handle this use case. The first is a little more code but could be done with any JAXB implementation. The second is less code, but requires you use EclipseLink JAXB (MOXy).
OPTION #1 - ANY JAXB (JSR-222) IMPLEMENTATION
Demo
You could use a filtered stream reader to filter out the unwanted elements and have your JAXB implementation unmarshal that.
package forum11586106;
import javax.xml.bind.*;
import javax.xml.stream.*;
import javax.xml.transform.stream.StreamSource;
public class Demo {
private static final String LANGUAGE_CODE = "en";
public static void main(String[] args) throws Exception {
XMLInputFactory xif = XMLInputFactory.newFactory();
XMLStreamReader xsr = xif.createXMLStreamReader(new StreamSource("src/forum11586106/input.xml"));
xsr = xif.createFilteredReader(xsr, new StreamFilter() {
private boolean isReading = true;
#Override
public boolean accept(XMLStreamReader reader) {
if(reader.isStartElement() && "Name".equals(reader.getLocalName())) {
isReading = LANGUAGE_CODE.equals(reader.getAttributeValue("", "language"));
return isReading;
} else if(reader.isEndElement() && !isReading) {
isReading = true;
return false;
}
return true;
}});
JAXBContext jc = JAXBContext.newInstance(Countries.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
Countries countries = (Countries) unmarshaller.unmarshal(xsr);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(countries, System.out);
}
}
Countries
package forum11586106;
import javax.xml.bind.annotation.*;
#XmlRootElement
public class Countries {
private String name;
#XmlElement(name="Name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
input.xml
With this approach the language attribute is not included in the output:
<countries>
<Name language="en">Australia</Name>
<Name language="se">Australien</Name>
</countries>
Output
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<countries>
<Name>Australia</Name>
</countries>
OPTION #2 - ECLIPSELINK JAXB (MOXy)
We will leverage MOXy's #XmlPath extension to map to the Name element that has a language attribute with value en (see http://blog.bdoughan.com/2011/03/map-to-element-based-on-attribute-value.html).
Countries
package forum11586106;
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlPath;
#XmlRootElement
public class Countries {
private String name;
#XmlPath("Name[#language='en']/text()")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
jaxb.properties
To use MOXy as your JAXB provider you need to include a file called jaxb.properties in the same package as your domain model with the following entry (see: http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html).
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Demo
With this approach the element filtering is handled by the #XmlPath mapping, so the runtime portion becomes much simpler. Note how only the standard JAXB runtime APIs are used.
package forum11586106;
import java.io.File;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Countries.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("src/forum11586106/input.xml");
Countries countries = (Countries) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(countries, System.out);
}
}
input.xml
<countries>
<Name language="en">Australia</Name>
<Name language="se">Australien</Name>
</countries>
Output
With this approach the language attribute is included in the output:
<?xml version="1.0" encoding="UTF-8"?>
<countries>
<Name language="en">Australia</Name>
</countries>
I have the following xml format that i want to bind it through a POJO and using JAXB annotations. The XML format is the following:
<datas>
<data>apple<data>
<data>banana<data>
<data>orange<data>
<datas>
And i'm trying to bind the data through the following POJO:
#XmlRootElement()
#XmlAccessorType(XmlAccessType.FIELD)
public class Datas {
#XmlElement
private List<String> data;
//get/set methods
}
And also i try and this POJO:
#XmlRootElement()
#XmlAccessorType(XmlAccessType.FIELD)
public class Datas {
#XmlElement
private List<Data> datas;
//get/set methods
}
//
#XmlRootElement()
#XmlAccessorType(XmlAccessType.FIELD)
public class Data{
#XmlElement
private String data;
//get/set methods
}
In the first case it retrieves only the first data: apple. In the second case doesn't retrieve anything. Could someone help me to provide the appropriate POJO and annotations in order to bind all data?
You can do one of the following options:
OPTION #1
Datas
package forum11311374;
import java.util.List;
import javax.xml.bind.annotation.*;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Datas {
private List<String> data;
//get/set methods
}
For More Information
http://blog.bdoughan.com/2010/09/jaxb-collection-properties.html
OPTION #2
Datas
package forum11311374;
import java.util.List;
import javax.xml.bind.annotation.*;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Datas {
#XmlElement(name="data")
private List<Data> datas;
//get/set methods
}
Data
package forum11311374;
import javax.xml.bind.annotation.*;
#XmlAccessorType(XmlAccessType.FIELD)
public class Data{
#XmlValue
private String data;
//get/set methods
}
For More Information
http://blog.bdoughan.com/2011/06/jaxb-and-complex-types-with-simple.html
The following can be used with both options:
input.xml/Ouput
I have updated the XML document to contain the necessary closing tags. <data>apple</data> instead of <data>apple<data>.
<datas>
<data>apple</data>
<data>banana</data>
<data>orange</data>
</datas>
Demo
package forum11311374;
import java.io.File;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Datas.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("src/forum11311374/input.xml");
Datas datas = (Datas) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(datas, System.out);
}
}
The first option did work for me... not sure why you are getting the problem...
Try this annotation...
#XmlElements(#XmlElement(name="data", type=String.class))
private List<String> datas; //ignore the variable name
I am working with Jaxb, Unmarshalling an xml. I am using java 1.6. This is the class which is generated through JWSDP 2.0. (xjc.bat) but what my problem is i am unable to compile the generated class. i am getting an syntax error as shown below.
"Type mismatch: cannot convert from XmlAccessType to AccessType"
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;
#XmlAccessorType(XmlAccessType.FIELD)// here i am getting sytax error
#XmlType(name = "personinfo", propOrder = {
"firstname",
"lastname",
"address"
})
public class Personinfo {
#XmlElement(required = true)
protected String firstname;
#XmlElement(required = true)
protected String lastname;
#XmlElement(name = "Address", required = true)
protected PersonAddress address;
............................
can any one help in this regard,
I tried the Personinfo class from your question with the demo code below and everything worked correctly. Since you are using Java SE 6 (which includes a JAXB implementation) you will want to make sure you don't have any of the JAXB APIs from the JWSDP 2.0 on your class path.
I would also recommend using the XJC utility from Java SE 6 instead of JWSDP, as JWSDP is quite old:
http://java.sun.com/webservices/downloads/previous/webservicespack.jsp
Demo
package forum10514244;
import java.io.File;
import javax.xml.bind.*;
import javax.xml.transform.stream.StreamSource;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Personinfo.class);
File xml = new File("src/forum10514244/input.xml");
Unmarshaller unmarshaller = jc.createUnmarshaller();
JAXBElement<Personinfo> je = unmarshaller.unmarshal(new StreamSource(xml), Personinfo.class);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(je, System.out);
}
}
input.xml/Output
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root>
<firstname>Jane</firstname>
<lastname>Doe</lastname>
<Address/>
</root>