JavaEE: Unit test custom request wrapper - java

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;
}

Related

How to have query string parameter(s) and field name(s) different

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(){}
}

What is a good way to create a table of mapping functions to apply to each query parameter in Java

My Java REST service accepts some query parameters and values. I want to apply some transformation functions to these parameter and values before I pass these to another service through REST API. I want to know the best way to transform these parameters in such a way that it can be as clean as possible for extension.
Here was my attempt to do this before and hope it also illustrates this better -
I created an enum which takes a Function like this:
public enum MyQueryParam {
ID("id", new MyCryptoFunction()),
PRICE("price", new CurrencyConvertFunction()),
...
private String mappedParam;
private Function<String, String> mappingFunction;
MyQueryParam(String mappedParam, Function<String, String> mappingFunction) {
this.mappedParam = mappedParam;
this.mappingFunction = mappingFunction;
}
public String getMappedParam() {
return mappedParam;
}
}
static class MyCryptoFunction implements Function<String, String> {
public String apply(String msg) {
// do the hash function
}
}
// .. somewhere in the code where I get the query params and values as a map
paramMap.forEach((param, value) -> uriBuilder.addParameter(param.getMappedParam(), param.mappingFunction.apply(value)));
So my id parameter gets encrypted and my price parameter gets currency converted statically.
Problem now comes when, these transformations need to be done based on some additional context that comes with each parameter. For example, I want to pass the locale from the request to the CurrencyConvertFunction. And I want to pass a secret key to the CryptoFunction. I cannot do new CurrencyConvertFunction(locale) in the enum given its static. What is a clean and elegant way to map my query parameters to applying some transformations and make it extensible?
(For example, I can check the value of the param as I am iterating through each parameter and do the validation there, but that feels like making the code un-maintainable).
You can update MyCryptoFunction to
static class MyCryptoFunction implements Function<Pair<String, String>, String> {
public String apply(Pair<String, String> param) {
// do the hash function
}
}
and also change the type of mappingFunction in MyQueryParam accordingly.
Then you can call the mappingFunction as
param.mappingFunction.apply(Pair.of(value,"additionalParam")).
You can also replace Pair with your custom class if you like.

How to take only one value for each field in #RequestBody in java in SpringBoot

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 –

What is the best way to call one #RequestMapping method from another in Java?

I have 3 methods in a controller, looking something like this.
#RequestMapping(value="export-data")
public ExcelView exportData(String urlForData, String paramToPass) {
List<Data> data; //WHAT SHOULD I DO HERE?
return new ExcelView(data);
}
#RequestMapping(value="get-data-1")
public List<Data> getData1(String param) {
//return the data based on param
}
#RequestMapping(value="get-data-2")
public List<Data> getData2(String param) {
//return the data based on param
}
The value for urlForData will be either get-data-1 or get-data-2. And I'll need to call the specified method with the given paramToPass.
Is there a way to call the methods via Spring (versus just doing a String equality check)? Notice that this is not a redirect as I want to remain in the exportData method (versus giving up control to the other methods).

Jackson: What happens if a property is missing?

What happens if I annotate a constructor parameter using #JsonProperty but the Json doesn't specify that property. What value does the constructor get?
How do I differentiate between a property having a null value versus a property that is not present in the JSON?
Summarizing excellent answers by Programmer Bruce and StaxMan:
Missing properties referenced by the constructor are assigned a default value as defined by Java.
You can use setter methods to differentiate between properties that are implicitly or explicitly set. Setter methods are only invoked for properties with explicit values. Setter methods can keep track of whether a property was explicitly set using a boolean flag (e.g. isValueSet).
What happens if I annotate a constructor parameter using #JsonProperty but the Json doesn't specify that property. What value does the constructor get?
For questions such as this, I like to just write a sample program and see what happens.
Following is such a sample program.
import org.codehaus.jackson.annotate.JsonProperty;
import org.codehaus.jackson.map.ObjectMapper;
public class JacksonFoo
{
public static void main(String[] args) throws Exception
{
ObjectMapper mapper = new ObjectMapper();
// {"name":"Fred","id":42}
String jsonInput1 = "{\"name\":\"Fred\",\"id\":42}";
Bar bar1 = mapper.readValue(jsonInput1, Bar.class);
System.out.println(bar1);
// output:
// Bar: name=Fred, id=42
// {"name":"James"}
String jsonInput2 = "{\"name\":\"James\"}";
Bar bar2 = mapper.readValue(jsonInput2, Bar.class);
System.out.println(bar2);
// output:
// Bar: name=James, id=0
// {"id":7}
String jsonInput3 = "{\"id\":7}";
Bar bar3 = mapper.readValue(jsonInput3, Bar.class);
System.out.println(bar3);
// output:
// Bar: name=null, id=7
}
}
class Bar
{
private String name = "BLANK";
private int id = -1;
Bar(#JsonProperty("name") String n, #JsonProperty("id") int i)
{
name = n;
id = i;
}
#Override
public String toString()
{
return String.format("Bar: name=%s, id=%d", name, id);
}
}
The result is that the constructor is passed the default value for the data type.
How do I differentiate between a property having a null value versus a property that is not present in the JSON?
One simple approach would be to check for a default value post deserialization processing, since if the element were present in the JSON but had a null value, then the null value would be used to replace any default value given the corresponding Java field. For example:
import org.codehaus.jackson.annotate.JsonAutoDetect.Visibility;
import org.codehaus.jackson.annotate.JsonMethod;
import org.codehaus.jackson.map.ObjectMapper;
public class JacksonFooToo
{
public static void main(String[] args) throws Exception
{
ObjectMapper mapper = new ObjectMapper().setVisibility(JsonMethod.FIELD, Visibility.ANY);
// {"name":null,"id":99}
String jsonInput1 = "{\"name\":null,\"id\":99}";
BarToo barToo1 = mapper.readValue(jsonInput1, BarToo.class);
System.out.println(barToo1);
// output:
// BarToo: name=null, id=99
// {"id":99}
String jsonInput2 = "{\"id\":99}";
BarToo barToo2 = mapper.readValue(jsonInput2, BarToo.class);
System.out.println(barToo2);
// output:
// BarToo: name=BLANK, id=99
// Interrogate barToo1 and barToo2 for
// the current value of the name field.
// If it's null, then it was null in the JSON.
// If it's BLANK, then it was missing in the JSON.
}
}
class BarToo
{
String name = "BLANK";
int id = -1;
#Override
public String toString()
{
return String.format("BarToo: name=%s, id=%d", name, id);
}
}
Another approach would be to implement a custom deserializer that checks for the required JSON elements. And yet another approach would be to log an enhancement request with the Jackson project at http://jira.codehaus.org/browse/JACKSON
In addition to constructor behavior explained in #Programmer_Bruce's answer, one way to differentiate between null value and missing value is to define a setter: setter is only called with explicit null value.
Custom setter can then set a private boolean flag ("isValueSet" or whatever) if you want to keep track of values set.
Setters have precedence over fields, in case both field and setter exist, so you can "override" behavior this way as well.
I'm thinking of using something in the style of an Option class, where a Nothing object would tell me if there is such a value or not. Has anyone done something like this with Jackson (in Java, not Scala, et al)?
(My answer might be useful to some people finding this thread via google, even if it doesn't answer OPs question)
If you are dealing with primitive types which are omittable, and you do not want to use a setter like described in the other answers (for example if you want your field to be final), you can use box objects:
public class Foo {
private final int number;
public Foo(#JsonProperty Integer number) {
if (number == null) {
this.number = 42; // some default value
} else {
this.number = number;
}
}
}
this doesn't work if the JSON actually contains null, but it can be sufficient if you know it will only contain primitives or be absent
another option is to validate the object after deserialization either manually or via frameworks such java bean validation or, if you are using spring, the spring validation support.

Categories