-
Notifications
You must be signed in to change notification settings - Fork 39
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Introduce MoreTypes
utility class
#234
Conversation
7cda41b
to
7990365
Compare
7990365
to
c267b8f
Compare
Rebased and resolved conflict. |
c267b8f
to
7602247
Compare
I'm wondering whether we should make the check that uses Within that check, we could give different error messages based on the type. Instead of double nested types like We could also do this later though. (Started reviewing this one). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a commit.
Have some suggestions and questions 😄.
The PR itself is very cool! Nice one to review :).
private MoreTypes() {} | ||
|
||
/** | ||
* Creates a supplier of the type with the given fully qualified name. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason for not using {@link Supplier}
? :)
/** | ||
* A set of helper methods which together define a DSL for defining {@link Type types}. | ||
* | ||
* <p>These methods are meant to be statically imported. Example usage: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's add this class to StaticImport
.
* @return A supplier which returns the described type if available in the given state, and {@code | ||
* null} otherwise. | ||
*/ | ||
public static Supplier<Type> supOf(Supplier<Type> type) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
public static Supplier<Type> supOf(Supplier<Type> type) { | |
public static Supplier<Type> superOf(Supplier<Type> type) { |
I think this makes the difference between sub
and sup
a bit more clear. WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I liked the symmetry, but: sure :)
// method name. But the DSL wouldn't look as nice that way. | ||
@SafeVarargs | ||
@SuppressWarnings("varargs") | ||
public static Supplier<Type> generic(Supplier<Type> type, Supplier<Type>... typeArgs) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
public static Supplier<Type> generic(Supplier<Type> type, Supplier<Type>... typeArgs) { | |
public static Supplier<Type> genericWithParams(Supplier<Type> type, Supplier<Type>... typeArgs) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To me, generic
could be a bit more descriptive. One needs to really dive into the MoreTypes
before understanding how this works. genericWithParams
would be a nice option.
Another option would be genericType{,WithParams}
with String
as first parameter. However, in the current situation we always pass Type
s as parameter.
I know MoreTypes.genericType(......
has a little duplication, but we statically import every method here of course.
But the DSL wouldn't look as nice that way.
IMHO the DSL is very concise (even if we would make some of the method names a little longer).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The given
type
should be a generic type
In EP I see checks for this:
boolean isGeneric = typeParams != null && !typeParams.isEmpty();
Maybe it'd be nice to add a check for that in this method? Using checkArgument
we can enforce that others use this DSL correctly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not yet feeling the first suggestion: in practice the code will look like generic(type("fqcn"), ...)
, which should be clear enough. The class also has only a few methods, and there's an example at the top, which shows how this method can be used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
W.r.t. the second suggestion: since the type evaluation is deferred, I'm not sure an IllegalArgumentException
is warranted; perhaps an IllegalStateException
would fit. Even so: the type might not have a matching set of generic type parameters due to an unexpected type on the classpath (perhaps due to an unsupported dependency version), which IMHO should not cause an error, but simply cause the expression to yield false
.
final class MoreTypesTest { | ||
private static final ImmutableSet<Supplier<Type>> TYPES = | ||
ImmutableSet.of( | ||
type("java.lang.Nonexistent"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we should have a test that verifies use cases like this:
private static Stream<Arguments> incorrectTypesTestCases() {
return Stream.of(
arguments(type("")),
arguments(type("java.lang.Nonexistent")),
arguments(generic(type("java.util.Integer"), unbound())));
...
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The first one throws an exception. The third can be added to the list here, as that will verify that (a) it doesn't match and (b) doesn't throw an exception. (Which I think it shouldn't, for the reason mentioned above. That will of course feel weird for java.util.Integer
, but not for custom.package.TypeThatWasRefactoredToHaveADifferentNumberOfTypeArgs
.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The first one throws an exception.
Together with the other proposed change, that would be exactly what we could test 😄.
I now understand why it wouldn't be nice to add these extra checks, so I'm fine to leave it as is :).
Rebased and added a small commit. |
26a75f2
to
df41c50
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rebased and added a commit. Tnx for the critical review!
We could also do this later though.
Yeah, let's defer the generalization idea; need to think how useful/desirable that is (for example, on the face of it disallowing Flux<Flux<?>>
seems to make sense, until one realizes that this type is produced with Flux#groupBy
. The same might hold in a few other cases.)
private MoreTypes() {} | ||
|
||
/** | ||
* Creates a supplier of the type with the given fully qualified class name. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't need to be a class.
* Creates a supplier of the type with the given fully qualified class name. | |
* Creates a supplier of the type with the given fully qualified name. |
.github/workflows/build.yaml
Outdated
@@ -20,7 +20,7 @@ jobs: | |||
- name: Check out code | |||
uses: actions/[email protected] | |||
- name: Set up JDK | |||
uses: actions/setup-java@v3.5.1 | |||
uses: actions/setup-java@v3.6.0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have some stray commits here; will rebase.
// method name. But the DSL wouldn't look as nice that way. | ||
@SafeVarargs | ||
@SuppressWarnings("varargs") | ||
public static Supplier<Type> generic(Supplier<Type> type, Supplier<Type>... typeArgs) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not yet feeling the first suggestion: in practice the code will look like generic(type("fqcn"), ...)
, which should be clear enough. The class also has only a few methods, and there's an example at the top, which shows how this method can be used.
// method name. But the DSL wouldn't look as nice that way. | ||
@SafeVarargs | ||
@SuppressWarnings("varargs") | ||
public static Supplier<Type> generic(Supplier<Type> type, Supplier<Type>... typeArgs) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
W.r.t. the second suggestion: since the type evaluation is deferred, I'm not sure an IllegalArgumentException
is warranted; perhaps an IllegalStateException
would fit. Even so: the type might not have a matching set of generic type parameters due to an unexpected type on the classpath (perhaps due to an unsupported dependency version), which IMHO should not cause an error, but simply cause the expression to yield false
.
* @return A supplier which returns the described type if available in the given state, and {@code | ||
* null} otherwise. | ||
*/ | ||
public static Supplier<Type> supOf(Supplier<Type> type) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I liked the symmetry, but: sure :)
final class MoreTypesTest { | ||
private static final ImmutableSet<Supplier<Type>> TYPES = | ||
ImmutableSet.of( | ||
type("java.lang.Nonexistent"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The first one throws an exception. The third can be added to the list here, as that will verify that (a) it doesn't match and (b) doesn't throw an exception. (Which I think it shouldn't, for the reason mentioned above. That will of course feel weird for java.util.Integer
, but not for custom.package.TypeThatWasRefactoredToHaveADifferentNumberOfTypeArgs
.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the explanations!
Tweaks look good to me 😄.
final class MoreTypesTest { | ||
private static final ImmutableSet<Supplier<Type>> TYPES = | ||
ImmutableSet.of( | ||
type("java.lang.Nonexistent"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The first one throws an exception.
Together with the other proposed change, that would be exactly what we could test 😄.
I now understand why it wouldn't be nice to add these extra checks, so I'm fine to leave it as is :).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good 👍 Don't have much to add, nothing caught my eye 🤷♂️
return null; | ||
} | ||
|
||
return state.getType(baseType, /* isArray= */ false, params); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isArray
is always false
because Suppliers.arrayOf(...)
should be used to describe that type, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's been a while since I wrote this, but indeed, I think Suppliers.arrayOf(...)
would then be used to wrap the result of this method. 👍
The static methods of this class allow one to construct complex types, against which expression types can subsequently be matched.
df41c50
to
79ee60b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rebased; will merge once built.
return null; | ||
} | ||
|
||
return state.getType(baseType, /* isArray= */ false, params); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's been a while since I wrote this, but indeed, I think Suppliers.arrayOf(...)
would then be used to wrap the result of this method. 👍
Suggested commit message:
I'll also push these changes to #224, to show how they can simplify that PR.