Custom model/data binder for a grpc service - spring-boot

I'm wondering if there is smth like a custom data binder (from Spring MVC) or custom model binder (from ASP.NET MVC )
in the grpc framework?
The goal is to be able to convert a protobuf object (i.e. request, transport-level DTO) into a domain entity.
E.g. instead of this code in my service implementation:
public void createCustomer(Protobuf.CreateCusomerRequest request) {...}
I want to be able to say:
public void createCustomer(Domain.CreateCusomerCommand command) {...}
Provided I have a custom converter Protobuf.CreateCusomerRequest -> Domain.CreateCusomerCommand I want to plug it into the grpc pipeline so that the runtime would call that converter to convert the request into command and then call the service passing the command instead of the request.
Any ideas are welcome.

What we did is that we implemented our own protoc compiler plugin that knows how to convert transport message to entity message. So implementation of the service looks like domainService.persist(protoRequestMessage.toDomainObject() )
The day will come and it will become open source :-)

Related

SpringBoot get InputStream and OutputStream from websocket

we want to integrate third party library(Eclipse XText LSP) into our SpringBoot webapp.
This library works "interactively" with the user (like chat). XText API requires input and output stream to work. We want to use WebSocket to let users interact with this library smoothly (send/retrieve json messages).
We have a problem with SpringBoot because SpringBoot support for WebSocket doesn't expose input/output streams. We wrote custom TextWebSocketHandler (subclass) but none of it's methods provide access to in/out streams.
We also tried with HandshakeInterceptor (to obtain in/out streams after handshake ) but with no success.
Can we use SpringBoot WebSocket API in this scenario or should we use some lower level (Servlet?) API ?
Regards Daniel
I am not sure if this will fit your architecture or not, but I have achieved this by using Spring Boot's STOMP support and wiring it into a custom org.eclipse.lsp4j.jsonrpc.RemoteEndpoint, rather than using a lower level API.
The approach was inspired by reading through the code provided in org.eclipse.lsp4j.launch.LSPLauncher.
JSON handler
Marhalling and unmarshalling the JSON needs to be done with the API provided with the xtext language server, rather than Jackson (which would be used by the Spring STOMP integration)
Map<String, JsonRpcMethod> supportedMethods = new LinkedHashMap<String, JsonRpcMethod>();
supportedMethods.putAll(ServiceEndpoints.getSupportedMethods(LanguageClient.class));
supportedMethods.putAll(languageServer.supportedMethods());
jsonHandler = new MessageJsonHandler(supportedMethods);
jsonHandler.setMethodProvider(remoteEndpoint);
Response / notifications
Responses and notifications are sent by a message consumer which is passed to the remoteEndpoint when constructed. The message must be marshalled by the jsonHandler so as to prevent Jackson doing it.
remoteEndpoint = new RemoteEndpoint(new MessageConsumer() {
#Override
public void consume(Message message) {
simpMessagingTemplate.convertAndSendToUser('user', '/lang/message',
jsonHandler.serialize(message));
}
}, ServiceEndpoints.toEndpoint(languageServer));
Requests
Requests can be received by using a #MessageMapping method that takes the whole #Payload as a String to avoid Jackson unmarshalling it. You can then unmarshall yourself and pass the message to the remoteEndpoint.
#MessageMapping("/lang/message")
public void incoming(#Payload String message) {
remoteEndpoint.consume(jsonHandler.parseMessage(message));
}
There may be a better way to do this, and I'll watch this question with interest, but this is an approach that I have found to work.

Custom Logging Interceptor is not getting triggered

We are developing a RESTFUL services in spring framework and the log framework we are using is apache CXF.
We get the request in the form of JSON from the consumers of our services and we need to mask some of the contents of JSON before printing in the log files.
We are trying to have a custom interceptor to intercept the logger messages but the request never reaches the custom interceptor class. Can you please provide your thoughts to resolve the issue.
Below are the additional details :
public class CustomLogInterceptor extends LoggingInInterceptor {
public String transform(String originalLogString) {
// Custom logic will be here to mask the originalLogString
}
}
spring context XML changes:
The CustomLogInterceptor class is included in the spring context XML file.
Any help is greatly appreciated!

Spring MVC interceptor

I need inputs related to Spring MVC, I have a URL to which a client will send a post request with an xml as the pay load. I plan to have a controller method which maps to the requested url, I want that xml to be validated/converted to an object using jaxb before controller method is executed. And also, the controller method should have only the object as the parameter to its methods and no httprequest etc.
So, how do I achieve this? Will interceptor be helpful? If yes, how will it be done?
I plan to use Spring 3.
Simply use #RequestBody in conjunction with #Valid on a method argument and that is all you need.
public void myRequestHandlingMethod(#Valid #RequestBody YourJaxbObject jaxbObject) { … }
I strongly suggest you take a look at the Spring reference guide

JIRA Rest Service with Bandana Manager

I have a JIRA plugin that I'm developing that has a REST service. That service should be able to accept POSTed requests, unmarshall some data and store it. The seemingly suggested way to do this in JIRA is to make use of the Bandana persistence framework. According to this page, I should be able to simply define a setter that Spring should call to give me my Bandana manager.
#Path("/path")
public class SCMService {
private BandanaManager bandanaManager;
// setter called by Spring
public void setBandanaManager(BandanaManager bandanaManager) {
this.bandanaManager = bandanaManager;
}
//...More methods...
}
However, when I test this, the setter is never being called and my manager is null. I'm guessing this should be as simple as registering this service with Spring for injection somehow but I can't seem to find anything like that.
How would I get my setter called? Is there a better way to do this?
Er, I'm not sure that JIRA uses Bandana in that way, though Confluence does. You can certainly post data to a JIRA rest resource and then store it using properties tables
Something like this:
#POST
#Consumes (MediaType.APPLICATION_XML)
public Response createComponentAndIssues(#Context HttpServletRequest request, ...

Validation framework for business app built on Spring 2.5

What could the best strategy for writing validation layer for mid-enterprise level business application built on Spring 2.5
I know that Spring provides facility where we can implement Validator interface and write validation logic in validate method. But this will be restricted to only web requests coming through spring controller.
I would like to develop the validation framework which can be utilized during web-services calls.
In other words, the framework can remain and be called independently without the need of implementing Validator interface and then too it can be automatically integrated into Spring MVC flow.
Hope you get my point.
The Spring Validation framework can be used outside of Spring MVC. What WebServices Stack are you using? If you are using Spring-WS (Spring's Web Services stack) they have special instructions on how to set up the validator here:
http://static.springframework.org/spring-ws/sites/1.5/reference/html/server.html#d0e2313
If you are using some other stack, it is probably easier to implement something for that stack (or find one) that will use Spring's validation framework.
Recall that the Validator interface defines two methods:
boolean supports(Class clazz)
void validate(Object target, Errors errors)
The Object target is your form object, which is the whole object representing the page to be shown to the user. The Errors instance will contain the errors that will be displayed to the user.
So, what you need to do is define an intermediary that can be called with the specifics in your form that you want to validate which are also the same as in your web service. The intermediary can take one of two forms:
(probably the best):
public interface ErrorReturning {
public void getErrors(Errors errors);
}
(this can get ugly really fast if more than two states are added):
public interface ValidationObject {
public Errors getErrors(Errors errors);
public Object getResultOfWebServiceValidation();
}
I would suggest that the first approach be implemented. With your common validation, pass an object that can be used for web service validation directly, but allow it to implement the getErrors() method. This way, in your validator for Spring, inside your validation method you can simply call:
getCommonValidator().validate(partialObject).getErrors(errors);
Your web service would be based around calls to getCommonValidator().validate(partialObject) for a direct object to be used in the web service.
The second approach is like this, though the interface only allows for an object to be returned from the given object for a web service validation object, instead of the object being a usable web service validation object in and of itself.

Resources