I have a controller which will have 3 query strings.
Instead of having 3 fields in controller, I am defining them in class.
public class PassengerInformation{
String travellerAddress;
String travellerAge;
String travellerName;
}
Now in controller , I am able to accept them
#GetMapping("/passenger-info)
public TravelInformation getPassengerInfo(PassengerInformation info){
//Call a service
}
Now, this works as expected, if I pass the query string as is. eg: /passenger-info?travellerAge=21.
But, How do I accept the query parameter names different to it's corresponding fieldName.
I should be able to call it as below:
/passenger-info?traveller_age=21&traveller_name=JohnWick&traveller_address=ST.
Try to add the following constructor to your class
public class PassengerInformation{
String travellerAddress;
String travellerAge;
String travellerName;
#ConstructorProperties({"traveller_address", "traveller_age", "traveller_name"})
public PassengerInformation(String travellerAddress, String travellerAge, String travellerName) {
this.travellerAddress = travellerAddress;
...
}
}
The best you can do by the default features without any customisation is to use #ConstructorProperties :
public class PassengerInformation {
String travellerAddress;
String travellerAge;
String travellerName;
#ConstructorProperties({ "traveller_address", "traveller_age", "traveller_name" })
public PassengerInformation(String travellerAddress, String travellerAge, String travellerName) {
this.travellerAddress = travellerAddress;
this.travellerAge = travellerAge;
this.travellerName = travellerName;
}
}
This behaviour is mentioned at the docs as follows :
The #ModelAttribute parameter instance (i.e PassengerInformation)
is sourced in one of the following ways:
Retrieved from the model where it may have been added by a
#ModelAttribute method.
Retrieved from the HTTP session if the model attribute was listed in
the class-level #SessionAttributes annotation.
Obtained through a Converter where the model attribute name matches
the name of a request value such as a path variable or a request
parameter (see next example).
Instantiated using its default constructor.
Instantiated through a “primary constructor” with arguments that match
to Servlet request parameters. Argument names are determined through
JavaBeans #ConstructorProperties or through runtime-retained parameter
names in the bytecode.
The caveat here is that you need to make sure there are no default constructor in the PassengerInformation :
public class PassengerInformation {
public PassengerInformation(){}
}
Related
I have a Class
public class TestClass {
private String name;
private String id;
private String accountID;
}
Post Method:
#RequestMapping(value="/testclass", method=RequestMethod.POST)
public void create(#RequestBody TestClass testClass) {
//implementation using testClass
}
This works fine until the body in the request is as requires but
When a POST call with body having multiple values of a variable, the #RequestBody takes the last given value of the variable.
For Example:
POST call Body:
{
"name":"qwerty",
"id":"qw123"
"accountID":"111111",
"accountID":"222222",
"accountID":"333333",
"accountID":"444444"
}
then the testClass object has values name=qwerty,id=qw123,accountID=444444
Thus, this allows any kind of request with any number of values in the body to be processed.
Is it possible to identify this multiple values in the request so as to validate all the request prior to the implementation?
I.e I want the request to fail before reaching the code. I want to process the request only if it has single values. Also, it's not just about the given variables, the request may contain other variables as well , but the requestbody simply ignores it and takes the relevant variables alone. I want it to fail in that case too –
I have a custom wrapper class around an httpServletRequest object. The purpose of the wrapper is to validate the parameters against whitelists before sending the request on through the filterChain.
The issue I'm having is that I have overridden the getParameter method of the standard request object in the wrapper; It checks if the parameter is in a hashmap, and if so it will perform validation on the parameter using an instance of another class. How can I unit test the getParameter method, considering i cant set the query string or set parameters onto the object? I have created unit tests for the actual object(Class that utilises Esapi.Validator()) that checks if the parameter value is valid input and returns a boolean value back to the wrapper, so is it even worth my time testing the wrapper?
TestRequestWrapper.java
public class TestRequestWrapper extends HttpServletRequestWrapper{
private static HashMap<String, EsapiParameterValidator> validationMap = new HashMap<String, EsapiParameterValidator>();
static{
/* esapiParameterValidator takes the param name,
* name of regex in Esapi.properties, field length
* and boolean indicating if the parameter can be null
*/
validationMap.put("lob", new EsapiParameterValidator("lob", "REG.lob", 3, false));
// number of other entries
}
public TestRequestWrapper(HttpServletRequest request){
super(request);
}
public String getParameter(String parameter){
String value = super.getParameter(parameter);
if(validationMap.containsKey(parameter)){
EsapiParameterValidator epv = validationMap.get(parameter);
value = epv.getValidatedParam(value) ? value : "";
}
return value;
}
Colleagues in my office are developping a web system with JAX-RS(JSR339).
I need to get values by name(string) and I asked them to. But they have few idea.
I'm quite new to JAX-RS and googled it and I learned that
JAX-RS injects values to variables by annotations like
#Path("/sample")
public interface SampleResource {
#GET
#Path("/hello/{message}")
String sayHello(#PathParam("message") String message);
}
However I want to get values by name at runtime like
#Path("/sample")
public interface SampleResource {
String name = "message"; // dynamic value
#GET
#Path("/hello/{" + name + "}")
String sayHello(#PathParam(name) String message);
}
Perhaps this is a wrong code. My question is how to get values by name like the example above.
(I'm afraid the sample codes aren't correct ones but I hope you grasp my idea and concerns. Thanks.)
Try something like this.
Example of the bean which will be used as #BeanParam
public class MyBeanParam {
#PathParam("p")
private String pathParam;.
public String getPathParam() {
return pathParam;
}
}
Injection of MyBeanParam as a method parameter:
#GET
String sayHello(#BeanParam MyBeanParam beanParam, String entity){
final String pathParam = beanParam.getPathParam(); // contains injected path parameter "p"
...
}
OR
You can use UriInfo to get QueryParam. For example application see this
I am trying implement a generic controller class where each method has a structure similar to this:
#RequestMapping(value="cadastra")
#PreAuthorize("hasPermission(#user, 'cadastra_#this.class.name')")
public ModelAndView cadastra() throws InstantiationException, IllegalAccessException {
return new ModelAndView("privado/"+this.entity.getClass().getName()+"/cadastra", "command", this.entity.getClass().newInstance());
}
I am having trouble with the annotation PreAuthorize. the name for the permissionhave this structure: _. right now, I am getting a 403 Error when I try access the view mapped by the method. I also tried other variations like:
#PreAuthorize("hasPermission(#user, 'cadastra_'+#this.class.name)")
or
#PreAuthorize("hasPermission(#user, 'cadastra_#this.getClass().getName()')")
but with the same result. Anyone knows the right way to accomplish this?
UPDATE
I try call this function inside the methods from controller secured by this tag PreAuthorize:
private void expressionParser() {
System.out.println("expressionHandler()");
ExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression("'cadastra_'+#this.class.name");
String message = (String) expression.getValue();
System.out.println("Message is " + message);
}
and when I run the application and open the view should be mapped by a method from controller, like this one:
#RequestMapping(value="cadastra")
#PreAuthorize("hasPermission(#user, 'cadastra_'+#this.class.name)")
public ModelAndView cadastra() throws InstantiationException, IllegalAccessException {
this.expressionParser();
return new ModelAndView("privado/"+this.entityClass.getName()+"/cadastra", "command", this.entityClass.newInstance());
}
No message is displayed on the console. So, I am thinking my application somehow aren't calling the methods from my generic controller. Am I right? If so, how I fix this?
My derived controllers follow this structure:
#Controller
#RequestMapping(value="usuario")
public class UsuarioController extends controller<Usuario> {
public UsuarioController() {
super(Usuario.class);
}
}
So you have difficulties with dynamic construction of permission name in the form of [methodName]_[classFullName] in SpEL expression.
See what SpEL documentation says about #this variable below
The variable #this is always defined and refers to the current evaluation object
(against which unqualified references are resolved).
Based on the documentation and a bit digging in the code the actual object the #this represents should be in your case an instance of org.springframework.security.access.expression.method.MethodSecurityExpressionRoot class. The class contains several helpful methods among others also getThis() method that returns the target object on which the secured method (a method annotated with #PreAuthorize) is being invoked.
Armed with this knowledge it should not be a big deal to construct the expression you require. In case of method named "cadastra", it should be as follows.
#PreAuthorize("hasPermission(#user, 'cadastra_'+#this.this.class.name)")
Hopefully it will also work correctly for secured methods inherited from a base class.
So, I solved this issue with this approach:
1) Adding a new method to my generic controller, where I return the name of the class:
public String getName() {
String expressao = entityClass.getName();
String nome_classe = new String();
StringTokenizer st = new StringTokenizer(expressao, ".");
while (st.hasMoreTokens()) {
nome_classe = st.nextToken();
}
return nome_classe;
}
2) Inside the annotation, I use the returned value by this method and concatenate the result with the constant string (using the notation described by the user #pgjecek in this topic):
#PreAuthorize("hasPermission(#user, 'cadastra_'+#this.this.name)")
and now it1s working perfectly.
I use FlexJson for serialization, the only problem is that it generates the field names lower case while I need them to start with upper case:
class Person
{
String name;
public String getName() { return name;}
}
When serialized the field is serialized as name, while I need it to be Name.
How can I specify the output field name? Is there some attribute I can put to specify the required serialization name?
You can achieve this by using a Custom Transformer. As per Flexjson page transformer is:
Responsible for deciding how to translate the passed in object to
JSON, making the appropriate calls on the JSONContext object to output
the JSON, and/or passing the object along the transformation process.
Flexjson has provided an abstract class AbstractTransformer for this purpose; Extend and override transform(Object object) to handle the transformation by yourself.
Pasted below is the code of FieldNameTransformer which I wrote for specifying the field name s manually:
public class FieldNameTransformer extends AbstractTransformer {
private String transformedFieldName;
public FieldNameTransformer(String transformedFieldName) {
this.transformedFieldName = transformedFieldName;
}
public void transform(Object object) {
boolean setContext = false;
TypeContext typeContext = getContext().peekTypeContext();
//Write comma before starting to write field name if this
//isn't first property that is being transformed
if (!typeContext.isFirst())
getContext().writeComma();
typeContext.setFirst(false);
getContext().writeName(getTransformedFieldName());
getContext().writeQuoted(object.toString());
if (setContext) {
getContext().writeCloseObject();
}
}
/***
* TRUE tells the JSONContext that this class will be handling
* the writing of our property name by itself.
*/
#Override
public Boolean isInline() {
return Boolean.TRUE;
}
public String getTransformedFieldName() {
return this.transformedFieldName;
}
}
Following is how to use this custom transformer:
JSONSerializer serializer = new JSONSerializer().transform(new FieldNameTransformer("Name"), "name");
where original field's name is 'name' but in json ouput it will be replaced with Name.
Sample out:
{"Name":"Abdul Kareem"}