Execute main-method inside spring-application upon URL call - java

I've got a spring-application (Spring Roo uses Spring MVC) on a Tomcat-server.
There are some java-files inside the application. One contains a main-method.
I'd like to be able to execute this main-method when I call a URL like http://localhost/execute
How can I map this?

First you need to be able to handle http://localhost/execute request. You can use servlet or spring-mvc. I don't know Spring Roo, but it most likely has some mechanism to handle HTTP calls (maybe this will help: Spring MVC /Roo - Request method 'GET' not supported).
Once you are able to run arbitrary code on incoming HTTP request, simply call:
SomeClass.main();
or:
SomeClass.main(arg1, arg2);
insider your servlet/controller/whatever.

Maain is just a regular static method. Just call it: MyClass.main("aaa", "bbb"); where MyClass is the class you want to call, "aaa" and "bbb" are the "command line" parameters.

Morning,
calling a method from a class requires you to instatiate this class (or have it instatiated by Spring) and then to call your main method on that object.
As noted in the comments, since your main-Method is a static method, you can call it just on the class level, like this: MyClass.main(args)
Does that help you?

Related

How #ControlAdvice captures exceptions?

I'm on learning phase of Spring boot
I've code where its written like below to handle exception in whole application. Not sure how its working, but I have NoDataFoundException class in code and its being used at place where no data found issues are happening.
#ControlAdvice
class ControllerAdvisor {
#ResponseStatus(HttpStatus.BAD_REQUEST)
#ExceptionHandler(NoDataFoundException.class)
#ResponseBody
public ResponseEntity<Object> handleNodataFoundException(
NoDataFoundException ex, WebRequest request) {
Map<String, Object> body = new LinkedHashMap<>();
body.put("timestamp", LocalDateTime.now());
body.put("message", "No cities found");
return new ResponseEntity<>(body, HttpStatus.NOT_FOUND);
}
Want to know, how and when handleNodataFoundException method automatically gets called when NoDataFoundException instance gets created ?
Does spring calls this method handleNodataFoundException on the basis of #ExceptionHandler(NoDataFoundException.class) which is bind to method itself and moreover irrespective of name of the method ?
how spring looks for parameters required for above method ? what if it has more parameters in it ?
This is done by proxying (Proxy.class).
Proxying is a mechanism in which a kind of pseudo class is created dynamically and mimics your own class (same methods) and is used to intercept all the method calls. This way it can act before and after the method calls as it please, and in the middle call the real method that you developed.
When you create a #Service in Spring, or a #Stateless in EJB, you never actually create the instances, you delegate the instance creation on the framework (Spring or EJB). Those frameworks proxy your classes and intercept every call.
In your case, and putting it simple, the proxy has a catch around the real call to your method, that catch captures exceptions, and acts upon the framework configuration built based on all the annotations that you created (#ControlAdvice, #ExceptionHandler and so on). And so it can call the handleNodataFoundException(...) in the cases that you defined with annotations.
Update visualization via stacktrace
For instance, if you have two Spring #Component (or #Service, #Repository or whatever), and one calls the other one in a plain call, and you get an exception, in the stacktrace you see plenty of method calls (involving all kind of different classes) between your two component classes, all those are proxies and framework classes that take care of proxying, invoking, configuration and all the magic that the framework does. And everything is triggered by the proxy of your second component just before calling the real code that you developed, because the first component, at execution time, doesn't really call an instance of your class, but an instance of the proxy of your class that the framework created.
If you run a plain main, with two classes calling one to the other, instantiated by you with new, you will only see 3 lines in the stacktrace, because there the instances are plain instances created by you.

Run annotation processor before every method invocation in a service

I am building a service with RestAPI's. I want to put a custom annotation as mentioned below.
#CustomAnnnotation
public APIResponse apiMethod(APIRequest request) {
}
Functionality of this custom annotation :
Whenever there is a request to this apiMethod, before the execution of this method , i want to call an API in different server with some of the request parameters from this function. Example mentioned below. Basically for every method invocation i want to call a different server.
Instead of doing this
public APIResponse apiMethod(APIRequest request) {
newServiceClient.newAPI(request.getName())
}
I want to do this functionality by using a custom annotation. I know that i can use interceptors to intercept this request and call the API. Is there any other way ?
Edit :
To summarise this question. There is a method(This might not be API start point. It can also be a normal method in your application) in my java code. Whenever i annotate this method, for every invocation of this method in application, i want do some functionality. I want to have this in annotation because i am thinking of providing a library for this annotation so that any function can be annotated

multiple parameters with no annotation error on Javax WS and retrofit when I use "suspend" , how to handle?

I am creating a very basic controller using Kotlin with javax.ws and retrofit libraries.
I created a controller like this...
#POST
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
suspend fun sayHello(request: StudentRequest): StudentResponse {
that basically calls another service.
But when I run the app I get this error:
[FATAL] Method public final java.lang.Object MyResource.sayHello(StudentRequest,kotlin.coroutines.Continuation) on resource class MyResource contains multiple parameters with no annotation. Unable to resolve the injection source.;
handlerConstructors=[org.glassfish.jersey.server.model.HandlerConstructor#a0bf272]},
definitionMethod=public final java.lang.Object my.org.package.MyResource(sayHello,k**otlin.coroutines.Continuation**),
the weird part is that are couple of similar posts Jersey #PathParam : contains multiple parameters with no annotation
How can I pass multiple parameter to restful webservice using http post
https://github.com/dropwizard/dropwizard/issues/1115
but are not the same because my problem is with my ONLY parameter
There is no missing tag to my body request and I basically dont know what to look for at this point, any idea what could be wrong with this?
After debugging I noticed that there are two parameters, mine and one injected by Kotlin, when removing the "suspend" everything works fine, but then I am not able to make my async call.
To use coroutines from blocking code you need to use coroutine builder (e.g. launch {} or runBlocking {}).
Unfortunately in this case you can't just mark your glassfish controller as a suspendable function because framework don't know how to deal with continuations.

AspectJ with Spring : intercepted methods lose their parameters annotations

I recently added AOP with aspectJ and spring-aop to my existent spring project. The goal was to actually intercept controller calls to modify the response they send back, in order to bind some values to this response I didn't want to add manually to each and everyone of my controllers, for example the expiration date of the actual token used by the end-user (which I wasn't even able to showcase within my controller in any case). I actually managed to get it working until I started my unit tests :
In my unit tests I call directly my controller methods using Reflection feature from java, then replicate usual process (calling the filter chain, pre handler and post handlers, and the controller method itself which is first manually validated using spring validator when annotation #Valid is present on one of my parameters. All this process works fine and gets executed properly). The problem is that now that the controller method is intercepted by spring-aop, it's mentionned as coming from the proxy controller created, and all of my parameters annotations disapear. Here is a controller example :
#Override
public ResponseEntity<Object> editPassword(#Valid #RequestBody PasswordEditForm passwordEditForm, HttpServletRequest request) {
return factorizedUserBaseController.editPassword(passwordEditForm, request, User.class);
}
the parameter PasswordEditForm has the annotation #Valid so in my test cases it was first validated before any other step, but now as I double checked it, the #Valid annotation is not present on the proxy method, and therefore the parameter doesn't get validated, any clue for how to fix this and make my parameters annotation still understandable from my test point of view?
Note : when running the spring through mvn spring-boot:run, parameters with #Valid annotation gets correctly validated and then goes to my error handler method properly.
Problem Solved : from several other stackoverflow posts I understand that CGLIB (aop proxy lib used by Spring) doesn't support annotations. ( see Retain annotations on CGLIB proxies?). But my problem wasn't here, I was literally sure I was finding the method using the controller class itself (the one I coded) but what I was wrong about is that I was giving the controller instance as a parameter to some other parts of my code which in turn would use this controller class to find the method which of course wasn't working because thanks to Spring proxies, it wasn't anymore my controller itself but a proxy class extending my own controller class. Instead, I just had to replace :
Class<?> controllerClass = controllerInstanciationContainer
.getController()
.getClass();
with
Class<?> controllerClass = controllerInstanciationContainer
.getController()
.getClass()
.getSuperclass();

getRequestDispatcher() is returning null (Portlet)

I am working on a Java Portlet (extending GenericPortlet), using JBoss 7.02 and LifeRay Portal 6.1.0 GA1. This is one of the bundles that can be downloaded from LifeRay's release archive.
During deployment, when the init() method is called, getRequestDispatcher() returns null. Below is the exact error message:
09:22:15,972 ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[default-host].[/my-portlet-name]] (MSC service thread 1-15) Error during mapping: java.lang.NullPointerException
Below is a snippet from my init() method:
PortletConfig config = getPortletConfig();
PortletContext context = getPortletContext();
PortletRequestDispatcher normalView = context.getRequestDispatcher("/portlet.jsp");
As a temporary workaround, I have moved all getRequestDispatcher() calls to doView() where it executes without problem. I do not understand why getRequestDispatcher() can locate portlet.jsp when called during doView, but not when its called during init()
Am I missing a preceding call of some other method that would resolve this? Is this a known issue?
Thanks for any help.
Getting the request dispatcher in the doView is the only place I've seen it done. I would imagine that it returns null during init because there is no actual request to dispatch.
Typically the init method is used for time-expensive operations that you don't want to incur for each request. This might be something like reading data from a file, or creating a reusable SQL connection.
You should also keep in mind that you should keep any portlet state thread safe. Don't create class or object variables that can only be used for one request at a time. The portlet methods are not inhererently thread safe, so you need to make sure that whatever variables a request is interacting with won't be manipulated by another request that is executing concurrently.
I'm not familiar with Portlets, but the answer should be the same as for Servlets.
The init() method is called exactly once, when your application is initially deployed. There is no active request (no one is asking for anything) or response (no one is going to read what the output is). Therefore, it is very reasonable forgetRequestDispatcher() to return null. In doView(), when you're handling a request and response, it makes sense to ask another resource to generate part (or all) of the response.
To address your question directly, getRequestDispatcher() has no problem locating portlet.jsp from init(); it's the request that's missing. (Where do you expect to see the result of portlet.jsp, anyway?)
If you do want to print some output during initialization, you can try logging it to a file, if your application is set up for that. Or, you can display data on System.out, if you know where the container's console is. (I use this second option quite often with servlets.)

Categories