简体   繁体   中英

Java: implicit type conversion, or implicit toString() invocation

In my Java application I created methods that return Either<String, T> objects.

This is because in some places I invoke these methods as the parameter of (3rd party) methods that expect a String parameter as input. While in other places I invoke these methods as the parameter of (3rd party) methods that expect some other parameter type (T) as input.

So depending on the place where I invoke the methods that I created, the code looks like:

their.thirdPartyExpectsString(my.calculateEither().getLeft());
their.thirdPartyExpectsString(my.calculateEither() + "");

or

their.thirdPartyExpectsDouble(my.calculateEither().getRight());

(I defined Either.toString() as Either.getLeft() ).

Pay attention, I cannot change the 3rd party code (anyway not without bytecode manipulation), and I would like to keep my design in which I return Either from my methods.

Is there a way to simplify my code and make it look like

their.thirdPartyExpectsString(my.calculateEither());
their.thirdPartyExpectsDouble(my.calculateEither());

Ie, not having to add the getLeft()/getRight() or + "" all the time?

Actually, it does not bother me much if I will have to do

their.thirdPartyExpectsDouble(my.calculateEither().getRight());

because I don't have to do it often. But I would like to get rid of the need to call getLeft() or + "" when my.calculateEither() returns a Left (a String).

Given an either , it's not hard to see if it represents Right or Left , simply by checking which side has a null .

But the problem is with the type conversion, ie the compilation error when thirdPartyExpectsString() expects a String but gets an Either .

I was able to catch the return value of my.calculateEither() by AspectJ but I could not see a way how to use something like @AfterReturning advice to make the compiler understand that I want to return my.calculateEither().getLeft() , ie a String ....

Any ideas?

Add the following method to your implementation of the Either class:

@SuppressWarnings("unchecked")
public <T> T whichever() {
    return (T) (isLeft() ? getLeft() : getRight());
}

Note that I'm purposefully ignoring the warning about the unchecked cast, and indeed will cause a ClassCastException if you use it in a place where the external API you interface with expects a left value but you invoke it on an Either instance which contains a right value. This method will do an implicit cast based on where you use it. It will cast to a T type where you pass it to another method which expects an argument of type T or you try to assign the method return value to a variable of type T.

So the following demo code:

Either<String, Double> containsString = Either.<String, Double>left("first");
Either<String, Double> containsDouble = Either.<String, Double>right(2d);

their.expectsString(containsString.whichever());
their.expectsDouble(containsDouble.whichever());
their.expectsDouble(containsString.whichever());

will work well in the first invocation and will cause a ClassCastException in the third invocation, just an one would expect, because we consider it as an illegal use case.

In conclusion, it's nice to know that it will work in all places where the T type to which we are implicitly casting is assignable to the actual value contained by the Either object. Unfortunately, you will only find out at run time , should this not be the case.

Add a helper method. Since you cannot add new methods to their , you have to add a static to a class of your own.

Pseudo-code:

public static void thirdParty(Their their, Either either) {
    if (either.isLeft())
        their.thirdPartyExpectsString(either.getLeft());
    else
        their.thirdPartyExpectsDouble(either.getRight());
}

You can now call:

MyHelper.thirdParty(their, my.calculateEither())

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM