Spring AMQP XML Message Converter - spring-amqp

I'm trying to read a message from RabbitMQ using spring-amqp and convert it to my domain object.
I've successfully configured it to receive a json message and map it to my domain object using the Jackson2JsonMessageConverter class.
Now, I'm trying to use the ContentTypeDelegatingMessageConverter and add the ability to receive XML (in addition to JSON).
But, unfortunately, I'm having a hard time finding either a built-in message converter that handles XML or documentation on how to configure one of the built-in converters to handle XML.
The documentation on how to handle XML using spring-amqp seems pretty sparse. So, I'd appreciate a code sample that adds to mine below (please see TODO):
#Bean
MessageConverter messageConverter() {
ContentTypeDelegatingMessageConverter messageConverter = new ContentTypeDelegatingMessageConverter();
Jackson2JsonMessageConverter jsonMessageConverter = new Jackson2JsonMessageConverter();
messageConverter.addDelegate("application/json", jsonMessageConverter);
// TODO: messageConverter.addDelegate("application/xml", xxx);
return messageConverter;
}
Thanks!!

Use a MarshallingMessageConverter configured with a Spring OXM marshaller/unmarshaller - see Spring Framework OXM documentation for information about the various marshallers/unmarshallers using a number of different technologies.

Related

Propagate X-B3-TraceId between applications using SNS and SQS

I have 2 spring based applications both of them uses spring-sleuth.
Application-1:
AmazonSNS snsPublisher;
snsPublisher.publish(message)
I would like to add MDC context here somehow, so that application-2 can use the same context. Is there any integration that is provided to achieve this ?
Application-2:
#SqsListener
public void process(String message, #Headers Map<String, MessageAttributeValue> sqsHeaders)
When I receive the MDC context(traceId) set by other application in headers, then I need an integration which can add that same MDC context in application-2 as well. So that, when I look at logs I will have a whole picture of what has happened with that request combining both of these applications.

Slow swagger Scanning - s.d.s.w.s.ApiListingReferenceScanner : Scanning for api listing references

I am trying to add a grpc protofile to my swagger-ui. I am consuming a grpc webservice which needs a protofile as input. The input to my spring boot restful webservice needs to have that same grpc structure as its interface. I recevied a jar from the individual that made the protofile and imported it to my webserivce. When I try to add the #ResponseBody tag around the object from the protofile jar, my app hangs on this in the console at startup:
s.d.s.w.s.ApiListingReferenceScanner : Scanning for api listing references
Thanks,
Brian
Never return entity objects in controller method.
in my case. my Controller methods takes this parameter.
"#AuthenticationPrincipal UserSession userSession"
when i exlude UserSession object swagger back to normal.
There were 2 way to do that
first is "#ApiIgnore #AuthenticationPrincipal UserSession userSession"
second is in swaggerConfig class
private Class[] clazz = {UserSession.class};
Docket().ignoredParameterTypes(clazz)
Incase someone needs a solution, what I did was as a work around for now.
in my service's code (response is a String)
return JsonFormat.printer().print(myProtoObject);
in my client's code:
Builder b = ProtoObject.newBuilder();
JsonFormat.parser().merge(result.getBody(), b);
ProtoObject protoObject = b.build();

How to generate dynamic response from the stubs without re-generating it again?

I know Groovy DSL is able to generate a random value.
I have used stub runner server so that I can hit the stubs from the server and get response. however when I refresh the browser I get the same response again. The Groovy DSL is just generating a static stub, and is always returning the same response as I requested.
How can I get a random response without re-generate the stubs in this case?
Also a similar question was asked by someone a year ago, it was written in the answer that it is not possible. Is it still not possible or there is a way now to do it?
You would have to create your own WireMock extension. Check this section of the docs: https://docs.spring.io/spring-cloud-contract/docs/current/reference/html/advanced.html#customization-wiremock
95.5.6 Registering Your Own WireMock Extension WireMock lets you register custom extensions. By default, Spring Cloud Contract
registers the transformer, which lets you reference a request from a
response. If you want to provide your own extensions, you can register
an implementation of the
org.springframework.cloud.contract.verifier.dsl.wiremock.WireMockExtensions
interface. Since we use the spring.factories extension approach, you
can create an entry in META-INF/spring.factories file similar to the
following:
org.springframework.cloud.contract.verifier.dsl.wiremock.WireMockExtensions=\
org.springframework.cloud.contract.stubrunner.provider.wiremock.TestWireMockExtensions
org.springframework.cloud.contract.spec.ContractConverter=\
org.springframework.cloud.contract.stubrunner.TestCustomYamlContractConverter
The following is an example of a custom extension:
TestWireMockExtensions.groovy.
package org.springframework.cloud.contracthttps://docs.spring.io/spring-cloud-contract/docs/current/reference/html/advanced.html#customization-wiremock.verifier.dsl.wiremock
import com.github.tomakehurst.wiremock.extension.Extension
/** * Extension that registers the default transformer and the custom one */ class TestWireMockExtensions implements WireMockExtensions { #Override List<Extension> extensions() { return [
new DefaultResponseTransformer(),
new CustomExtension() ] } }
class CustomExtension implements Extension {
#Override String getName() { return "foo-transformer" } }
You would have to create an extension that modifies the response and generates a piece of it. That extension needs to be available both on the consumer and the producer sides.

Should image be base64 encoded in a JSON message or returned as BytesMessage in Spring AMQP?

I have setup basic Request/Reply Messaging via spring amqp using POJOs and these are exchanged over RabbitMQ via a JSON message converter.
My response pojo's payload so far has been simple strings but now I need to reply back with an image at times as well.
Q1) What would be the best way to handle this? Should the image be base64 encoded as the payload string for the JSON message?
Q2) Is it possible to simply return the image as a BytesMessage instead?
Q2.a) Would spring-amqp be able to handle two separate listeners, one that returns POJOs and another that returns BytesMessage? I would think not but here's some pseudo-code around what I'm asking:
<listener-container>
<listener ref="requestHandlerA" method="handleMessage" queue-names="#{requestQueue.name}" />
<listener ref="requestHandlerB" method="handleMessage" queue-names="#{requestQueue.name}" />
</listener-container>
public class RequestHandlerA {
public ResponseDelegatePojo handleMessage(RequestDelegatePojo requestDelegate) {...}
}
public class RequestHandlerB {
public BytesMessage handleMessage(RequestDelegatePojo requestDelegate) {...}
}
Q2.b) OR ... If the MessageListener returns an Object (may be a POJO sometimes, may be a BytesMessage at other times) ... would the spring-amqp framework be able to adjust accordingly at runtime to send back POJO serialized as json sometimes and the BytesMessage as-is at other times?
Two listeners like that won't work - it will simply create two competing consumers on the same queue. One solution would be to use different queues (and different listeners).
If you want to use the same queue for both request types, probably the simplest solution would be to have your listener POJO return Object (POJO or byte[]) (Q2b) and use a custom MessageConverter.
The custom messageConverter would be pretty simple; assuming you always get JSON on the inbound, it would always delegate to a JsonMessageConverter in fromMessage() and on the outbound side (toMessage) should delegate to either a JsonMessageConverter or a SimpleMessageConverter:
if (object instanceof byte[]) {
return this.simpleMessageConverter.toMessage(object, messageProperties);
else {
return this.jsonMessageConverter.toMessage(object, messageProperties);
}
The SimpleMessageConverter will set the contentType property to application/octet-stream but you can change that if you want after calling its toMessage method (message.getMessageProperties().setContentType(...);.

Using the Json.NET serializer in an MVC4 project

I'm starting to learn Json.NET, but I'm having trouble using its serializer. I have a new MVC4 project with a Web.API service:
public class PTE_TestsController : ApiController {
PTE_TestsRepository _repository = new PTE_TestsRepository();
// GET /api/PTE_Tests/5
public HttpResponseMessage<string> Get(int id) {
try {
PTE_Test test = _repository.GetTest(id);
return new HttpResponseMessage<string>(JsonConvert.SerializeObject(test));
} catch {
return new HttpResponseMessage<string>(HttpStatusCode.NotFound);
}
}
}
JsonConvert.SerializeObject() works as expected and returns a string. My Web.API controller returns that as part of an HttpResponseMessage. The end result, when viewed in Fiddler, is not JSON data, but JSON data being serialized again (I think):
"{\"ID\":1,\"Name\":\"Talar Tilt\",\"TagID\":1,\"PracticeID\":1,
\"SpecificAreaID\":1,\"TypeID\":1,\"VideoID\":1,\"PicID\":1}"
Does someone know how to turn off the default serializer so I can use Json.NET directly? By the way, I'm not using the default serializer because I can't figure out how to make it work with complex objects (PTE_Test will eventually contain members of type List).
Alternately, it will also solve my problem if someone can explain how to use the default serializer with complex objects. MSDN's explanation didn't help me.
Rick Strahl has a blog on that here with a code that works.
As others have pointed out, you need to create a formatter and replace the DataContractSerializer with the JSON.NET serializer. Although, if you're not in a rush for JSON.NET specifically, rumor has it that next beta/rc is going to have support for JSON.NET built in.
Conceptually, however, you're missing part of the magic of WebAPI. With WebAPI you return your object in it's native state (or IQueryable if you want OData support). After your function call finishes the Formatter's take over and convert it into the proper shape based on the client request.
So in your original code, you converted PTE_Test into a JSON string and returned it, at which point the JSON Formatter kicked in and serialized the string. I modified your code as follows:
public class PTE_TestsController : ApiController {
PTE_TestsRepository _repository = new PTE_TestsRepository();
public HttpResponseMessage<PTE_Test> Get(int id) {
try {
PTE_Test test = _repository.GetTest(id);
return new HttpResponseMessage(test);
} catch {
return new HttpResponseMessage<string>(HttpStatusCode.NotFound);
}
}
}
Notice how your function returns PTE_Test instead of string. Assuming the request came in with a request header of Accept = application/json then the JSON formatter will be invoked. If the request had a header of : Accept = text/xml the XML formatter is invoked.
There's a decent article on the topic here. If you're a visual learner, Scott Gu shows some examples using fiddler in this video, starting around 37 minutes. Pedro Reys digs a little deeper into content negotiation here.
The way to do this is to use formatters.
Check out: https://github.com/WebApiContrib/WebAPIContrib/tree/master/src/WebApiContrib.Formatting.JsonNet.
Json.NET support will be in the RC release of Web API.

Resources