apiguardian-team / apiguardian Goto Github PK
View Code? Open in Web Editor NEW@API Guardian
Home Page: https://apiguardian-team.github.io/apiguardian/docs/current/api/
License: Apache License 2.0
@API Guardian
Home Page: https://apiguardian-team.github.io/apiguardian/docs/current/api/
License: Apache License 2.0
apiguardian-api-1.0.0.jar does not have LICENSE/NOTICE files (e.g. to META-INF/ folder), so it is kind of hard to tell the licensing for the artifact.
It would be nice if you add Bundle-License
manifest attribute on top of adding LICENSE file: https://github.com/bndtools/bnd/blob/master/biz.aQute.bnd.annotation/src/aQute/bnd/annotation/headers/BundleLicense.java
For instance: Bundle-License: Apache-2.0
API.consumers
allows according to the documentation the usage of wildcards:
The supplied packages can be fully qualified package names or patterns containing asterisks that will be used as wildcards.
However, it is not very specific regarding the following:
*
?a.*
match a.b
and a.b.c
?a
cannot be seen by a type in a.b
.a.b.*
matching a.b
*.a.*.b
a.tes*
matching a.test
and a.testing
Note that I do not suggest that the behavior described above is the desired one, it only lists what one might expect from wildcards.
Could you please clarify this in the documentation and possibly include some examples?
Please clearly indicate the names of the authors and the copyright date.
One of the nice things about Maven's pom.xml
file is that it defines a machine-readable format for listing the project title (name), license, main authors, contributors, inception year, project homepage, and other useful metadata. Such data can be fed into ORT, which helps to automatically generate a software bill of materials. IMO, it was a bit of an oversight by the Gradle team to not require such items as part of the build scripts (e.g., as standard property file entries).
Javadoc 1.8 cannot link to the documentation published at https://apiguardian-team.github.io/apiguardian/docs/1.1.0/api/
.
build.gradle
plugins {
id 'java-library'
}
sourceCompatibility = JavaVersion.VERSION_1_8
repositories.mavenCentral()
ext.apiGuardianVersion = '1.1.0'
dependencies {
api "org.apiguardian:apiguardian-api:${apiGuardianVersion}"
}
tasks.named('javadoc').configure {
options.links = [
'https://docs.oracle.com/javase/8/docs/api/',
"https://apiguardian-team.github.io/apiguardian/docs/${apiGuardianVersion}/api/"
] as String[]
}
src/main/java/Test.java
import org.apiguardian.api.API;
@API(status = API.Status.EXPERIMENTAL)
public class Test {}
$ ./gradlew javadoc
> Task :javadoc
javadoc: warning - Error fetching URL: https://apiguardian-team.github.io/apiguardian/docs/1.1.0/api/
1 warning
BUILD SUCCESSFUL in 1s
2 actionable tasks: 2 executed
$ ./gradlew --version
------------------------------------------------------------
Gradle 5.2.1
------------------------------------------------------------
Build time: 2019-02-08 19:00:10 UTC
Revision: f02764e074c32ee8851a4e1877dd1fea8ffb7183
Kotlin DSL: 1.1.3
Kotlin: 1.3.20
Groovy: 2.5.4
Ant: Apache Ant(TM) version 1.9.13 compiled on July 10 2018
JVM: 1.8.0_242 (AdoptOpenJDK 25.242-b08)
OS: Mac OS X 10.15.3 x86_64
Whereas
https://apiguardian-team.github.io/apiguardian/docs/current/api/
https://apiguardian-team.github.io/apiguardian/docs/1.0.0/api/
work.
Using Gradle 6.2.1 produces the same warning message.
@API
is only declared on public types/methods.Some fluent APIs use multiple intermediate types to restrict the available methods depending on what methods were called earlier in the call chain.
As an illustration, imagine a fictitious library that models SQL as Java method call chains:
// Compiles fine
Result result = db.select().from(table).where(criterion1).and(criterion2).execute();
// COMPILER ERROR: cannot find symbol and() on type Select1
Result result = db.select().from(table).and(criterion2).execute();
Adding new features to such APIs often causes changes in the state machine and thus re-numbering of intermediate types. Therefore, the library explicitly discourages users from defining variables such as Select2 select = db.select().from(table).where(criterion1);
.
Consequently, in its SemVer documentation the library excludes the names of these intermediate types from the public API. However, it promises that any method chain that worked in one release will still work in a subsequent minor release (albeit with possibly different intermediate type names).
Could such a library use API Guardian? If so, how? To me, the closest match would be documenting the entry point (the one with select()
with STABLE and the intermediate types (Select0
, Select1
etc) with INTERNAL - but the methods on those intermediate types would be STABLE. I interpret this to mean "don't rely on this type name, but rest assured the method will stay available".
With this interpretation, I could (and intent to) use API Guardian for fluent APIs in puretemplate. However, that usage may be counterintuitive to users and even frowned upon by the API Guardian team because the Javadocs for @API
say the following (emphasis mine):
If
@API
is present on a type, it is considered to hold for all public members of the type as well. However, a member of such an annotated type is allowed to declare aAPI.Status
of lower stability.
My "INTERNAL class with STABLE methods" trick is the exact reverse of this.
So, what do you think of this? Please note that I'm fine with any answer; I just wanted to bring this to your attention.
Here are some alternatives I can imagine:
API.Status
of lower stability" wording to "declare a different API.Status
", followed by two examples: one is the "with lower stability" case, the other is "INTERNAL class with STABLE methods, e.g. for fluent APIs".ANONYMOUS
for this. (No, I'm not seriously suggesting that.)The current set of Status
values looks consistent for most of projects. However, in a framework or library — which are intended to be used as building blocks — there is also often an additional need to indicate the designed extension points.
SPI
status solves such a task by taking "it is safe to use" semantic (i.e. STABLE
) and appending it with "you are welcome to extend this element" — as per SPI definition.
Some libraries dedicate a package to this purpose. However, package-based approach isn't always possible and it's way less convenient for tasks such as code inspection/post-processing.
In a way, this issue is similar to #9, but instead of restricting the API extension, I'd propose to mark the elements that are designed for it.
When should API.Status.DEPRECATED
be used? Normally you would use @java.lang.Deprecated
which has since Java 9 the elements since
and forRemoval
and is likely supported by every IDE.
So what are cases where one would (only) use API.Status.DEPRECATED
? Is it intended for situations where the public API will be removed, but the annotated element will still be available internally afterwards (though wouldn't @Deprecated
then be better as well)?
I am reviewing mockito/mockito#2047 atm, which adds apiguardian statements to various Mockito internal classes that are used by the mockito-junit-jupiter
extension. This approach is quite ad-hoc, as we would have to add the annotation when we start using it. An alternative approach would be to add the annotation to every single class we have in org.mockito.internal
, but that seems to be quite invasive as well.
Would it be possible to allow the annotation to be added on package statements (e.g. in a package-info.java
) for org.mockito.internal
? That would then indicate that all classes in its (sub-)packages are marked internal.
I am not sure if OSGi tooling would need to be updated to support the new location, but at least it would allow us to more nicely integrate apiguardian
into Mockito.
CC @rotty3000
For Frameworks and libraries it is quite common to provide interfaces and classes. But not all interfaces are intended to be implemented by clients, or classes may not be intended to be instantiated. If you write plugins for Eclipse you can use the Eclipse API Annotations to express such restrictions (and the IDE supports them by generating violation errors).
It would be nice to have a common-lib/apiguardian
that provides these so they may become standard.
Copied directly from Eclipse API Annotations:
Annotation Type | Description |
---|---|
NoExtend | Classes and interfaces tagged with this annotation are declaring they are not to be extended by clients. |
NoImplement | Interfaces tagged with this annotation are declaring they are not to be implemented by clients. |
NoInstantiate | Classes tagged with this annotation are declaring they are not to be instantiated by clients. |
NoOverride | Methods tagged with this annotation are declaring they are not to be overridden by clients. |
NoReference | Classes, interfaces, annotations, enums, methods and fields tagged with this annotation are declaring they are not to be referenced at all by clients. |
I'm missing API status that would mean "this is completely new feature and it will almost definitely change - expect SOME solution to problem solved by this, but don't get too attached to current form".
That way EXPERIMENTAL would mean something like "this API may morph, but gradually", while INCUBATING would mean "we have no clue how to describe this domain/context, but here's an approach".
I wouldn't provide any contract on what happens to such features in future versions, but I'd say that INCUBATING features shouldn't be promoted directly to MAINTAINED or STABLE and should go through EXPERIMENTAL stage first.
In the end, EXPERIMENTAL would mean "we're polishing this", while INCUBATING would mean "we're coming up with this".
From discussion in junit-team/junit5#2547, it was noted that the @API
annotation of API guardian has RUNTIME
retention policy - which means that some code might reasonably expect it to be available at runtime. (This is in contrast to a comment made earlier here stating that it was a compile-only dependency.)
Given that runtime retention implies that runtime usage is anticipated, API Guardian should probably at some stage get its own OSGi metadata to make it available at runtime in an OSGi context.
Status quo is that the statuses (huh, accidental wordplay, nice) are only described with javadocs. Missing part is some formal definition of state graph.
This API is only documentational unless there will be some tools provided that would check whether annotated elements behave as expected between versions. It can be quite easy to misinterpret the javadoc in some minor detail and that would result with different tools behaving differently (one could consider some API change as valid, another one could raise a warning in the same case). There should be strict definiton of rules that would be later shared by these tools.
See the picture for proposed graph, suited for 1.0.0 of apiguardian API.
An issue to be discussed: can STABLE go to MAINTAINED?
I'd say that it shouldn't. IMO STABLE should mean that API element in that state will stay for the end of major version lifecycle.
Another one: are there any restrictions on what happens when major version changes?
Again, I'd say that there shouldn't be. Change of major version defines basically a new API that may or may not look similiar to the previous one.
There is a pull request #3 that splits the repo to several modules. I would propose adding yet another module apiguardian-contract
that would contain some simple graph model (that would have domain names, so e.g. ApiElementState instead of Node and StateTransitionRule instead of Edge) and an utility class with static content that would provide set of rules describing the graph that was agreed upon and some ways to inspect it (methods like isValidStateChange(...)
and validStatesFrom(...)
).
There is WIP pull request #8 for my implementation draft.
Providing such module would make it easier for creators of tools to keep their behaviour consistent with different tools.
Sometimes a whole package could profit of an API annotation. Please add ElementType.PACKAGE
as allowed target.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.