The difference between the attribute name, value and path of the annotation #RequestMapping in SpringMVC - spring-mvc

I am struggling to understand the differences between the attribute name, path and value in #RequestMapping. I looked into the API, but it doesn't illustrate it clearly. I googled for hours but it just works partially. Can you tell me the details? Thank you!

Let's see the javadoc. Start with path:
The path mapping URIs (e.g. "/profile").
So that's the path(s) that will be used by Spring to decide if this methd should be called or not, based on the actual path of the request.
Now value:
The primary mapping expressed by this annotation.
This is an alias for path(). For example, #RequestMapping("/foo") is equivalent to #RequestMapping(path="/foo").
So, it's quite clear: value and path are exactly equivalent.
And finally name:
Assign a name to this mapping.
So this is completely different. It gives a name to this mapping. Why could a name be useful for a mapping? You can discover that by clicking on the "See also" classes linked to attrbibute in the documentation. The javadoc for HandlerMethodMappingNamingStrategy says:
Applications can build a URL to a controller method by name with the help of the static method MvcUriComponentsBuilder#fromMappingName [...]
So, as you see, the name of a mapping can be used to construct a URL that will match to a given controller method by using the name of its mapping. That makes it possible to change the path of a mapping without changing it everywhere, by using names rather than paths.
The reference documentation, in addition to the javadoc, should be your first destination. This is usually way more effective when you want to learn about the framework than googling.

Related

API Platform custom IRI with value objects

I am currently trying to create a custom IRI for one of my entities in API Platform.
I know there is page in the documentation describing how to use a custom IRI (https://api-platform.com/docs/core/identifiers/), but I can't get it working.
My entity uses a value object for the id (currently used for IRI) and also for the name (should be used for IRI). But the values themself are priviate and scalar in the entity.
API Platform seems to get the information what should be used as the identifier, from my XML Doctrine mapping. I already tried to overwrite it by usung annotations, attributues and YAML definitions. Without luck.
The returned error reads:
preg_match(): Argument #2 ($subject) must be of type string
(at this point it receives the value object instead of the actual value)
best regards,
spigandromeda
I solved my problem.
To explain the solution, I have to dig a little into API Platform response generation.
API platform generates an IRI for every entity it returns (colelction and item operation)
it's using the Symfony router go generate the URI
all the necessary information can draw API Platform from different sources (YAML, XML, annotations, attributes)
the information include the identifier(s) defined for the entities resource
API Platform gets the value for the identifier via Symfony property accessor
because the property accessor is using getters before accessing private properties via reflection, it will return the VO
an ordinary VO cannot be used by the Symfony URL generator to create the URL
As I explained, I am using a VO for my Id as well. So I tried to figure out why it was working with the Id VO but not with the name VO.
Simple answer: the Id VO implemented the __toString method and the name VO didn't. So the solution was to let the name VO implement this method as well.
It was interesing to dig into the internal process of API Platform, but I also feel a little stupid :D

What is the point of #WebInitParam?

#WebInitParam is an annotation that goes at class level.
It defines initialization parameters for the servlet.
I would like to know, what is the difference between doing this and using static variables, and why do it the #WebInitParam way rather than using statics?
What does defining k/v pairs as #WebInitParams allow you to do that you couldn't do if you declared static variables instead?
I have looked and all I can find is a million people saying how to define #WebInitParams. Well yes that's the easy bit. It's what I can do with that that is really what is of interest.
Thanks very much.
From a "raison d'etre" perspective, the annotation exists as a better design and architecture alternative to just peppering a class with static fields. #WebInitParam is a self-documenting approach to the initialization parameters a servlet or filter class needs, available via web.xml as well. It serves this purpose for the end developers as well as the JavaEE platform as a whole.
Think about it this way: in a vanilla project, you have the option of hardcoding a bunch of parameters in the class as static fields, or defining the same parameters in a property file. Which would you pick? Under what circumstances?
From a purely functional angle, apart from the function of using the annotation to override defaults set in web.xml, one other major reason is that you will sometimes need to get a hold of those initialization parameters from another component in your application. Using the annotation essentially increases the visibility of the parameter. In JSF for example, the API allows you to retrieve FacesServlet initialization parameters with:
//get all the parameters
FacesContext.getCurrentInstance().getExternalContext().getInitParameterMap()
//get a specific parameter
FacesContext.getCurrentInstance().getExternalContext().getInitParameter("aParameter");
In JSF-2.3 , it gets even more convenient with the following CDI-enabled injection:
#InitParameterMap Map<String,String> servletParameterMap;
Bear in mind that because it's CDI, it means this facility is available throughout the JavaEE platform, not just in web applications/JSF.
It's going to be a hassle to retrieve init parameters if the only mechanism available is a static field in the servlet class - you'll need to obtain an instance of the filter or servlet to get the static fields in it.
Separately, one could make the argument that maybe one should favour context-params over servlet-params because then, you get even more flexibility that isn't tied to any given servlet. That's a separate matter entirely :)

best approach to implement getRealPath()

I am working on struts 2.0 . I am designing a web application.
I am using Jasper Report in my application. I want to access the *.jrxml files in my action class. I don't want to give hard coded path to the files. So to get the path dynamically I googled it and got the solution that I can get the path using getRealPath() method. But I found two implementation of doing this:
Using HttpSession to get object of ServletContext and using the getRealPath() method of the ServletContext object.
Like this:
HttpSession session = request.getSession();
String realPath = session.getServletContext().getRealPath("/");
The second approach to do it directly using the static method getServletContext() of ServletActionContext. And then we can get the real path of the application using the getRealPath() method.
Like this:
String realPath = ServletActionContext.getServletContext().getRealPath("/");
Please tell me, is there any difference between the above two and also please tell me whether there is any other way to get the path?
Neither is "better", really, and I'd argue that neither is particularly good, either.
I might try getting the context path in an initialization servlet and stick it into the application context, then make your action(s) ApplicationAware and retrieve the value from the map.
This has the added benefit of aiding testability and removing the static references in the action.
That said, I see zero reason to go through the extra mechanics of your first approach: it adds a lot of noise for no perceivable benefit; I'm not even sure why it wuld be considered.
I'd also be a little wary of tying your actions to a path like this unless there's a real need, what's the specific use? In general you shouldn't need to access intra-app resources by their path.

DefaultAnnotationHandlerMapping for portlets vs. servlets

I have been developing with Spring MVC in a Servlet environment for quite some time, mostly on Spring 3.1.x and 3.2.x, but recently moved jobs to a company that uses a mixture of Portlets and Servlets using Spring 3.0.6.
Fist, there seems to be two versions of DefaultAnnotationHandlerMapping, one for Portlets and one for Servlets. My limited knowledge of Portlets makes me believe they are just an extention of Servlets, so I can vaguely understand the need to have two separate HandlerMappings, one to handle generic Servlets, the other to handle specifics to Portlest. What is throwing me is how they each seems to behave differently with regaurds to how they handle the #RequestMapping annotations, and how my new employer has chosen to set things up.
In my past, I have had one DispatchHandler for the entire application. I know you can have multiple DispatchHandlers, but I never saw the benefit past segregation of sub-context XMLs. Anyhow, in the past I would have a DispatchHandler mapped to "/", and then each Controller set a mapping on top using #RequestMapping("/someUrl") and then another #RequestMapping on each handler method further extending the URL mapping. So, from a browser I would get something like:
http://somehost.com/myWar/myController/myMethod
where the first "/myWar" is mapped to the WAR deployment, the next "/" is mapped to the DispatchServlet, "/myController" is the Controller's mapping, and anything after is matched to some method using a combination of URL signature, request method, parameters, etc.
Now lets evaluate what I am seeing at my new firm. First, each Controller gets its own DispatchServlet, so there is like 20-30 DispatchServlets defined, all with different base URIs mapped, some with the same base Application Context XML, some with different ones, all using the same Application Context from the ContextLoaderListener. Each of the subsequent DispatchServlet's path is the same as the #RequestMapping on their "mapped" Controller, so in the above example DispatchServlet would have the path "/myController" and the Controller would have #RequestMapping("/myController"). On top of that, at the Controller's method level, the value specified on #RequestMapping seems to totally ignore any additional pathing applied to it.
So, for instance, if I have a Controller with #RequestMapping("/myController"), followed by a method with #RequestMapping("/edit"), hitting the URL http://somehost.com/myWar/myContoller/edit gives me a 404. However, if I change the method-level #RequestMapping to #RequestMapping(parameter="actionMethod=edit"), and the URL to http://somehost.com/myWar/myController?actionMethod=edit, it maps just fine and I get my page. Further, if I change my method-level #RequestMapping to #RequestMapping(value="/edit",params="actionMethod=view") neither http://somehost.com/myWar/myController?actionMethod=edit nor http://somehost.com/myWar/myController/edit?actionMethod=edit work at all. The problem is that now to get to anything besides the default mapping at the method level requires me to take on "?actionMethod=edit", instead of simply extending the URI with the added paths. Also, it prevents me from using a RESTful approach, since now I can't define something like #RequestMapping("/somePath/{id}").
I have so much confussion in my brain, like why is the DispatchServlet mapping in the web.xml overlapping the Controllers #RequestMapping, and why is the #RequestMapping at the Controller's method level not working when I set the value property to a valid URI mapping, but works fine when I set some parameter mapping?
Oh, and sorry for the long posting. I just want to get a better understanding of what is happening here so I can either deal with it with an intellegent approach, or go back to my new group and say "this should be changed, and this is why". I can extend this lengthy question with some simplified code examples if that helps.

Ordered RequestMapping in spring MVC

I'm working on a Spring MVC project using Annotated Controller.
One thing that I'm interested in is about the order which #RequestMapping instruction to be processed.
For example, I want all /green/basic/welcome to be mapped to GreenController.welcome()
but green/{treeId}/{treeName} to be mapped to GreenController.viewTree(treeId, treeName).
I guess I need to specify two #RequestMapping with #RequestMapping of /green/basic/welcome to be processed first, so that it won't be interpreter as a call to GreenControllerviewTree("basic", "welcome").
Can you guys guide me on that?
An exact match for a RequestMapping will take precedence over one with a PathVariable. So you would have two request mappings like you pointed out. One to handle the specific url, and the variable version will catch everything else. Spring checks for direct path matches before checking for path variable matches, so order does not matter unless you have two request mappings with the same number of path variables, which may spit out an IllegalStateException
Check the source of org.springframework.web.servlet.handler.AbstractHandlerMethodMapping for the specifics. It is handled in lookupHandlerMethod().
To determine the best match of two RequestMappings that aren't exact matches, the compareTo() method of RequestMappingInfo is used.

Resources