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.

Table of Contents

Regarding data

Source of data

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.

What data

Annotations

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.

Subclasses that implement a certain interface

Interestingly, the interfaces will also get recorded and sent to ASMDataTable. FML has some built in functions around ICrashCallable and such.

How to use ASMDataTable

Structure of ASMData

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.

If it is annotation data...

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 of ModAnnotation.
  • If this attribute is a Class, then it's org.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>.
If you still don't understand how to use that map... I have no idea how to teach you that.

If it is interface data

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.

Obtaining an instance of ASMDataTable

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.

For those who want ASMData early

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:

  1. 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. Extend DummyModContainer or its subclasses instead.
  1. Add it to you IFMLLoadingPlugin
Simple. Return null or empty arrays for unwanted methods.
  1. Add IFMLLoadingPlugin to your jar manifest.
Key: FMLCorePlugin
Value: fully qualified name of your IFMLLoadingPlugin class

For ordinary users modders

preInit event has it.


The evil of ModAnnotations and EnumHolders

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 of Enum.

All evils come with reasons

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.

What are they?

ModAnnotation is similiar to the ASMData class.

ASMData field name ModAnnotation's way
candidate -
annotationName modAnnotation.asmType.getClassName()
className -
objectName modAnnotation.member
info values(*)
\*: Same type, different names.

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.

⚠️ **GitHub.com Fallback** ⚠️