The direct answer to your question is very very simple: Nope. No can do, impossible.
Java simply doesn't have what you want; there is no option to write intersection types and no option to let java provide for you a combinatory explosion of your various desired options here.
So we need to get creative; there are many many options that fulfill the general idea of what you want whilst not actually being what you specifically asked for.
Overloads
You have 4 different types you want to accept (File
, Image
, String
, and Color
), for each of 4 parameters. That's 4*4*4*4
= 256 methods required. You can write them all (oooof!), or you can use a code gen tool to generate them for you. Presumably you wouldn't want to regenerate it every time you change something, so code gen integrated into the build process: Annotation Processors.
It's... possible. But complicated, and I really don't think you'd want this. There's a limit to the # of methods in a single class file, and the java community as a whole just doesn't do it this way. As a consequence, the tools provided in the ecosystem don't expect it and therefore won't act 'nice' with this. Trivial case in point: If you really were to make 256 overloads here, any attempt to auto-complete on this one method is going to show all 256 methods in the dropdown and probably have a significant slowdown effect on your IDE, as the authors of the code completion code weren't thinking of this scenario.
Thus, I recommend strongly against this plan.
Sealed types and wrappers
Java16 brings sealed types directly, but even without java16 you can effectively have them by using access control of constructors.
Make a type called, I dunno, Border
, perhaps. This type has no public constructor; it only has 4 static methods that create a Border:
public class Border {
private Border(...) {}
public static Border ofColor(Color color) { ... }
public static Border ofImage(Color color) { ... }
...
}
You then write 1 setBorders
method that takes 4 Border
parameters, and that is all. One would call it as follows:
foo.setBorders(Border.ofColor(BLACK), Border.ofImage(leftImage), ...);
Given that there are only 4 ofX
methods and those are the only way to create Border objects, this is the only way you can invoke this method.
There is a slight issue with wordiness; Border.ofColor(Color.BLACK)
is a little superfluous and doesn't add much more visual info than the much shorter Color.BLACK
. That is unfortunate. One could statically import the ofX
methods, resulting in just ofColor(Color.BLACK)
which is a bit better, perhaps.
Builders
Even with the 'fix' of using sealed types/wrappers, one needs to remember that the ordering of the borders. Was it like CSS and ordered top, right, bot, left? Or was it something else? Yes, IDEs will help, but still. A builder solves both problems. You still need 17 methods, but that's better than 256.
Example:
public SetBordersBuilder setBorders() {
return new SetBordersBuilder();
}
public static class SetBordersBuilder {
private SetBordersBuilder() {}
public left(Image borderImage) { ... }
public left(String borderColorName) { .... }
// same for top, right, and bottom.
public void go() {
// actually sets the borders.
}
}
To use this, one would go:
foo.setBorders()
.left(Color.BLACK)
.top(someImage)
.. etcetera
.go();
runtime check only
Write one method, give them 4 parameters of type Object
, and go on an instanceof
bonanza. This is cruddy API: It lacks discoverability. Perusing just the signatures (for example, by reading an auto-complete dialog) I have no idea. It's a bit of a mystifying method call: I pass in 4 borders, and a border can be... any object? Weird. It's hard to know without diving into the docs what kinds of objects I can pass and what that might mean (how would I know that passing a String works and means the string is interpreted as the name of a border color?), and if I misunderstand and pass a type that the setBorders method doesn't understand I won't know it until I run that code and I get the exception. Much nicer if I get a red wavy underline as a type, and guidance as I call this thing. Hence, not recommended.
My advice? The builder solution, hands down.