I'm using JAXB to marshall Java Objects into XML. The ide i'm using is JDeveloper 11.1.1.7.0 in windows OS. Whenever i run that particular java code i get an error message which says
"Error(1,1): file:/C:/JDeveloper/mywork/bugdashboard/Model/src/model/BugReport.xml<Line 1, Column 1>: XML-20108: (Fatal Error) Start of root element expected."
Even though there seem to be no errors in the code still i'm not able to get the desired output..Please Help..
My JAVA code..
package model;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
public class JavaObvjecttoXml {
public void xmlGenerator() {
//super();
JavaServiceFacade fcd = new JavaServiceFacade();
bugvalue track, track1, track2;
List<ReportDto> bugReport, bugrePort1, bugrePort2;
List<bugvalue> reportMetaData= new ArrayList<bugvalue>();
ReportMetaData rmd = new ReportMetaData();
try {
rmd.setBugreportmetadata(new ArrayList<bugvalue> ());
JAXBContext context = JAXBContext.newInstance(ReportMetaData.class);
Marshaller marshaller;
marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
track = new bugvalue();
bugReport = fcd.getBugSeverityReport();
track.setBugReport(bugReport);
track.setLabel("Bug by severity");
track.setTile("severity");
track.setChatType("PIE");
track.setXAxisLabel("Label");
track.setYAxisLAbel("Label Count");
track1 = new bugvalue();
bugrePort1 = fcd.getBugStatusReport();
track1.setBugReport(bugrePort1);
track1.setLabel("Bug by Status");
track1.setTile("status");
track1.setChatType("bar");
track1.setXAxisLabel("count");
track1.setYAxisLAbel("Label");
track2 = new bugvalue();
bugrePort2 = fcd.getBugCategoryReport();
track2.setBugReport(bugrePort2);
track2.setLabel("Bug by Category");
track2.setTile("category");
track2.setChatType("PIE");
track2.setXAxisLabel("count");
track2.setYAxisLAbel("Label");
reportMetaData.add(track);
reportMetaData.add(track1);
reportMetaData.add(track2);
rmd.setBugreportmetadata(reportMetaData);
File output = new File("C:\\JDeveloper\\mywork\\bugdashboard\\Model\\src\\model\\BugReport.xml");
marshaller.marshal(rmd, output);
}
catch(JAXBException e){
e.printStackTrace();
}
}
/**
* #param args
*/
public static void main(String[] args) {
JavaObvjecttoXml obj = new JavaObvjecttoXml();
obj.xmlGenerator();
}
}
File ReportMetaData.java
package model;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlRootElement;
# XmlRootElement(name = "ReportMetaData")
public class ReportMetaData {
private List<bugvalue> bugreportmetadata = new ArrayList<bugvalue>();
public List<bugvalue> getBugreportmetadata() {
return bugreportmetadata;
}
*/ #param bugreportmetadata
*/
public void setBugreportmetadata(List<bugvalue> bugreportmetadata) {
this.bugreportmetadata = bugreportmetadata;
}
public ReportMetaData() {
super();
}
}
The error message..
The file BugReport.xml
As you can see from the above screen shot the file BugReport.xml is being generated but it's empty..
I suspect you need to annotate the fields you intend to output when you mashall the object to XML. Java™ sources generated by the JAX-B schema compiler I use apply the following annotation to the object attribute definitions:
#XmlElement(required = true)
In this case, the relevant section of your ReportMetaData class would look like this:
#XmlElement(required = true)
private List<bugvalue> bugreportmetadata = new ArrayList<bugvalue>();
The JAX-B schema compiler also generates two additional annotations before the #XmlRootElement annotation:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"bugreportmetadata"
})
In a JAX-B generated class structure, each class definition has these annotations. In addition, the #XmlType annotations for the nested class definitions contain the name of the type, so that the annotation for the bugvalue class might look like this:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "bugvalue", propOrder = {
// TODO: list the fields for BugValue as defined
})
The all lower case definition of bugvalue, depending on the coding for the JAX-B marshaller, may also create a problem. When marshalling an object, the JAX-B processor has to dynamically access and class definitions and generate element identifiers from them. If the JAX-B processor relies on Java naming conventions to do this, code that does not adhere to these conventions may potentially fail.
Related
To learn how to use #XmlAnyElement, I created the following test service:
#WebService(serviceName = "TestServices")
#Stateless()
public class TestServices {
#WebMethod(operationName = "testMethod")
public ServiceResult testMethod() {
ServiceResult result = new ServiceResult();
result.addObject(new SimpleObj(1, 2));
result.addObject(new SimpleObj(3, 4));
return result;
}
}
SimpleObj is a simple class with 2 int fields. Below is the code for the ServiceResult class:
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
#XmlSeeAlso({SimpleObj.class})
public class ServiceResult {
#XmlAnyElement(lax = true)
private List<Object> body;
public void addObject(Object objToAdd) {
if (this.body == null)
this.body = new ArrayList();
this.body.add(objToAdd);
}
// Getters and Setters
}
To consume the above service, I created an appclient with the following Main class:
public class Main {
#WebServiceRef(wsdlLocation = "META-INF/wsdl/localhost_8080/TestServices/TestServices.wsdl")
private static TestServices_Service service;
private static TestServices port;
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
port = service.getAdminServicesPort();
ServiceResult result = port.testMethod();
for (Object o : result.getAny()) {
System.out.println("TEST: " + o);
}
}
}
Based on the documentation, with #XmlAnyElement, the unmarshaller will eagerly unmarshal this element to a JAXB object. However, what I observed is that JAXB only parsed my object into JAXBElement instead of going all the way into SimpleObj.
I'd be extremely grateful if you could show me how I can get SimpleObj out of the ServiceResult.
UPDATE:
Below is the SimpleObj class:
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class SimpleObj {
private int a;
private int b;
public SimpleObj() {}
public SimpleObj(int a, int b) {
this.a = a;
this.b = b;
}
// Getters and Setters
}
I am unable to reproduce the issue that you are seeing. Below is some demo code that interacts directly with JAXB.
import java.io.*;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(ServiceResult.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
StringReader xml = new StringReader("<serviceResult><simpleObj/><simpleObj/></serviceResult>");
ServiceResult result = (ServiceResult) unmarshaller.unmarshal(xml);
for(Object item : result.getBody()) {
System.out.println(item.getClass());
}
}
}
The output from running the demo code shows that it is instances of SimpleObj in the field annotated with #XmlAnyElement(lax=true).
class forum27871349.SimpleObj
class forum27871349.SimpleObj
UPDATE #1
On the side note, I've read your blog articles on #XmlAnyElement and
I've never seen you had to include #XmlSeeAlso({SimpleObj.class}) in
any of your examples.
I'm not sure why I never leverage #XmlSeeAlso in my examples.
However, in my case, if I don't have this, I would have the error
saying Class *** nor any of its super class is known to this context.
It'd be great if you could also show me if there is a way to make all
of these classes known to the consumer without using #XmlSeeAlso
When you are creating the JAXBContext yourself, you simply need to include anything you would have referenced in an #XmlSeeAlso annotation as part of the classes you used to bootstrap the JAXBContext.
JAXBContext jc = JAXBContext.newInstance(ServiceResult.class, SimpleObj.class);
In a JAX-WS (or JAX-RS) setting where you don't have direct access to the JAXBContext I would recommend using the #XmlSeeAlso annotation like you have done.
UPDATE #2
Regarding the #XmlAnyElement, from the documentation, I thought if the
unmarshaller cannot unmarshal elements into JAXB objects or
JAXBElement objects, I will at least get a DOM node.
When you have a property mapped with #XmlAnyElement(lax=true) the following will happen:
If the element corresponds to the #XmlRootElement of a class, then you will get an instance of that class.
If the element corresponds to the #XmlElementDecl of a class on the ObjectFactory or another class annotated with #XmlRegistry then you will get an instance of that class wrapped in an instance of JAXBElement.
If JAXB does not have an association between the element and a class, then it will convert it to a DOM Element.
I will demonstrate below with an example.
ObjectFactory
import javax.xml.namespace.QName;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.*;
#XmlRegistry
public class ObjectFactory {
#XmlElementDecl(name="simpleObjJAXBElement")
public JAXBElement<SimpleObj> createSimpleObj(SimpleObj simpleObj) {
return new JAXBElement<SimpleObj>(new QName("simpleObjJAXBElement"), SimpleObj.class, simpleObj);
}
}
Demo
import java.io.*;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(ServiceResult.class, ObjectFactory.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
StringReader xml = new StringReader("<serviceResult><simpleObj/><unmapped/><simpleObjJAXBElement/></serviceResult>");
ServiceResult result = (ServiceResult) unmarshaller.unmarshal(xml);
for(Object item : result.getBody()) {
System.out.println(item.getClass());
}
}
}
Output
class forum27871349.SimpleObj
class com.sun.org.apache.xerces.internal.dom.ElementNSImpl
class javax.xml.bind.JAXBElement
I have a situation here, trying to act as a gateway between two APIs. What I need to do, is:
make a request to an APIa;
parse (marshal) the XML response into an java object;
make little changes to it;
and then give a response in XML (unmarshal) to the other end (APIb).
The thing is that I use the same object to parse the API response and to send the response to the other end.
public class ResponseAPI{
#XmlElement(name="ResponseCode") //I receive <ResponseCode> but I need to send <ResultCode>
private String responseCode;
//getter and setter
}
as the comment says: I receive but I need to send
Is there a way to get this done without having to create another extra class which carries ResultCode?
thanks in advance!
You can try next solution using #XmlElements annotaion
#XmlAccessorType(XmlAccessType.FIELD)
public class ResponseAPI
{
#XmlElements(
{
#XmlElement(name = "ResponseCode"),
#XmlElement(name = "ResultCode")
})
private String responseCode;
// ...
}
In this case both ResponseCode and ResultCode will be used during unmarshalling (xml -> object) and only ResultCode during marshalling (object -> xml).
So you can unmarshall XML like
<responseAPI>
<ResponseCode>404</ResponseCode>
</responseAPI>
After marshalling object will looks like
<responseAPI>
<ResultCode>404</ResultCode>
</responseAPI>
Note:
The answer given by Ilya works but isn't guaranteed to work across all implementations of JAXB or even across versions of a single JAXB implementation. The #XmlElements annotation is useful when the decision of which element to marshal depends on the type of the value (see: http://blog.bdoughan.com/2010/10/jaxb-and-xsd-choice-xmlelements.html). In your use case both the ResponseCode and ResultCode elements correspond to type String, unmarshalling will always work fine, but the choice of which element to output is arbitrary. Some JAXB Impls may have last specified wins, but others could easily have first wins.
You could do the following by leveraging #XmlElementRef.
Java Model
ResponseAPI
We will change the responseCode property from type String to JAXBElement<String>. The JAXBElement allows us to store the element name as well as the value.
import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.*;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class ResponseAPI{
#XmlElementRefs({
#XmlElementRef(name = "ResponseCode"),
#XmlElementRef(name = "ResultCode")
})
private JAXBElement<String> responseCode;
public JAXBElement<String> getResponseCode() {
return responseCode;
}
public void setResponseCode(JAXBElement<String> responseCode) {
this.responseCode = responseCode;
}
}
ObjectFactory
The #XmlElementRef annotations we used on the ResponseAPI class correspond to #XmlElementDecl annotations on a class annotated with #XmlRegistry. Traditionally this class is called ObjectFactory but you can call it anything you want.
import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.*;
import javax.xml.namespace.QName;
#XmlRegistry
public class ObjectFactory {
#XmlElementDecl(name="ResponseCode")
public JAXBElement<String> createResponseCode(String string) {
return new JAXBElement<String>(new QName("ResponseCode"), String.class, string);
}
#XmlElementDecl(name="ResultCode")
public JAXBElement<String> createResultCode(String string) {
return new JAXBElement<String>(new QName("ResultCode"), String.class, string);
}
}
Demo Code
input.xml
<responseAPI>
<ResponseCode>ABC</ResponseCode>
</responseAPI>
Demo
When creating the JAXBContext we need to ensure that we include the class that contains the #XmlElementDecl annotations.
import java.io.File;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(ResponseAPI.class, ObjectFactory.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("Scratch/src2/forum24554789/input.xml");
ResponseAPI responseAPI = (ResponseAPI) unmarshaller.unmarshal(xml);
ObjectFactory objectFactory = new ObjectFactory();
String responseCode = responseAPI.getResponseCode().getValue();
JAXBElement<String> resultCodeJAXBElement = objectFactory.createResultCode(responseCode);
responseAPI.setResponseCode(resultCodeJAXBElement);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(responseAPI, System.out);
}
}
Output
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<responseAPI>
<ResultCode>ABC</ResultCode>
</responseAPI>
I'm looking for a Java JSPON serializer that can handle references according to the JSPON specification.
Are there any available that can do this currently? Or is there any way to modify an existing serializer to handle object refs with the $ref notation?
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB 2 (JSR-222) expert group.
If you are interested in an object-JSON binding approach, below is how it could be done using MOXy. The example below is based on the example one from the JSPON Core Spec:
http://www.jspon.org/JSPON_Core_Spec.htm
Parent
The Parent class is the domain object that corresponds to the root of the JSON message. It has two fields that are of type Child.
package forum9862100;
import javax.xml.bind.annotation.*;
#XmlAccessorType(XmlAccessType.FIELD)
public class Parent {
protected Child field1;
protected Child field2;
}
Child
The Child class may be referenced by its key. We will handle this use case with an XmlAdapter. We link to an XmlAdapter via the #XmlJavaTypeAdapter annotation.
package forum9862100;
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
#XmlJavaTypeAdapter(ChildAdapter.class)
#XmlAccessorType(XmlAccessType.FIELD)
public class Child {
protected String id;
protected String foo;
protected Integer bar;
}
ChildAdapter
Below is the implementation of the XmlAdapter. This XmlAdapter is stateful which means we will need to set an instance on the Marshaller and Unmarshaller.
package forum9862100;
import java.util.*;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class ChildAdapter extends XmlAdapter<ChildAdapter.AdaptedChild, Child>{
private List<Child> childList = new ArrayList<Child>();
private Map<String, Child> childMap = new HashMap<String, Child>();
public static class AdaptedChild extends Child {
#XmlElement(name="$ref")
public String reference;
}
#Override
public AdaptedChild marshal(Child child) throws Exception {
AdaptedChild adaptedChild = new AdaptedChild();
if(childList.contains(child)) {
adaptedChild.reference = child.id;
} else {
adaptedChild.id = child.id;
adaptedChild.foo = child.foo;
adaptedChild.bar = child.bar;
childList.add(child);
}
return adaptedChild;
}
#Override
public Child unmarshal(AdaptedChild adaptedChild) throws Exception {
Child child = childMap.get(adaptedChild.reference);
if(null == child) {
child = new Child();
child.id = adaptedChild.id;
child.foo = adaptedChild.foo;
child.bar = adaptedChild.bar;
childMap.put(child.id, child);
}
return child;
}
}
Demo
The code below demonstrates how to specify a stateful XmlAdapter on the Marshaller and Unmarshaller:
package forum9862100;
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(Parent.class);
StreamSource json = new StreamSource(new File("src/forum9862100/input.json"));
Unmarshaller unmarshaller = jc.createUnmarshaller();
unmarshaller.setProperty("eclipselink.media-type", "application/json");
unmarshaller.setProperty("eclipselink.json.include-root", false);
unmarshaller.setAdapter(new ChildAdapter());
Parent parent = (Parent) unmarshaller.unmarshal(json, Parent.class).getValue();
System.out.println(parent.field1 == parent.field2);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setProperty("eclipselink.media-type", "application/json");
marshaller.setProperty("eclipselink.json.include-root", false);
marshaller.setAdapter(new ChildAdapter());
marshaller.marshal(parent, System.out);
}
}
Output
Below is the output from running the demo code. Note how the two instances of Child pass the identity test.
true
{
"field1" : {
"id" : "2",
"foo" : "val",
"bar" : 4
},
"field2" : {
"$ref" : "2"
}}
For More Information
http://blog.bdoughan.com/2011/09/mixing-nesting-and-references-with.html
http://blog.bdoughan.com/2011/08/json-binding-with-eclipselink-moxy.html
I would use one of the many Object to JSon serialization libraries. Many of the libraries are extensible, but I suspect adding references could get complicated unless you make some pragmatic choices as to when to use these.
I have
xml1:
<abc><name>hello</name></abc>
xml2
<xyz><name>hello</name></xyz>
I have one java class.
#XmlRootElement(name="abc") (this
public class Foo{
#XmlElement
String name;
}
I do not want another class, but would like to accomodate xml2 with the Foo class itself.
I'm okay to intercept or modify it during pre-marshalling/pre-unmarshalling.
Thanks!
}
Depending on exactly what you mean by "I don't want another class", maybe this will work out for you:
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlSeeAlso;
import java.io.StringReader;
public class JaxbBindTwoRootElementsToSameClass {
public static void main(String[] args) throws Exception {
String xml1 = "<abc><name>hello</name></abc>";
String xml2 = "<xyz><name>hello</name></xyz>";
Unmarshaller unmarshaller = JAXBContext.newInstance(Foo.class).createUnmarshaller();
Object o1 = unmarshaller.unmarshal(new StringReader(xml1));
Object o2 = unmarshaller.unmarshal(new StringReader(xml2));
System.out.println(o1);
System.out.println(o2);
}
#XmlSeeAlso({Foo.Foo_1.class, Foo.Foo_2.class})
static class Foo {
#XmlRootElement(name = "abc")
static class Foo_1 extends Foo {}
#XmlRootElement(name = "xyz")
static class Foo_2 extends Foo {}
#XmlElement
String name;
#Override
public String toString() {
return "Foo{name='" + name + '\'' + '}';
}
}
}
Output:
Foo{name='hello'}
Foo{name='hello'}
It has the benefit of using JAXB almost exactly the way you usually would. It's just a slightly unconventional class organization. You even only have to pass Foo.class to the JAXBContext when you create it. No tinkering with JAXB internals needed.
Unmarshalling
You could use the unmarshal methods that take a class parameter. When a class is specified the JAXB implementation does not need to use the root element to determine the class to unmarshal to.
Marshalling
When marshaling you can wrap the root object in a JAXBElement to provide the root element information.
I have a java bean without any annotations. And I have a class inherited from this bean with JAXB annotations.
Jersey (JAX-RS) serialize the second class to JSON. And inherited properties occur in JSON twice: with name from XmlElement annotation and with 'camel-case' name of java-bean property. Here is a code which illustrates this:
class MyBean {
private Integer beanField;
public Integer getBeanField() { return beanField; }
public void setBeanField(Integer value) { this.beanField = value; }
}
#XmlRootElement
class AnnotatedBean extends MyBean {
#Override
#XmlElement(name="field")
public Integer getBeanField() { return super.getBeanField(); }
}
}
After serialization I get the next JSON:
{
"field" : 5,
"beanField" : 5
}
(while I want it to contain only one field with name field).
I investigated JAXB marshaller implementation and found that it marshals properties from all superclasses of the given class (and that means that it's impossible to get rid of the odd beanField property in my example).
But I still hope that I could miss something. Is there a way to serialize only annotated properties?
To get only the annotated properties use XmlAccessType.NONE:
#XmlAccessorType(XmlAccessType.NONE)
#XmlRootElement
class AnnotatedBean extends MyBean {
...
}
Mapping the 3rd Party Class Using Externalized Metadata
You could use the external metadata extension in EclipseLink JAXB (MOXy), I'm the tech lead. It allows you to provide metadata for 3rd party classes. For this example the metadata will look like:
<?xml version="1.0"?>
<xml-bindings
xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
package-name="third.party.package">
<java-types>
<java-type name="MyBean" xml-transient="true"/>
</java-types>
</xml-bindings>
To use MOXy you need to add a file named jaxb.properties in with your model classes with the following entry:
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
The following article has instructions on configuring MOXy to work with Jersery:
http://bdoughan.blogspot.com/2010/08/creating-restful-web-service-part-35.html
Context Resolver - Leveraging the Metadata
You would need to use a ContextResolver to get your JAXBContext to leverage the external bindings file. The metadata is specified through a property when the JAXBContext is instantiated:
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import javax.ws.rs.Produces;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;
import javax.xml.bind.JAXBContext;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import org.eclipse.persistence.jaxb.JAXBContextFactory;
#Provider
#Produces({"application/xml", "application/json"})
public class AnnotatedBeanContextResolver implements ContextResolver<JAXBContext> {
private JAXBContext jaxbContext;
public PurchaseOrderContextResolver() {
try {
Map<String, Object> properties = new HashMap<String, Object>(1);
properties.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, new File("src/blog/bindingfile/binding.xml"));
jaxbContext = JAXBContext.newInstance(new Class[] {AnnotatedBean.class}, properties);
} catch(Exception e) {
throw new RuntimeException(e);
}
}
public JAXBContext getContext(Class<?> clazz) {
if(AnnotatedBean.class == clazz) {
return jaxbContext;
}
return null;
}
}