javajava-streamaccess-modifiersmap-function

Java Streams Map Function with Private Inner Class Error


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.


Solution

  • 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())