I would like to know if Camel provides any standard aggregation strategies out-of-the-box. I have been researching but I have only be able to find some of the in the unit test. Those ones cannot be used from the actual code. I am trying to use it with Apache Camel 2.12.1 and Spring DSL.
In particular, I am looking for this one:
public Exchange aggregate(Exchange oldExchange, Exchange newExchange) {
if (oldExchange == null) {
return newExchange;
}
String oldBody = oldExchange.getIn().getBody(String.class);
String newBody = newExchange.getIn().getBody(String.class);
oldExchange.getIn().setBody(oldBody + "+" + newBody);
return oldExchange;
}
If they are not included in the package, is there any solution to do the same in Spring DSL without having to create the AggregationStrategy in code?
Thanks for the help!
A generic aggregator would not work. The example you have works if both bodies are Strings and assumes they don't need to be separated with any delimiters. But what about JSON or XML? Simple concatenating those would not work as you'd end up with 2 top level elements. I believe that's why Camel has you implement your own.
At least in version 2.13.1 (the one I'm using now), there exists a GroupedExchangeAggregationStrategy which extends AbstractListAggregationStrategy<Exchange>. The GroupedExchangeAggregationStrategy concatenates all members into a List<T>. After that, it's a matter of converting a list to another type, probably by using a POJO.
Related
I have the following method that accepts xml and I do some data feeding with the content.
I am supposed to return a SOAP message as well, something along these lines:
<ow-e:Envelope revision='2.0' xmlns:ow-e='http://www.url.com/test-envelope'>
<ow-e:Header>
<ow-e:Properties>
<ow-e:SentAt>2004-12-14T13:54:36</ow-e:SentAt>
<ow-e:Topic>SOME_STRING</ow-e:Topic>
</ow-e:Properties>
</ow-e:Header>
</ow-e:Envelope>
So right now what I am doing is the following:
String some_string = "qwe";
String response = "";
response = "<ow-e:Envelope revision='2.0' xmlns:ow-e='http://www.url.com/test-envelope'><ow-e:Header><ow-e:Properties><ow-e:SentAt>2004-12-14T13:54:36</ow-e:SentAt><ow-e:Topic>" + some_string + "</ow-e:Topic></ow-e:Properties></ow-e:Header></ow-e:Envelope>";
return response;
Which is absolutely terrible. Any idea how I can actually make it more bearable? Using a framework is not an option at the moment.
This is the first time I am dealing with SOAP messages/responses and it feels like hell coming from REST. I probably need to create some kind of hierarchy to populate the values correctly, but I am not sure how it can be done just by using Java without any frameworks.
You mentioned using frameworks is not an option, but something more lightweight may be available in your platform:
JAXB. JAXB allows you to map Java classes to XML representations using annotations. It's far better than doing marshaling and unmarshaling by hand or by concatenating or parsing strings. With properly structured and annotated POJOs, JAXB can handle things for you. You might even be able to cheat and use xjc with your WSDL file to create annotated classes with the -wsdl option (experimental though).
SAAJ. Bluntly put, SAAJ is just like a specific builder and parser for SOAP messages. It will handle the structure and namespaces for you. Speaking of which...
... the example you are showing isn't really valid SOAP message. SOAP is a protocol. You need to properly format it and use the right namespaces otherwise you are just returning some XML messages that look like SOAP, but aren't.
We are trying to create a Java client for an API created with Spring Data.
Some endpoints return hal+json responses containing _embedded and _links attributes.
Our main problem at the moment is trying to wrap our heads around the following structure:
{
"_embedded": {
"plans": [
{
...
}
]
},
...
}
When you hit the plans endpoint you get a paginated response the content of which is within the _embedded object. So the logic is that you call plans and you get back a response containing an _embedded object that contains a plans attribute that holds an array of plan objects.
The content of the _embedded object can vary as well, and trying a solution using generics, like the example following, ended up returning us a List of LinkedHashMap Objects instead of the expected type.
class PaginatedResponse<T> {
#JsonProperty("_embedded")
Embedded<T> embedded;
....
}
class Embedded<T> {
#JsonAlias({"plans", "projects"})
List<T> content; // This instead of type T ends up deserialising as a List of LinkedHashMap objects
....
}
I am not sure if the above issue is relevant to this Jackson bug report dating from 2015.
The only solution we have so far is to either create a paginated response for each type of content, with explicitly defined types, or to include a List<type_here> for each type of object we expect to receive and make sure that we only read from the populated list and not the null ones.
So our main question to this quite spread out issue is, how one is supposed to navigate such an API without the use of Spring?
We do not consider using Spring in any form as an acceptable solution. At the same time, and I may be quite wrong here, but it looks like in the java world Spring is the only framework actively supporting/promoting HAL/HATEOAS?
I'm sorry if there are wrongly expressed concepts, assumptions and terminology in this question but we are trying to wrap our heads around the philosophy of such an implementation and how to deal with it from a Java point of view.
You can try consuming HATEOS API using super type tokens. A kind of generic way to handle all kind of hateos response.
For example
Below generic class to handle response
public class Resource<T> {
protected Resource() {
this.content = null;
}
public Resource(T content, Link... links) {
this(content, Arrays.asList(links));
}
}
Below code to read the response for various objects
ObjectMapper objectMapper = new ObjectMapper();
Resource<ObjectA> objectA = objectMapper.readValue(response, new TypeReference<Resource<ObjectA>>() {});
Resource<ObjectB> objectB = objectMapper.readValue(response, new TypeReference<Resource<ObjectB>>() {});
You can refer below
http://www.java-allandsundry.com/2012/12/json-deserialization-with-jackson-and.html
http://www.java-allandsundry.com/2014/01/consuming-spring-hateoas-rest-service.html
I'm writing an API using the HalBuilder library for HAL representations.
As it stands now, I need to have two different methods for the JSON and HAL representations. As an example, my VersionResource includes the following two methods:
#GET
#ApiOperation(value = "Find all versions", response = Version.class, responseContainer = "List")
#Produces({MediaType.APPLICATION_JSON})
public Response getAsJson() {
List<Version> versions = repository.selectAll();
return Response.ok().entity(versions).build();
}
#GET
#ApiOperation(value = "Find all versions", notes="Returns HAL format", response = Representation.class, responseContainer = "List")
#Produces({RepresentationFactory.HAL_JSON})
public Representation getAsHalJson() {
List<Version> versions = repository.selectAll();
return this.versionRepresentationFactory.createResourceRepresentation(versions);
}
(Note: I'm sure there's a better way of collapsing these methods, and I'm looking into a way to do that)
But my immediate problem is that using two methods causes duplicate entries in my Swagger documentation:
Those two GET /versions are effectively the same thing, but they have different return types, so Swagger wants them to be different.
I'd like to collapse those two. What are my options here?
[It's probably worth pointing out that I'm using the Swagger Maven plugin to generate my documentation. The application is also using Guice for DI and Jersey for JSON representations.]
I read in https://github.com/swagger-api/swagger-spec/issues/146#issuecomment-59082475:
per design, we don't overload response type definitions for the same response code.
So I think the Maven plugin creates an invalid Swagger document.
What are your options?
Be patient and watch these Swagger issues: https://github.com/swagger-api/swagger-spec/issues/146 and https://github.com/swagger-api/swagger-spec/issues/182
Don't use Swagger
I want to set a property on a Camel Exchange and then use this property when saving the file. In my camel dsl I have the following:
.process(processorToSetExhangeProperty) // sets the property <uid> on the exchange
.to("file:/tmp?fileName=file-" + property("uid") + ".xml")
The file is being saved as:
"file-property{uid}.xml" though
My processor is as follows:
#Override
public void process(Exchange exchange) throws Exception {
UUID uuid = UUID.randomUUID();
exchange.setProperty("uid", uuid.toString());
exchange.setOut(exchange.getIn());
}
Any thoughts on what may be going wrong or how I can achieve this?
The to in the Camel is not interpreted at runtime.
You should use recipientList if you want to construct your URI dynamically.
See https://camel.apache.org/manual/latest/faq/how-to-use-a-dynamic-uri-in-to.html
UPDATED
New answer accepted above instead of this previous one:
The answer is [was]:
.to("file:/tmp?fileName=file-${property.uid}") + ".xml")
This simple expression pulls in the exchange property. For a complete list of what you can pull in, see the Simple Expression Language Reference
Please use toD() if you want a dynamic destination. The expression in the parenthesis is interpreted with simple() language. No simple() needed.
toD("file:/tmp?fileName=file-${exchangeProperty.uid}.xml")
But pay attention to not creating too many endpoints.
https://camel.apache.org/components/3.18.x/eips/toD-eip.html
GWT 2.1.1 has very good framework - RequestFactory with all the EntityProxy and stuff.
I am looking for a way to serialize runtime instances that implement EntityProxy for debugging and logging etc. I do not care for format as long as it human readable.
To be more specific I would like to have something like the provided by Apache Commons Lang
ReflectionToStringBuilder
May be there is some way to use the JSON serialization mechanics that GWT has inside? if yes how to make it a bit more readable?
import org.apache.commons.lang.builder.ReflectionToStringBuilder;
String stringRep = ReflectionToStringBuilder.toString(this);
There are at least 2 solutions:
First: Based on the idea by Thomas Broyer
public static String toString(EntityProxy entityProxy)
{
DefaultProxyStore store = new DefaultProxyStore();
Swap.requestFactory.getSerializer(store).serialize(entityProxy);
return store.encode();
}
Which produce something like this:
{"V":"211","P":{"1#2#biz.daich.swap.shared.dto.UserAccountProxy":{"O":"PERSIST","R":"2","Y":1,"T":"biz.daich.swap.shared.dto.UserAccountProxy","P":{"id":null,"items":null,"channelId":null,"lastActive":1296194777916,"name":null,"emailAddress":"test#example.com","lastReported":1296194777916,"lastLoginOn":1296194777916}}}}
Second: Based on the AutoBean framework
public static String toJson(EntityProxy entityProxy)
{
return AutoBeanCodex.encode(AutoBeanUtils.getAutoBean(entityProxy)).getPayload();
}
Which produce string like
{"emailAddress":"test#example.com","lastActive":1296194777916,"lastLoginOn":1296194777916,"lastReported":1296194777916}
The second is just what I need - it more readable in log.
I haven't tried it but have a look at RequestFactory#getSerializer, there's some sample code in the javadoc for the ProxySerializer.
If using the method
toJson(EntityProxy entityProxy)
change this to
toJson(BaseProxy proxy)
and then you can log Value and Entity Proxy objects.