Around Advice not working when dependent on response from other REST service - spring-mvc

I am working with Spring AOP to define a common fallback method instead of duplicating code.
I used #Around as I have to return the object from Aspect.I am trying to decide #Around advice depending on the response returned,but not able to do so.
Here is my controller:
#RequestMapping(value = "/add/employee", method = RequestMethod.GET)
public EmployeeResponse addEmployee(#RequestParam("name") String name, #RequestParam("empId") String empId) {
EmployeeResponse employeeResponse=employeeService.createEmployee(name, empId);
return employeeResponse;
}
createEmployee in the service class is used to call another endpoint to insert some data.I want to decide my advice based on the employeeResponse but not able to do so.
I tried #AfterReturning also,but I can't return the object if I use that.
Below is my aspect class:
#Around(value = "execution(* com.test.service.EmployeeService.*(..)) and args(name,empId)")
public Object getAllAdvice2(ProceedingJoinPoint pjp, String name,String empId) throws Throwable {
System.out.println("Inside Aspect");
Object[] arguments = pjp.getArgs();
if (!checkForPath()) {
return pjp.proceed();
}
System.out.println("Call Second path please!!");
return arguments;
}
private boolean checkForPath() {
HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
.getResponse();
return response.getStatus()==501?true:false;
}
}
I did use HttpServletResponse and RequestContextHolder to get the context but seems it will take the present context i.e. "/add/employee".
How can I return the actual status from the checkForPath () (since I don't need to call pjp.proceed for every status code returned) so that I can execute the line System.out.println("Call Second path please!!"); depending on my error code.
Can anyone pls suggest where it is going wrong?

Your aspect code is quite chaotic and does not make much sense:
You are trying to check for a response before calling proceed(), as R.G said. Use something like EmployeeResponse response = (EmployeeResponse) proceed() instead, inspect the response and then decide what to do next.
You already bind the method parameters to name and empId, there is no need to use pjp.getArgs().
return arguments does not make sense because you ought to return an EmployeeResponse object (either the original result or another one), not the array of method arguments.

Related

Return a data object with a BadRequestResult / BadRequestErrorMessageResult

I'd like to return a data object that contains the details of the error with a BadRequestErrorMessageResult or BadRequestErrorMessageResult object like so:
public IHttpActionResult Action(Model model)
{
var validationResult = model.Validate();
if (validationResult.Successful)
{
// this one's okay; it supports sending data with a 200
return Ok(validationResult);
}
else
{
// However, how do I return a custom data object here
// like so?
// No such overload, I wish there was
// return BadRequest(validationResult);
}
}
The only three overloads of the ApiController.BadRequest() method are:
1. BadRequest();
2. BadRequest(string message);
3. BadRequest(ModelStateDictionary modelState);
Even with #3, a model state dictionary is ultimate a deep collection with one layer upon another, at the bottom of which, though, is a bunch of KeyValuePair<string, ModelError> where each ModelError also only has either a string or an Exception object.
Therefore, even with #3, we are only able to pack a string to send and not a custom object like I want to.
I am really not asking how I may go about working a hack or a kludge around the situation. My question is: is there an overload or another way baked into the .NET API to send an object to the client with a Bad Request HTTP status code?
I am using ASP.NET Web API version 5.2.4 targeting .NET Framework version 4.6.1.
You can use the Content<T>(...) method to do this. It returns a NegotiatedContentResult, which is serialized depending on the request headers (e.g. json, xml), and allows you to specify a HttpStatusCode.
You can use it like this:
return Content(HttpStatusCode.BadRequest, myObject);
If you wanted to, you could create your own BadRequest<T>(T obj) method in the controller as a wrapper, so then you could call it as you wanted:
public IHttpActionResult BadRequest<T>(T obj)
{
return Content(HttpStatusCode.BadRequest, obj);
}
public IHttpActionResult Action()
{
// do whatever validation here.
var validationResult = Validate();
// then return a bad request
return BadRequest(validationResult);
}
You can build/format the string in JSON format, pass it as string in the BadRequest() parameter and convert it to JSON again or any object on the caller's backend.
Haven't tried that but that should work.

HttpServletRequest - Get Literal Path

I have a method marked with Spring's #RequestMapping that includes an HttpServletRequest method parameter.
If I print out the results of a call to "request.getServletPath()" when the path is, say, "/things/{thingId}", I will get "/things/2489sdfjk43298f," where the {thingId} path parameter has been replaced with the actual value.
I want to print out the literal request path "/things/{thingId}"; I.e. with the curly-braced, un-replaced path parameter "{thingId}."
Is this possible in any way?
Edit: After looking at Sotirios's second comment below, I realize I may be looking at the problem backward. Here's what I'm actually trying to do...
I am trying to making a single endpoint under "/**" that gets the path from the HttpServletRequest, which I use to look up a value in an enum. This enum has several fields, one of which is obviously the aforementioned path, but another is the path of a target JSP file. I then put this path into a ModelAndView object and return it to display the page.
This was going just fine until I hit the first endpoint with a path parameter, because I obviously can't place the value "/things/2489sdfjk43298f" into the enum, because that will only match for that one specific thing with that one specific ID.
So perhaps the actual question would be: How would I do that look-up when parts of the path will change due to path parameters? Is there some sort of wildcard-containing String format I can use?
I guess this is turning into more of a enum-lookup/String-matching question. My bad.
Edit 2: Shortened example of the enum thing I'm talking about:
public enum JspEndpointType {
HOME("/home", "jsp/home");
private static final Map<String, String> pathMap;
private String requestPath;
private String jspPath;
static {
pathMap = new HashMap<>();
for (JspEndpointType jspEndpointType : JspEndpointType.values()) {
pathMap.put(jspEndpointType.getRequestPath(), jspEndpointType.getJspPath());
}
}
private JspEndpointValue(String requestPath, String jspPath) {
this.requestPath = requestPath;
this.jspPath = jspPath;
}
public String getRequestPath() {
return requestPath;
}
public String getJspPath() {
return jspPath;
}
public static String getByRequestPath(String requestPath) {
return pathMap.get(requestPath);
}
}
Shortened example of my endpoint:
#RequestMapping(value = "/**", method = RequestMethod.GET)
public ModelAndView showPage(HttpServletRequest request) {
return new ModelAndView(JspEndpointType.getByRequestPath(request.getServletPath()));
}
So things essentially boil down to trying to add to the enum a value like this:
THINGS("/things/{thingId}", "jsp/things/whatever")
..and then being able to pass in the path "/things/2489sdfjk43298f" and get back "/jsp/things/whatever."
Edit 3: I found this StackoverFlow question which directed me to Spring's UriComponentsBuilder, specifically the "fromPath" method. However, that seems to be the reverse of what I'm trying to do...
You may look for the #RequestMapping annotation on your own, using reflection.

What kind of datatypes should I use for the return value of a Web API method?

I have a Web API controller that returns data to my client. The code looks like this:
[HttpGet]
[ActionName("Retrieve")]
public IEnumerable<Reference> Retrieve(int subjectId)
{
return _referenceService.Retrieve(subjectId);
}
Can someone tell me is it necessary to specify the ActionName?
Also should I return an IEnumerable, an IList or something else?
I believe if your ASP.NET routing is setup correctly you don't need to specify the ActionName, for example:
protected void Application_Start()
{
RouteTable.Routes.MapHttpRoute("0", "{controller}/{action}/{arg1}");
}
Will match /YourControllerName/Retrieve/132
What you return is based entirely on your media-type formatters, of which the default is XmlFormatter and JsonFormatter. These can be found in GlobalConfiguration.Configuration.Formatters and will be chosen based on the Accept header provided by the client.
We, for example, use JSON.Net for our response formatting, configured by:
protected void Application_Start()
{
RouteTable.Routes.MapHttpRoute("0", "{controller}/{action}/{arg1}");
MediaTypeFormatterCollection formatters = GlobalConfiguration.Configuration.Formatters;
formatters.Remove(formatters.XmlFormatter);
var jsonFormatter = GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings;
jsonFormatter.Formatting = Formatting.Indented;
jsonFormatter.ContractResolver = new CamelCasePropertyNamesContractResolver();
}
This tells WebApi to disallow any XML formatting and only return JSON using the provided JSON.Net contract resolver. JSON.Net supports serializing IEnumerable.
I would, however, recommend returning a HttpResponseMessage instead. This allows you to set the status code as well (This still uses the media type formatter, it's just a cleaner wrapper). You can use this like so:
[HttpGet]
public HttpResponseMessage Retrieve(int subjectId)
{
var response _referenceService.Retrieve(subjectId);
return Request.CreateResponse(HttpStatusCode.OK, response);
}
You should return HttpStatusCode instead of data if have not requirement, like POST method should return OK or whatever.
or if want record like Get method should return type of record.
also you no need to add attribute on method like Get,Put,Delete etc because webapi automatically detect method according to action like if you are getting data then your method name should be start with Get like GetEmployee etc.

Spring MVC: get RequestMapping value in the method

In my app, for certain reasons I would like to be able to get the value of the #RequestMapping in the corresponding methods, however, I can't find a way to do that. Here are more details about what I want:
Suppose, I have a method like this:
#RequestMapping(value = "/hello")
#ResponseBody
public void helloMethod(AtmosphereResource atmosphereResource) {
...
}
I would like to be able to get the mapping "/hello" within the method. I know, I can use placeholders in the mapping in order to get their values when the actual requests come, but I need a finite set of processable requests, and I don't want a chain of ifs or switches in my method.
Is it at all possible?
This would effectively be the same, wouldn't it?
private final static String MAPPING = "/hello";
#RequestMapping(value = MAPPING)
#ResponseBody
public void helloMethod(AtmosphereResource atmosphereResource) {
// MAPPING accessible as it's stored in instance variable
}
But to answer the original question: I wouldn't be surprised if there wasn't a direct way to access that, it's difficult to think of valid reasons to access this information in controller code (IMO one of biggest benefits of annotated controllers is that you can completely forget about the underlying web layer and implement them with plain, servlet-unaware methods)
You can get get this method's annotation #RequestMapping as you would get any other annotation:
#RequestMapping("foo")
public void fooMethod() {
System.out.printf("mapping=" + getMapping("fooMethod"));
}
private String getMapping(String methodName) {
Method methods[] = this.getClass().getMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName() == methodName) {
String mapping[] = methods[i].getAnnotation(RequestMapping.class).value();
if (mapping.length > 0) {
return mapping[mapping.length - 1];
}
}
}
return null;
}
Here I pass method's name explicitly. See a discussion o how to obtain current method name, if absolutely necessary here: Getting the name of the current executing method

Building a single entry point to a WCF service: need unified approach to return objects and collections

Subject says it all: I'm creating a secure and generic wrapper to access a WCF service transparently.
A little background:
what I have done is that I've created similar business classes definition both on server and client. The server-side contains the actual logic while the client side contains only method definitions. Additionally, the client-side classes derive from a SecureFactory which implements a Call method. The body of every method of each derived class contains only a call to Call method. This Call method is responsible for invoking the server service passing such things as to the type of business class and which of its method to invoke to perform the requested operation.
This approach is being designed in order to simplify security checks by restricting passing of security information to only between SecureFactory and Server service. There are tuns of other benefits which you most of already aware of.
Now here's the issue: I'm stuck at as to how to return objects (especially arrays of objects) from Server to Call method?
The server may return a single business object (DataContract applied) as well as list of such objects. Since it's a generic approach, I have only Object to be used as return type. Following is the Call method
public object Call(params object[] parameters)
{
var mb = (new StackFrame(1).GetMethod());
using (Proxy.ServerClient server = new Security.BO.Proxy.ServerClient())
{
try
{
if (((MethodInfo)mb).ReturnType.IsGenericType)
{
var response = server.InvokeForList(SecurityManager.Current.SID, SecurityManager.Current.Token, mb.DeclaringType.ToString(), mb.Name, parameters);
return response.Result.ToList();
}
else
{
var response = server.Invoke(SecurityManager.Current.SID, SecurityManager.Current.Token, mb.DeclaringType.ToString(), mb.Name, parameters);
return response.Result;
}
}
catch (Exception ex)
{
System.Diagnostics.Debugger.Break();
}
}
return null;
}
server methods:
public CollectionResponse InvokeForList(string SID, string token, string type, string method, object[] parameters)
{
// Validation here
var t = assemblyBO.GetType(type, true);
object BO = Activator.CreateInstance(t);
var mi = t.GetMethod(method);
if (mi == null)
throw new MethodNotImplementedException("Method " + method + " could not be found on type " + t.ToString());
object res = mi.Invoke(BO, parameters);
// Convert list to t[]
object list = res.GetType().GetMethod("ToArray").Invoke(res, new object[0]);
// Error here! cannot convert t[] into object[]
return new CollectionResponse((object[])list);
}
The other method Invoke(...) is similar accept it returns Response object instead of CollectionResponse.
Here's the CollectionResponse class: (Response is similar:just it takes only one object)
[DataContract]
public class CollectionResponse
{
[DataMember]
private Object[] _result;
public Object[] Result
{
get
{
return _result;
}
}
public CollectionResponse(Object[] result)
{
this._result = result;
}
}
Initially I was thinking to have only one Invoke for both lists and singleton – but failed with "Connection was closed unexpectedly." still I'm not able to achieve – how can I convert T[] into object[].
Do you have any suggestion to improve it, or any other way of achieving the same?
Thanks
I can see an immediate problem here. You are using reflection which is far less perfromant than the direct call.
For me, that is enough not to follow this route.

Resources