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
Related
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
I have taken the MixedType example code that comes with the java stream client (https://github.com/GetStream/stream-java) and added a update step using updateActivities. After the update the activity stored in stream loses the 'type' attribute. Jackson uses this attribute when you get the activities again and it is deserialising them.
So I get:
Exception in thread "main" Disconnected from the target VM, address: '127.0.0.1:60016', transport: 'socket'
com.fasterxml.jackson.databind.JsonMappingException: Could not resolve type id 'null' into a subtype of [simple type, class io.getstream.client.apache.example.mixtype.MixedType$Match]
at [Source: org.apache.http.client.entity.LazyDecompressingInputStream#29ad44e3; line: 1, column: 619] (through reference chain: io.getstream.client.model.beans.StreamResponse["results"]->java.util.ArrayList[1])
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:148)
at com.fasterxml.jackson.databind.DeserializationContext.unknownTypeException(DeserializationContext.java:849)
See here where I have updated the example:
https://github.com/puntaa/stream-java/blob/master/stream-repo-apache/src/test/java/io/getstream/client/apache/example/mixtype/MixedType.java
Any idea what is going on here?
The issue here is originated by Jackson which cannot get the actual instance type of an object inside the collection due to the Java type erasure, if you want to know more about it please read this issue: https://github.com/FasterXML/jackson-databind/issues/336 (which also provides some possible workarounds).
The easiest way to solve it, would be to manually force the value of the property type from within the subclass as shown in the example below:
#JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type", visible = true)
#JsonSubTypes({
#JsonSubTypes.Type(value = VolleyballMatch.class, name = "volley"),
#JsonSubTypes.Type(value = FootballMatch.class, name = "football")
})
static abstract class Match extends BaseActivity {
private String type;
public String getType() {
return type;
}
}
static class VolleyballMatch extends Match {
private int nrOfServed;
private int nrOfBlocked;
public VolleyballMatch() {
super.type = "volley";
}
public int getNrOfServed() {
return nrOfServed;
}
public void setNrOfServed(int nrOfServed) {
this.nrOfServed = nrOfServed;
}
public void setNrOfBlocked(int nrOfBlocked) {
this.nrOfBlocked = nrOfBlocked;
}
public int getNrOfBlocked() {
return nrOfBlocked;
}
}
static class FootballMatch extends Match {
private int nrOfPenalty;
private int nrOfScore;
public FootballMatch() {
super.type = "football";
}
public int getNrOfPenalty() {
return nrOfPenalty;
}
public void setNrOfPenalty(int nrOfPenalty) {
this.nrOfPenalty = nrOfPenalty;
}
public int getNrOfScore() {
return nrOfScore;
}
public void setNrOfScore(int nrOfScore) {
this.nrOfScore = nrOfScore;
}
}
I cant unmarshall xml because don't understand how to annotate object class in the another object. Please help.
XML:
<?xml version="1.0" encoding="UTF-8"?>
<ODZ xmlns="http://www.company.com/1.0" >
<Data DataID="ZZZ">
<UserData UserKey="user_001">
<UserEvent>...</UserEvent>
</UserData>
</Data>
</ODZ>
Container classes:
I. First level with link to the second (ODZ -> Data).
#XmlAccessorType(XmlAccessType.NONE)
#XmlRootElement(name = "ODZ", namespace = "http://www.company.com/1.0")
public class ODZContainer {
private ImportContainer importContainer;
#XmlElement (name = "Data", type=ImportContainer.class)
public ImportContainer getImportContainer() {
return importContainer;
}
}
II. Second level with link to the third level(Data -> UserData).
#XmlAccessorType(XmlAccessType.NONE)
#XmlRootElement(name = "Data")
public class ImportContainer {
private String DataID;
private ArrayList<UserDataBean> userDataBean;
#XmlElement (name = "UserData", type=UserDataBean.class)
public ArrayList<UserDataBean> getUserDataBean() {
return userDataBean;
}
#XmlAttribute(name = "DataID")
public String getDataID() {
return DataID;
}
}
III. Third level with link to the fourth level(UserData-> UserEvent).
#XmlAccessorType(XmlAccessType.NONE)
#XmlRootElement(name = "UserData")
public class UserDataBean {
private ArrayList<UserEventBean> userEventData;
private String userEventID;
#XmlAttribute(name = "UserKey")
public String getUserEventID() {
return userEventID;
}
#XmlElement (name = "UserEvent", type=UserEventBean.class)
public ArrayList<UserEventBean> getUserEventBean() {
return userEventData;
}
}
The namespace qualification in your JAXB metadata does not match your XML. You can use the package level #XmlSchema annotation to specify the namespace qualification for your model.
#XmlSchema(
namespace = "http://www.company.com/1.0",
elementFormDefault = XmlNsForm.QUALIFIED)
package example;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
For More Information on JAXB and Namespaces
http://blog.bdoughan.com/2010/08/jaxb-namespaces.html
Notes About Your Metadata
Since the type of the ArrayList is already specified, you don't need to specify it via the #XmlElement annotation. It doesn't hurt, but its not necessary.
#XmlElement (name = "UserData", type=UserDataBean.class)
public ArrayList<UserDataBean> getUserDataBean() {
return userDataBean;
}
#XmlAccessorType(XmlAccessType.NONE) means that nothing is mapped unless it is explicitly annotated. This may or not be what you want. You may find the following article useful:
http://blog.bdoughan.com/2011/06/using-jaxbs-xmlaccessortype-to.html
I'm running a sample (which i can't find anymore) from Blaise Doughans blog on Glassfish 3 using EclipseLink 2.5 MOXy for JAXB service.
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Company {
#XmlElementWrapper(name="employees")
#XmlElement(name = "employee", type=Employee.class)
private List<Employee> employees;
}
#XmlAccessorType(XmlAccessType.FIELD)
public class Employee {
private String id;
private String name;
}
I added some annotations to the classes, to produce the desired json structure:
{
"employees": [
{
"id": "1",
"name": "Jane Doe",
"report": []
}
]
}
When i try to unmarshal this JSON it sadly fails, returning an object with an empty employees list.
Adding another element to the JSON list OR removing the #XmlElementWrapper works.
But i want the key element to be named employees, so i have to use the wrapper annotation, or not?
Edit:
public class MyApplication extends Application {
#Override
public Set<Class<?>> getClasses() {
HashSet<Class<?>> set = new HashSet<Class<?>>(2);
set.add(MOXyJsonProvider.class);
set.add(Index.class);
return set;
}
#Override
public Set<Object> getSingletons() {
MOXyJsonProvider moxyJsonProvider = new MOXyJsonProvider();
moxyJsonProvider.setAttributePrefix("#");
moxyJsonProvider.setFormattedOutput(true);
moxyJsonProvider.setIncludeRoot(false);
moxyJsonProvider.setMarshalEmptyCollections(true);
moxyJsonProvider.setValueWrapper("$");
moxyJsonProvider.setWrapperAsArrayName(true);
HashSet<Object> set = new HashSet<Object>(1);
set.add(moxyJsonProvider);
return set;
}
}
I have confirmed the issue that you are seeing and have opened the following bug:
http://bugs.eclipse.org/411001
UPDATE
The fix for this issue has been checked into the EclipseLink 2.5.1 and 2.6.0 streams. You can get the fix in the corresponding nightly builds from the following link starting June 19, 2013:
http://www.eclipse.org/eclipselink/downloads/nightly.php
I have a Object with two fields "name" and "address". JAXB ignores the empty elements while transforming the object into XMl.
For ex: if I have name="xyz" and address=null then out will be
<name>xyz</name>
but what I want as an output as
<name>xyz</name>
<address></address>
I have seen the option #XmlElement(nillable="true") but this gives the output as
<name>xyz</name>
<address xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
Please help me getting the desired output.
Thanks in advance.
A JAXB (JSR-222) implementation will output an empty String "" value as an empty element. You can set the address property to this to get the desired effect.
UPDATE #1
I have updated my question. Basically the address element is NULL. Is
this solution applicable to that as well?
You could leverage Marshal Event Callbacks to adjust the value of address.
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.*;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Customer {
private String name;
private String address;
private void beforeMarshal(Marshaller marshaller) {
if(null == address) {
address = "";
}
}
private void afterMarshal(Marshaller marshaller) {
if("".equals(address)) {
address = null;
}
}
}
UPDATE #2
The only concern is that if I have 10 fields in the class I will have
to write if for all the fields. Is there any other solution?
If you use EclipseLink MOXy as your JAXB provider (I'm the MOXy lead), then you could use an XmlAdapter for this use case.
XmlAdapter (StringAdapter)
package forum14691333;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class StringAdapter extends XmlAdapter<String, String> {
#Override
public String marshal(String string) throws Exception {
if(null == string) {
return "";
}
return string;
}
#Override
public String unmarshal(String string) throws Exception {
if("".equals(string)) {
return null;
}
return string;
}
}
package-info
Then if you specify it at the package level it will apply to all mapped fields/properties of type String within that package.
#XmlJavaTypeAdapter(value=StringAdapter.class, type=String.class)
package forum14691333;
import javax.xml.bind.annotation.adapters.*;
For More Information
http://blog.bdoughan.com/2012/02/jaxb-and-package-level-xmladapters.html
http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html
If you use EclipseLink MOXy as your JAXB provider then you could use
#XmlNullPolicy(emptyNodeRepresentsNull = true, nullRepresentationForXml = XmlMarshalNullRepresentation.EMPTY_NODE)
#XmlElement(name = "address", nillable = true)
private String address;
By using this way, you don't have to write adapter for all the fields
Simply set an empty string default value on the field.
#XmlElement(required="true")
private String address = "";
and you will get
<address></address>