JavaPoet动态生成代码

javapoet动态生成java代码 刚接触第一感觉      动态生成java代码???java代码不就是一个后缀名为.java的txt文档吗?仔细想了下,如果要生成这样的代码的确挺麻烦,你要考虑导包的问题,以及复杂的语法javapoet代码仓库地址其实git地址官方介绍的demo写的很清楚,这里我只是坐下笔记先说几个核心类MethodSpec定义方法TypeSpec定义类丶接口丶抽象类丶枚举JavaFile定义一个输出java文件... 阅读详情

一、项目简介

JavaPoet是square推出的开源Java代码生成框架,提供Java Api生成.java源文件。这个框架功能非常有用,我们可以很方便的使用它根据注解、数据库模式、协议格式等来对应生成代码。通过这种自动化生成代码的方式,可以让我们用更加简洁优雅的方式要替代繁琐冗杂的重复工作。

项目主页及源码:https://github.com/square/javapoet

二、项目总览

该项目代码量相对较小,只有一个package(com.squareup.javapoet),所有类均位于该package下。

2.1 大体结构图

JavaFile.png

2.2 关键类说明

class 说明  
JavaFile A Java file containing a single top level class 用于构造输出包含一个顶级类的Java文件
TypeSpec A generated class, interface, or enum declaration 生成类,接口,或者枚举
MethodSpec A generated constructor or method declaration 生成构造函数或方法
FieldSpec A generated field declaration 生成成员变量或字段
ParameterSpec A generated parameter declaration 用来创建参数
AnnotationSpec A generated annotation on a declaration 用来创建注解

在JavaPoet中,JavaFile是对.java文件的抽象,TypeSpec是类/接口/枚举的抽象,MethodSpec是方法/构造函数的抽象,FieldSpec是成员变量/字段的抽象。这几个类各司其职,但都有共同的特点,提供内部Builder供外部更多更好地进行一些参数的设置以便有层次的扩展性的构造对应的内容。

另外,它提供$L(for Literals), $S(for Strings), $T(for Types), $N(for Names)等标识符,用于占位替换。

三、相关使用

3.1 API使用

关于JavaPoet 的API使用,官方Github主页已经有很详细的使用说明和示例了,具体可前往查看。此处不赘述,详见 项目主页、源码及使用说明

3.2 一个简单示例

下面就让我们以一个简单HelloWorld的例子来开启我们的JavaPoet之旅。

引入库: 
build.gradle

compile 'com.squareup:javapoet:1.9.0'
 
  • 1
  • 1

例子如下:

package com.example.helloworld;

public final class HelloWorld {
  public static void main(String[] args) {
    System.out.println("Hello, JavaPoet!");
  }
}
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

上方的代码是通过下方代码调用JavaPoet的API生成的:

MethodSpec main = MethodSpec.methodBuilder("main")
    .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
    .returns(void.class)
    .addParameter(String[].class, "args")
    .addStatement("$T.out.println($S)", System.class, "Hello, JavaPoet!")
    .build();

TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
    .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
    .addMethod(main)
    .build();

JavaFile javaFile = JavaFile.builder("com.example.helloworld", helloWorld)
    .build();

javaFile.writeTo(System.out);
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

四、源码浅析

下面来看看调用了JavaFile的writeTo后实际做了些什么。

  public void writeTo(Appendable out) throws IOException {
    // First pass: emit the entire class, just to collect the types we'll need to import.
    CodeWriter importsCollector = new CodeWriter(NULL_APPENDABLE, indent, staticImports);
    emit(importsCollector);
    Map<String, ClassName> suggestedImports = importsCollector.suggestedImports();

    // Second pass: write the code, taking advantage of the imports.
    CodeWriter codeWriter = new CodeWriter(out, indent, suggestedImports, staticImports);
    emit(codeWriter);
  }
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

通过源码可以知道,writeTo分为两部分:第一步收集import,记录下来后第二步才跟随内容一起写到CodeWriter。

另外我们可以看到源码中的emit方法,通过查看其它源码发现,在JavaPoet中,所有java文件的抽象元素都定义了emit方法,如TypeSepc,ParameterSepc等,emit方法传入CodeWriter对象输出字符串。上层元素调用下层元素的emit方法,如JavaFile的emit方法调用TypeSpec的emit方法,从而实现整个java文件字符串的生成。

下面我们以MethodSpec为例,查看其emit代码:


  void emit(CodeWriter codeWriter, String enclosingName, Set<Modifier> implicitModifiers)
      throws IOException {
    codeWriter.emitJavadoc(javadoc);
    codeWriter.emitAnnotations(annotations, false);
    codeWriter.emitModifiers(modifiers, implicitModifiers);

    if (!typeVariables.isEmpty()) {
      codeWriter.emitTypeVariables(typeVariables);
      codeWriter.emit(" ");
    }

    if (isConstructor()) {
      codeWriter.emit("$L(", enclosingName);
    } else {
      codeWriter.emit("$T $L(", returnType, name);
    }

    boolean firstParameter = true;
    for (Iterator<ParameterSpec> i = parameters.iterator(); i.hasNext(); ) {
      ParameterSpec parameter = i.next();
      if (!firstParameter) codeWriter.emit(",").emitWrappingSpace();
      parameter.emit(codeWriter, !i.hasNext() && varargs);
      firstParameter = false;
    }

    codeWriter.emit(")");

    if (defaultValue != null && !defaultValue.isEmpty()) {
      codeWriter.emit(" default ");
      codeWriter.emit(defaultValue);
    }

    if (!exceptions.isEmpty()) {
      codeWriter.emitWrappingSpace().emit("throws");
      boolean firstException = true;
      for (TypeName exception : exceptions) {
        if (!firstException) codeWriter.emit(",");
        codeWriter.emitWrappingSpace().emit("$T", exception);
        firstException = false;
      }
    }

    if (hasModifier(Modifier.ABSTRACT)) {
      codeWriter.emit(";\n");
    } else if (hasModifier(Modifier.NATIVE)) {
      // Code is allowed to support stuff like GWT JSNI.
      codeWriter.emit(code);
      codeWriter.emit(";\n");
    } else {
      codeWriter.emit(" {\n");

      codeWriter.indent();
      codeWriter.emit(code);
      codeWriter.unindent();

      codeWriter.emit("}\n");
    }
  }

 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60

可以看出,MethodSepc通过调用codeWriter的emit方法依次输出javadoc,annotation,parameter,codeblock等。

五、使用场景

5.1 根据编译时注解生成代码

5.1.1 前言

用过butterknife的同学会发现,使用butterknife我们可以省去平时重复书写的findViewById之类的代码,通过注解的方式即可实现。而早期的butterknife使用的注解是运行时注解,即运行时通过注解然后使用反射实现,存在一定的性能问题,后面作者做了改进,使用编译时注解,编译期间,在注解处理器中对注解进行处理生成相应代码。

通过查看butterknife源码,如下:

  • build.gradle (butterknife-parent)
  ext.deps = [
    ...
    javapoet: 'com.squareup:javapoet:1.8.0',
    ...
  ]
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5
  • build.gradle (butterknife-compiler)
dependencies {
    ...
    compile deps.javapoet
    ...
}
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5
  • ButterKnifeProcessor.java (butterknife-compiler) 
    (注解处理器)
  @Override 
  public boolean process(Set<? extends TypeElement> elements, RoundEnvironment env) {
    Map<TypeElement, BindingSet> bindingMap = findAndParseTargets(env);

    for (Map.Entry<TypeElement, BindingSet> entry : bindingMap.entrySet()) {
      TypeElement typeElement = entry.getKey();
      BindingSet binding = entry.getValue();

      JavaFile javaFile = binding.brewJava(sdk);
      try {
        javaFile.writeTo(filer);
      } catch (IOException e) {
        error(typeElement, "Unable to write binding for type %s: %s", typeElement, e.getMessage());
      }
    }

    return false;
  }
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

可以看到butterknife在编译时在Processor中获取对应的注解,然后使用JavaPoet进行代码生成工作。(事实上开源框架Dagger也使用了JavaPoet)

5.1.2 一个简单示例

本节将简单演示利用编译时注解+JavaPoet来实现编译期间动态生成代码。

工程目录结构:

  • Hello 
    • app
    • hello-annotation (注解相关)
    • hello-compiler (处理器生成代码相关)

①. 导入依赖:

build.gralde (project)

buildscript {
    ...
    dependencies {
        ...
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
    }
}
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

build.gradle (Module:app)

apply plugin: 'com.neenbedankt.android-apt'
dependencies {
    ...
    compile project(':hello-annotation')
    apt project(':hello-compiler')
}
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

build.gradle (Module:hello-compiler)

dependencies {
    ...
    compile 'com.squareup:javapoet:1.9.0'
    compile 'com.google.auto.service:auto-service:1.0-rc2'
}
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

注: 自Android Gradle 插件 2.2 版本开始,官方提供了名为 annotationProcessor 的功能来完全代替 android-apt。 
若工程使用gradle版本>=2.2,则此处无需引用com.neenbedankt.android-apt相关,将 apt project(':hello-compiler') 改为 annotationProcessor project(':hello-compiler') 即可。

②. 定义注解: (Module:hello-annotation)

HelloAnnotation.java

@Retention(RetentionPolicy.CLASS)
@Target(ElementType.TYPE)
public @interface HelloAnnotation {
}
 
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

③. 定义Processor: (Module:hello-compiler)

HelloProcessor.java


@AutoService(Processor.class)
public class HelloProcessor extends AbstractProcessor {
    private Filer filer;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        filer = processingEnv.getFiler(); // for creating file
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        for (TypeElement element : annotations) {
            if (element.getQualifiedName().toString().equals(HelloAnnotation.class.getCanonicalName())) {
                // main method
                MethodSpec main = MethodSpec.methodBuilder("main")
                        .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
                        .returns(void.class)
                        .addParameter(String[].class, "args")
                        .addStatement("$T.out.println($S)", System.class, "Hello, JavaPoet!")
                        .build();
                // HelloWorld class
                TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
                        .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
                        .addMethod(main)
                        .build();

                try {
                    // build com.example.HelloWorld.java
                    JavaFile javaFile = JavaFile.builder("com.example", helloWorld)
                            .addFileComment(" This codes are generated automatically. Do not modify!")
                            .build();
                    // write to file
                    javaFile.writeTo(filer);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return true;
    }

    @Override
    public Set<String> getSupportedAnnotationTypes() {
        return Collections.singleton(HelloAnnotation.class.getCanonicalName());
    }

    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }

}
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54

④. 使用注解并调用生成的类函数 
MainActivity.java (Module:app)

@HelloAnnotation
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        HelloWorld.main(null);
    }
}
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

未编译前,HelloWorld.java是不存在的,这里会报错。那么,我们尝试编译一下,就会发现HelloWorld.java会自动生成,如下:

//  This codes are generated automatically. Do not modify!
package com.example;

import java.lang.String;
import java.lang.System;

public final class HelloWorld {
  public static void main(String[] args) {
    System.out.println("Hello, JavaPoet!");
  }
}

 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

5.2 根据协议文件生成对应代码

假设我们对类的声明以及接口的声明是以特定格式写在一个协议文件中,那么我们可以先读取该协议文件内容,使用JavaPoet根据协议对应生成Java代码。

如定义以下协议文件:

service TestDemo {
    rpc doRequest (MyRequest) returns (MyResponse) { // 请求接口定义
    }

    message MyRequest { // 请求内容实体
        string content;
    }

    message MyResponse { // 返回内容实体
        int32 status_code;
        string entity;
    }
}
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

那么利用JavaPoet我们可以生成对应的TestDemo.java, MyRequest.java, MyResponse.java, 以及TestDemo.java中对应的请求接口和实现。

注:此部分协议定义参考自google开源的protobuffer和grpc

5.3 更多待扩展

六、知识储备

6.1 注解处理器(Annotation Processor)

注解处理器(Annotation Processor)是javac的一个工具,它用来在编译时扫描和处理注解(Annotation)。你可以自定义注解,并注册相应的注解处理器(自定义的注解处理器需继承自AbstractProcessor)。

6.1.1 自定义注解处理器

定义一个注解处理器,需要继承自AbstractProcessor。如下所示:

package com.example;

public class MyProcessor extends AbstractProcessor {

    @Override
    public synchronized void init(ProcessingEnvironment env){ }

    @Override
    public boolean process(Set<? extends TypeElement> annoations, RoundEnvironment env) { }

    @Override
    public Set<String> getSupportedAnnotationTypes() { }

    @Override
    public SourceVersion getSupportedSourceVersion() { }

}
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • init(ProcessingEnvironment env): 每一个注解处理器类都必须有一个空的构造函数。然而,这里有一个特殊的init()方法,它会被注解处理工具调用,并输入ProcessingEnviroment参数。ProcessingEnviroment提供很多有用的工具类如Elements, Types和Filer等。
  • process(Set< ? extends TypeElement> annotations, RoundEnvironment env): 这相当于每个处理器的主函数main()。你在这里写你的扫描、评估和处理注解的代码,以及生成Java文件。输入参数RoundEnviroment,可以让你查询出包含特定注解的被注解元素。
  • getSupportedAnnotationTypes(): 这里你必须指定,这个注解处理器是注册给哪个注解的。注意,它的返回值是一个字符串的集合,包含本处理器想要处理的注解类型的合法全称。
  • getSupportedSourceVersion(): 用来指定你使用的Java版本。通常这里返回SourceVersion.latestSupported()。

注: 注解处理器是运行在独立的虚拟机JVM中,javac启动一个完整Java虚拟机来运行注解处理器。

6.1.2 注册注解处理器

那么,如何将我们自定义的处理器MyProcessor注册到javac中呢?首先我们需要将我们的注解处理器打包到一个jar文件中,其次在这个jar中,需要打包一个特定的文件javax.annotation.processing.Processor到META-INF/services路径下。以下是这个jar的大致结构示意图:

  • MyProcessor.jar 
    • com 
      • example 
        • MyProcessor.jar
    • META-INF 
      • services 
        • javax.annotation.processing.Processor

打包进MyProcessor.jar中的javax.annotation.processing.Processor的内容是,注解处理器的合法的全名列表,每一个元素换行分割:

com.example.MyProcessor  
com.foo.OtherProcessor  
net.blabla.SpecialProcessor  
 
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

把MyProcessor.jar放到你的builpath中,javac会自动检查和读取javax.annotation.processing.Processor中的内容,并且注册MyProcessor作为注解处理器。

6.1.3 com.google.auto.service:auto-service

Google提供了一个插件来帮助我们更方便的注册注解处理器,你只需要导入对应的依赖包,在自定义的Processor类上方添加@AutoService(Processor.class)即可。如下:

  • 导入依赖包
compile 'com.google.auto.service:auto-service:1.0-rc2'
 
  • 1
  • 1
  • 添加声明
@AutoService(Processor.class)
public class MyProcessor extends AbstractProcessor {
    ...
}
 
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4
6.1.4 com.neenbedankt.android-apt

该插件用于处理注解处理器,用法如下:

  • 添加plugin声明:
apply plugin: 'com.neenbedankt.android-apt'
 
  • 1
  • 1
  • 添加classpath声明:
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
 
  • 1
  • 1
  • 添加处理声明:
apt project(':xxx-compiler')
 
  • 1
  • 1

注: 自Android Gradle 插件 2.2 版本开始,官方提供了名为 annotationProcessor 的功能来完全代替 android-apt。

若工程使用gradle版本>=2.2,则无需引用com.neenbedankt.android-apt相关,将原先的 apt project(':xxx-compiler') 改为 annotationProcessor project(':xxx-compiler') 即可。

七、小结

  • JavaPoet为square出品,并且诸如butterknife、Dagger等著名开源框架也使用该库,可见其质量保障性和稳定性。
  • JavaPoet提供的api清晰明了,使用起来简单方便,功能方面也很齐全,发布了很久目前也已迭代了很多个版本,趋于稳定阶段。
  • 运用JavaPoet预生成代码的方式,在省去我们频繁书写重复代码的同时,也避免了使用运行时反射造成的效率问题。

八、参考资料

javapoet:用于生成.java源文件的Java API JavaPoet JavaPoet是用于生成.java源文件的Java API。 在执行诸如批注处理或与元数据文件(例如,数据库模式,协议格式)交互之类的操作时,源文件的生成可能非常有用。 通过生成代码,您无需编写样板文件,同时还保留了元数据的唯一真实来源。 例子 这是一个(无聊的) HelloWorld类: package com.example.helloworld ; public final class HelloWorld { public static void main ( String [] args ) { System . out . println( " Hello, JavaPoet! " ); } } 这是用JavaPoet生成的(令人兴奋的)代码: MethodSpec main = MethodSpec . methodBuilder 立即下载

相关推荐

史上最全的Logisim存储系统实验教程(基于华中科技大学计算机组成原理实验)内赋源码下载

本博客是最全的最好的解释的华中科技大学计算机组成实验存储系统实验,本博客给出了电路实现,也给出了使用电路的原因有利于新手学习十分详细。并且内赋源码下载。

qq_62325622的博客 2万+

JavaPoet的基本介绍

本文主要以JavaPoet的使用方法介绍为主,会将JavaPoet的基本API都介绍一遍,你也可以理解成JavaPoet的中文简易教程 JavaPoet的基本介绍 (1)JavaPoet是一款可以自动生成Java文件的第三方依赖 (2)简洁易懂的API,上手快 (3)让繁杂、重复的Java文件,自动化生成,提高工作效率,简化流程 JavaPoet的小试牛刀 为了展示JavaPoet的能力,这里以自动生成一个全新的MainActivity为例。 public class MainActivity

代码代替 1382

Nginx下ModSecurity模块安装详细教程

本文提供了在Nginx 1.28.0上安装ModSecurity v3的完整教程。首先需安装编译依赖,然后从源码编译安装ModSecurity库并设置优化参数。接着编译Nginx动态模块并配置加载。核心配置包括设置规则引擎、日志路径及性能优化参数。安装OWASP核心规则集后,在Nginx站点配置中启用ModSecurity。最后测试规则有效性并给出性能优化建议,如规则排除、精简规则集等。整个过程包含详细的命令和配置示例,确保安全防护功能正常运作。

深山技术宅的博客 1782

Java注解(二):Java模板引擎 —— JavaPoet的简单使用

1. 絮絮叨叨 在学习注解时,自己就有一个疑问:RUNTIME周期的注解,可以通过反射机制让注解生效。如果是SOURCE或者CLASS呢? 比如,在Spring Boot中经常使用@Value注解,为字段设置默认值、从properties读取value初始化字段、读取bean的某个属性以初始化字段 按照我一个菜鸟的理解,一定有一段注解处理代码,可以将@Value注解中的值赋值给对应字段 可能是在对象创建完成后,通过setter方法进行设置;也可能是直接修改源文件,在定义字段时就进行初始化 @

lucyLee的博客 3439

【ROS】ROS局域网下多机通讯方法

最近工作中需要用到多机通讯,这里稍微总结一下使用方法。一、网络配置ifconfig这里举个例子,主机的IP地址为192.168.1.127,从机的IP地址为192.168.1.126;之后可测试一下能否互相ping通,成功后进行下一步。

weixin_43326110的博客 3360

论文阅读笔记:Extended Vision Transformer (ExViT) for Land Use and Land Cover Classification

注意力机制驱动的深度模型最近取得了成功,如最具代表性的视觉转换器(ViT),吸引了一波高级研究来探索它们对更广泛领域的适应。然而,遥感(RS)领域中基于Transformer的方法更关注单模态数据,这可能会在充分利用不断增长的多模态地球观测数据时失去可扩展性。为此,我们提出了一种新的多模式深度学习框架,通过在最小修改的情况下扩展传统的ViT,针对土地利用和土地覆盖(LULC)分类任务。

嗑研狗的日常 945

JavaPoet使用详解

JavaPoet 是用于生成 .java 源文件的 Java API。 在执行诸如注释处理或与元数据文件(例如,数据库模式、协议格式)交互等操作时,源文件生成非常有用。通过生成代码,您无需编写样板,同时还为元数据保留了单一的真实来源。 例子 这是一个(无聊的)HelloWorld 类: package com.example.helloworld; public final class HelloWorld { public static void main(String[] args) {

ruanyandong的博客 6263

linux和mac安装+配置circos(

一定要下载完这两个包,GD才会work,要不然会报错,且-modules显示也是fail。官网的教程说的很明白,但是很多包都已经过时了需要在网上找。一般来讲,所有包的安装都不会太困难,除了GD。1.是因为官网给的链接下出来的tgz无法解压。2.我的电脑安装后GD照样是fail的。,进入这个地址下一个.tgz。第二点的原因在于,官网的情况。,进入这个地址,按部就班。GD安装困难有以下几点。搞了一天终于配置成功。

xiufan1的博客 549

【JavaPoet】浅析JavaPoet的APT代码生成功能

简单介绍了APT技术、分析了JavaPoet在路由框架的作用和使用方法

摸鱼小小虫的博客 2188

32、机械臂数字孪生模型创建指南

本文介绍了如何在MATLAB Simscape中为一款3自由度(DOF)微型机械臂创建数字孪生模型。内容涵盖硬件参数测量、Simulink模型搭建流程,包括初始条件设置、基座与上部主体构建、上臂结构设计等关键步骤。通过使用Solid、Revolute Joint和Rigid Transform等模块,实现机械臂多体系统建模,并支持后续运动仿真与物理系统的对比诊断。读者可依据指南逐步完成模型构建,相关资源可通过MATLAB File Exchange或指定网站获取。

qsc9012345的博客 214

SAP CDS View 教程里的标准视图:SEPM_I_SalesOrderItem_E 当成一张表来用之前,你需要先弄清它到底是什么

摘要:SEPM_I_SalesOrderItem_E 是 SAP EPM demo 中的预交付 CDS 视图,用于表示销售订单行项目数据。它采用 VDM 命名规范,_E 后缀表示对外隐藏内部 UUID 键,提供业务友好的外部 ID 接口。该视图常见于 ABAP Platform 7.50+、开发版系统及 Gateway 教程中,可像表一样通过 Open SQL 查询。实际项目中,这类视图能有效解决内外系统键值映射问题,示例代码展示了如何查询其数据。使用时需注意系统是否安装了 EPM demo 内容。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 547

编译时动态生成代码技术之javapoet(四)

先说几个核心类 MethodSpec定义方法 TypeSpec定义类丶接口丶抽象类丶枚举 JavaFile定义一个输出java文件 MethodSpec介绍 MethodSpec main = MethodSpec.methodBuilder(“main”)//定义方面名 .addModifiers(Modifier.PUBLIC, Modifier.STATIC)//定义修饰符 .return...

Android开发那些年 1468

基于毫米波生物感知雷达+STM32设计的独居老人居家监护系统(微信小程序)(192)

当前基于STM32设计的独居老人居家监护系统为独居老人提供一种简便、实时的健康监护服务。该系统通过集成多种传感器和功能模块,能够实时监测老人的生理指标、姿态以及室内环境状况,并通过微信小程序远程显示数据,当出现异常情况时及时发出报警提醒。

1万+

JavaPoet动态生成代码,flutter开发工具idea

32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 ..

m0_66264673的博客 227

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

最全JavaPoet动态生成代码,从入门到核心实战

用过的同学会发现,使用butterknife我们可以省去平时重复书写的findViewById之类的代码,通过注解的方式即可实现。而早期的butterknife使用的注解是运行时注解,即运行时通过注解然后使用反射实现,存在一定的性能问题,后面作者做了改进,使用编译时注解,编译期间,在注解处理器中对注解进行处理生成相应代码。12345123451234512345(注解处理器)123456789101112131415161718。

2401_84102759的博客 321

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

JavaPoet动态生成代码,大厂程序员35岁后的职业出路在哪

该项目代码量相对较小,只有一个package(com.squareup.javapoet),所有类均位于该package下。 2.1 大体结构图 2.2 关键类说明 | class | 说明 |   | | — | — | — | | JavaFile | A Java file containing a single top level class | 用于构造输出包含一个顶级类的Java文件 | | TypeSpec | A generated class, interface, or e.

m0_66685251的博客 178

JavaPoet动态生成代码,高薪程序员必会

5 1 2 3 4 5 build.gradle (butterknife-compiler) dependencies { ... compile deps.javapoet ... } 1 2 3 4 5 1 2 3 4 5 ButterKnifeProcessor.java (butterknife-compiler) (注解处理器) @Override public boolean process(Set<? ex..

m0_66264819的博客 515

JavaPoet动态生成代码,安卓常见面试题

6 7 8 9 10 11 12 13 14 15 16 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 四、源码浅析 下面来看看调用了JavaFile的writeTo后实际做了些什么。 public void writeTo(Appendable out) throws IOException { // First pass: emit the entire cl..

m0_65146387的博客 286

JavaPoet开源项目的使用

JavaPoet开源项目的使用准备工作引入开源项目实践 JavaPoet是出自JakeWharton一个可以生成.java源代码的开源项目,我们可以结合注解处理器在程序编译阶段动态生成我们想要的代码。下面我们来看看如何使用 JavaPoet项目地址 准备工作 在已有的Android项目中或新建项目中创建一个Module,如图1-1 然后,在弹出的窗口选择Java Library点击Next,起...

Wei_Ethan的博客 751

JavaPoet动态生成代码,面试初级java工程师问题

定义一个注解处理器,需要继承自AbstractProcessor。12345678910111213141516171234567891011121314151617init(ProcessingEnvironment env): 每一个注解处理器类都必须有一个空的构造函数。然而,这里有一个特殊的init()方法,它会被注解处理工具调用,并输入ProcessingEnviroment参数。

2401_83621918的博客 227

linux操作系统原理与应用张玲答案,JavaPoet动态生成代码

用过的同学会发现,使用butterknife我们可以省去平时重复书写的findViewById之类的代码,通过注解的方式即可实现。而早期的butterknife使用的注解是运行时注解,即运行时通过注解然后使用反射实现,存在一定的性能问题,后面作者做了改进,使用编译时注解,编译期间,在注解处理器中对注解进行处理生成相应代码。12345123451234512345(注解处理器)123456789101112131415161718。

2401_84412988的博客 303

javapoet使用

javapoet简介 javapoet是一个用于生成.java源文件的Java API。相关的还有javaWriter是javapoet的一个分支,ASM是一个java字节码操纵框架,它能被用来动态生成类或者增强既有类的功能。ASM 可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟机之前动态改变类行为。javapoet常用来做编译时java文件生成,在butterknif...

starlight_2012的博客 1173

Android:AOP之javaPoet技术

javapoet是可以快速的根据注解,然后动态生成代码的技术。 首先我们需要创建一个java lib 包,然后把想要扫描的注解注册上: @Target(ElementType.METHOD) @Retention(RetentionPolicy.CLASS) public @interface MyAnnotation { int action() default 0; } 第二步:创建一个java lib包,进行代码的扫描添加工作: 首先 build.gradle 中需要依赖两个库:

BunnyCoffer的博客 417

JavaPoet简介

Poet 诗人。 JavaPoet是一个动态生成代码的开源项目,在某些情况下具有特殊用处。Github地址:https://github.com/square/javapoet 在Github上有JavaPoet的官方教程,权威且全面。 首先,我们想用代码生成这个类,且在当前的项目下。 public class Hello { public static void main(String[] ...

WillScorpio 4198
上一篇: Android动画详解
下一篇: Android Studio的常用快捷键
cding1818
博客等级 码龄17年 963粉丝 154原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值