Skip to content
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

Document how to declare that your JPMS module uses JSpecify #495

Open
xenoterracide opened this issue Mar 14, 2024 · 11 comments
Open

Document how to declare that your JPMS module uses JSpecify #495

xenoterracide opened this issue Mar 14, 2024 · 11 comments

Comments

@xenoterracide
Copy link

xenoterracide commented Mar 14, 2024

I'm not certain what libraries should do as far as their own jpms

should I have

import org.jspecify.annotations.NullMarked;

@NullMarked module com.xenoterracide.jpa {
  requires transitive static org.jspecify;
}

or

import org.jspecify.annotations.NullMarked;

@NullMarked module com.xenoterracide.jpa {
  requires static org.jspecify;
}

I would generally think the second, but then I'm constantly plagued by warnings from java of annotations at compile time that are missing, or missing dependent fields of. Is static actually appropriate? I notice that the annotations are marked as "runtime" but I don't understand the use case for that.

@SentryMan
Copy link

transitive and static cannot both take effect at the same time

@xenoterracide
Copy link
Author

xenoterracide commented Mar 15, 2024

is that true? I would think it'd be roughly equivalent to compileOnlyApi in gradle... it doesn't result in a compile error. I can't find anything that says either way.

https://www.oracle.com/corporate/features/understanding-java-9-modules.html

is like, we're going to glaze over that... reading it sounds like it would be optional, but any module, if it's available? would also be able to read it based on using mine... which doesn't sound mutually exclusive.

@agentgt
Copy link

agentgt commented Mar 15, 2024

I think and I’m tired so this is probably wrong

requires static transitive

The sort of reason is JSpecify annotations are retention RUNTIME.

I would say less than 1% of Java devs know this so it is a good point.

edit I will say I have never done requires transitive and static both so maybe there are compat issues or maybe it doesn’t work but iirc it does.

I use the eclipse annotations which are CLASS so requires static is good enough.

@SentryMan
Copy link

SentryMan commented Mar 15, 2024

is that true?

I guess not, but modules that depend on it will need to have jspecify in the dependency tree or they'll get a module not found error.

@agentgt
Copy link

agentgt commented Mar 15, 2024

I’m not sure of that when it comes to annotations. Like if you are just sniffing via reflection which is precisely why you want the transitive for nullness.

That is a third party runtime library trying to deduce if a field to inject is nullable or not.

@agentgt
Copy link

agentgt commented Mar 15, 2024

I wasn't at my computer before but it appears on googling @lukaseder had compat issues with Maven and I believe I did as well: jOOQ/jOOQ#13619

I will need to double check but I believe mine were with Javadoc of all things.

Ultimately I don't think it matters as the annotations are public but I believe requires static transitive is technically correct assuming tooling works in an application. For a library that may not be desired.

Later today I will try experimenting. @bowbahdoe do you have any experience with requires static transitive? I am sorry to ping you but there are not many (like I said I wager 1% of java devs are aware of most of the module rules) and at this point I think its more about compat with external tooling.

@bowbahdoe
Copy link

bowbahdoe commented Mar 15, 2024

@agentgt Yeah - i'm not too sure of a good usage for requires static transitive. You need it at compile time and dependent modules need it at compile time, but none need it at runtime.

Annotations that aren't on the module path just become invisible, so its perfectly fine to not require the jspecify annotations downstream. For me, I think thats interesting/important only when you want to have a zero dependency library. Once you have one dependency might as well have two.

I don't really understand the state of tooling either.

@cpovirk cpovirk changed the title provide JPMS advice in the user guide Document how to declare that your JPMS module uses JSpecify Mar 15, 2024
@cpovirk
Copy link
Collaborator

cpovirk commented Mar 15, 2024

@xenoterracide
Copy link
Author

xenoterracide commented Mar 15, 2024

I have one further comment about when annotations currently seem to be required on the compile class path, but I've only for sure seen this coming from things that you use the automatic modules. Since most libraries only use automatic modules currently.

The example would be if spring had a non-null (on my phone) annotation that had a field that supported A Jspecify annotation, then, in my experience spring needs to export in some way jspecify as well or you will get compiler warnings. This only happens of course if you're using that specific annotation from spring. I do not know and haven't tested if this is a problem when full JPMS is used. I can link an issue I opened in spring boot with this recently if it's helpful. Since the solution and Gradle would be to use the API or compile only API dependency scope.

@agentgt
Copy link

agentgt commented Mar 15, 2024

The example would be if spring had a non-null (on my phone) annotation that had a field that supported A Jspecify annotation, then, in my experience spring needs to export in some way jspecify as well or you will get compiler warnings. This only happens of course if you're using that specific annotation from spring. I do not know and haven't tested if this is a problem when full JPMS is used. I can link an issue I opened in spring boot with this recently if it's helpful. Since the solution and Gradle would be to use the API or compile only API dependency scope.

With javac you do not get compiler warnings or errors unless of course you actually access the annotations methods (the methods on the annotation itself). With ecj aka Eclipse Java compiler you will get a warning if you have a generic parameter annotated albeit I believe that is a bug. I can't recall if I have already told Stephan Herrmann about that.

You can actually see this through my current two projects code bases of jstachio and rainbowgum where I constantly have to SuppressWarnings of "exported".

@SuppressWarnings("exports")
public @Nullable /* this one is fine */ Object blah(List<@Nullable /* this one causes warnings */ Object> o) {
}

EDIT I think I misunderstood you. Yes you will need to requires as Spring does not have true modules.

Speaking of which you should never requires transitive any of Springs stuff because they are automatic modules. Which is annoying.

@xenoterracide
Copy link
Author

xenoterracide commented Mar 15, 2024

For clarity on warnings I'm referring to issues like this (linking to reproducer comment) spring-projects/spring-boot#39901 (comment)

spring-core currently has this exact kind of issue with jsr305

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants