In short:
I am trying to use a Java stream + map function to create a list of objects to return as response entities. But the compiler complains about private access for an inner class (despite not doing so in other circumstances).
Code:
public class Donkey {
...
public DonkeyResponseEntity toResponseEntity() {
DonkeyResponseEntity dre = new DonkeyResponseEntity();
dre.id = this.id;
dre.name = this.name;
dre.numDonkeysInPossee = this.numDonkeysInPossee;
return dre;
}
private class DonkeyResponseEntity {
public Long id;
public String name;
public Integer numDonkeysInPossee;
}
}
public class DonkeyService {
...
public ResponseEntity<?> getDonkeys(List<Donkey> previousDonkeyList) {
...
List<Object> donkeyPossee = previousDonkeyList.stream()
.map(donkey -> donkey.toResponseEntity()).collect(Collectors.toList()); // !!ERROR HERE!!
return new ResponseEntity<>(donkeyPossee, HttpStatus.OK);
}
...
}
The error happens on the line with .map(donkey -> donkey.toResponseEntity())
.
Why I'm Confused:
If I wrote something like the following, there is no access error:
Object d = previousDonkeyList.get(0).toResponseEntity();
or even
List<Object> donkeyPossee = previousDonkeyList.stream()
.filter(donkey -> donkey.toResponseEntity() == null);
Request:
Can someone please explain why this happens? I'm not quite sure why map
would take issue with this.
Clarification:
I'm not looking for alternative ways to accomplish this (using forEach
and manually adding to a List
works); I just want to know why map
doesn't approve.
The differences here come from the fact that the map
method in the Stream
class actually uses the type of the object returned from the mapping function - in this case it's DonkeyResponseEntity
. The filter
method does not operate in any way on the actual type, only on the object instance (verifies if the reference points to null
and returns a boolean). When getting the first element from the list you also do not refer to the type, because the reference is of type Object
:
// no error
Object d = previousDonkeyList.get(0).toResponseEntity();
If you were to use reference of type DonkeyResponseEntity
, the compiler would mark it as an error as well:
// error
DonkeyResponseEntity d = previousDonkeyList.get(0).toResponseEntity();
Interestingly if you used var
, the compiler would not mark it as an error, because no explicit private type is used:
// no error
var d = previousDonkeyList.get(0).toResponseEntity();
but even if the private class had public methods, you wouldn't be able to access them.
If you casted the returned object in the map
method, the compiler would not mark it as an error, because it doesn't need to know ("see" - have access to) the actual type of the object:
// no error
.map(donkey -> (Object) donkey.toResponseEntity())