Annotation Interface GenerateLibrary.Abstract
- Enclosing class:
GenerateLibrary
AbstractMethodError if they are not exported for a given
receiver type. To customize this behavior the library message can specify a method body and
annotate it with GenerateLibrary.Abstract to keep requiring an implementation from exports.
For example:
@GenerateLibrary
public abstract class ArrayLibrary extends Library {
@Abstract(ifExported = "read")
public boolean isArray(Object receiver) {
return false;
}
@Abstract(ifExported = "isArray")
public int read(Object receiver, int index) {
throw new UnsupportedOperationException();
}
}
In this example a receiver that does not export the ArrayLibrary will return
false for isArray and throw an
UnsupportedOperationException for read calls. A message may be made
conditionally abstract by specifying the ifExported() attribute.- Since:
- 19.0
- See Also:
-
Optional Element Summary
Optional ElementsModifier and TypeOptional ElementDescriptionString[]Specifies a message to be abstract only if another message is implemented.String[]Specifies a message to be abstract only if another message is implemented.Specifies a custom replacement method to handle delegation for a message declared withreplacementOf().A tool to deprecate and replace messages during library evolution.
-
Element Details
-
ifExported
String[] ifExportedSpecifies a message to be abstract only if another message is implemented. Multiple other messages can be specified. If the list is empty, the message is always abstract unlessifExportedAsWarning()is not empty. If the list is not empty it takes precedence overifExportedAsWarning().For example:
@GenerateLibrary public abstract class ArrayLibrary extends Library { @Abstract(ifExported = "read") public boolean isArray(Object receiver) { return false; } @Abstract(ifExported = "isArray") public int read(Object receiver, int index) { throw new UnsupportedOperationException(); } }In this example the isArray message only needs to be exported if the read message is exported and vice-versa.- Since:
- 19.0
- Default:
{}
-
ifExportedAsWarning
String[] ifExportedAsWarningSpecifies a message to be abstract only if another message is implemented. Multiple other messages can be specified. The message is not actually made abstract unless it is in theifExported()list. Only a warning is produced that prompts the user to implement the messageFor example:
@GenerateLibrary public abstract class MaybeNumberLibrary extends Library { public boolean isNumber(Object receiver) { return false; } @Abstract(ifExportedAsWarning = "isNumber") public Number getNumber(Object receiver) { throw new UnsupportedOperationException(); } }In this example, if the isNumber message is exported and the getNumber message is not, the user gets a warning.- Since:
- 23.0
- Default:
{}
-
replacementOf
String replacementOfA tool to deprecate and replace messages during library evolution.The primary use case is to facilitate transitions from one message to another by designating a new message as a replacement for an older, deprecated message. When this annotation is present, and the deprecated message is not explicitly implemented, a default implementation is generated that delegates from the deprecated message to its designated replacement. The message specification may optionally include argument types in parentheses. When delegation cannot be handled automatically, a custom implementation can be provided using
replacementMethod().The migration behavior between deprecated and replacement messages depends on whether the exporter (the library implementer) and the client (the library user) have migrated to the new API. The following combinations are supported:
- Both exporter and client use the deprecated API: The original deprecated message is used exactly as before deprecation. No delegation or generated replacement is involved.
- Exporter uses the deprecated API, client uses the new API: The default implementation of the new message is used. It delegates to the exporter's implementation of the deprecated message.
- Exporter uses the new API, client uses the deprecated API: The annotation
processor generates an implementation of the deprecated message that delegates to the
exporter's new message. When the default delegation is insufficient, the
replacementMethod()can be used to provide a custom conversion or adapter. - Both exporter and client use the new API: The generated deprecated message is no longer needed and can be safely removed once all usages have migrated.
Example:
@GenerateLibrary public abstract class ArrayLibrary extends Library { @Abstract(ifExported = "isArray") @Deprecated public int read(Object receiver, int index) { throw new UnsupportedOperationException(); } @Abstract(ifExported = "isArray", replacementOf = "read(Object, int)") public int read(Object receiver, long index) { throw new UnsupportedOperationException(); } }In this example, theread(Object, long)message replacesread(Object, int). If only the new message is implemented, the following delegation is generated automatically:public int read(Object receiver, int index) { return read(receiver, (long) index); }Legacy clients can continue calling the deprecated message, while exporters need only implement the new message signature.- Since:
- 25.1
- See Also:
- Default:
""
-
replacementMethod
String replacementMethodSpecifies a custom replacement method to handle delegation for a message declared withreplacementOf().This attribute provides a way to manually implement delegation logic when automatic delegation from the deprecated message to its replacement cannot be generated correctly. Typical reasons include differences in argument semantics, necessary type conversions, or behavioral changes that cannot be inferred automatically.
This element is only valid when
replacementOf()is also set. Using it withoutreplacementOfwill result in a compilation error. The specified method must have a compatible signature and be accessible from the annotated message.Example:
@Abstract(ifExported = "isArray", replacementOf = "read(Object, int)", replacementMethod = "readLegacy") public int read(Object receiver, long unsignedIndex) { throw new UnsupportedOperationException(); } protected final int readLegacy(Object receiver, int index) { long unsignedIndex = Integer.toUnsignedLong(index); return read(receiver, unsignedIndex); }In this example, the deprecatedread(Object, int)message cannot be automatically delegated toread(Object, long)because the index must be treated as unsigned. The customreadLegacymethod therefore provides the correct conversion logic.- Since:
- 25.1
- See Also:
- Default:
""
-