Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8311907

Field variables crash stream filtering

XMLWordPrintable

      ADDITIONAL SYSTEM INFORMATION :
      Windows 10, Java 17 Temurin

      A DESCRIPTION OF THE PROBLEM :
      In my case, when I use streams for filtering fields of specific class, if I use my method, that returns stream, and after this I use lambdas instead of method links, it will always return empty collection (or map, or any other. Lambda can be placed even not in filtering part)

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      1. Create simple class that helps to work with Reflection API:
      @RequiredArgsConstructor(staticName = "of", onConstructor = @__(@NonNull))
      public class UnsafeSupport<T> {

          private final Class<T> targetClass;

          public Stream<Field> getAllFieldsUpTo(Class<? super T> maximumSuperClass) {
              return Stream.<Class<?>>iterate(
                              targetClass,
                              Objects::nonNull,
                              Class::getSuperclass)
                      .flatMap(currentClass -> Arrays.stream(currentClass.getDeclaredFields()))
                      .filter(field -> maximumSuperClass.isAssignableFrom(field.getDeclaringClass()))
                      .filter(field -> !maximumSuperClass.equals(field.getDeclaringClass()));
          }
      }

      3. Create additional utility class for our expiriment:

      @UtilityClass
      public class StreamUtils {

          public <T> T self(T value) {
              return value;
          }
      }

      2. Use this method in separated class, for instance:

      public abstract class ReactiveViewProcessor extends ReactiveDataTableProcessor {

          private Map<Field, Field> generateIdentifierMap() {
              return UnsafeSupport.of(getClass())
                      .getAllFieldsUpTo(ReactiveViewProcessor.class)
                      .collect(Collectors.toUnmodifiableMap(
                              StreamUtils::self,
                              StreamUtils::self));
          }
      }

      3. If we call everything with StreamUtils::self (method reference), everything is fine, but if we use
      field -> field
      instead any of StreamUtils::self, it will always return empty collection (or map in our case)

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      Expectation was that it is allowed to do the same with lambdas
      ACTUAL -
      Results differ if we use or not method referencing instead of lambdas

      ---------- BEGIN SOURCE ----------
      @RequiredArgsConstructor(staticName = "of", onConstructor = @__(@NonNull))
      public class UnsafeSupport<T> {

          private final Class<T> targetClass;

          public Stream<Field> getAllFieldsUpTo(Class<? super T> maximumSuperClass) {
              return Stream.<Class<?>>iterate(
                              targetClass,
                              Objects::nonNull,
                              Class::getSuperclass)
                      .flatMap(currentClass -> Arrays.stream(currentClass.getDeclaredFields()))
                      .filter(field -> maximumSuperClass.isAssignableFrom(field.getDeclaringClass()))
                      .filter(field -> !maximumSuperClass.equals(field.getDeclaringClass()));
          }
      }

      @UtilityClass
      public class StreamUtils {

          public <T> T self(T value) {
              return value;
          }
      }

      public abstract class ReactiveViewProcessor extends ReactiveDataTableProcessor {

          private Map<Field, Field> generateIdentifierMap() {
              return UnsafeSupport.of(getClass())
                      .getAllFieldsUpTo(ReactiveViewProcessor.class)
                      .collect(Collectors.toUnmodifiableMap(
                              StreamUtils::self,
                              StreamUtils::self));
          }
      }

      ---------- END SOURCE ----------

      FREQUENCY : always


            tongwan Andrew Wang
            pnarayanaswa Praveen Narayanaswamy
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: