Apache Camel: Convert JSON to a POJO using Camel methods - java

I have a REST server which sends JSON in response body. I have recently started reading about Apache Camel. I use following to send requests to my REST service.
from("direct:start").setHeader("token", simple("234da"))
.to("http://localhost:8088/foo/bar/?foo1=bar1");
Now the response will be a JSON, is there any way I get this JSON directly into a POJO using some method ahead of to() (something like this)?
to("http://localhost:8088/foo/bar/?foo1=bar1").toPOJO();
I would prefer a non Spring solution.
Thanks

Little details from my side - although late
Create jsonFormatter and then unmarshal with class you need
JsonDataFormat jsonDataFormat = new JsonDataFormat(JsonLibrary.Jackson);
this can be used in marshalling
from("direct:consume-rest")
.log("calling bean method...")
.to("http://localhost:8080/greeting?name=baba")
//.process(svProcessor) // any extra process if you want
.unmarshal().json(JsonLibrary.Jackson, Greeting.class)
.bean(GreetingHelper.class, "print")
.log("converted to bean ...")
.end()
;
Helper class method
public void print (#Body Greeting greeting) {

Apache Camel provides a component to marshal and unmarshal POJO to and from JSON.
In your case, it would be :
from("direct:start").setHeader("token", simple("234da"))
.to("http://localhost:8088/foo/bar/?foo1=bar1")
.unmarshal().json();
By the way, you may need to configure your json library to do it and I suggest you take look at the official configuration.

Related

Apache Camel modifies JSON when CONTENT_TYPE is application/json

I'm building my REST-API with Apache Camel and I use "bindingMode(RestBindingMode.json)" for my restConfiguration with jetty. In one of my Processors I set the "body" of the "out" object with a String that actually is a JSON object. When I set the Exchange.CONTENT_TYPE to "text/plain" the response comes in as expected and can directly be parsed to a JSON object.
{"mockBasicData":"123"}
But when I set the Exchange.CONTENT_TYPE to "application/json" or if I don't set it at all, Camel manipulates the body and escapes it, like it wouldn't already be a JSON object.
{\"mockBasicData\":\"123\"}
Is there a way to avoid that auto-escaping in Camel, as I need the CONTENT_TYPE to be "application/json"?
The typical use of the RestBinding is to specify the marshalling from POJO to json or xml. If I understand correctly what you said, you are converting a json string body to json, right ?
If so, have you tried to set the body of the out object with the JSON Object it-self ?
Please also note the following:
From Camel 2.16.3 onwards the binding from POJO to JSon/JAXB will only
happen if the content-type header includes json or xml. This allows
you to specify a custom content-type if the message body should not
attempt to be marshalled using the binding. This is useful if, for
example, the message body is a custom binary payload.
Adding "bindingMode(RestBindingMode.off)" directly to the route (not to rest()!) solved it for me.

How does biding happens in JAX-Rs xml to object?

I have been exploring on how to consume the web services and I found a good articles on JAX-Rs and it is the way to consume Rest Webservices. my task is to hit the URL which returns the XML as response and should be converted into Object which I have achieved using following code.
client = ClientBuilder.newClient();
//example query params: ?q=Turku&cnt=10&mode=json&units=metric
target = client.target(
"http://api.openweathermap.org/data/2.5/weather")
.queryParam("appid", apikey)
.queryParam("units", "metric")
;
And here is the piece of code which will map my XML response to java object
Example exampleObject = target.request(MediaType.APPLICATION_XML).get(Example.class);
This works fine, but the issue is my lead is saying use JIBX since it's faster.
Question 1 : How does target.request converts the xml response (does it use jibx or jaxb etc ?? )
Question 2 : If I have use JIBX I need to download the response as stream and do the marshalling and unmarshalling which I found not a right way to consume webservices, I am I right??
Please do help on this.
1: JAX-RS uses MessageBodyReaders to convert the HTTP entity stream into an object. By default, all JAX-RS implementations are required to ship a MessageBodyReader (and Writer) that uses JAXB to serialize/deserialize to/from XML when the content type is application/xml.
2: If you want to use something other than JAXB to deserialize XML, you could write your own MessageBodyReader that consumes “application/xml”. That would override the built-in JAXB reader.
An example of how to do this is available here:
https://memorynotfound.com/jax-rs-messagebodyreader/
Hope this helps, Andy

Jersey MOXy JSON Case-Insensitive Unmarshalling

I'm trying to setup a REST-service with Jersey 2.x that consumes a JSON-Response by POST using MOXy.
Everything works fine as long as all the JSON-attributes are named exactly like the properties in my POJO. Is there any way to configure MOXy so that it allows case-insensitive unmarshalling? For example: Match JSON-attribute "testid" to "TestID" in my POJO.
The POJO-Field is camel case, but the incoming JSON-Attribute could be in any case and my sevice should be able to process it nonetheless.
Thank you for your help!
Without defining a custom unmarshaller (or parsing directly from the HttpServletRequest) you can only define the expected key name, as pointed out in the comment of rmlan, with the JAXB annotation #XmlElement(name="testid"). However this will not protect your service from a JSON input with a key like "TestID" or "TESTID".

Camel CXF Soap Client calling web service with multiple input parameters

I'm using Camel and have generated code from a WSDL using CXF. I generated a client stub and the implementation appears like this:
SetDeviceDetailsv4 port = ss.getSetDeviceDetailsv4Port();
com.vodafone.gdsp.ws.SetDeviceDetailsv4_Type _setDeviceDetailsv4_parameters = null;
com.vodafone.gdsp.ws.GdspHeader _setDeviceDetailsv4_gdspHeader = null;
com.vodafone.gdsp.ws.SetDeviceDetailsv4Response _setDeviceDetailsv4__return = port.setDeviceDetailsv4(_setDeviceDetailsv4_parameters, _setDeviceDetailsv4_gdspHeader);
System.out.println("setDeviceDetailsv4.result=" + _setDeviceDetailsv4__return);
As you one can see, the port takes two parameters and returns the response, which I want to delegate back to my Camel Route. What's the best way to implement this in Camel? I already have my CXF Enpoint defined, I'm just struggling with the DSL Routing part of it. Should I add a processor like what is found in this link? Apache Camel and web services
Thanks
You can use jax-ws client (implement as bean) and use it in camel DSL. JAX-WS client bean definition takes service class/interface and allow you configure additional properties like SSL config & etc. In route, we can use it as bean. It takes JAXB generated Request object (WSDL request object) as input and returns the JAXB generated Response Object (WSDL response object). To convert you pojo to JAXB classes, Dozer framework can be used or custom mapping can be also used.
Jax-WS client is also flexible to take XML as request and response. In that case, properties need to be set as DATAFORMAT as PAYLOAD.
I'm not sure if this is the correct way to do it but I added both of my "input" objects as a Camel Header, then I wrote a processor that grabbed what I needed and put the two objects that the service call needed as parameters.
public void process(Exchange exchange) throws Exception {
Message inMessage = exchange.getIn();
gdspHeader = inMessage.getHeader(GDSP_HEADER, com.vodafone.gdsp.ws.GdspHeader.class);
commModule = inMessage.getHeader(COMM_MODULE_HEADER, resmed.hi.ngcs.datastore.model.CommModule.class);
SetDeviceDetailsv4_Type deviceDetails = createSetDeviceDetailsv4(commModule);
List<Object> params = new ArrayList<>();
params.add(deviceDetails);
params.add(gdspHeader);
inMessage.setBody(params);
}
`

Using JERSEY and JACKSON to parse a POST request with unknown structure

I'm in a current situations in which I have a REST endpoint that accepts POST of incoming JSON messages.
The thing is that I don't think I can specify the POJO object so Jackson can marshall the JSON into the POJO object. Reason for this is that I don't have control of what comes to that endpoint, and number of fields and type can change over time, thus, defining a POJO before hand seems not an option.
So I guess the question is....can I simply tell Jackson to don't do any marshalling and give the String of the response? I can deal with that later with JSONObject-JSONArray or Gson maybe. Say I'd have a method like this:
#POST
#Path("/callback")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public Response facebookUpdate(String json) {
//Do something with the json response...
}
If this is not feasible with Jersey-JAX...any other alternatives?
Thanks!
Alejandro
The easiest is to simply not inject the json into the method and use the request object instead:
public Response facebookUpdate(#Context request) {
try(InputStream is=request.getEntityInputStream()) {
...
}
}
From the request you can then get an inputstream for the request and parse it whichever way you like.
For parsing I can recommend my own jsonj library, which was written specifically to support open ended scenarios like you describe and uses jackson to deserialize into heavily customised implementations of java.util.Map and java.util.List. Gson is also a very solid choice.
If you want to do this application wide, you can instead write your own #Provider and do the same there. This is how I use my library currently actually.

Categories

Resources