any way to convert xml to object in java? - java

I am trying to use a XML and access to all fields and data on an easy way, so, I decided to use JaxB , but I have no idea how to create all the classes for the objects, I tried manually like this.
#XmlRootElement(name = "Response")
public class Response {
#XmlElement(ns = "SignatureValue")
String signatureValue;
}
But I get an error on #XmlElement saying the annotation is disallowed for this location...
I checked other posts and they work great if I have something like Hellw but doesnt work with more complex formats, an example of first part of mine is like this
<?xml version="1.0" encoding="UTF-8"?><DTE xsi:noNamespaceSchemaLocation="http://www.myurl/.xsd" xmlns:gs1="urn:ean.ucc:pay:2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
any idea how to do all this??
Thanks in advance
EDIT:
I forgot to say, the XML is actually a String with the entire XML.

The #XmlElement annotation is valid on a field. If you have a corresponding property then you should annotate the class with #XmlAccessorType(XmlAccessType.FIELD) to avoid a duplicate mapping exception.
Java Model
Annotating the Field
#XmlRootElement(name = "Response")
#XmlAccessorType(XmlAccessType.FIELD)
public class Response {
#XmlElement(name = "SignatureValue")
String signatureValue;
public String getSignatureValue() {
return signatureValue;
}
public void setSignatureValue(String signatureValue) {
this.signatureValue = signatureValue;
}
}
Annotating the Property
import javax.xml.bind.annotation.*;
#XmlRootElement(name = "Response")
public class Response {
String signatureValue;
#XmlElement(name = "SignatureValue")
public String getSignatureValue() {
return signatureValue;
}
public void setSignatureValue(String signatureValue) {
this.signatureValue = signatureValue;
}
}
For More Information
http://blog.bdoughan.com/2011/06/using-jaxbs-xmlaccessortype-to.html
Demo Code
Below is some demo code that reads/writes the XML corresponding to your Response class.
Demo
import java.io.File;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Response.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("src/forum19713886/input.xml");
Response response = (Response) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(response, System.out);
}
}
input.xml/Output
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<SignatureValue>Hello World</SignatureValue>
</Response>

Related

How to marshal xml to a jaxb wrapper class?

<myresponse>
<field1></field1>
<field2></field2>
//...
</myresponse>
#XmlRootElement(name = "myresponse")
#XmlAccessorType(XmlAccessType.FIELD)
public class MyResponse {
//fields
}
The following would work fine:
JAXBContext jaxbContext = JAXBContext.newInstance(MyResponse.class);
Problem: I'd like to create a wrapper class around that response, and marshall it into this new class. But how, if the XML structure remains the same?
public class CustomResponse {
#XmlElement(name = "myresponse")
private MyResponse myresponse;
//some more DTO fields or bean logic
}
JAXBContext.newInstance(CustomResponse.class);
How can I tell jaxb to actually map anything from the xml response into the #XmlElement(name = "myresponse") object, if possible?
Sidenote: I have no control of the xml received.

How does EclipseLink/MOXy create the property name?

I am writing a code to set XmlTransient at runtime using MOXy. Here is the part of the code which is adapted from the example on http://blog.bdoughan.com/2011/06/moxy-extensible-models-refresh-example.html
public void setXmlTransient(Class<?> domainClass, String propertyName) {
XmlTransient xmlTransient = new XmlTransient();
xmlTransient.setJavaAttribute(propertyName);
JavaType javaType = getJavaType(domainClass);
javaType.getJavaAttributes().getJavaAttribute().add(objectFactory.createXmlTransient(xmlTransient));
}
Since I am doing this programmatically, I need to be able to create the propertyName exactly the same way as MOXy does. For most getter method names, like getOrder, the property name is done by removing get from the method name and change upper-case O to lower-case o, i.e. property name is order. However, I am hitting the case which my getter method is getXInA but xInA doesn't seem to be a valid property name. MOXy throws a warning like
Ignoring attribute [xInA] on class [Atom] as no Property was generated for it.
Does anyone know what the rules are used by MOXy for creating the property name from getters? or know where I can find out about this without reading the MOXy source code?
SHORT ANSWER
Because there are two capital letters in a row the property name is going to be XInA.
LONG ANSWER
Domain Model (Foo)
Below is a sample Java class with the property from your question.
package forum14945664;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class Foo {
private String x;
public String getXInA() {
return x;
}
public void setXInA(String x) {
this.x = x;
}
}
MetadataSource (ExampleMetadataSource)
MetadataSource is a programmatic way to provide MOXy with the mapping metadata.
package forum14945664;
import java.util.*;
import org.eclipse.persistence.jaxb.metadata.MetadataSourceAdapter;
import org.eclipse.persistence.jaxb.xmlmodel.*;
import org.eclipse.persistence.jaxb.xmlmodel.JavaType.*;
import org.eclipse.persistence.jaxb.xmlmodel.XmlBindings.*;
public class ExampleMetadataSource extends MetadataSourceAdapter {
private ObjectFactory objectFactory;
private Map<Class<?>, JavaType> javaTypes;
private XmlBindings xmlBindings;
public ExampleMetadataSource() {
objectFactory = new ObjectFactory();
javaTypes = new HashMap<Class<?>, JavaType>();
xmlBindings = new XmlBindings();
xmlBindings.setPackageName("forum14945664");
xmlBindings.setJavaTypes(new JavaTypes());
}
#Override
public XmlBindings getXmlBindings(Map<String, ?> properties, ClassLoader classLoader) {
return xmlBindings;
}
public JavaType getJavaType(Class<?> clazz) {
JavaType javaType = javaTypes.get(clazz);
if(null == javaType) {
javaType = new JavaType();
javaType.setName(clazz.getSimpleName());
javaType.setJavaAttributes(new JavaAttributes());
xmlBindings.getJavaTypes().getJavaType().add(javaType);
javaTypes.put(clazz, javaType);
}
return javaType;
}
public void setXmlTransient(Class<?> domainClass, String propertyName) {
XmlTransient xmlTransient = new XmlTransient();
xmlTransient.setJavaAttribute(propertyName);
JavaType javaType = getJavaType(domainClass);
javaType.getJavaAttributes().getJavaAttribute().add(objectFactory.createXmlTransient(xmlTransient));
}
}
Specify MOXy as JAXB Provider (jaxb.properties)
To specify MOXy as the JAXB provider you need to include a file called jaxb.properties in the same package as your domain model with the following entry.
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Demo
In the demo code below we will create a JAXBContext based on the domain model and we will marshal an instance to XML. Then we will use the MetadataSource to make the property transient, refresh the JAXBContext and marshal the instance again.
package forum14945664;
import java.util.*;
import javax.xml.bind.*;
import org.eclipse.persistence.jaxb.JAXBContextProperties;
import org.eclipse.persistence.jaxb.JAXBHelper;
public class Demo {
public static void main(String[] args) throws Exception {
ExampleMetadataSource metadata = new ExampleMetadataSource();
Map<String, Object> properties = new HashMap<String, Object>(1);
properties.put(JAXBContextProperties.OXM_METADATA_SOURCE, metadata);
JAXBContext jc = JAXBContext.newInstance(new Class[] {Foo.class}, properties);
Foo foo = new Foo();
foo.setXInA("Hello World");
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(foo, System.out);
metadata.setXmlTransient(Foo.class, "XInA");
JAXBHelper.getJAXBContext(jc).refreshMetadata();
marshaller.marshal(foo, System.out);
}
}
Output
First we see the XInA property marshalled, then after we make it transient we see that it is not in the XML from the second marshal operation.
<?xml version="1.0" encoding="UTF-8"?>
<foo>
<XInA>Hello World</XInA>
</foo>
<?xml version="1.0" encoding="UTF-8"?>
<foo/>

"Class has two properties of the same name" error when converting an XML file into a Java object [duplicate]

This question already has answers here:
Jaxb, Class has two properties of the same name
(19 answers)
Closed 10 days ago.
I have an XML file like below, and I want to convert it into a Java object.
<P1>
<CTS>
Hello
</CTS>
<CTS>
World
</CTS>
<P1>
So I created the following Java classes with their properties.
P1 class
#XmlRootElement
public class P1 {
#XmlElement(name = "CTS")
List<CTS> cts;
}
CTS class
public class CTS {
String ct;
}
Test Class
File file = new File("D:\\ContentTemp.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(P1.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
P1 p = (P1) jaxbUnmarshaller.unmarshal(file);
But I am getting the following error:
com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException:
2 counts of IllegalAnnotationExceptions
Class has two properties of the same name "cts"
com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException:
2 counts of IllegalAnnotationExceptions
Class has two properties of the same name "cts"
By default a JAXB (JSR-222) implementation creates mappings based on properties and annotated fields. When you annotate a field for which there is also a property it will cause this error.
You have two options:
Use #XmlAccessorType(XmlAccessType.FIELD)
You could annotate the field you need to specify #XmlAccessorType(XmlAccessType.FIELD) on the class.
#XmlRootElement(name="P1)
#XmlAccessorType(XmlAccessType.FIELD)
public class P1 {
#XmlElement(name = "CTS")
List<CTS> cts;
}
Option #2 - Annotate the Property (get method)**
Alternatively you could annotate the get method.
#XmlRootElement(name="P1)
public class P1 {
List<CTS> cts;
#XmlElement(name = "CTS")
public List<CTS> getCts() {
return cts;
}
}
For More Information
http://blog.bdoughan.com/2011/06/using-jaxbs-xmlaccessortype-to.html
FULL EXAMPLE
CTS
You can use the #XmlValue annotation to map to Java class to a complex type with simple content.
#XmlAccessorType(XmlAccessType.FIELD)
public class CTS {
#XmlValue
String ct;
}
P1
import java.util.List;
import javax.xml.bind.annotation.*;
#XmlRootElement(name="P1")
#XmlAccessorType(XmlAccessType.FIELD)
public class P1 {
#XmlElement(name = "CTS")
List<CTS> cts;
}
Demo
import java.io.File;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(P1.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("src/forum13987708/input.xml");
P1 p1 = (P1) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(p1, System.out);
}
}
input.xml/Output
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<P1>
<CTS>
Hello
</CTS>
<CTS>
World
</CTS>
</P1>
For More Information
http://blog.bdoughan.com/2011/06/jaxb-and-complex-types-with-simple.html
Two issues I can see:
1) You need to use P1.class in your JAXBContext. You haven't said what the Presentation class is, but if your root element is P1, that's what you need in the context:
JAXBContext jaxbContext = JAXBContext.newInstance(P1.class);
2) You need to specify the name of the root xml element:
#XmlRootElement(name="P1")
public class P1 {
...
Your XML looks like this:
<P1>
<CTS>
Hello
</CTS>
<CTS>
World
</CTS>
</P1>
But considering your mapping it should look like:
<p1>
<CTS>
<CT>
Hello
</CT>
</CTS>
<CTS>
<CT>
World
</CT>
</CTS>
</p1>
In order to change root element from p1 to P1 use attribute name from #XmlRootElement.
If you want to parse the first version of XML you posted, change your P1 class like this:
#XmlRootElement(name="P1")
public class P1 {
#XmlElement(name = "CTS")
List<String> cts;
}
You could try the following,
If you could, make xml as of the following structure.
<P1>
<CTSList>
<CTS value="Hello"/>
<CTS value="World"/>
</CTSList>
<P1>
And use,
#XMLRootElement(name="P1")
public class P1 {
List CTSList;
#XMLElementWrapper(name="CTSList")
#XMLELement(name="CTS")
public void setCTSList(List<CTS> ctsList) {
this.CTSList = ctsList;
}
public List<CTS> getCTSList() {
return this.CTSList;
}
}
#XMLRootElement(name="CTS")
public class CTS {
String cts;
#XMLAttribute(name = "value")
public String getCts() {
return this.cts;
}
public void set setCts(String cts) {
this.cts = cts;
}
}

Convert Java object to XML

I am trying to convert a Java object inside of a Java library to an XML file. However, I got this problem:
A a = new A();
// initializing for a
JAXBContext jc = JAXBContext.newInstance("libraryA.A");
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(a, System.out);
Then I got this exception:
javax.xml.bind.JAXBException: "libraryA.a" doesnt contain ObjectFactory.class or jaxb.index
at com.sun.xml.internal.bind.v2.ContextFactory.createContext(ContextFactory.java:186)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:128)
at javax.xml.bind.ContextFinder.find(ContextFinder.java:290)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:372)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:337)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:244)
If I change: JAXBContext jc = JAXBContext.newInstance("libraryA.a");
to:
JAXBContext jc = JAXBContext.newInstance(libraryA.A.class);
then I have another exception:
com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 2 counts of IllegalAnnotationExceptions
library.A is an interface, and JAXB can't handle interfaces.
this problem is related to the following location:
at library.A
library.A does not have a no-arg default constructor.
this problem is related
to the following location:
at library.A
Background Info (From Related Question)
From the comment you made on my answer to your previous question the domain model is already being used with JAXB. The easiest way to have your client and server communicate via XML is to leverage the already annotated model on both ends.
I just have checked the source code of
my client. In the process, we need to
convert back a xml file which is
generated from java objects to xml
file using: javax.xml.bind.JAXBContext
& javax.xml.bind.Marshaller. so my
question is it possible to read back
the xml file to the same java objects?
then we can use the java objects for a
further step. Thanks in advance!
UPDATE
It appears as though your issue is due to having a domain model that is defined through interfaces with backing implementation classes. Below I'll demonstrate how you can handle this using a JAXB implementation (Metro, MOXy, JaxMe, etc).
Demo Code
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(CustomerImpl.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("input.xml");
Customer customer = (Customer) unmarshaller.unmarshal(xml);
Address address = customer.getAddress();
System.out.println(address.getStreet());
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(customer, System.out);
}
}
Interface Model
The following interfaces represent our domain model. These interfaces when not be leveraged to bootstrap the JAXBContext.
Customer
public interface Customer {
public Address getAddress();
public void setAddress(Address address);
}
Address
public interface Address {
public String getStreet();
public void setStreet(String street);
}
Implementation Classes
The implementation classes are what will be mapped to XML using JAXB.
CustomerImpl
Note in the CustomerImpl class we use the #XmlElement annotation on the address property to specify the type is AddressImpl.
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name="customer")
public class CustomerImpl implements Customer {
private Address address;
#XmlElement(type=AddressImpl.class)
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}
AddressImpl
public class AddressImpl implements Address {
private String street;
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
}
input.xml
<?xml version="1.0" encoding="UTF-8"?>
<customer>
<address>
<street>1 Any Street</street>
</address>
</customer>
If you don't have to use JAXB, perhaps you can use XStream ?
It imposes very few restrictions on what you can serialise to/from XML, and may be appropriate if you don't need JAXB specifically.

JAXB Adding attributes to a XmlElement for simple data types

I want to add some attributes to Xml Elements using JAXB when marshalling from JavaBeans. The Xml Elements are simple data types like String. So I do not want to create new Classes. For example, a desired output would be:
<notifications>
<date>04/20/2011</date>
<subject creditcard_num="22678" checknum="8904">Credit Card Charge Back</subject>
<body payment_amount="34.00" return_status="charged back">some text</body>
</notifications
I do not want to define subject and body as separate classes.
-Anand
My solution require defining a class for subject and body, but the desired output will be as requested
I use #XmlValue for the message and #XmlAttribute for the attributes
#Test
public void testAll() throws JAXBException
{
String msg = "<notifications><date>04/20/2011</date><subject creditcard_num='22678' checknum='8904'>Credit Card Charge Back</subject><body payment_amount='34.00' return_status='charged back'>some text</body></notifications>";
Notifications tested = (Notifications) JAXBContext.newInstance(Notifications.class).createUnmarshaller().unmarshal(new StringReader(msg));
assertEquals("Credit Card Charge Back",tested.subject.value);
assertEquals("8904",tested.subject.checknum);
assertEquals("22678",tested.subject.creditcard_num);
}
#XmlRootElement
public static class Notifications{
public String date;
public Subject subject;
}
public static class Subject
{
#XmlValue
public String value;
#XmlAttribute(name="creditcard_num")
public String creditcard_num;
#XmlAttribute(name="checknum")
public String checknum;
}
NOTE:I only wrote the subject part, I wonder if using #XmlPath can be used to remove the need for different classes
You could use EclipseLink JAXB (MOXy)'s #XmlPath annotation to solve this problem (I'm the MOXy tech lead):
Notifications
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import org.eclipse.persistence.oxm.annotations.XmlPath;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Notifications {
private String date;
#XmlPath("subject/#creditcard_num")
private String creditcardNum;
#XmlPath("subject/#checknum")
private String checknum;
private String subject;
#XmlPath("body/#payment_amount")
private String paymentAmount;
#XmlPath("body/#return_status")
private String returnStatus;
private String body;
}
jaxb.properties
To use MOXy as your JAXB implementation you need to put a file named jaxb.properties in the same package as your model classes with the following entry:
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Demo
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Notifications.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
Notifications notifications = (Notifications) unmarshaller.unmarshal(new File("input.xml"));
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(notifications, System.out);
}
}
For More Information:
http://bdoughan.blogspot.com/2010/07/xpath-based-mapping.html
http://bdoughan.blogspot.com/2010/09/xpath-based-mapping-geocode-example.html
http://bdoughan.blogspot.com/2011/03/map-to-element-based-on-attribute-value.html

Categories