#Gateway(payloadExpression="..") vs #Payload("...") - annotations

Spring integration documentation explains that a payload expression must be specified when declaring a gateway from an interface method with no arguments, so that the framework knows what payload should be set on the generated message.
However, if I do the following:
<int:gateway id="myGateway"
service-interface="com.example.MyGateway"
default-request-channel="requestChannel"
default-reply-channel="replyChannel" />
for the following interface:
package com.example;
public interface MyGateway {
#Gateway(payloadExpression = "''")
String doSomething();
}
this leads to an error: "receive is not supported, because no pollable reply channel has been configured".
This works instead:
public interface MyGateway {
#Payload("''")
String doSomething();
}
Indeed, the same above documentation specifies that the payload should be specified with either #Payload or with payload-expression attribute on method elements.
However, as a user, I find it quite surprising that setting a payload expression through the #Gateway annotation does not work here, especially because the same annotation works in other contexts.
Is this on purpose or an oversight?

It is not clear why the documentation is confusing, but feel free to suggest improvements.
The #Gateway annotation is intended for configuration when using annotation-based configuration
https://docs.spring.io/spring-integration/docs/5.3.2.RELEASE/reference/html/messaging-endpoints.html#gateway-configuration-annotations
The docs clearly state to use #Payload or payload-expression when using XML configuration.

Related

Where to put #OpenAPIDefinition?

The documentation for defining general API information using the quarkus-smallrye-openapi extension is extremely sparse, and does not explain how to use all the annotations for setting up the openApi generation.
For some background, I am using a clean and largely empty project (quarkus version1.0.1.FINAL) generated from code.quarkus.io, with a single class defined as followed (With the attempted #OpenAPIDefinition annotation):
#OpenAPIDefinition(
info = #Info(
title = "Custom API title",
version = "3.14"
)
)
#Path("/hello")
public class ExampleResource {
#GET
#Produces(MediaType.TEXT_PLAIN)
public String hello() {
return "hello";
}
}
I have eventually found that general api information (contact info, version, etc) through much digging is defined using the #OpenAPIDefinition annotation, but when used on my existing endpoint definition, no changes are made to the generated openapi specification. What am I doing wrong?
Try putting the annotation on the JAX-RS Application class. I realize you don't need one of those in a Quarkus application, but I think it doesn't hurt either. For reference in the specification TCK:
https://github.com/eclipse/microprofile-open-api/blob/master/tck/src/main/java/org/eclipse/microprofile/openapi/apps/airlines/JAXRSApp.java

ProtoBuf - Azure Service Fabric

I am looking at replacing the default serializer for RPC in ASF. This involves implementing a few interfaces, one of which is passed between services communicating via RPC
public interface IServiceRemotingResponseMessageBody
{
void Set(object response);
object Get(Type paramType);
}
As the implementation needs to be serializable, the obvious ProtoBuf implementation is something like
[ProtoContract]
public class ProtoBufRemotingResponseBody : IServiceRemotingResponseMessageBody
{
[ProtoMember(1)]
public object Value { get; set; }
public void Set(object response)
{
Value = response;
}
public object Get(Type paramType)
{
return Value;
}
}
Unfortunately this fails miserably with
No serializer defined for type: System.Object
Is there a workaround here? System.Object has no contract, but the OOTB DataContract serializer can, as can MessagePack here, but these are not schematized which creates versioning headaches when using reliable collections. I have tried using a common base type, but Value can be IEnumerable<T> or T etc.
Can anyone help?
Thanks,
KH
At the moment, protobuf-net does not have good support for object, except via some messy hacks. The simplest to try (just to see if it works for your scenario) is to find the "dynamic types" flag on that proto-member attribute and set it to true. This library-specific hack burns some type metadata into to data to allow it to work with unknown types, but it is far from perfect.
The "better" fix here would involve me finding the time to implement the "any" feature (added to the Google library relatively recently, around the time of proto3 IIRC). This works broadly similarly, but would be implemented in a cross-library way.

Registering a type with both EnableClassInterceptors and WithParameter

I'm having an issue with Autofac where it seems like EnableClassInterceptors is interfering with my ability to use .WithParameter(...). When the constructor is being called on Service using the code below, someString is not being populated. Notes:
I've tried using ResolvedParameter instead, it does not help (note: my Resolved parameter still includes the name of the parameter when I tried that)
If I remove EnableClassInterceptors and InterceptedBy, the parameter does get populated properly. This, however, isn't a valid solution as I need the interceptors.
Re-ordering WithParameter, EnableClassInterceptors, and InterceptedBy does not help.
Looking at Type Interceptors, specifically the "Class Interceptors and UsingConstructor" section, on docs.autofac.org, it mentions that using EnableClassInterceptors will cause ConstructUsing to fail. I think something similar might be happening with my scenario below.
Snippet of my registration code looks like this:
var builder = new ContainerBuilder();
builder.RegisterType<Dependency>.As<IDependency>.InstancePerLifetimeScope();
builder.RegisterType<Service>()
.As<IService>()
.WithParameter(new NamedParameter("someString", "TEST"))
.EnableClassInterceptors()
.InterceptedBy(typeof(LogExceptionsInterceptor));
Service's constructor looks something like this:
public class Service : IService
{
public Service(IDependency dependency, string someString)
{
if(dependency == null)
throw ArgumentNullException(nameof(dependency));
if(someString == null)
//**throws here**
throw ArgumentNullException(nameof(someString));
}
}
[Guess] What I'm thinking is happening is that when EnableClassInterceptors is called, a proxy class is generated with a constructor that works on top of the existing one, but the parameter names do not copy over into the proxy class/constructor.
Is this a problem? Is there a way to form the registration that allows both WithParameter and EnableClassInterceptors to be used together? Is it a bug in Autofac?
Your guess is correct: the generated proxy class does not keep the constructor parameter names.
Currently there is no way to influence this in DynamicProxy so this is not a bug of Autofac (although this edge case currently not documented on the Autofac documentation website).
This is how your original Service class's parameters look like:
typeof(Service).GetConstructors()[0].GetParameters()
{System.Reflection.ParameterInfo[2]}
[0]: {ConsoleApplication10.IDependency dependency}
[1]: {System.String someString}
But the generated proxy does not keep the names:
GetType().GetConstructors()[0].GetParameters()
{System.Reflection.ParameterInfo[3]}
[0]: {Castle.DynamicProxy.IInterceptor[] }
[1]: {ConsoleApplication10.IDependency }
[2]: {System.String }
So you have two not very robust options to workaround this limitation with WithParameter:
use the TypedParamter with string as the type:
.WithParameter(new TypedParameter(typeof(string), "TEST"))
However if you have multiple paramters with the same type this won't work
use the PositionalParameter in this case you need to add 1 if the type is proxied
.WithParameter(new PositionalParameter(2, "TEST"))
Another options would be to don't use a primitive string type but create a wrapper e.g. MyServiceParameter or create another service which can provide these string configuration values to your other services.

Ribbon: Unable to set default configuration using #RibbonClients(defaultConfiguration=...)

The #RibbonClients annotation allows us to customise the Ribbon configuration per client. This process is described in the documentation at http://projects.spring.io/spring-cloud/spring-cloud.html#_customizing_the_ribbon_client
This is all fine. I tried to use the same approach to override the default configuration that should be applied to all my clients. So I defined the following configuration class and made sure it is considered by the component scan:
#Configuration
#RibbonClients(defaultConfiguration = MyDefaultRibbonConfig.class)
public class MyRibbonAutoConfiguration {
}
Unfortunately, it turns out that MyDefaultRibbonConfig is not taken into account when building the ribbon client's application context. A quick look and trace at RibbonClientConfigurationRegistrar let me think my #RibbonClients(default=...) annotation is unconditionally overridden by the one provided by org.springframework.cloud.netflix.ribbon.eureka.RibbonEurekaAutoConfiguration.
However, it works if the #RibbonClients annotation is set on a inner class instead of a top-level class:
#Configuration
public class MyRibbonAutoConfiguration {
#Configuration
#RibbonClients(defaultConfiguration = MyDefaultRibbonConfig.class)
static class SubConfig {
}
}
This is a side-effect the strategy followed by RibbonClientConfigurationRegistrar to give a name to the discovered configuration beans:
registerClientConfiguration(registry,
"default." + metadata.getEnclosingClassName(),
attrs.get("defaultConfiguration"));
The configuration for annotations declared on a top-level class are then registered with a bean name set to default.null.defaultConfiguration - so the next one overrides the previous (not sure the order is predictable though).
This behaviour looks strange to me. Did I miss something? Should I proceed differently?
This was an issue in SpringCloud-Netflix 1.0.1. See https://github.com/spring-cloud/spring-cloud-netflix/issues/374 for more information.

Implementing Hypermedia in RESTful JAX-RS Apache CXF

I am working in a RESTful application developed in Apache CXF and I would like to introduce hypermedia functionality to it.
Most of our jaxrs:serviceBeans follow this template:
#GET
#Path("/{exampleId}")
public ExampleJSON get(#PathParam("exampleId") Integer exampleId) {
ExampleJSON example;
// Load data from repository here...
// Add link to self.
String href = javax.ws.rs.core.Link.fromResource(ExampleService.class).build().getUri().toString();
// HypermediaLink is a custom object to hold a "href" and "rel" strings
HypermediaLink linkToSelf = new HypermediaLink();
linkToSelf.setHref(href + example.getId());
linkToSelf.setRel("self");
// Inherited method, just adds a HypermediaLink to a collection in the parent class
example.addHypermediaLink(linkToSelf);
// Return JSON compatible object, JACKSON will serialize it nicely.
return example;
}
This is the basic concept. Keep in mind that I simplified this code for explanation purposes; so, it can be easily understood.
This code works fine; but I am wondering if there is a better way to do this with Apache CXF. I have some ideas for how to enhancing it; however, it will require some custom annotations.
I see some examples using Jersey, but I would like to stick with Apache CXF.
Any help would be appreciated.
Thanks
I would leverage some features of JAX-RS and / or Jackson to implement the link adding under the hood at the serialization level. So you wouldn't need to have a specific field for the link within the bean itself.
You could implement a custom MessageBodyWriter to generate a different JSON payload (for example) for your POJOs than the default. So you could dynamically add the link.
See this answer for more details: How to write an XML MessageBodyWriter provider with jersey.
If you use Jackson for the serialization, you could implement a custom serializer. Note that this is generic and will work for all supported format of Jackson.
Below is a sample code:
public class LinkBeanSerializer extends JsonSerializer<SomeBean> {
#Override
public void serialize(SomeBean bean, JsonGenerator jgen,
SerializerProvider provider) throws IOException,
JsonProcessingException {
jgen.writeStartObject();
// Fields
jgen.writeNumberField("id", bean.getId());
// Things could be generic using reflection
// Link
String href = javax.ws.rs.core.Link.fromResource(SomeBean.class).build().getUri().toString();
HypermediaLink linkToSelf = new HypermediaLink();
linkToSelf.setHref(href + bean.getId());
linkToSelf.setRel("self");
jgen.writeObjectField("hypermediaLink", linkToSelf);
jgen.writeEndObject();
}
}
Note that we could make this serializer more generic I think (something like extends JsonSerializer<Object>)
See this answer for more details: Processing JSON response using JAX-RS (how to register the custom serializer within JAX-RS, ...).
Perhaps implementing a WriterInterceptor could solve your problem but there is impact on the beans since you need to have field hypermediaLink. The interceptor could be responsible of filling the field.
See this answer for more details: Jersey Update Entity Property MessageBodyWriter.
IMO the more convenient solution is the second one. It's transparent and support all the formats supported by Jackson.
Hope it helps you,
Thierry