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 FMLStateEvent
s.
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 ModContainer
s 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. ExtendDummyModContainer
or 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
IFMLLoadingPlugin
to your jar manifest.
- Key:
FMLCorePlugin
- Value: fully qualified name of your
IFMLLoadingPlugin
class
- 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
Class
object. Sometimes you will even get fully qualified names instead. (Read on to see when) - You will get
EnumHolder
if 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.