JAXB how to deal with the header of XML response - jaxb

I want to map the xml response to JAVA class, but how should I deal with the header?
<?xmlversion="1.0"encoding="UTF-8"standalone="yes"?>
<ns: someProperty xmlns: ns="http://example.namespace.com">
<ns: errorMsg>OK</ns: errorMsg>
<ns: list>
<ns: version>777</ns: version>
</ns: list>
</ns: someProperty>

Related

Jaxb XML marshaling ISO20022

I try to generate (java 6) xml file which should have as a root:
<Document xmlns=”urn:iso:std:iso:20022:tech:xsd:pain.001.001.03”
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”>
I have package-info is like below
#XmlSchema(
namespace="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03",
elementFormDefault=XmlNsForm.QUALIFIED,
xmlns={
#XmlNs(prefix="", namespaceURI="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03"),
#XmlNs(prefix="xsi", namespaceURI="http://www.w3.org/2001/XMLSchema-instance")
}
)
I get xml file like this
<ns2:Document xmlns:ns2="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03" xmlns:ns3="inner">
<ns2:CstmrCdtTrfInitn>
<ns2:GrpHdr>..........
..............
</ns2:CstmrCdtTrfInitn>
</ns2:Document>
I have no idea what is wrong.

marshal JAXB generated classes without XmlRootElement with Apache camel

In order to marshal jaxb classes with Apache Camel the jaxb class needs to include a XmlRootElement annotation.
When generating jaxb classes from XSD the XmlRootElement annotation might not be generated.
This will lead to an Exception during marshalling
"No type converter available to convert from type: "
As soon as I add the #XmlRootElement manually, everything works fine, but since these Jaxb classes are generated, adding the anntotation manually is no option.
According to the Camel documentation in such a case, the JaxbDataFormat can be set to 'fragement(true)
JaxbDataFormat jaxbMarshal = new JaxbDataFormat();
jaxbMarshal.setContextPath(ObjectFactory.class.getPackage().getName());
jaxbMarshal.setFragment(true);
Unfortunately I still get the same exception.
Is there a way to configure JaxbDataFormat different, i.e. to define the JAXBElement which is the root element, like I would do in Java
marshaller.marshal( new JAXBElement( new QName("uri","local"),
MessageType.class, messageType ));
or is there another strategy available to get the XML marshalled?
EDIT
the used route :
from("file://inbox").unmarshal(jaxbDataFormat)
.marshal(jaxbDataFormat).to("file://outbox");
the stacktrace:
java.io.IOException: org.apache.camel.NoTypeConversionAvailableException: No type converter
available to convert from type: com.xyz.AddressType to the required
type: java.io.InputStream with value com.xyz.AddressType#32317e9d at
org.apache.camel.converter.jaxb.JaxbDataFormat.marshal(JaxbDataFormat.java:148)
~[camel-jaxb-2.16.0.jar:2.16.0] at
org.apache.camel.processor.MarshalProcessor.process(MarshalProcessor.java:83)
~[camel-core-2.16.0.jar:2.16.0] at
...
[na:1.8.0_25] at java.lang.Thread.run(Thread.java:745) [na:1.8.0_25]
Caused by: org.apache.camel.NoTypeConversionAvailableException: No
type converter available to convert from type: com.xyz.AddressType to
the required type: java.io.InputStream with value
com.xyz.AddressType#32317e9d at
org.apache.camel.impl.converter.BaseTypeConverterRegistry.mandatoryConvertTo(BaseTypeConverterRegistry.java:185)
~[camel-core-2.16.0.jar:2.16.0] at
...
In Camel 2.17, the #XmlRootElement was not required. As of 2.21, it is. Unless...
The class org.apache.camel.converter.jaxb.FallBackTypeConverter changed it's implementation from:
protected <T> boolean isJaxbType(Class<T> type) {
return hasXmlRootElement(type) || JaxbHelper.getJaxbElementFactoryMethod(camelContext, type) != null;
}
To:
protected <T> boolean isJaxbType(Class<T> type) {
if (isObjectFactory()) {
return hasXmlRootElement(type) || JaxbHelper.getJaxbElementFactoryMethod(camelContext, type) != null;
} else {
return hasXmlRootElement(type);
}
}
By default the isObjectFactory() method returns false. If you set the property CamelJaxbObjectFactoryon your CamelContext to true. then the JaxbHelper.getJaxbElementFactoryMethod(camelContext, type) will return true and the deserialization works again as before without the need for an #XmlRootElement. For completeness:
<camelContext xmlns="http://camel.apache.org/schema/spring" id="camelContext">
<properties>
<property key="CamelJaxbObjectFactory" value="true"/>
</properties>
</camelContext>
I experienced the equivalent behaviour with JaxB (#XmlRootElement annotation not present in the generated class), and I suppose it comes from the way the root element is defined in the XML schema.
For example:
<xsd:element name="DiffReport" type="DiffReportType" />
<xsd:complexType name="DiffReportType">
...
</xsd:complexType>
it will generate you the DiffReportType class without the #XmlRootElement annotation. But if you directly define your root element as following, you'll get the annotation set in your generated class (the name of the root class is then DiffReport in my example).
<xsd:element name="DiffReport">
<xsd:complexType>
...
Note: I used the first way to define the complex types in my schema for class name consistency.
You can use the "partClass" option of the jaxb data format of camel. Your question is answered in the camel docs for jaxb, which describes how to marshall XML fragments (or XML generated without the XmlRootElement annotation).
Use partClass and provide the actual class name to which you wish to marshall. In case of marshalling you also have to provide the partNamespace which is the target namespace of the desired XML object.

JAX-RS 2 and Jersey 2 : how to pass an (hash)map on a GET request

I simply want to pass an map to my #GET method on my web services using JAX-RS 2. I want to know if it's possible and how to make it, even if GET's methods don't have any body.
Like this :
#GET
#Path(??)
#Produces({"application/xml", "application/json"})
public User find(#PathParam(??) HashMap<String, String> map) {
// work on map !
}
I've seen that it existed the MultiValued map but it's for the parameters. How to pass an map please ?
Thanks by advance !
You will need to have Jackson jars in your classpath (or any other XML / JSON to Map mapper)
You probably don't want to pass the map on the #PathParam, for aesthetical, convention and security reasons. You usually pass a JSON / XML object as the request body, e.g. using a POST / PUT
#POST
#Path("/anypath")
#Consumes({"text/xml", "application/json"})
public User find(HashMap<String, String> map) {
//magic should happen
}
Then just pass a POST / PUT request with content type application/json or text/xml that has
e.g.
{
"key1": "value1"
"key2": "value2"
}
If you have the right Jackson / Moxy etc mapper in the classpath, it will do the conversion between the JSON / XML format to a java.util.Map (or even a POJO) for you
The #Produces is only needed if you intend to also return XML / JSON, but since you are expecting either XML or JSON, then having a #Consumes makes sense here.
However, if you must pass the JSON object on a GET request, e.g. as a request param, take a look at this question: Convert JSON query parameters to objects with JAX-RS
p.s. for xml the mime is text/xml and not application/xml
Get comfortable with #Context.
#GET
public Response superSpecialSearch(#Context UriInfo info, #Context HttpHeaders headers, #Context SecurityContext securityContext) {
var iAmAMutivalueMap = info.getQueryParameters(true);
var searchResults = searchForThings( iAmAMultivalueMap );
return Response.ok(searchResults )
}

How can I override the XML serialization format on a type by type basis in servicestack

I have a type that requires custom XML serialization & deserialization that I want to use as a property on my requestDto
For JSON i can use JsConfig.SerializeFn, is there a similar hook for XML?
ServiceStack uses .NET's XML DataContract serializer under the hood. It is not customizable beyond what is offered by the underlying .NET's Framework implementation.
In order to support custom requests you can override the default request handling.
ServiceStack's Serialization and Deserialization wiki page shows different ways to customize the request handling:
Register a Custom Request DTO binder
base.RequestBinders.Add(typeof(MyRequest), httpReq => ... requestDto);
Skip auto deserialization and read directly from the Request InputStream
Tell ServiceStack to skip deserialization and handle it yourself by getting your DTO to implement IRequiresRequestStream and deserialize the request yourself (in your service):
//Request DTO
public class Hello : IRequiresRequestStream
{
/// <summary>
/// The raw Http Request Input Stream
/// </summary>
Stream RequestStream { get; set; }
}
Override the default XML Content-Type format
If you would prefer to use a different XML Serializer, you can override the default content-types in ServiceStack by registering your own Custom Media Type, e.g:
string contentType = "application/xml";
var serialize = (IRequest request, object response, Stream stream) => ...;
var deserialize = (Type type, Stream stream) => ...;
//In AppHost.Configure method pass two delegates for serialization and deserialization
this.ContentTypes.Register(contentType, serialize, deserialize);

JAXB MOXy Binder issue when using #XmlAnyElement annotation

I have an issue when using the Binder implementation in MOXy.
Here is the input XML document (input.xml)
<?xml version="1.0" encoding="utf-8"?>
<root>
<unmapped />
</root>
And now, here is the source code used to unmarshal XML into a Binder instance and then update the XML from the corresponding Java object:
JAXBContext context = JAXBContext.newInstance(Input.class);
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = documentBuilderFactory.newDocumentBuilder();
Document document = builder.parse(new File("input.xml"));
Binder<Node> binder = context.createBinder(Node.class);
Input input = (Input) binder.unmarshal(document);
binder.updateXML(input);
In the end, the very simple Input class file:
#XmlRootElement(name = "root")
public class Input {
#XmlAnyElement
protected Object[] elements;
}
When the updateXML() method is invoked, the following exception is thrown:
java.lang.NullPointerException
at org.eclipse.persistence.internal.jaxb.DomHandlerConverter.convertObjectValueToDataValue(DomHandlerConverter.java:97)
We have been able to confirm this issue and it looks like it will be a very quick fix. You can use the link below to track our progress on this issue.
http://bugs.eclipse.org/391237
UPDATE
A fix has been checked into the EclipseLink 2.5.0 stream, a nightly download can be obtained from the following location:
http://www.eclipse.org/eclipselink/downloads/nightly.php
We have also checked in a fix to the EclipseLink 2.4.2 stream. A nightly download can be obtained from the above location starting October 12, 2012.

Resources