• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Signature Formats
2
3This document describes the signature file format created and used by metalava,
4doclava, apicheck, etc.
5
6There are currently 3 versions of this format:
7
81. ~~The format emitted by doclava, and used for Android's signature files up
9   through Android P. Note that this isn't actually a single format; it evolved
10   over time, so older signature files vary a bit (many of these changes were
11   due to bugs getting fixed, such as type parameters missing from classes
12   and methods until they start appearing), and some were deliberate changes,
13   such as dropping the "final" modifier in front of every member if the
14   containing class is final.~~
15
16   <br/>**This version is deprecated and can no longer be specified as an output
17   format. It can still be consumed but there are no guarantees that it will
18   behave as expected.**<br/><br/>
19
202. The "new" format, which is described below, and is used in Android Q. This
21   format adds new information, such as annotations, parameter names and default
22   values, as well as cleans up a number of things (such as dropping
23   java.lang. prefixes on types, etc)
24
253. This is format v2, but with all nullness annotations replaced by a
26   Kotlin-syntax, e.g. "?" for nullable types, "!" for unknown/platform types,
27   and no suffix for non-nullable types. The initial plan was to include this
28   in format v2, but it was deferred since type-use annotations introduces
29   some complexities in the implementation.
30
31
32## Motivation
33
34Why did we change from the historical doclava signature format (v1)
35to a new format?
36
37In order to support Kotlin better (though this will also benefit Java
38developers), we'd like to have nullness annotations (as well as some other
39annotations) be a formal part of the SDK.
40
41That means the annotations should be part of the signature files too -- such
42that we can not just record explicitly what the API contract is, but also
43enforce that changes are not only deliberate changes but also compatible
44changes. (For example, you can change the return value of a final method from
45nullable to non null, but not the other way around.)
46
47And if we were going to change the signature format, we might as well make some
48other changes too.
49
50
51### Comments
52
53In v2, line comments (starting with //) are allowed. This allows us to leave
54reminders and other issues with the signature source (though the update-api task
55will generally blow these away, so use sparingly.)
56
57### Header
58
59New signature files (v2+) generally include a file header comment which states
60the version number. This makes it possible for tools to more safely interpret
61signature files. For example, in v3 the type "String" means "@NonNull String",
62but in v2 "String" means "String with unknown nullness".
63
64The header looks like this:
65
66```
67// Signature format: 2.0
68```
69
70Here "2" is the major format version; the .0 allows for compatible minor
71variations of the format.
72
73### Include Annotations
74
75The new signature format now includes annotations; not all annotations (such as
76@Override etc); only those which are significant for the API, such as nullness
77annotations, etc.
78
79Annotations are included on the same line as the class/field/method, right
80before the modifiers.
81
82Here's how this looks:
83
84
85```
86  method @Nullable public static Integer compute1(@Nullable java.util.List<java.lang.String>);
87```
88
89
90(Notice how the annotations are not using fully qualified name; that's discussed
91below.)
92
93The annotations to be included are annotations for annotation types that are not
94hidden, and have class file or runtime retention.
95
96The annotations should be sorted alphabetically by fully qualified name.
97
98
99### Use Special Syntax or Nullness Annotations
100
101(Note: Only in version format 3+)
102
103As a special optimization, since we eventually want **all** APIs to have
104explicit nullness, use Kotlin's syntax for nullness. That means that for
105nullable elements, we add "?" after the type, for unknown nullness we add "!",
106and otherwise there's no suffix. In other words:
107
108
109<table>
110  <tr>
111   <td>
112   </td>
113   <td>Java Type
114   </td>
115   <td>Signature File Type
116   </td>
117  </tr>
118  <tr>
119   <td>Nullable
120   </td>
121   <td>@Nullable String
122   </td>
123   <td>String?
124   </td>
125  </tr>
126  <tr>
127   <td>Not nullable
128   </td>
129   <td>@NonNull String
130   </td>
131   <td>String
132   </td>
133  </tr>
134  <tr>
135   <td>Unknown nullability
136   </td>
137   <td>String
138   </td>
139   <td>String!
140   </td>
141  </tr>
142</table>
143
144
145The above signature line is turned into
146
147
148```
149 method public Integer? compute1(java.util.List<java.lang.String!>?);
150```
151
152
153### Clean Up Terminology
154
155Format v2 also cleans up some of the terminology used to describe the class
156structure in the signature file. For example, in v1, an interface is called an
157"abstract interface"; an interface extending another interface is said to
158"implement" it instead of "extend"-ing it, etc; enums and annotations are just
159referred to as classes that extend java.lang.Enum, or java.lang.Annotation etc.
160
161With these changes, these lines from v1 signature files:
162
163
164```
165  public abstract interface List<E> implements java.util.Collection { ... }
166  public class TimeUnit extends java.lang.Enum { ... }
167  public abstract class SuppressLint implements java.lang.annotation.Annotation { ... }
168```
169
170
171are replaced by
172
173
174```
175    public interface List<E> extends java.util.Collection<E> { ... }
176    public enum TimeUnit { ... }
177    public @interface SuppressLint { ... }
178```
179
180
181
182### Use Generics Everywhere
183
184The v1 signature files uses raw types in some places but not others.  Note that
185in the above it was missing from super interface Collection:
186
187
188```
189  public abstract interface List<E> implements java.util.Collection { ... }
190```
191
192
193 whereas in the v2 format it's included:
194
195
196```
197    public interface List<E> extends java.util.Collection<E> { ... }
198```
199
200
201Similarly, v1 used erasure in throws clauses. For example, for this method:
202
203
204```
205    public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X
206```
207
208v1 used this signature:
209
210
211```
212 method public <X extends java.lang.Throwable> T orElseThrow(java.util.function.Supplier<? extends X>) throws java.lang.Throwable;
213```
214
215Note how that's "throws Throwable" instead of "throws X". This results in b/110302703.
216
217In the v2 format we instead use the correct throws type:
218
219```
220 method public <X extends java.lang.Throwable> T orElseThrow(java.util.function.Supplier<? extends X>) throws X;
221```
222
223
224### Support Annotations
225
226The old format was completely missing annotation type methods:
227
228```
229  public static abstract class ViewDebug.ExportedProperty implements java.lang.annotation.Annotation {
230  }
231```
232
233We need to include annotation member methods, as well as their default values
234since those are API-significant. Here's how this looks in the v2 file format
235(also applying the @interface terminology change described above) :
236
237
238```
239  public static @interface ViewDebug.ExportedProperty {
240    method public abstract String category() default "";
241    method public abstract boolean deepExport() default false;
242    method public abstract android.view.ViewDebug.FlagToString[] flagMapping() default {};
243    method public abstract boolean formatToHexString() default false;
244    method public abstract boolean hasAdjacentMapping() default false;
245    method public abstract android.view.ViewDebug.IntToString[] indexMapping() default {};
246    method public abstract android.view.ViewDebug.IntToString[] mapping() default {};
247    method public abstract String prefix() default "";
248    method public abstract boolean resolveId() default false;
249  }
250```
251
252
253### Support Kotlin Modifiers
254
255This doesn't currently apply to the SDK, but the signature files are also used
256in the support library, and some of these are written in Kotlin and exposes
257Kotlin-specific APIs.
258
259That means the v2 format can express API-significant aspects of Kotlin. This
260includes special modifiers, such as sealed, inline, operator, infix, etc:
261
262```
263 method public static operator int get(android.graphics.Bitmap, int x, int y);
264 method public static infix android.graphics.Rect and(android.graphics.Rect, android.graphics.Rect r);
265```
266
267### Support Kotlin Properties
268
269Kotlin's Java support means that it wil take a Kotlin property and compile it
270into getters and setters which you can call from Java. But you cannot calls
271these getters and setters from Kotlin; you **must** use the property
272syntax. Therefore, we need to also capture properties in the signature files. If
273you have this Kotlin code:
274
275
276```
277         var property2: String? = "initial"
278```
279
280it will get recorded in the signature files like this:
281
282```
283         property public java.lang.String? property2 = "initial";
284         method public java.lang.String? getProperty2();
285         method public void setProperty2(java.lang.String? p);
286```
287
288The last two elements are "redundant"; they could be computed from the property
289name (and included if the property declaration uses special annotations to name
290the getters and setters away from the defaults), but it's helpful to be explicit
291(and this allows us to specify the default value).
292
293### Support Named Parameters
294
295Kotlin supports default values for parameters, and these are a part of the API
296contract, so we need to include them in the signature format.
297
298Here's an example:
299
300```
301    method public static void edit(android.content.SharedPreferences, boolean commit);
302```
303
304In v1 files we only list type names, but in v2 we allow an optional parameter
305name to be specified; "commit" in the above.
306
307Note that this isn't just for Kotlin. Just like there are special nullness
308annotations to mark up the null contract for an element, we will also have a
309special annotation to explicitly name a Java parameter:
310@android.annotation.ParameterName (which is hidden). This obviously isn't usable
311from Java, but Kotlin client code can now reference the parameter.
312
313Therefore, the following Java code (not signature code) will also produce
314exactly the same signature as the above:
315
316```
317    public static void edit(SharedPreferences prefs, @ParameterName("commit") boolean ct) {…}
318```
319
320(Note how the implementation parameter doesn't have to match the public, API
321name of the parameter.)
322
323### Support Default Values
324
325In addition to named parameters, Kotlin also supports default values. These are
326also be part of the v2 signature since (as an example) removing a default value
327is a compile-incompatible change.
328
329Therefore, the v2 format allows default values to be specified after the type
330and/or parameter name:
331
332```
333    method public static void edit(SharedPreferences, boolean commit = false);
334```
335
336For Kotlin code, the default parameter values are extracted automatically, and
337for Java, just as with parameter names, you can specify a special annotation to
338record the default value for usage from languages that support default parameter
339values:
340
341```
342    public static void edit(SharedPreferences prefs, @DefaultValue("false") boolean ct) {…}
343```
344
345
346### Include Inherited Methods
347
348Consider a scenario where a public class extends a hidden class, and that hidden
349class defines a public method.
350
351Doclava did not include these methods in the signature files, but they **were**
352present in the stub files (and therefore part of the API). In the v2 signature
353file format, we include these.
354
355An example of this is StringBuilder#setLength. According to the old signature
356files, that method does not exist, but clearly it's there in the SDK. The reason
357this happens is that StringBuilder is a public class which extends hidden class
358AbstractStringBuilder, which defines the public method setLength.
359
360
361### No Hardcoded Enum Methods
362
363Doclava always inserted two special methods in the signature files for every
364enum: values() and valueOf():
365
366```
367  public static final class CursorJoiner.Result extends java.lang.Enum {
368    method public static android.database.CursorJoiner.Result valueOf(java.lang.String);
369    method public static final android.database.CursorJoiner.Result[] values();
370    enum_constant public static final android.database.CursorJoiner.Result BOTH;
371    enum_constant public static final android.database.CursorJoiner.Result LEFT;
372    enum_constant public static final android.database.CursorJoiner.Result RIGHT;
373  }
374```
375
376It didn't do that in stubs, because you can't: those are special methods
377generated by the compiler. There's no reason to list these in the signature
378files since they're entirely implied by the enum, you can't change them, and
379it's just extra noise.
380
381In the new v2 format these are no longer present:
382
383```
384  public static enum CursorJoiner.Result {
385    enum_constant public static final android.database.CursorJoiner.Result BOTH;
386    enum_constant public static final android.database.CursorJoiner.Result LEFT;
387    enum_constant public static final android.database.CursorJoiner.Result RIGHT;
388  }
389```
390
391### Remove "deprecated" Modifier
392
393The old signature file format used "deprecated" as if it was a modifier. In the
394new format, we instead list these using annotations, @Deprecated.
395
396### Standard Modifier Order
397
398Doclava had a "random" (but stable) order of modifiers.
399
400In the new signature format, we're using the standard modifier order for Java
401and Kotlin, wihch more closely mirrors what is done in the source code.
402
403Version format 1 order:
404
405```
406public/protected/private default static final abstract synchronized transient volatile
407```
408
409Version format 2 order:
410
411```
412public/protected/internal/private abstract default static final transient volatile synchronized
413```
414
415The above list doesn't include the Kotlin modifiers, which are inserted
416according to the Kotlin language style guide:
417https://kotlinlang.org/docs/reference/coding-conventions.html#modifiers
418
419### Sort Classes By Fully Qualified Names
420
421In "extends" lists, the signature file can list a comma separated list of
422classes. The classes are listed by fully qualified name, but in v1 it was sorted
423by simple name. In the v2 format, we sort by fully qualified name instead.
424
425### Use Wildcards Consistently
426
427Doclava (v1) would sometimes use the type bound <?> and other times use <?
428extends Object>. These are equivalent. In the v2 format, <? extends Object> is
429always written as <?>.
430
431### Annotation Simple Names
432
433We have a number of annotations which are significant for the API -- not just
434the nullness as deprecation ones (which are specially supported in v3 via the
435?/! Kotlin syntax and the deprecated "modifier"), but annotations for permission
436requirements, range constraints, valid constant values for an integer, and so
437on.
438
439In the codebase, these are typically in the android.annotation. package,
440referencing annotation classes that are generally **not** part of the API. When
441we generate the SDK, we translate these into publicly known annotations,
442androidx.annotation, such that Studio, lint, the Kotlin compiler and others can
443recognize the metadata.
444
445That begs the question: which fully qualified name should we put in the
446signature file? The one that appeared in the source (which is hidden, or in the
447case of Kotlin code, a special JetBrains nullness annotation), or the one that
448it gets translated into?
449
450In v2 we do neither: We use only the simple name of the annotations in the
451signature file, for annotations that are in the well known packages. In other
452words, instead of any of these alternative declarations:
453
454```
455   method public void setTitleTextColor(@android.annotation.ColorInt int);
456   method public void setTitleTextColor(@androidx.annotation.ColorInt int);
457```
458
459in v2 we have simply
460
461```
462   method public void setTitleTextColor(@ColorInt int);
463```
464
465### Simple Names in Java.lang
466
467In Java files, you can implicitly reference classes in java.lang without
468importing them. In v2 offer the same thing in signature files. There are several
469classes from java.lang that are used in lots of places in the signature file
470(java.lang.String alone is present in over 11,000 lines of the API file), and
471other common occurrences are java.lang.Class, java.lang.Integer,
472java.lang.Runtime, etc.
473
474This basically builds on the same idea from having an implicit package for
475annotations, and doing the same thing for java.lang: Omitting it when writing
476signature files, and implicitly adding it back when reading in signature files.
477
478This only applies to the java.lang package, not any subpackages, so for example
479java.lang.reflect.Method will **not** be shortened to reflect.Method.
480
481### Type Use Annotations
482
483In v3, "type use annotations" are supported which means annotations can appear
484within types.
485
486### Skipping some signatures
487
488If a method overrides another method, and the signatures are the same, the
489overriding method is left out of the signature file. This basically compares the
490modifiers, ignoring some that are not API significant (such as "native"). Note
491also that some modifiers are implicit; for example, if a method is implementing
492a method from an interface, the interface method is implicitly abstract, so the
493implementation will be included in the signature file.
494
495In v2, we take this one step further: If a method differs **only** from its
496overridden method by "final", **and** if the containing class is final, then the
497method is not included in the signature file. The same is the case for
498deprecated.
499
500### Miscellaneous
501
502Some other minor tweaks in v2:
503
504*   Fix formatting for package private elements. These had two spaces of
505    indentation; this is probably just a bug. The new format aligns their
506    indentation with all other elements.
507*   Don't add spaces in type bounds lists (e.g. Map<X,Y>, not Map<X, Y>.)
508
509## Historical API Files
510
511Metalava can read and write these formats. To switch output formats, invoke it
512with for example --format=v2.
513
514The Android source tree also has checked in versions of the signatures for all
515the previous API levels. Metalava can regenerate these for a new format.
516For example, to update all the signature files to v3, run this command:
517
518```
519$ metalava android-jars-to-signatures *<android source dir>* --format=v3
520```
521