In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-16 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >
Share
Shulou(Shulou.com)06/01 Report--
Editor to share with you how to generate code through annotations in Dart. I hope you will get something after reading this article. Let's discuss it together.
Background recently used the annotation code generation technology in Dart in the project, which is still different from the previous APT+JavaPoet code generation technology in Java, such as
How can I get class-related information in Flutter when dart:mirror is disabled and reflection cannot be used?
Dart files are not limited to class, but can be function or class, so how do you get layers of information instead of just toplevel information when the scope of annotation scanning is different?
How do you generate complex template code when the annotation information is extracted?
How to solve the above problems in Flutter? The mystery will be unveiled step by step.
A simple example.
Let's start with a simple example of how to generate code through annotations in dart.
Declare a comment and use it
In Dart, just decorate the constructor with const. You can see that the annotation of Dart is relatively simple to declare, unlike in java, there have to be run types such as RunTime, Source, etc.
Generator for parsing annotations
In Dart, we generally use GeneratorForAnnotation in source_gen, which inherits from Generator, which is similar to the responsibility of processor in Java APT. We need to fill in the generics of GeneratorForAnnotation with the comments we need to deal with.
Builer that triggers the generator
With the above generator for generating annotations, we also need Builder to trigger
Create a profile build.yaml
Run builder
Because Flutter disables dart:mirror cannot use reflection, it can only be triggered at compile time through the command. Execute the following command, and you will see the generated code
Do you feel the peculiarity of the code generated by Dart annotations, such as Generator of AnnotationProcessor Tool in Java, but with Builder and build.yaml, so how do these work together to generate annotations?
Macroscopic concept
Use binoculars to get a macroscopic overview of the whole process
When we trigger build after using buildrunner's build, we will read the configuration information of the build.yaml file, which will eventually be read by the BuildConfig class in buildconfig.dart, and then trigger the annotation generator (TestGenerator) by reading to builder, the testBuilder of the above example. To extract information from the abstract syntax tree (because source_gen encapsulates the parsing library analysis and the resource processing library build, which actually blocks the parsing process), like java, they are all Element. For more information, please see the implementation class of the code.
To sum up, there are the following core parts:
User trigger-file scanning-lexical analysis-annotation extraction-code generation
Micro exploration
Then use a magnifying mirror to study the details:
Build.yaml configuration
In Java, we use AutoService annotations provided by Google to generate META-INF/services/javax.annotation.processing.Processor files associated with annotation processors, but dart annotations in Flutter can only be written at compile time, so we need a configuration to tell the compiler which builder is triggered, corresponding to the build.yaml file, first take a look at a build.yaml configuration and feel it.
The information of build.yaml configuration will eventually be read by the BuildConfig class in buildconfig.dart. At present, there is not much information about the parameter description. Here, we recommend the official description buildconfig, which can be parsed through the BuildeConfig under the buildconfig package.
The parsing entry is as follows
As you can see from build_config.dart, there are mainly four major parts to be parsed. Here are two commonly used ones for analysis.
Targets
You can see a description of the supporting attributes in build_target.dart#BuildTarget, including a builder attribute that is used more frequently.
There are three commonly used properties in TargetBuilderConfig
Enable
Whether the current builder is effective
Generate_for
This attribute is important to determine which files / folders are scanned or which files input_set.dart are excluded, using the following
You can also see the use of the generatefor attribute in its yaml file in jsonseriable's build.yaml
Options
This property allows you to carry some configuration data to the code generator in the form of key-value pairs, corresponding to the BuildOption parameter, which will be described again when interpreting builder.
Builder
Have a builder.
BuilderOptions can be extracted to the above option attribute configuration
As described above in the build.yaml file, Map
For more configuration, please see builder_definition.dart.
There are two important attributes that are explained separately.
Run_before
You can specify the running order of builder. If several buidler depend on each other, for example, you can use this attribute in Ali's routing framework annotationroute. You can take a look at its yaml file. Mustache4dart is mainly used in the routing framework to collect routing information to fill the template. Its solution is to use two builder, one for collecting information (routeWriteBuilder). After collection, combine the mustache4dart template with another builder (routeBuilder) to generate the required routing table. For more information, please see its routegenerator.dart.
Auto_apply
If you look at the text, it may be a little obscure to understand, so create a picture to explain it. For example, the annotation function is used in the libB above:
When we set auto_apply to dependents:
If the annotation package is directly dependent on libB, you can only use the annotation normally on libB. Although the top-level Package package relies on libB, it still cannot be used properly.
When we set autoapply to allpackages:
If the annotation package is directly dependent on libB, then annotations can be used normally on both libB and top-level Package
When we set autoapply to rootpackage:
If the annotation package is directly dependent on the libB, then you can only use the annotation on the top-level Package. Although it is a dependency on the libB, it just cannot be used. However, when the annotation package is directly dependent on the top-level Package, it can be used normally regardless of whether the autoapply is set to dependents, allpackages or root_package.
About source_gen
Brief introduction
After understanding the yaml file for the basic configuration, I have to mention source_gen, a powerful library
Sourcegen provides a series of friendly wrappers based on the official analysis/build, while sourcegen is based on analyzer and build libraries, where
Build library is mainly the processing of resource files.
Analyser library is the dart file generation syntax structure source_gen mainly deal with dart source code, you can generate code through annotations.
Introduction to core classes
Sourcegen derives its own builder from the Builder provided by the build library and encapsulates three
Builder (builder.dart) | _ Builder (builder.dart) |-LibraryBuilder (builder.dart) |-SharedPartBuilder (builder.dart) |-PartBuilder (builder.dart)
SharedPartBuilder
Generate .g.dart files, just like jsonseriable, where you need to use part of references, so the biggest advantage is that you don't need to pay too much attention to referencing issues, but note that you need to use sourcegen | combining_builder, which merges all .g files.
LibraryBuilder generates separate files
PartBuilder Custom part File
Generator Generator
And source_gen encapsulates a set of Generator, the above buidler receives the collection of Generator, collects the output of Generator to generate a file, Generator is just an abstract class, and the concrete implementation class is GeneratorForAnnotation, which can only intercept elements at the top-level level (explained later) by default, and will be accepted by the annotation generator as a specified annotation type, that is, GeneratorForAnnotation is a single annotation processor, for example
Because analyser provides the abstract element Element and its metadata field of the syntax node, corresponding to ElementAnnotation, the annotation generator can check whether the metadata type of the element matches the declared annotation type, so as to find out the information about the annotated element and its context, and then wrap the information to the user.
The core method generateForAnnotatedElement, for example, we have an annotation code like this.
From the above, we can see that the generateForAnnotatedElement method is mainly overridden, with three key parameters
Element element
The element modified by annotation can obtain the name, metadata, visibility, and so on.
For more api, check element.
About toplevel comments
As mentioned earlier, only elements at the toplevel level can be intercepted, so none of the internal methods in class can be scanned. This is because unlike java, a file can only correspond to one class, and the dart file can be function, class or others, so it can only be intercepted to the top-level level by default. Later, developers need to handle it manually. For example, ClassElement provides methods and fields to give developers the opportunity to further deal with annotations. The following shows the methods in the parsing class, and the properties are similar.
In addition to ClassElementImpl, Element also has a number of derivatives such as FunctionElementImpl, ParamElementImpl, etc., which can be checked on your own.
ConstantReader annotation
Represents the annotation object, through which you can extract annotation-related information and parameter values in two key ways
Read
Peek
The difference is that if the read method reads a parameter name that does not exist, it throws an exception, while peek does not return null.
BuildStep buildStep
Through the information built this time, you can get some input and output information, such as input file name and so on.
Core code analysis
Source_gen is also encapsulated from the Builder of the build library.
Sourcegen implements its own Builder according to Builder, and derives SharedPartBuilder, LibraryBuilder and PartBuilder according to different characteristics.
There's a core Generator in it.
When Builder runs, the generate method of Generator is called, passing in two important parameters:
Library can get source code information as well as annotation information
BuildStep represents a step in the build process, through which we can get the input and output information of some files.
Among them, the source code information contained in library is an Element element, Element is just an abstract class, concrete or a ClassElementImpl, FuncationElementImpl and so on. Source_gen implements this class of GeneratorForAnnotation
In the second point, library.annotatedWith (typeChecker) goes in to have a look.
Code generation
Pure string concatenation
Using three quotation mark syntax, this can only solve some low-level builds
Mustach
Prefabricated template, through certain rules, extract information and then fill it into the template. A typical example is as follows
The learning cost is low, and it is suitable for some fixed format code generation, such as routing table, which is adopted by Ali's annotation_route framework. You can take a look at its template tpl.
Then two generators are used, one to collect information and the other to inject the collected information into the mustach template
Code_builder
Very powerful, friends who have played with java annotations to generate code must be familiar with javapoet, the two are very similar, code_builder can be subdivided into expressions, statements, functions, classes, etc., but the learning cost is relatively high, so you need to generate the corresponding code according to its syntax, such as generating a class.
Generate an expression
Comparison with the code generated by java comments
After reading this article, I believe you have a certain understanding of "how to generate code through annotations in Dart". If you want to know more about it, you are welcome to follow the industry information channel. Thank you for reading!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.