I have two grpc service in same project built using spring boot. And I am trying to call Y service in X service using autowiring but I am not able to pass required StreamObserver to the Y service method.
Below is the code.
XService.java
#GrpcService
public class XService extends XServiceImplBase {
#Autowired
YService yService;
#Override
public void getInfo(RequestId request, StreamObserver<Info> responseObserver) {
// Not abe to pass the second argument here
yService.getData(request, <observer>);
}
}
YService.java
#GrpcService
public class YService extends YServiceImplBase {
#Override
public void getData(RequestId request, StreamObserver<Data> responseObserver) {
// Code Logic
}
}
Thanks in Advance!
Create a client with same name as server in application.properties and call with stub. Worked for me
Related
I developed 3 things.
a interceptor-library with my custom interceptor.
Application
another library. A-library
This interceptor in interceptor-library intercepts a request to the controller and reads the header value.
ex)Interceptor-library code
public class MyInterceptorConfig implements WebMvcConfigurer {
private final MyInterceptor interceptor;
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(interceptor);
}
public class MyInterceptor implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// get request.getHeader....
My application has dependency in this interceptor-library and A-library in build.gradle.
ex)Application's build.gradle (Actual working Application)
dependencies {
implementation myLibrary('interceptor-library')
implementation myLibrary('A-library')
The problem is that the other libraries that this application uses are also using the Controller.
ex) A-library
#RestController
public class ALibraryController{
#GetMapping("/api/library-works")
public ResponseEntity<?> test() {
During application operation, the interceptor works well for the controller declared "inside" the application.
However, the interceptor does not work on the controller in the A-library that the application uses.
(Interceptor can't intercept /api/library-works)
I thought the interceptor would intercept all the controllers in the "Application" and the controllers in "all the libraries" that the application has. ....
Is there a way to solve it?
Plz help me ......
I need to create objects with user defined data at runtime.TO do that i have used
google guice assisted inject.But when i run my test it throws null pointer exception.Please let me know where i made the mistake.
IArtifacts Interface
public interface IArtifacts {
MavenMetaDataXMLDTO getArtifactsVersions();
}
ArtifactsService.java
public class ArtifactsService implements IArtifacts {
private ProductProfile productProfile;
#Inject
public ArtifactsService(#Assisted ProductProfile productProfile){
System.out.println(productProfile.getArtifactManagementURL());
this.productProfile=productProfile;
}
#Override
public MavenMetaDataXMLDTO getArtifactsVersions() {
System.out.println(productProfile.getArtifactManagementURL());
return null;
}
}
ArtifactsFactory Interface
public interface ArtifactsFactory {
IArtifacts create(ProductProfile productProfile);
}
Module Class
#Override
protected void configure() {
install(new FactoryModuleBuilder().implement(IArtifacts.class,ArtifactsService.class).build(ArtifactsFactory.class));
}
TestArtifacts.java
public class TestArtifacts {
#Inject // this obj is null
private ArtifactsFactory artifactsFactory;
private IArtifacts s;
public TestArtifacts(){
}
public void getdata(){
//Pass custom data to factory
this.s=artifactsFactory.create(Products.QA.get());
System.out.println(s.getArtifactsVersions());
}
}
REST ENDPOINT
#GET
#Path("/test")
#Produces(MediaType.APPLICATION_JSON)
public String getartifacts(){
new TestArtifacts().getdata();
}
you created an Instance of the class TestArtifacts on your own in your Rest Endpoint class but all of your classes need to be created by the Guice Framework and not by you.
So how should the Guice Framework inject something into your class when you create them with new? You also need to inject the class TestArtifacts into your Rest Endpoint and your Rest Endpoint has to be created by Guice too.
Update:
Maybe this link will help you
https://sites.google.com/a/athaydes.com/renato-athaydes/posts/jersey_guice_rest_api
I was able to fix it adding following code snippet to below TestArtifacts.java class
TestArtifacts.java
private Injector injector=Guice.createInjector(new MYModule());//where implemented configuration
#Inject
private ArtifactsFactory artifactsFactory=injector.getInstance(ArtifactsFactory.class);
#Async method in #Service annotated class in standalone Spring Boot application doesn't run asynchronously. What am I doing wrong?
When I run the same method directly from main class (#SpringBootApplication annotated), it works. Example:
Main class
#SpringBootApplication
#EnableAsync
public class Application implements CommandLineRunner {
#Override
public void run(String... args) throws Exception {
// here when I call downloadAnSave() it runs asynchronously...
// but when I call downloadAnSave() via downloadAllImages() it does not run asynchronously...
}
}
and my service class (and here asynchronous behavior doesn't work):
#EnableAsync
#Service
public class ImageProcessorService implements IIMageProcessorService {
public void downloadAllImages(Run lastRun) {
// this method calls downloadAnSave() in loop and should run asynchronously....
}
#Async
#Override
public boolean downloadAnSave(String productId, String imageUrl) {
//
}
}
Calling async method from within the same class would trigger the original method and not the intercepted one.
You need to create another service with the async method, and call it from your service.
Spring creates a proxy for each service and component you create using the common annotations. Only those proxies contain the wanted behavior defined by the method annotations such as the Async. So, calling those method not via the proxy but by the original naked class would not trigger those behaviors.
Workaround is:
#EnableAsync
#Service("ip-service")
public class ImageProcessorService implements IIMageProcessorService {
#Autowired
#Qualifier("ip-service")
ImageProcessorService ipService;
public void downloadAllImages(Run lastRun) {
// this method calls downloadAnSave() in loop and should run asynchronously....
ipService.downloadAnSave(productId, imageUrl);
}
#Async
#Override
public boolean downloadAnSave(String productId, String imageUrl) {
//
}
}
With such approach you call method of proxy, not the class instance.
The same approach can be used with other tools working with proxies, e.g. #Transactional etc.
Is there any way to inject dependencies into manually created objects?
public class MyCommand {
#Inject Repository repository;
}
public Repository {
#Inject EntityManager em;
}
MyCommand command = new MyCommand();
Repository is properly registered the jersey ResourceConfig and can be injected in objects that are created through the CDI container for example a resource class.
But since I create the Command myself the #Inject annotation gets ignored.
Is there a way to get a registered class beside #Inject and #Context?
Something like Application.get(Repository.class)
public class MyCommand {
Repository repository;
public MyCommand() {
repository = Application.get(Repository.class);
}
}
----- EDIT -----
Thanks to your help and some rethinking I found a solution for my problem.
The first thing is that it's possible to inject the ServiceLocator without any preperation into you objects.
The second thing is that I moved from normal commands with a execute method to a a command bus system.
The reason for that is I have no controle over the creation of commands so there clean way to get dependencies injected.
The new approach looks like this:
class CommandBus {
private final ServiceLocator serviceLocator;
#Inject
public CommandBus(ServiceLocator serviceLocator) {
this.serviceLocator = serviceLocator;
}
public void dispatch(Command command) {
Class handlerClass = findHandlerClassForCommand(command);
CommandHandler handler = (CommandHandler) serviceLocator.getService(handlerClass);
handler.handle(command);
}
}
interface CommandHandler {
void handle(Command command);
}
interface Command {
}
class ConcreteCommand implements Command {
// I'm just a dto with getters and setters
}
class ConcreteHandler implements CommandHandler {
private final SomeDependency dependency;
#Inject
public ConcreteHandler(SomeDependency dependency) {
this.dependency = dependency;
}
#Override
public void handle(ConcreteCommand command) {
// do some things
}
}
And in my resources I have something like this:
#Path("/some-resource")
class Resource {
#Context
private CommandBus bus;
#POST
#Consumes(MediaType.APPLICATION_JSON)
public void runCommand(ConcreteCommand command) {
bus.dispatch(command);
}
}
As pointed out by jwells - HK2 is an injection framework :)
I spent some time looking into it - I have to say, I find it much more complicated than say guice or spring. Maybe this is due to the fact that I use Dropwizard and it makes it not as easy to access the Service locators.
However, here is how you can do that.
First, you will have to get a reference to your ServiceLocator. It must be the same ServiceLocator that jersey is using as well. You can access it for example like:
How to get HK2 ServiceLocator in Jersey 2.12?
In my example code I will use an event listener, which is due to my Dropwizard Setup.
You now have 2 choices: Register your command with your Service Locator and have the injection framework handle creation, or pass the ServiceLocator to your command in order to use it.
I wrote up a quick example using Dropwizard and jersey:
public class ViewApplication extends io.dropwizard.Application<Configuration> {
#Override
public void run(Configuration configuration, Environment environment) throws Exception {
environment.jersey().register(new ApplicationEventListener() {
#Override
public void onEvent(ApplicationEvent event) {
if (event.getType() == ApplicationEvent.Type.INITIALIZATION_FINISHED) {
ServiceLocator serviceLocator = ((ServletContainer) environment.getJerseyServletContainer())
.getApplicationHandler().getServiceLocator();
ServiceLocatorUtilities.bind(serviceLocator, new AbstractBinder() {
#Override
protected void configure() {
bind(new Repository("test")).to(Repository.class);
bind(MyCommandInjected.class).to(MyCommandInjected.class);
}
});
MyCommandInjected service = serviceLocator.getService(MyCommandInjected.class);
MyCommandManual tmp = new MyCommandManual(serviceLocator);
}
}
#Override
public RequestEventListener onRequest(RequestEvent requestEvent) {
return null;
}
});
}
#Override
public void initialize(Bootstrap<Configuration> bootstrap) {
super.initialize(bootstrap);
}
public static void main(String[] args) throws Exception {
new ViewApplication().run("server", "/home/artur/dev/repo/sandbox/src/main/resources/config/test.yaml");
}
#Path("test")
#Produces(MediaType.APPLICATION_JSON)
public static class HelloResource {
#GET
#Path("asd")
public String test(String x) {
return "Hello";
}
}
public static class Repository {
#Inject
public Repository(String something) {
}
}
public static class MyCommandInjected {
#Inject
public MyCommandInjected(final Repository repo) {
System.out.println("Repo injected " + repo);
}
}
public static class MyCommandManual {
public MyCommandManual(final ServiceLocator sl) {
Repository service = sl.getService(Repository.class);
System.out.println("Repo found: " + service);
}
}
}
In the Run method, i get access to my ServiceLocator. I bind my classes in there (so there is an example of how to do that). You can alternatively also register Binders with jersey directly - they will use the correct ServiceLocator.
The 2 classes MyCommandInjected and MyCommandManual are examples of how you can create this command.
The relevant line for you is probably:
Repository service = sl.getService(Repository.class);
This asks the service locator for a new instance of the Repository.
Now, this is just a quick example. I am much more fond of the guice bridge than using HK2 directly :) I find it much easier to use and much clearer. Using the guice-jersey-bridge you can do everything through guice and it will automatically do the right thing.
Hope that brings some inside,
Artur
You can use the inject method of ServiceLocator in order to inject already created objects. ServiceLocator is the basic registry of HK2 and should be available in your resource.
I have a Java server which serves my clients (Not application server).
Now I'm interested to add REST support. I've initialized a Jetty server and created few REST resources.
My question is: How can I pass parameters at the creation of the REST resources?
Normally I would prefer in the constructor of each resource, but I don't control it.
I understand there is a way to inject dependencies. How to do it using Jersey 2.5??
Thank you!
Define your Application
public class MyApplication extends ResourceConfig {
public MyApplication() {
register(new FacadeBinder());
register(JacksonFeature.class);
register(MyEndpoint.class);
}
Configure injection
public class FacadeBinder extends AbstractBinder {
#Override
protected void configure() {
bind(MyManager.class).to(MyManager.class);
}
}
Inject configured classes in your endpoint
#Path("/jersey")
public class MyEndpoint {
#Inject
MyManager myManager;
...
}
I'm not sure to understand what do you mean with dependencies.
You should check this: https://jersey.java.net/documentation/latest/user-guide.html#d0e1810
Another option besides using dependency injection is to instantiate and register the REST endpoint yourself. Jersey allows you to do this in a very similar fashion as dependency injection as shown in Dymtro's example. Borrowing liberally from Dymtro, define your endpoint:
#Path("/jersey")
public class MyEndpoint {
private MyManager myManager;
public MyEndpoint(MyManager myManager) {
this.myManager = myManager;
}
....
}
Define your application:
public class MyApplication extends ResourceConfig {
public MyApplication(MyManager myManager) {
register(JacksonFeature.class);
register(new MyEndpoint(myManager));
....
}
}