How to use SPEL along with regex in RequestMapping - regex

I have a controller method as follows
#RequestMapping(value = "/{fruitName:Mango|Orange|Grapes}", method = RequestMethod.GET)
public String viewFruit(ModelMap model, #PathVariable String fruitName) {
...
}
Here I am hard-coding Mango, Orange and Grapes, such that if url matches with any of these, then only this method should execute.
What I want to do is that, instead of hard-coding these fruits here. I want to declare them in a properties file and by using SPEL, I should bring it here.
Is this possible to do?
I tried code below for this, but failed with error:
#RequestMapping(value = "/{fruitName:#{fruit['seasonFruit.requestMapping']}}", method = RequestMethod.GET)
public String viewFruit(ModelMap model, #PathVariable String fruitName) {
...
}
For following properties File (fruit.properties)
seasonFruit.requestMapping = Mango|Orange|Grapes
Please suggest, how this could be achieved?

#ArtemBilan So, isn't there any way by which we could achieve this? By separation of hard coding
Well, I hope you can do that from code:
#Value("#{ environment['seasonFruit.requestMapping'] }")
private String fruitName;
#RequestMapping(value = "/{fruitName:[a-z]", method = RequestMethod.GET)
public String viewFruit(ModelMap model, #PathVariable String fruitName) {
if (fruitName.matches(this.fruitName))
}

You may not be able to use combination of REGEX and values loaded from property files in requestMapping directly. But i am able to achieve in a sample app. Essentially i am resolving the entire regex pattern from property file, not just values of it. RequestMapping can resolve values from properties file.Hope this helps.
Property file
sample.test={url:mango|orange}
Controller method:
#RequestMapping(value = { "/example/${sample.test}" }, method = RequestMethod.GET)
public String testPattern(#PathVariable String url) {
System.out.println("url:" + url);
return sample;
}

Related

Springboot Requestmapper Regexpression

In my Springboot-Controller my Requestmapping method should support flexible subdirectory names. For that I like to use real regexpression. I have tested my regex and it works fine outside of SpringBoot and RequestMapping, however on top of RequestMapping it does not work.
If any http-requests gets in with
http://dir1 or http://dir2
my Method getFile should be called, but it doesn't.
#RequestMapping(value = "{reg:\\/(dir1|dir2)+}", method = RequestMethod.GET)
public void getFile(HttpServletResponse response, HttpServletRequest requ) throws IOException {
}
My question is how to accomplish this ....
The regex-based #RequestHandler can be achieved through (for more)
#RequestMapping(value = "{reg:regexPattern}", method = RequestMethod.GET)
public void getFile(HttpServletRequest request, HttpServletResponse response,
#PathVariable String reg) throws IOException {
...
}
But in your case, the regex pattern is a directory value that contains Slash("/") makes request handler difficult to find the exact mapping. Instead of #PathVariable, you can use #RequestParam
#RequestMapping(value = "\", method = RequestMethod.GET)
public void getFile(HttpServletRequest request, HttpServletResponse response,
#RequestParam("dir") String dir) throws IOException {
...
}
The solution is (Dirk Deyne gave me the hint) that the Slashes have to be outside the regexpression. Here is the solution, where I have extended the value with another subdir filedir to make it more clear:
#RequestMapping(value = "/{subdir:[dir1|dir2]+}/filedir", method = RequestMethod.GET)
public void getFile(HttpServletResponse response, HttpServletRequest requ) {
...
}
This will serve the following incoming requests:
http://localhost:8080/dir1/filedir
http://localhost:8080/dir2/filedir
Thank you!

How to write web api Get method with list a input

I would like to write web method(WebApi 2) as
GetArchiveDataForEngagements(collection of EngagementNumbers)
I have written code as
public async Task<IHttpActionResult> GetArchiveDataForEngagements(string[]
engagementNumber)
{
return Ok();
}
and using postman ,My input is like below
{
"engagementNumber":["one","two"]
}
I am getting "null" value for engagementNumber in web method.
Can anyone suggest , how can I achieve this?
You cannot pass data to a GET method using values in a body.
You could pass values as multiple query string values like this:
https://example.com/controller/GetArchiveDataForEngagements?engagementNumber=one&engagementNumber=two
You have not given enough routing information to make an accurate guess at the URL, but the query string part is the important part.
public class TEST
{
public string[] engagementNumber { get; set; }
}
[HttpPost]
[Route("test")]
public async Task<IHttpActionResult> GetArchiveDataForEngagements(TEST t)
{
return Ok();
}
Postman URL:
http:/localhost:8888/api/testCon/test
Postman Body: JSON(application/json)
{
"engagementNumber":["one","two"]
}
TestCon is the name of the controller.

#RequestParam spring MVC , make one of two request params mandatory

I am writing a service wherein I take in either an id or a location and I want to enforce the constraint that either the id or the location must be specified in my #Controller
#Controller
public class HelloController {
#RequestMapping(value="/loc.json",method = RequestMethod.GET)
public #ResponseBody String localiaztionRequest(#RequestParam(value = "location", required = false) String callback
,#RequestParam(value = "id", required = false) String uuid
,#RequestParam(value = "callback", required = false) String callback) {
//model.addAttribute("message", "Hello world!");
return "hello";
}
For clarity, I want each request to send either the location parameter or the id parameter. How do I enforce such a constraint on a pair of input parameters? Also as an aside could someone please explain to me the use of ModelMap , what is the effect of model.addAttribute("message","Hello World!") ?
Sorry if the questions seem rather naive, I'm extremely new to the spring framework.
Thanks in advance.
I think you should split it into two different controller methods
#RequestMapping(value="/loc.json",method = RequestMethod.GET, params={"location"})
public #ResponseBody String localizationRequestByLoc(#RequestParam String location, #RequestParam String callback) {
//model.addAttribute("message", "Hello world!");
return "hello";
}
#RequestMapping(value="/loc.json",method = RequestMethod.GET, params={"id"})
public #ResponseBody String localizationRequestById(#RequestParam String id, #RequestParam String callback) {
//model.addAttribute("message", "Hello world!");
return "hello";
}
One way to accomplish this (although indirect) would be to create a new object model representing the data to be passed in and another representing the data type and requiring both elements.
public enum MethodType
{
First,
Second
}
public class Filter
{
[Required]
public MethodType {get;set;}
[Required]
public string Data {get;set;}
}
use this object for the action method and view
and let the action method in the controller convert the object

How to send a property as a string in RestEasy response?

I have a class called Product which has a property called id of type long. Below is the class
public class Product {
private long id;
}
The value of id is beyond the value which javascript can handle. I realized this after seeing the below link
Parse json in javascript - long numbers get rounded
I dont want to declare the field as String in the domain class. But I want to say to RestEasy that it has to send the value as a string in the json response.
How can I do this? I dont want to use any third party api. Is it possible in RestEasy. I have gone through the documentation but did not find any such annotation or may be I did not go through the documentation properly.
Can anyone please help. Thanks all in advance.
If you are using Jackson as JSON Serializer you can extend the JacksonJsonProvider:
#Provider
public class JsonProvider extends org.codehaus.jackson.JacksonJsonProvider {
public JsonProvider() {
ObjectMapper objectMapper = locateMapper(ObjectMapper.class, MediaType.APPLICATION_JSON_TYPE);
objectMapper.configure(org.codehaus.jackson.JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS, true);
}
}
If you are using Jettison you can register a custom XmlAdapter:
public class LongAdapter extends XmlAdapter<String, Long> {
#Override
public String marshal(Long id) throws Exception {
if (id == null) {
return "";
}
return id.toString();
}
#Override
public Long unmarshal(String id) throws Exception {
return Long.parseLong(id);
}
}

Issues with mocking methods using Moq

I have the following class that has two static methods Retrieve and RetrieveWithQuery.
Below the classes listed here, I have included a snippet of the test.
All but the last assert of the test fails with the following message:
Failed TestMethod2 MoqTest Assert.AreEqual failed. Expected:. Actual:<(null)>.
I understand that the problem may be that the query that I setup in the mock
is a different instance from the query used in the RetrieveWithQuery method.
And that is why is would be returning null.
In a perfect world I would simply re-factor the service class, unfortunately I am
working with legacy code that is already production. The goal is to first complete
tests, then re-factor code and run regression testing before updating production
environment.
Is there a workaround or different way to test this?
public class MyService
{
public virtual string RetrieveMethod(string account)
{
if (account == "The abc company")
{
return "Peter Smith";
}
return "John Doe";
}
public virtual string RetrieveMethod(MyQuery query)
{
return RetrieveMethod(query.QueryString);
}
public static string Retrieve(MyService service, string value)
{
return service.RetrieveMethod(value);
}
public static string RetrieveWithQuery(MyService service, string value)
{
var query = new MyQuery
{
QueryString = value
};
return service.RetrieveMethod(query);
}
}
public class MyQuery
{
public string QueryString;
}
[TestMethod]
public void TestMethod2()
{
var mockService = new Mock<MyService>();
const string company = "The abc company";
const string expectedContact = "Peter Smith";
var queryAccount = new MyQuery
{
QueryString = company
};
// Setup base retrieve
mockService.Setup(myServ => myServ.RetrieveMethod(company)).Returns(expectedContact);
// Setup base retrieve with query
mockService.Setup(myServ => myServ.RetrieveMethod(queryAccount)).Returns(expectedContact);
// test base retrieve with query - PASS
Assert.AreEqual(expectedContact, mockService.Object.RetrieveMethod(queryAccount));
// test static method retrieve - PASS
Assert.AreEqual(expectedContact, MyService.Retrieve(mockService.Object, company));
// test static method retrieve with query - FAIL
Assert.AreEqual(expectedContact, MyService.RetrieveWithQuery(mockService.Object, company));
}
Try this for your setup:
// Setup base retrieve with query
mockService.Setup(myServ => myServ.RetrieveMethod(It.Is<Query>(q=>q.QueryString == queryAccount.QueryString)).Returns(expectedContact);
Or you could overload on Equals for Query so that the Query that gets created is equal to expectedQuery.
The Moq QuickStart page has good examples of this and more which should help a lot.