Springboot #PathVariable value is including parenthesis - spring-boot

I am creating simple SpringBoot application. I declared PUT operation as follows
#RequestMapping(method=RequestMethod.PUT, value= "/topics/{id}")
public void updateTopic(#PathVariable String id, Topic t){
System.out.println("Kaushik==="+id);
topicService.updateTopic(Integer.parseInt(id),t);
}
When I invoke PUT operation on URL http://localhost:8080/topics/{2}. It fails.
The value of variable id is "{2}" instead of simply "2" which is causing number format exception.
I also tried specifying parameter name. public void updateTopic(#PathVariable(name="id") String id, Topic t){ but ut did not work either.

Your decratation of the PUT endpoint is perfectly fine:
#RequestMapping(method=RequestMethod.PUT, value= "/topics/{id}")
To call the URL simply use the desired value in place of {id}:
http://localhost:8080/topics/2
The URL template variable {var} is just an expression which marks part of the URL to be converted into the method parameter.

Related

How to pass 2 or more variables using #PathParam in spring mvc? and suppose if I want to test it out using postman how to do that?

I'm trying to fetch value from db using JPA repository method
product findByIdNumberOrCifNumber(String idNumber , String cifNumber);
service class logic:-
public ResponseModel FindByCivIDOrCifNumber(String idNumber,String cifNumber) {
ResponseModel responseModel = new ResponseModel();
Optional<product> civId = Optional.ofNullable(productRepos.findByIdNumber(idNumber));
if (civId.isPresent()) {
responseModel.setResponse(productRepos.findByIdNumberOrCifNumber(idNumber,cifNumber));
} else {
errorModel errorModel1 = new errorModel();
enter image description here errorModel1.setErrorCode(productConstant.INVALID_REQUEST);
errorModel1.setErrorDescription("Requested Civil Id or CifNUmber is not present");
responseModel.setErrorModel(errorModel1);
}
return responseModel;
}
controller class:-
#GetMapping("/getByCifNoOrGetByIdNo")
public ResponseModel getProductByCifNoOrGetByIdNo(#RequestParam String idNumber,#RequestParam String cifNumber ) {
return productService.FindByCivIDOrCifNumber(idNumber,cifNumber);
}
post man:-
kindly help me out how to make it work:)
If you are looking for an answer to pass two or more path variables and test it with postman, you can try this.
#GetMapping("/api/mapping-name/{variable1}/{variable2}")
Here you will be getting two path variables which you can access by the syntax
#PathVariable("variable1") datatype variableName
Now in postman request url you can simply give the respective url, lets say:
https://localhost8080/api/mapping-name/:variable1/:variable2
which automaticaly will give you a key value section in the path variables section in the params with prepopulated key names as per the name you have given. In this case variable1 & variable2.
Give the respective value and it should work.

Is there any situation QueryString is present but HttpServletRequest.getParameterMap() is empty?

I have encouterd an odd situation while we are doing press testing in our test env. When the app load is high, the Query String will missing occasionally and the Spring will throw MissingServletRequestParameterException.
In order to find the root cause , I add some logs at the foremost Filter(code is shown below), and something weired happened.
public static void printRequestParameter(HttpServletRequest request) {
Map<String, String[]> parameterMap = request.getParameterMap();
log.info("Request URI : {}, method = {} , query string = {}", request.getRequestURI(), request.getMethod(), request.getQueryString());
if (MapUtils.isNotEmpty(parameterMap)) {
parameterMap.forEach((k, v) -> {
log.info("Request parameter name = {}, value = {}", k, ArrayUtils.isEmpty(v) ? Strings.EMPTY : Arrays.stream(v).collect(Collectors.joining(COMMA)));
});
}
}
The request.getParameterMap() is empty, but , the query string is not empty , and I got a log like :
Request URI : /a/b/c, method = POST , query string = foo=bar.
But no logs like:
Request parameter name = foo , value = bar
And our Controller use #RequestParam() String foo to receivce the parameter , finally , the Spring throws
MissingServletRequestParameterException Handler org.springframework.web.bind.MissingServletRequestParameterException: Required String parameter 'foo' is not present
at org.springframework.web.method.annotation.RequestParamMethodArgumentResolver.handleMissingValue(RequestParamMethodArgumentResolver.java:204)
at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.resolveArgument(AbstractNamedValueMethodArgumentResolver.java:114)
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121)
at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:167)
at org.springframework.web.method.support.InvocableH
I just wonder, why the parameter in query string is not contained in parameterMap?
Note:
The odd behavior is only happened occasionally, at most time it's just works.
My spring boot version is 2.3.9.RELEASE and the embedded tomcat version is 9.0.43.
Any help is appreciated!
Since the specification does not allow ServletRequest.getParameterMap to throw any exception, any failure in parameter parsing will cause the parameter list to be empty.
To detect this situation you can log the "org.apache.catalina.parameter_parse_failed_reason" attribute of your request.
Examples of query strings that should fail:
?=noname,
?urlEncoding=%ue

Grails: Call a localization message from within another message

Coming from Struts/XWorks I was able to do something like this
Messages.properties
myMessage.invalid.fieldvalue=Invalid input for $'{'getText("{0}")'}'
email.label=Email Address
Application Code
getText("myMessage.invalid.fieldvalue",new String[] {"email.label"})
Output: Invalid input for Email Address
So basically the parameter I am passing into a message is actually the code for another message and I want to render them both together.
I can't seem to find a way to do this with Grails/Spring messaging. Is this possible and if so how?
EDIT:
To more clearly show one of the reason I am asking for this take this example.
Lets say I have 5 Domain classes with the property emailAddress
To validate for NULL I would have to do this
myClass1.emailAddress.nullable=Email Address cannot be NULL
myClass2.emailAddress.nullable=Email Address cannot be NULL
myClass3.emailAddress.nullable=Email Address cannot be NULL
myClass4.emailAddress.nullable=Email Address cannot be NULL
myClass5.emailAddress.nullable=Email Address cannot be NULL
What I want to be able to do is simply the messaging by overriding the default validation message as such
OLD: default.null.message=Property [{0}] of class [{1}] cannot be null
NEW: default.null.message=getMessage({0}) cannot be null
emailAddress=Email Address
So now anytime any class has a property called emailAddress and it validates as NULL I will get the message Email Address cannot be null. There is no need to have 5 messages that basically say the same exact thing. If I had another class with the property emailAddress then its already handled and I dont have to copy and paste a 6th line.
Anytime I have classes with shared property names, all I have to do is add just add a single line for each property that will be applied to all classes
sharedProp1= Shared property 1
sharedProp2= Shared property 2
When in a controller, call message for the param you want to internationalize and store that in a local variable.
Then call message for the full message and add your local variable, with the internationalized param value, as a param to that message.
def emailLabel = message(code: "email.label")
def fullMessage = message(code: 'myMessage.invalid.fieldvalue', args: [emailLabel])
Your messages.properties would contain something like
myMessage.invalid.fieldvalue=Invalid input for {0}
email.label=Email Address
I was able to get this done by extending the MessageSource and overriding the resolveArguments method.
class CustomMessageSource extends ReloadableResourceBundleMessageSource {
#Override
protected Object[] resolveArguments(Object[] args, Locale locale) {
if (args == null) {
return new Object[0];
}
List<Object> resolvedArgs = new ArrayList<Object>(args.length);
for (Object arg : args) {
if (arg instanceof MessageSourceResolvable) {
resolvedArgs.add(getMessage((MessageSourceResolvable) arg, locale));
}
else {
//resolvedArgs.add(arg) **REPLACED THIS LINE
resolvedArgs.add(getMessage(arg, null, arg, locale));
}
}
return resolvedArgs.toArray(new Object[resolvedArgs.size()]);
}
}
I replaced a single line within the loop that evaluates your message arguments. I basically take the argument and see if its a key to another message. If yes, then replace the argument with that message, if no then continue as normal to use the argument
Make sure to map the new messageSource in your resources.groovy file
beans = {
messageSource(groovyUtils.CustomMessageSource) {
basenames = "messages"
}
}

Pass null String to Web API 2 (Visual Studio 2013)

I have a method like this:
public IEnumerable<Test> GetTest(Int32 idTest, String codTest, Int value)
and a test client like this:
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
response = await client.GetAsync("Test/GetTest/0/null/1/");
I need to pass null in the second parameter (that is not optional), but on server side I get a string with "null" inside and not the null value. I would not to put conversion functions for each parameter. I see that works if I put [FromBody] attribute to just one parameter, but if I set [FromBody] for all the string parameters I get internal server error.
Many thanks.
You typically shouldn't have optional parameters in the middle of a route.
I would recommend changing the order of your parameters, or add them as query parameters so they can be optional.
e.g. for http://example.com/Test/GetTest?a=0&b=&c=1
public IEnumerable<string> GetTest(Int32 idTest)
{
var queryPairs = Request.GetQueryNameValuePairs();
DoSomething(queryPairs);
...
}

Use of "#this" in Moles delegates

When I set a property of a moled type, it looks like they always require, as the first parameter, an object of the original moled type. I also noticed that some of the examples in the Moles Reference Guide assign this parameter as #this and I am trying to figure out why.
For instance, the original class looks something like this:
public class ProductDAO
{
internal void Insert(Product product, string id)
{
...
}
}
When I go to mole this method, the property is expecting a delegate whose first parameter is always the type of the moled object, in this case, a ProductDAO object. So in this case, the property is expecting a delegate of:
Action<ProductDAO, Product, string>
So do I always have to provide that moled object as the first parameter of my lambda expression? If so, what's the difference in using a regular variable name versus #this? What does #this mean/do?
MProductDAO.AllInstances.InsertProductString = (dao, product, id) => { };
versus
MProductDAO.AllInstances.InsertProductString = (#this, product, id) => { };

Resources