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