0

I've this code where two lists are compared on the "vendor_id" field and I perform join on them. However this line is throwing NPE. I tried guarding with null but it doesn't seem to help.

public List<PGRatingResponse> collatePGRatingsbyVendor(List<PGRatingConfig> pgRatingSansPgname, List<Vendor> vendors) {
    return
                pgRatingSansPgname.stream().map(o1 -> {
                    vendors.stream()
                            .filter(o2 -> o2.getVendorId().equals(o1.getVendorId()))
                            .findAny();

                    return new PGRatingResponse(
                        o1.getVendorId(), 
                        vendors.stream()
                            .filter(o -> 
                               o.getVendorId().equals(o1.getVendorId()) 
                               && o.getVendorId()!=null)
                            .findFirst()
                            .get()
                            .getVendorName(), 
                        o1.getRating()
                           .stream().map(o -> 
                               new RatingResponse(
                                   pgLookupTable().getOrDefault(
                                      o.getPgId()==null?"":o.getPgId(), 
                                      "Default"), 
                                   o.getPgId()==null?"":o.getPgId(), 
                                   o.getValue()))
                           .collect(Collectors.toList()));

                }).collect(Collectors.toList());
}

The inner return statement in the lambda expression is the line number where the stack trace points to.

I'm still getting this exception: java.lang.NullPointerException] with error Id, error code and message [[com.service.configuration.PGRatingConfigService.lambda$collatePGRatingsbyVendor$2(PGRatingConfigService.java:50),java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195), java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1655), java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484), java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474), java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913), java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234), java.base

even when I made changes to this line:

return new PGRatingResponse(o1.getVendorId(), "Default",/*vendors.stream().filter(o -> o.getVendorId()!=null && o.getVendorId().equals(o1.getVendorId())).findFirst().get().getVendorName(),*/ o1.getRating().stream().map(o -> new RatingResponse(pgLookupTable().getOrDefault(o.getPgId()==null?"":o.getPgId(), "Default"), o.getPgId()==null?"":o.getPgId(), o.getValue()==null?0.0:o.getValue())).collect(Collectors.toList()));
yoda
  • 539
  • 1
  • 12
  • 32
  • 2
    have you tried using Optional? – Stultuske May 20 '21 at 15:45
  • 1
    `o.getVendorId().equals(o1.getVendorId()) && o.getVendorId()!=null` is backwards. The first condition will throw an NPE when the second condition is false. If you flip that then, only when the second condition is true, the first condition will execute. It should be `o.getVendorId()!=null && o.getVendorId().equals(o1.getVendorId())`. Fix that first and update with new results. It'd also be extremely helpful to know where the NPE is thrown. – Richard Barker May 20 '21 at 15:46
  • I've added full method. Would it be prudent sending over Optional to the caller? – yoda May 20 '21 at 15:48
  • I agree with @RichardBarker answer, I also had the same issue once, and by adding null check it worked, but in the beginning, you need to check the null. Also, you can use optional too. – Shant Khayalian May 20 '21 at 15:53
  • If you return an optional to the caller, then they have to change to accommodate that. – Richard Barker May 20 '21 at 15:53
  • @RichardBarker I changed the null condition and placed it first, NPE doesn't go away – yoda May 20 '21 at 15:55
  • 2
    Never use `Optional.get()` withtout a previous `Optional.isPresent()`, look at `Optional.orElse`, or `Optional.map()`, `Optional.flatMap` and `Optional.stream()` to rewrite the `.get()`, 90% the error is there (after the `.findFirst()`) – rascio May 20 '21 at 15:57
  • BTW, the stacktrace and line numbers will help in debug – rascio May 20 '21 at 15:59
  • @rascio updated the line that throws NPE – yoda May 20 '21 at 16:05
  • @rascio has the right idea. `Optional.get` throws when optional value is null iirc. – Richard Barker May 20 '21 at 16:08
  • @FordPerfect That is indeed the purpose of an `Optional`, to return a value that might legitimately be null. See [this Answer](https://stackoverflow.com/a/26328555/642706) straight from the horse’s mouth, [Brian Goetz](https://www.linkedin.com/in/briangoetz). – Basil Bourque May 20 '21 at 16:27
  • @rascio I believe can directly call `orElse` like so `findFirst().orElse("Default")` – yoda May 20 '21 at 17:02

1 Answers1

0

This was one hair pulling exercise, the null was coming from the outer list. the Rating object had null fetched from DB.

This was how it was fixed.

pgRatingSansPgname.stream().filter(o1 -> o1.getRating() != null).filter(Objects:nonNull).map(o1 -> {
...
yoda
  • 539
  • 1
  • 12
  • 32