2

In my WebApplication I have to check many incoming query parameters from the requestBody. In order not to write the same code in every method, I want to write a function that returns a boolean. When all required parameters are received and the values of the entrySet are not null the method should return true (otherwise false), i can use the incoming query parameters later on in the programm.

Therefore I pack all incoming parameters into a HashMap. Additionally I put a specific list into the method, which provides the required parameters(keys) for checking.

Example Map of queryParams:

Map queryParams = new HashMap();

queryParams.put("id", "1");
queryParams.put("name", "Jane");
queryParams.put("lastname", "Doe");

Example Array:

String[] keys = {"id", "name", "lastname"};

Last version of method:



public static Boolean checkRequestParams(Request request, String[] keys) {
        Map params = (JsonUtil.fromJson(request.body(), HashMap.class));

        Iterator it = params.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry pair = (Map.Entry) it.next();
            for (int i = 0; i < keys.length; i++) {
                if (pair.getKey().equals(keys[i])) {
                    return true;
                }

            }

The Array provides the keys which are the QueryParams the client sent. No i want to compare them and check if the keys in the Hashmap equals to the given keys in the array and if the values of the keys in the Map are not null.

I have tried many variations. Either I got nullPointerExceptions or I always got a null return.

Hubi
  • 440
  • 1
  • 11
  • 25

4 Answers4

2

I might be wrong, but as I understood you want to do validate the following condition:

  1. The HashMap keys must belong to the following list of keywords {"id", "name", "lastname"}.
  2. No value from the HashMap should be equal to null.

You might use something similar to this:

map.entrySet()
   .stream()
   .allMatch(entry -> keys.contains(entry.getKey()) && entry.getValue() != null)

So we iterate over the entrySet and check if entry key belong to the defined set and if value is not null. Here is a more detailed example:

Set<String> keys = Set.of("id", "name", "lastname");
Map<String,List<Integer>> map = Map.of("id", List.of(1,2,3), "name", List.of(4,5,6));

map.entrySet()
        .stream()
        .allMatch(entry -> keys.contains(entry.getKey()) && entry.getValue() != null);

Map<String,List<Integer>> map1 = Map.of("id", List.of(1,2,3), "not in the keys", List.of(4,5,6));
map1.entrySet()
        .stream()
        .allMatch(entry -> keys.contains(entry.getKey()) && entry.getValue() != null);

Please note that I am using collections factory methods to create Map,List and Set which has been added to java-9, but stream api is available since java-8.

As for your code, you will always get true, because as soon as there is an entrySet which satisfies the condition the method will return result.

for (int i = 0; i < keys.length; i++) {
                if (pair.getKey().equals(keys[i])) {
                    return true; // one single match found return true. 
                }

            }

You can try to reverse the condition and return false as soon as there is a mismatch.

for (int i = 0; i < keys.length; i++) {
                if (!pair.getKey().equals(keys[i]) || pair.getValue() == null) {
                    return false; // mismatch found, doesn't need to verify 
                    // remaining pairs. 
                }

            }
return true; // all pairs satisfy the condition. 

I hope you find this useful.

Anton Balaniuc
  • 10,889
  • 1
  • 35
  • 53
1

Just using vanilla Java you could try something like this.

import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ValidatorExample {

    public boolean checkRequestParams(Map<String, Object> request, List<String> keys) {
        return isEqualCollection(request.keySet(), keys)
                && !containsAnyNull(request.values());
    }

    private boolean isEqualCollection (Collection<?> a,Collection<?> b){
        return a.size() == b.size()
                && a.containsAll(b)
                && b.containsAll(a);
    }

    private boolean containsAnyNull(Collection<?> collection){
        return collection.contains(null);
    }

    public static void main(String[] args) {
        ValidatorExample validatorExample = new ValidatorExample();
        List<String> keys = Arrays.asList("id", "name", "lastname");

        Map<String, Object> parametersOk = new HashMap<>();
        parametersOk.put("id", "idValue");
        parametersOk.put("name", "nameValue");
        parametersOk.put("lastname", "lastnameValue");
        // True expected
        System.out.println(validatorExample.checkRequestParams(parametersOk, keys));

        Map<String, Object> parametersWithInvalidKey = new HashMap<>();
        parametersWithInvalidKey.put("id", "id");
        parametersWithInvalidKey.put("name", "nameValue");
        parametersWithInvalidKey.put("lastname", "lastnameValue");
        parametersWithInvalidKey.put("invalidKey", "invalidKey");
        // False expected
        System.out.println(validatorExample.checkRequestParams(parametersWithInvalidKey, keys));

        Map<String, Object> parametersWithNullValue = new HashMap<>();
        parametersWithNullValue.put("id", null);
        parametersWithNullValue.put("name", "nameValue");
        parametersWithNullValue.put("lastname", "lastnameValue");
        // False expected
        System.out.println(validatorExample.checkRequestParams(parametersWithNullValue, keys));
    }


}

But I would recommend you to use a validation framework if your project allows it for a more accurate validation.

Ezequiel
  • 3,477
  • 1
  • 20
  • 28
0

Should not return immediately if a match is found as we want to test 'all required' parameters. Try something like:

String[] keys = {"id, "name", "lastname"};
public static Boolean checkRequestParams(Request request, String[] keys) {
    Map params = (JsonUtil.fromJson(request.body(), HashMap.class));
    for (int i = 0; i < keys.length; i++) {
        Iterator it = params.entrySet().iterator();
        boolean found = false;
        while (it.hasNext()) {
            Map.Entry pair = (Map.Entry) it.next();
            if (pair.getKey().equals(keys[i])) {
                found = true;
                break;
            }
        }
        if (!found) {
            return false;
        }
    }
    return true;
}
Jayr
  • 94
  • 1
  • 9
0

You are returning true on the first matching key, whereas you want to check whether all keys are present. Further, your code is incomplete, hence, it is impossible to give full diagnostics.

But anyway, there’s no sense in iterating over map here. Just use

public static Boolean checkRequestParams(Request request, String[] keys) {
    Map<?,?> params = JsonUtil.fromJson(request.body(), HashMap.class);
    for(String key: keys) {
        if(params.get(key) == null) return false;
    }
    return true;
}

This will ensure that each key is present and not mapping to null (as “not mapping to null” already implies being present).

When not considering the possibility of an explicit mapping to null, you could check the presence of all keys as simple as

public static Boolean checkRequestParams(Request request, String[] keys) {
    Map<?,?> params = JsonUtil.fromJson(request.body(), HashMap.class);
    return params.keySet().containsAll(Arrays.asList(keys));
}

Alternatively, you could consider a map invalid if any mapped value is null, even if its key is not one of the mandatory keys. Then, it would be as simple as

public static Boolean checkRequestParams(Request request, String[] keys) {
    Map<?,?> params = JsonUtil.fromJson(request.body(), HashMap.class);
    return params.keySet().containsAll(Arrays.asList(keys))
        && !params.values().contains(null);
}
Holger
  • 285,553
  • 42
  • 434
  • 765