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 is just for Kotlin. There is no support for using this for Java 308as Java does not consider parameter names to be part of the API and so Kotlin 309will not use parameter names when calling Java. 310 311### Support Default Values 312 313In addition to named parameters, Kotlin also supports default values. These are 314also be part of the v2 signature since (as an example) removing a default value 315is a compile-incompatible change. 316 317Therefore, the v2 format allows default values to be specified after the type 318and/or parameter name: 319 320``` 321 method public static void edit(SharedPreferences, boolean commit = false); 322``` 323 324For Kotlin code, the default parameter values are extracted automatically. 325However, Java does not provide any way of specifying default values. 326 327### Include Inherited Methods 328 329Consider a scenario where a public class extends a hidden class, and that hidden 330class defines a public method. 331 332Doclava did not include these methods in the signature files, but they **were** 333present in the stub files (and therefore part of the API). In the v2 signature 334file format, we include these. 335 336An example of this is StringBuilder#setLength. According to the old signature 337files, that method does not exist, but clearly it's there in the SDK. The reason 338this happens is that StringBuilder is a public class which extends hidden class 339AbstractStringBuilder, which defines the public method setLength. 340 341 342### No Hardcoded Enum Methods 343 344Doclava always inserted two special methods in the signature files for every 345enum: values() and valueOf(): 346 347``` 348 public static final class CursorJoiner.Result extends java.lang.Enum { 349 method public static android.database.CursorJoiner.Result valueOf(java.lang.String); 350 method public static final android.database.CursorJoiner.Result[] values(); 351 enum_constant public static final android.database.CursorJoiner.Result BOTH; 352 enum_constant public static final android.database.CursorJoiner.Result LEFT; 353 enum_constant public static final android.database.CursorJoiner.Result RIGHT; 354 } 355``` 356 357It didn't do that in stubs, because you can't: those are special methods 358generated by the compiler. There's no reason to list these in the signature 359files since they're entirely implied by the enum, you can't change them, and 360it's just extra noise. 361 362In the new v2 format these are no longer present: 363 364``` 365 public static enum CursorJoiner.Result { 366 enum_constant public static final android.database.CursorJoiner.Result BOTH; 367 enum_constant public static final android.database.CursorJoiner.Result LEFT; 368 enum_constant public static final android.database.CursorJoiner.Result RIGHT; 369 } 370``` 371 372### Remove "deprecated" Modifier 373 374The old signature file format used "deprecated" as if it was a modifier. In the 375new format, we instead list these using annotations, @Deprecated. 376 377### Standard Modifier Order 378 379Doclava had a "random" (but stable) order of modifiers. 380 381In the new signature format, we're using the standard modifier order for Java 382and Kotlin, wihch more closely mirrors what is done in the source code. 383 384Version format 1 order: 385 386``` 387public/protected/private default static final abstract synchronized transient volatile 388``` 389 390Version format 2 order: 391 392``` 393public/protected/internal/private abstract default static final transient volatile synchronized 394``` 395 396The above list doesn't include the Kotlin modifiers, which are inserted 397according to the Kotlin language style guide: 398https://kotlinlang.org/docs/reference/coding-conventions.html#modifiers 399 400### Sort Classes By Fully Qualified Names 401 402In "extends" lists, the signature file can list a comma separated list of 403classes. The classes are listed by fully qualified name, but in v1 it was sorted 404by simple name. In the v2 format, we sort by fully qualified name instead. 405 406### Use Wildcards Consistently 407 408Doclava (v1) would sometimes use the type bound <?> and other times use <? 409extends Object>. These are equivalent. In the v2 format, <? extends Object> is 410always written as <?>. 411 412### Annotation Simple Names 413 414We have a number of annotations which are significant for the API -- not just 415the nullness as deprecation ones (which are specially supported in v3 via the 416?/! Kotlin syntax and the deprecated "modifier"), but annotations for permission 417requirements, range constraints, valid constant values for an integer, and so 418on. 419 420In the codebase, these are typically in the android.annotation. package, 421referencing annotation classes that are generally **not** part of the API. When 422we generate the SDK, we translate these into publicly known annotations, 423androidx.annotation, such that Studio, lint, the Kotlin compiler and others can 424recognize the metadata. 425 426That begs the question: which fully qualified name should we put in the 427signature file? The one that appeared in the source (which is hidden, or in the 428case of Kotlin code, a special JetBrains nullness annotation), or the one that 429it gets translated into? 430 431In v2 we do neither: We use only the simple name of the annotations in the 432signature file, for annotations that are in the well known packages. In other 433words, instead of any of these alternative declarations: 434 435``` 436 method public void setTitleTextColor(@android.annotation.ColorInt int); 437 method public void setTitleTextColor(@androidx.annotation.ColorInt int); 438``` 439 440in v2 we have simply 441 442``` 443 method public void setTitleTextColor(@ColorInt int); 444``` 445 446### Simple Names in Java.lang 447 448In Java files, you can implicitly reference classes in java.lang without 449importing them. In v2 offer the same thing in signature files. There are several 450classes from java.lang that are used in lots of places in the signature file 451(java.lang.String alone is present in over 11,000 lines of the API file), and 452other common occurrences are java.lang.Class, java.lang.Integer, 453java.lang.Runtime, etc. 454 455This basically builds on the same idea from having an implicit package for 456annotations, and doing the same thing for java.lang: Omitting it when writing 457signature files, and implicitly adding it back when reading in signature files. 458 459This only applies to the java.lang package, not any subpackages, so for example 460java.lang.reflect.Method will **not** be shortened to reflect.Method. 461 462### Type Use Annotations 463 464In v3, "type use annotations" are supported which means annotations can appear 465within types. 466 467### Skipping some signatures 468 469If a method overrides another method, and the signatures are the same, the 470overriding method is left out of the signature file. This basically compares the 471modifiers, ignoring some that are not API significant (such as "native"). Note 472also that some modifiers are implicit; for example, if a method is implementing 473a method from an interface, the interface method is implicitly abstract, so the 474implementation will be included in the signature file. 475 476In v2, we take this one step further: If a method differs **only** from its 477overridden method by "final", **and** if the containing class is final, then the 478method is not included in the signature file. The same is the case for 479deprecated. 480 481### Miscellaneous 482 483Some other minor tweaks in v2: 484 485* Fix formatting for package private elements. These had two spaces of 486 indentation; this is probably just a bug. The new format aligns their 487 indentation with all other elements. 488* Don't add spaces in type bounds lists (e.g. Map<X,Y>, not Map<X, Y>.) 489 490## Historical API Files 491 492Metalava can read and write these formats. To switch output formats, invoke it 493with for example --format=v2. 494 495The Android source tree also has checked in versions of the signatures for all 496the previous API levels. Metalava can regenerate these for a new format. 497For example, to update all the signature files to v3, run this command: 498 499``` 500$ metalava android-jars-to-signatures *<android source dir>* --format=v3 501``` 502