-1

I am dirtying my hands with the fantastic library of vavr (0.9.2).

Here's a code snippet, that aims to collect an Either:

    Either<Tuple2<Enum<ReportByTeamExecutionErrors>,String>, List<MayurDAO>> payloadPreparationResult =
    new ReportByTeamCriteriaSchemaChecker("./json/schema/REQ_ReportByTeam_Schema.json")
    .validateSchema(payLoad) // payload is JSON and is a paramter to this holding function
.map(JsonPOJOBidirectionalConverter::pojofyCriteriaAllFieldsTeam)
.map((e) -> {
        CriteriaTeamAllFieldsValidator validator =  new CriteriaTeamAllFieldsValidator(e.right().get());
        return(validator.validate());
 })
 .map((e) -> retrieveRecordsAsPerCriteria(e.right().get())) // compiler doesn't approve of this line!!
 ;

The retrieveRecordsAsPerCriteria method is defined this way:

private Either<Tuple2<Enum<ReportByTeamExecutionErrors>,String>, List<MayurDAO>>
    retrieveRecordsAsPerCriteria(CriteriaAllFieldsTeam criteriaAllFieldsTeam) {

        Optional<List<MayurDAO>> retrievedRecords = new MayurModel().retrieveRecords(criteriaAllFieldsTeam);

        return( (retrievedRecords.isPresent())
                ? (Either.right(retrievedRecords.get()))
                : Either.left(
                        Tuple.of(
                             ReportByTeamExecutionErrors.NO_RECORDS_FOUND_TO_MATCH_CRITERIA,
                             "No records have been found, which match the criteria passed"
                        )
                       )
            );
    }

The compiler is complaining:

./com/myApp/application/ReportByTeamResource.java:58: error: incompatible types: cannot infer type-variable(s) L,R .map((e) -> retrieveRecordsAsPerCriteria(e.right().get())); ^ (actual and formal argument lists differ in length) where L,R are type-variables: L extends Object declared in method right(R) R extends Object declared in method right(R) 1 error

The List is from java.util.List.

I am at my wit's end to understand the source of the problem. The types should easily inferred, or so I think.

enter image description here

IntelliJ seems to be OK with the transformations till this objectionable line! In that line, however, the type parameter U is not decipherable. Could someone please nudge me to the path I am unable to see, for some reason?

Nirmalya
  • 717
  • 9
  • 19
  • Looks like quite some convoluted types with the nested Eithers. The thing that can make your snippet compile would be to replace the final `map` by a `flatMap`. But maybe it's a better idea to replace the nested `Either`, probably have a look at `flatMap` for this. – Hinse ter Schuur Dec 06 '18 at 18:13

1 Answers1

1

Probably you might want to use flatMap instead of map. The advantage of flatMap is that you don't get the nested eithers which you then need to unwrap in some way (like you are currently doing with .right().get() in your current code).

So the code would look something like this then:

Either<Tuple2<Enum<ReportByTeamExecutionErrors>,String>, List<MayurDAO>> payloadPreparationResult =
new ReportByTeamCriteriaSchemaChecker("./json/schema/REQ_ReportByTeam_Schema.json")
    .validateSchema(payLoad)
    .flatMap(JsonPOJOBidirectionalConverter::pojofyCriteriaAllFieldsTeam)
    .flatMap(e -> {
        CriteriaTeamAllFieldsValidator validator =  new CriteriaTeamAllFieldsValidator(e);
        return (validator.validate());
    })
    .flatMap(this::retrieveRecordsAsPerCriteria)
  • Yes, flatMap works - and many thanks for that - but doesn't it sound rather counter-intuitive? Well, from the Javadoc: _flatMap_ returns 'this as Either if this is a Left, otherwise the right mapping result', whereas _map_ returns 'a mapped Monad'! This probably explains it, because map is kind of 'wrapping' it again! I don't know if that is the correct behaviour. – Nirmalya Dec 07 '18 at 14:24
  • With `map` you transfrom the value if it's a right (success). But the `map` operations cannot indicate failure in terms of a `Left`. That is where the `flatMap` comes in. If you want your transforming operation to indicate success failure with an Either you should use flatMap. This will make sure that you will get a _flat_ `Either` back (instead of a nested `Either). Hence the name _flatMap_. – Hinse ter Schuur Dec 10 '18 at 06:51
  • Agreed. I understand that I ended my earlier comment, rather confusingly. Apologies. The map() returns a Monad, but I am looking for a definite projection (Left or Right). Therefore, what I could have done was to use a pattern-matching inside the mapper and return an explicit Left or Right. Of course, in such a case, I would perhaps repeat myself while treating the 'Left's! A flatMap() saves me from all that, because till the end I am not interested about what does Either's LeftProjection contains. Thanks for taking time to elaborate your point. – Nirmalya Dec 13 '18 at 10:49