JAXB: Empty object content gives error when marshalling - jaxb

Using com.sun.xml.bind jaxb-impl 2.2.6.
I've got parent and child object, what I would like to get after marshall is:
<parent/> or <parent></parent>
But what I get is an error like:
Caused by:
com.sun.xml.internal.bind.api.AccessorException: Object must have some value in its #XmlValue field: com.test.data.Child#....
Here is the code:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {"content"})
#XmlRootElement(name = "child")
public class Child {
#XmlValue
protected String content;
public String getContent() {
return content;
}
}
...
Then
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {"child"})
#XmlRootElement(name = "parent")
public class Parent {
protected Child child;
public Child getChild() {
return child;
}
}
What I do is (that's because I want to be able to "maybe" fill the content of child later):
if(parent.getChild == null)
parent.setChild(new Child());
Then, when I try to marshall, I get the error seen above.
If I try:
if(parent.getChild == null) {
Child child = new Child();
child.setContent("");
parent.setChild(child);
}
Then I get the expected:
<parent><child></child></parent>
And I can get what I want by never setting the child object in its parent (so no parent.setChild(...)), but as stated above, it would save me time to set it earlier.
Basically I am trying to do exactly the opposite as in the post:
JAXB: Empty string does not produce empty element
Is there anything I am doing wrong, or maybe something I did not setup correctly?
Thanks,
Yoann
Edit:
Is there any other way than to either:
- Set it back to null later: parent.setChild(null);
- Never set it as an object in the first place

Related

How to solve the JAXB IllegalAnnotationException error

I am trying to consume a web service using JAX-WS, and it throws me the following error corresponding to the following classes:
Class 1
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "validarComprobante", propOrder = { "xml" })
public class ValidarComprobante {
protected byte[] xml;
public byte[] getXml() {
return xml;
}
public void setXml(byte[] value) {
this.xml = value;
}
}
Class 2
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "validarComprobanteResponse", propOrder = { "respuestaRecepcionComprobante" })
public class ValidarComprobanteResponse {
#XmlElement(name = "RespuestaRecepcionComprobante")
protected RespuestaSolicitud respuestaRecepcionComprobante;
public RespuestaSolicitud getRespuestaRecepcionComprobante() {
return respuestaRecepcionComprobante;
}
public void setRespuestaRecepcionComprobante(RespuestaSolicitud value) {
this.respuestaRecepcionComprobante = value;
}
}
These classes were generated with wsimport.exe which is inside the Java 8 SDK. The error is as follows:
com.sun.xml.ws.spi.db.DatabindingException: com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 2 counts of IllegalAnnotationExceptions
Two classes have the same XML type name "{http://ec.gob.sri.ws.recepcion}validarComprobante". Use #XmlType.name and #XmlType.namespace to assign different names to them.
this problem is related to the following location:
at com.horus.microservices.ebillinginvoice.sri.recepcion.ValidarComprobante
at public javax.xml.bind.JAXBElement com.horus.microservices.ebillinginvoice.sri.recepcion.ObjectFactory.createValidarComprobante(com.horus.microservices.ebillinginvoice.sri.recepcion.ValidarComprobante)
at com.horus.microservices.ebillinginvoice.sri.recepcion.ObjectFactory
this problem is related to the following location:
at recepcion.ws.sri.gob.ec.ValidarComprobante
Two classes have the same XML type name "{http://ec.gob.sri.ws.recepcion}validarComprobanteResponse". Use #XmlType.name and #XmlType.namespace to assign different names to them.
this problem is related to the following location:
at com.horus.microservices.ebillinginvoice.sri.recepcion.ValidarComprobanteResp
at public com.horus.microservices.ebillinginvoice.sri.recepcion.ValidarComprobanteResp com.horus.microservices.ebillinginvoice.sri.recepcion.ObjectFactory.createValidarComprobanteResponse()
at com.horus.microservices.ebillinginvoice.sri.recepcion.ObjectFactory
this problem is related to the following location:
at recepcion.ws.sri.gob.ec.ValidarComprobanteResponse
at com.sun.xml.ws.db.glassfish.JAXBRIContextFactory.newContext(JAXBRIContextFactory.java:105)
at
Please any help
Thanks

failed to lazily initialize a collection of role for a Map<Integer,String>

I have the follwoing entity
#Entity
#Table(name = "Parent")
public class Parent {
#ElementCollecion(fetch = FetchType.Eager)
Map<Integer,String> myMap;
public Map<Integer,String> getMyMap() {
return this.myMap;
}
}
Then somewhere in the code I have the follwoing
parent.getMyMap().get(someKey);
This line consistently throws a LazyInitialization exception. I have set the fetchType to eagerly load the collection so that the values are available at all times. What have I missed> Is it because of the access of the getMap.GetKey call?
I dont see any more information in the debug logs or anywhere else.
Generally the #ElementCollection is accompanied with a #CollectionTable along with #MapKeyColumn & #Column annotation to provide the table and values to load the content for the map.
#Entity
#Table(name = "Parent")
public class Parent {
#ElementCollection(fetch = FetchType.Eager)
#CollectionTable(name="example_attributes", joinColumns=#JoinColumn(name="example_id"))
#MapKeyColumn(name="name")
#Column(name="value")
Map<Integer,String> myMap;
public Map<Integer,String> getMyMap() {
return this.myMap;
}
}

How to set the namespace of marshalled xml using camel jaxb?

For starters, I'm creating some routes using Camel ver 2.15 (in Fuse 6.2.1).
In my route, i'm trying to create a XML from a pojo that was generated using cxf-xjc maven plugin (cxf-xjc read some xsd somewhere then from the xsd, the pojos with jaxb annotations were produced).
The pojos are TempProject and TempProjects.
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(
name = "",
propOrder = {"ecode", "tempName"}
)
#XmlRootElement(
name = "TempProject"
)
public class TempProject implements Serializable {
#XmlElement(
name = "Ecode",
required = true
)
protected String ecode;
#XmlElement(
name = "TempName",
required = true
)
protected String tempName;
public TempProject() {
}
public String getEcode() {
return this.ecode;
}
public void setEcode(String value) {
this.ecode = value;
}
public String getTempName() {
return this.tempName;
}
public void setTempName(String value) {
this.tempName = value;
}
}
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(
name = "",
propOrder = {"tempProjects"}
)
#XmlRootElement(
name = "TempProjects"
)
public class TempProjects implements Serializable {
#XmlElement(
name = "TempProject",
required = true
)
protected List<TempProject> tempProjects;
public TempProjects() {
}
public List<TempProject> getTempProjects() {
if (this.tempProjects == null) {
this.tempProjects = new ArrayList();
}
return this.tempProjects;
}
}
I can generate the xml using this code:
JAXBContext jaxbContext = JAXBContext.newInstance(new Class[]{TempProjects.class});
jaxbContext.createMarshaller();
JaxbDataFormat jaxbDataFormat = new JaxbDataFormat(jaxbContext); //import org.apache.camel.converter.jaxb.JaxbDataFormat;
I call
.marshal(jaxbDataFormat)
in my route to effect the marshalling from the pojo to xml.
The generated xml is posted below:
<TempProjects xmlns="http://blah.blah/foo/schema/v2">
<TempProject>
<Ecode>1</Ecode>
<TempName>Tempname1</TempName>
</TempProject>
<TempProject>
<Ecode>2</Ecode>
<TempName>Tempname2</TempName>
</TempProject>
How can i generate a marshalled xml that will have a namespace like this...
<TempProjects xmlns:myprefix="http://blah.blah/foo/schema/v2">
Reason being why I needed a namespaceprefix is because I plan to split the values (e.g. Ecode) in the xml using xpath and I needed a namespaceprefix to do that (thats what ive researched, i might be wrong).
My planned code in my route is
.marshal(jaxbDataFormat)
.split( xpath("/TempProjects/TempProject/Ecode/text()").namespaces(ns1),
new ProjectIdsAggregator()) //the above xpath doesn't work because it doesn't have a namespace prefix
//Namespaces ns1 = new Namespaces("myprefix", "http://blah.blah/foo/schema/v2" );
I looked at jaxbDataFormat.setNamespacePrefixRef("myprefix"), but i got an error (org.apache.camel.NoSuchBeanException: No bean could be found in the registry for: myprefix of type: java.util.Map)
I'm actually quite new in the apache camel routing world, so i might be missing some basic stuff.
You don't need to change your XML at all. It is fine.
With the XML you posted and the Namespace declaration you posted, the following XPath works fine to split the XML (as an example) into two TempProject parts:
xpath("/myprefix:TempProjects/myprefix:TempProject").namespaces(ns1)
Because you declared the XML namespace like this:
Namespaces ns1 = new Namespaces("myprefix", "http://blah.blah/foo/schema/v2" )
Your XPath must use the prefix myprefix for all elements:
/myprefix:TempProjects/myprefix:TempProject

JAXB unmarshalling doesn't work when field is declared as List but doesn't work when same field is declared as ArrayList

I recently started working on a code which contains some JAXB serializable/deserializable classes. One of the classes has a few lists in it and I wanted to add a new list to it. The lists were initially declared as ArrayList. Similarly, the get methods were also returning ArrayList. I changed all of them to List and added the new list as well as List. But after that, I was not able to unmarshal the xml for this object into a JAVA object. When I change the fields back to ArrayList without any other change, the unmarshalling works fine. I have also tried to attach the DefaultValidationEventHandler to the Unmarshaller but it doesn't spit out any error while unmarshalling. Below is how the class looks like with class and variable names change
#XmlRootElement(name = "commandSet")
public class CommandSet {
private final ArrayList<Command> xCommands;
private final ArrayList<Command> yCommands;
#Override
#XmlElementWrapper(name = "xCommands")
#XmlElement(name = "xCommand", type = Command.class)
public ArrayList<Command> getXCommands() {
return this.xCommands;
}
#Override
#XmlElementWrapper(name = "yCommands")
#XmlElement(name = "yCommand", type = Command.class)
public ArrayList<Command> getYCommands() {
return this.yCommands;
}
}
When xCommands and yCommands are declared as List and the getters also return List, the unmarhsalling doesn't work.
In all the examples that I have found for unmarshalling lists, people have used List<> instead of ArrayList<>. Any ideas why is it not working for me with List<>?
Things I Noticed About Your Code
There are a couple of weird things I notice about your code that may or may not factor into your problem. At the very least I suspect the model you are experiencing the problem with is different from the model you posted in your question.
You have the fields marked final, but never initialize them.
You annotated both of the get methods with #Override but since CommandSet doesn't inherit from anything (other than Object), you aren't overriding anything.
Complete Working Example
Java Model
CommandSet
In this version of the CommandSet class I have made one of the properties type ArrayList and the other of type List to demonstrate that they both work. I have also removed the weird things about your code mentioned above.
import java.util.*;
import javax.xml.bind.annotation.*;
#XmlRootElement
public class CommandSet {
private final ArrayList<Command> xCommands;
private final List<Command> yCommands;
public CommandSet() {
xCommands = new ArrayList<Command>();
yCommands = new ArrayList<Command>();
}
#XmlElementWrapper(name = "xCommands")
#XmlElement(name = "xCommand")
public ArrayList<Command> getXCommands() {
return this.xCommands;
}
#XmlElementWrapper(name = "yCommands")
#XmlElement(name = "yCommand")
public List<Command> getYCommands() {
return this.yCommands;
}
}
Command
public class Command {
}
Demo Code
Demo
import java.io.File;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(CommandSet.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("input.xml");
CommandSet commandSet = (CommandSet) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(commandSet, System.out);
}
}
input.xml/Output
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<commandSet>
<xCommands>
<xCommand/>
<xCommand/>
</xCommands>
<yCommands>
<yCommand/>
<yCommand/>
</yCommands>
</commandSet>

How can I specify which instances of a class are unmarshalled using an XMLAdapter?

I have the following java class and have placed an XmlJavaAdapter annotation on the payerPartyReference variable. I want the adapter PartyReferenceAdapter to be used for unmarshalling ONLY this variable, not any other variables which have the same type of PartyReference, whether in this class or some other class. How can I do this? Thanks for your help!
public class InitialPayment extends PaymentBase
{
// Want PartyReferenceAdapter to be used here
#XmlJavaTypeAdapter(PartyReferenceAdapter.class)
protected PartyReference payerPartyReference;
//
// Dont want PartyReferenceAdapter to be used here
protected PartyReference receiverPartyReference;
//
protected AccountReference receiverAccountReference;
#XmlSchemaType(name = "date")
protected XMLGregorianCalendar adjustablePaymentDate;
#XmlSchemaType(name = "date")
protected XMLGregorianCalendar adjustedPaymentDate;
protected Money paymentAmount;
}
My Adapter is defined as follows:
public class PartyReferenceAdapter
extends XmlAdapter < Object, PartyReference > {
public PartyReference unmarshal(Object obj) throws Exception {
Element element = null;
if (obj instanceof Element) {
element = (Element)obj;
String reference_id = element.getAttribute("href");
PartyReference pr = new PartyReference();
pr.setHref(reference_id);
return pr;
}
public Object marshal(PartyReference arg0) throws Exception {
return null;
}
}
Field/Property Level
If you set #XmlJavaTypeAdapter on a field/property it will only be used for that property.
http://bdoughan.blogspot.com/2010/07/xmladapter-jaxbs-secret-weapon.html
Type Level
If you set #XmlJavaTypeAdapter on a type, then it will used for all references to that type.
http://bdoughan.blogspot.com/2010/12/jaxb-and-immutable-objects.html
Package Level
If you set #XmlJavaTypeAdapter on a package, then it will be used for all references to that type within that package:
http://bdoughan.blogspot.com/2011/05/jaxb-and-joda-time-dates-and-times.html

Resources