RKB00014 ASMDataTable: Data of annotations and interfaces - Glease/RKB GitHub Wiki
ASMDataTable, as it's being called, is a table to store data obtained by analyzing class files with ASM. It is closely related to the ASM mechanism. Modders may use it for meta-programming. A sample usage is forestry plugin discovery.
The data comes from the subtypes of ITypeDiscoverer, namely JarDiscoverer and DirectoryDiscoverer. The ITypeDiscoverer will use the ASMModParser, which uses ModXXXVisitor to visit all the class files in the given classpath entry, that is, a jar or a directory, recursively of course. The underlying data will be sent to the ASMDataTable passed to the ITypeDiscoverer by the Loader.
The data mainly concerns about various annotations on ALMOST EVERYTHING!!! No matter the annotation is on a class, on a interface, on a method, on a constructor (actually ASM treats a method and a constructor in the same way) or on a field, it will all be part of that data. Its type wont't matters, too. Annotations on types, local variables or parameters are not that data though, which can hardly be useful.
Interestingly, the interfaces will also get recorded and sent to ASMDataTable. FML has some built in functions around ICrashCallable and such.
ASMData has no javadoc but/and its field name is both quite self-explaining and confusing. What may be confusing is that the ASMData class is both used to represent interface data and annotation data. The field annotation, className and objectName's meanings varys according to the context.
The annotation is the internal name of the annotation class. The className is the internal name of the class that has this annotation. The objectName is the name of the ... uh, object, that has such annotation. That objcet could be a type, a field or a method. annotationInfo field will be a bit complex.
annotationInfo is a String=>Object Map, it's key is the name of attribute of one annotation, its value's type is:
- If this attribute is a primitive value, then it's its boxed type
- If this attribute is an annotation, then it's
ModAnnotation. Werid class, right? I'll talk about that later. - If this attribute is a enum value, then it's its
EnumHolder. Yet another werid class. It's an inner class ofModAnnotation. - If this attribute is a
Class, then it'sorg.objectweb.asm.Type. - If this attribute is an array of any above types, then it's the corresponding
List<X>type. - If this attribute is an array of annotation, then it's
List<ModAnnotation>.
The annotation is the **class descriptor** of the interface class, not its fully qualified name. The className is the internal name of the class that has this interface implemented. The objectName and annotationData field will be null.
The class is very simple and easy to use. However, the only problem is, well, how one can obtain an instance of ASMDataTable. The ASMDataTable is in fact distributed via some FMLStateEvents.
The eariest one is FMLConstructionEvent, but yet I have no idea if subscribing that event directly ever works because the state is LoaderState.CONSTRUCTING and your mod class will have probably not yet loaded. You may need a IFMLLoadingPlugin and inject a ModContainer for this because ModContainer has a registerBus method which allow you to register necessary event handlers. Just a side note, the forge team has somehow a convention to using ModContainers as event handlers.
Here is a simple example:
- Implement a
ModContainer
- This is not a hard task. Just don't be so foolish to build it from scratch just because you need a
registerBus()method. ExtendDummyModContaineror its subclasses instead.
- This is not a hard task. Just don't be so foolish to build it from scratch just because you need a
- Add it to you
IFMLLoadingPlugin
- Simple. Return null or empty arrays for unwanted methods.
- Add
IFMLLoadingPluginto your jar manifest.
- Key:
FMLCorePlugin - Value: fully qualified name of your
IFMLLoadingPluginclass
- Key:
preInit event has it.
What are they? They are classes that represent an annotation. They could just be seen as a naive version of annotations you get via AnnotatedElement::getAnnotation, but without language intrinsics to support many features.
- You will have to manually downcast everything to their proper type.
- You will be getting some werid strings called _class descriptors_ instead of the standard
Classobject. Sometimes you will even get fully qualified names instead. (Read on to see when) - You will get
EnumHolderif you try to get an enum value, and it's not an instance ofEnum.
The ASMData is harvested even before mod is discovered. At that time it can't load any mod classes, so it's impossible to use concrete annotation and enum types, or it would bugs.
ModAnnotation is similiar to the ASMData class.
| ASMData field name | ModAnnotation's way |
|---|---|
| candidate | - |
| annotationName | modAnnotation.asmType.getClassName() |
| className | - |
| objectName | modAnnotation.member |
| info | values(*) |
EnumHolder is a simple class. The value field is the name of enum constant. The desc field is actually class descriptor, not fully qualified names and can't be directly used in Class::forName, though you won't be using that field because you should know the actual type of that enum so you can just use EnumFoo.class syntax, unless you want to somehow do some validation works.
