spring XD - http-client add application/json header - spring-integration

I've installed Spring XD in my PaaS environment and for legacy issue I'm stuck with version 1.0.0.M1. ( see reference doc).
My goal is to call a http rest API using the http-client module. My stream definition is:
http | httpclient --url='''<my_url>''' --http-method=POST --mappedRequestHeaders=HTTP_REQUEST_HEADERS | log --expression=#root
Unfortunately, since the http module only sends the payload to the httpclient, the httpclient returns a 415 error due to the absence of the content-type header.
Considering that I can neither add new modules nor modify existing ones (in such a version you can only reference to the spring repository), I would like to use a tranform module to inject the content-type header.
How can I achieve such a goal?
Many thanks for your help.
EDIT:
I just found that httpclient processor (link) supports headersExpression A SpEL expression used to derive the http headers map to use. However:
--headers-expression='{Content-Type:'application/json'}'
Gives the following parse exception:
org.springframework.expression.spel.SpelEvaluationException: EL1008E:
(pos 1): Property or field 'Content' cannot be found on object of type 'org.springframework.messaging.support.GenericMessage' - maybe not public?

See GH issue for more StackTrace.
First of all it isn't Spring XD any more. Spring Cloud Dataflow is different product and its behavior maybe not that which you had with Spring XD before.
Second: it is in version 1.0.0.RC1 already. So, consider to upgrade.
Now on the problem. Look:
headersExpression
A SpEL expression used to derive the http headers map to use.
So, this expression must return a Map and it is confirmed by the code:
if (properties.getHeadersExpression() != null) {
Map<?, ?> headersMap = properties.getHeadersExpression().getValue(message, Map.class);
Now let's take a look into the problem:
org.springframework.expression.spel.SpelEvaluationException: EL1008E:(pos 1): Property or field 'Content' cannot be found on object of type 'org.springframework.messaging.support.GenericMessage' - maybe not public?
org.springframework.expression.spel.ast.PropertyOrFieldReference.readProperty(PropertyOrFieldReference.java:224) ~[spring-expression-4.2.4.RELEASE.jar!/:4.2.4.RELEASE]
org.springframework.expression.spel.ast.PropertyOrFieldReference.getValueInternal(PropertyOrFieldReference.java:94) ~[spring-expression-4.2.4.RELEASE.jar!/:4.2.4.RELEASE]
org.springframework.expression.spel.ast.PropertyOrFieldReference.getValueInternal(PropertyOrFieldReference.java:81) ~[spring-expression-4.2.4.RELEASE.jar!/:4.2.4.RELEASE]
org.springframework.expression.spel.ast.OpMinus.getValueInternal(OpMinus.java:98) ~[spring-expression-4.2.4.RELEASE.jar!/:4.2.4.RELEASE]
OpMinus is a root of cause. So, SpEL treats Content-Type expression as a minus operator.
Sad, of course, but the workaround is like wrapping the key into quotes as well:
--headers-expression={'Content-Type':'application/json'}

Related

No MessageBodyWriter for Single

I'm trying to use resteasy-rxjava2 to provide an XML document using jaxb, within a vertx application (using a non-vertx legacy library we have). But I get:
Could not find MessageBodyWriter for response object of type:
org.jboss.resteasy.rxjava2.propagation.ContextPropagatorOnSingleAssemblyAction$ContextPropagatorSingle of media type:
application/xml;charset=UTF-8
From what I can tell, this comes down to the difference between a MessageBodyWriter and the AsyncResponseProvider that is in the resteasy-rxjava2 dependency for a Single (SingleProvider).
I have the following resteasy service definition
#GET
#Path(FdsnwsPaths.QUERY)
#Produces(MediaType.APPLICATION_XML)
#Stream
// CHECKSTYLE:OFF too many parameters
public Response getQuery(...)
How do I get resteasy to properly serve the data asynchrously, using the SingleProvider or otherwise.
The #Get method must return the Single explicitly or it doesn't work. (Can't use Response or Object). In my case, the Single contains the jaxb xml root element.
#GET
#Path(FdsnwsPaths.QUERY)
#Produces(MediaType.APPLICATION_XML)
#Stream
public Single<FDSNStationXML> getQuery(...)
Then, to make things more complicated, in order to handle specific exception types and map them to specific response status codes, I have to create a custom ExceptionMapper which creates the Response object I used to be able to create directly in the method. (in resteasy-vertx, I found no documentation on how to do this, but in my case, I am creating my own VertxRestEasyDeployment object so I can register the class of the ExceptionMapper(s) like this:
VertxResteasyDeployment deployment = new VertxResteasyDeployment();
deployment.getActualProviderClasses().addAll(providerClasses);
For reference, this is all being done with:
RestEasy 5.0.3.Final (including resteasy-rxjava2)
RxJava 2.2.20
Vertx 3.9.5

Can SpEL in Spring Integration Router use Java's String class methods

This is an extension question to How to use SpEL to read payload and header content in a Spring Integration Router
Technologies in my project
Spring Boot 2
Spring Integration (XML style)
Java 8
Tomcat 9.x/Liberty 19.0.0.1
As a part of my Spring Integration project (REST API with an inbound-http-gateway, that takes an XML input and produces an XML output), this is the setup for my question:
There is a Builder-pattern-based Java object (say, MyPOJO) that is the payload in the flow.
MyPOJO has a String property/instance variable (say, String response) along with a getter and setter.
Somewhere in the flow, MyPOJO gets built and response gets set.
Inside response, there is a keyword/specific piece of text that will determine the further course of the flow.
This said, is it possible to write a Router (using XML configuration) that can check if the response inside Message<MyPOJO> contains that keyword/specific piece of text to determine where to go next?
Illustratively, something like this:
<int:router input-channel="inputChannel" expression="payload.getResponse().contains("keyword")">
<int:mapping value="true" channel="oneRoute"/>
<int:mapping value="false" channel="anotherRoute"/>
</int:router>
When I do this and launch the application, the error is:
nested exception is org.xml.sax.SAXParseException; lineNumber: 44; columnNumber: 98; Element type "int:router" must be followed by either attribute specifications, ">" or "/>"
Specifically speaking, the expression="payload.getResponse().contains("keyword")" part seems to be having an issue getting resolved and this could be something to do with the quotation marks around the keyword
Any help on this is greatly appreciated.
Sincerely,
Bharath
OK. I see you have an XML syntax error. The fix is like this:
expression="payload.getResponse().contains('keyword')"
The keyword is in single quotes, not double.
This is definitely how SpEL works: when you would like to specify a literal in the expression, you need to use single quotes: https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#expressions-evaluation

Binding Exception with Ninject

We have a central logging component which I am now trying to use in a WebJob that I am developing. I am basically following this example. My Activator is identical, I have the bindingModule that has my Bind statements in it. One thing I have done differently here is to use the method versions:
Kernel.Bind(typeof(IExternalSystemLogger)).To(typeof(ExternalSystemLogger));
instead of the generic versions in the example. I currently have constructor injection implemented but I have also set up the parameter injection as per the example. Which ever way I try to do this I end up with the error:
Error indexing method 'Functions.ProcessQueueMessage' ---> System.InvalidOperationException: Cannot bind parameter
or
a null reference exception (with parameter injection). Further into the error I am told that
Make sure the parameter Type is supported by the binding
which is the part that I am finding it difficult to resolve. I have looked at the available method calls on the config object available in WebJob.program but none seems to work. What is it I need to call so that I am correctly resolving my type when I am using a QueueTrigger or BlobTrigger?

NonProxyHosts usage with Groovy HttpBuilder

If I create my httpBuilder as shown below (assume that a proxyUsername IS set, so setCredentials is called), then calls to httpAddress-es that are passed in properly are routed through the proxy. However, the Application has some http calls that are within the local network. Can http.nonProxyHosts be used to work around this and bypass the Proxy? If so, how? Use System.setProperty? Or something on HttpBuilder?
HTTPBuilder httpBuilder = new HTTPBuilder(httpAddress)
httpBuilder.setProxy(webProxyHost, webProxyPort, webProxyProtocol)
if (proxyUsername) {
httpBuilder.client.getCredentialsProvider().setCredentials(
new AuthScope(webProxyHost, webProxyPort),
new UsernamePasswordCredentials(proxyUsername, proxyPassword))
}
}
In the code above, all of the various named elements (webProxyHost, etc) are declared as String and set accordingly.
In answer to the question in the above comment, our primary 'nonProxyHost' need was for 'localhost' which is there by default. Thus this ceased to be an issue. Did not ever really find out how to accomplish this as it is somewhat version-specific on HttpClient.
You can set the System property:
System.setProperty('http.nonProxyHosts', myNonProxyHosts)
However, if you call 'setProxy' on HttpBuilder, even if you call 'useSystemProperties' it will not. This is in their documentation, just not obvious!
Finally, you might be able to call:
httpBuilder.client.params.setParameter('http.nonProxyHosts', myNonProxyHosts)
But I do not know for sure if that is the property name and documentation of those properties is hard to find. Worse - those 'params' are deprecated - you are supposed to use the better 'config' classes, though once again finding comprehensive documentation on all the parameters for that is not the easiest! Wish I could have been of more help!

Gateway interface breaking after upgrading from SI v 2.2 to v 3.0.5

After upgrading SI from v 2.2 to v 3.0.5 I'm getting an error for the following gateway. Has the behaviour of gateway interfaces changed in v 3.x to not accept Message types?? Any hints would be appreciated as to why this is happening.
org.springframework.expression.spel.SpelEvaluationException: EL1004E:(pos 8): Method call: Method sendStat(my.domain.ReplyStatEvent) cannot be found on com.sun.proxy.$Proxy22 type]
void sendStat(#Payload Message<? extends LiveStatEvent> message);
ReplyStatEvent extends LiveStatEvent and the gateway is invoked using a service activator definition like this:
<int:service-activator ref="liveStatsGateway" method="sendStat" />
It works fine after changing the interface to the following.
void sendStat(#Payload LiveStatEvent message);
Even if it had worked before, it doesn't mean that it was correct syntax.
If your gateway's param is marked with #Payload, it is assumed that Framework will inject to that arg a payload of the Message, but not entire Message.
We just fixed that ambiguity and show you now that your use-case isn't correct.
So, if you want to use just payload, you'll be able to specigy just payload type for param.
The #Payload isn't necessary is this case. It is required, if your method has several args and Framewrok can't determine which one for payload.
If you want get deal with whole Message, there is just enough to have an arg of that type.
Anyway a combination #Payload Message<?> isn't correct. Hence you just need to fix those Migration Guide cases.

Resources