2

I have code like this:

    ArrayList<Map<String, String>> resultArray = resultList.stream() //
            .map(parser::parseJson) //
            .filter(ev -> ev.entrySet().containsAll(filter.entrySet())) //
            .collect(Collectors.toCollection(ArrayList::new));

The caller resultList is an ArrayList, which is an array of JSON(s). I want to parse each element into map, filter the map, and collect the arrays of maps.

The code in the above line has no complier error. But at runtime it gives error as:

Error:(51, 25) java: incompatible types: cannot infer type-variable(s) 
R,A,capture#1 of ?,T,C,E (argument mismatch;
java.util.stream.Collector<java.util.Map<java.lang.String,java.lang.String>,capture#2 of 
?,java.util.ArrayList<java.util.Map<java.lang.String,java.lang.String>>
> cannot be converted to java.util.stream.Collector<? super 
java.util.Map,capture#2 of 
?,java.util.ArrayList<java.util.Map<java.lang.String,java.lang.String>>
>)

I've tried many different ways like Collectors.toList() but it doesn't work. I'm still after a clean solution for parsing each String element to map and collecting all of them as an ArrayList.

Update: the parser is from com.json.parsers.JSONParser;

1
  • 1
    what is parser::parseJson? can improve to List<Map<String, String>> resultArray as well. Commented Sep 21, 2018 at 19:44

1 Answer 1

3

According to the (almost cryptic) error message, the problem is in the parseJson method of your parser instance, which is returning a raw Map, i.e. a map that doesn't specify the types of its keys and values.

You need that method to return a Map<String, String>, or at least, to be generic, so that it can return the required type.


EDIT: I've never heard of your JSON parser. A quick google search showed that it is barely used and it seems like it's an archived project. I highly recommend you to move to a better JSON library, such as Jackson, Gson or maybe JSON.simple.

A quick and dirty solution with what you already have would be to cast the returned map to Map<String, String>, if you're sure that you actually have strings as values for all your keys (otherwise you might face the dreaded ClassCastException).

To accomplish this, you should change your code to:

List<Map<String, String>> resultArray = resultList.stream()
    .map(json -> (Map<String, String>) parser.parseJson(json))
    .filter(ev -> ev.entrySet().containsAll(filter.entrySet()))
    .collect(Collectors.toCollection(ArrayList::new));

But, again, bear in mind that this is not very clean and that you might be introducing more bugs with that cast. Best solution would be to use i.e. Jackson:

ObjectMapper mapper = new ObjectMapper(); // Jackson JSON lib entry-point

List<Map<String, String>> resultArray = resultList.stream()
    .map(json -> {
        try {
            return mapper.readValue(json, new TypeReference<Map<Striong, String>>() {});
        } catch (IOException e) {
            throw new UncheckedIOExpcetion(e);
        }
    })
    .filter(ev -> ev.entrySet().containsAll(filter.entrySet()))
    .collect(Collectors.toCollection(ArrayList::new));

Recommendation: you'd better move the whole try/catch block inside the map operation to a private method that returns Map<String, String>.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, I updated the question in the last line. Given that I can't modify that function, is there any way to make it work just from the code above?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.