使用JavaPoet创建Spring Beans

huangapple go评论62阅读模式
英文:

Using JavaPoet to create Sping Beans

问题

I'm working on spring as part of my classwork and using Javapoet for code generation.

Is there a way I can create Spring Beans via JavaPoet?

I have a use case where I wish to create Java classes based on the configuration and load them up into spring context as beans.

I am aware I can use the @Profile to achieve the same, but I have been asked to do it via Javapoet because the annotation would be too easy.

Update - Here is my main class

package com.example.PhotoAppDiscoveryService;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.javapoet.AnnotationSpec;
import org.springframework.javapoet.JavaFile;
import org.springframework.javapoet.MethodSpec;
import org.springframework.javapoet.TypeSpec;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.lang.model.element.Modifier;
import java.io.IOException;
import java.nio.file.Paths;

@SpringBootApplication
public class PhotoAppDiscoveryServiceApplication {

    public static void main(String[] args) throws IOException {
        generateRestController();
        SpringApplication.run(PhotoAppDiscoveryServiceApplication.class, args);
    }

    private static void generateRestController() throws IOException {
        MethodSpec main = MethodSpec.methodBuilder("getMapper")
                .addModifiers(Modifier.PUBLIC)
                .addAnnotation(
                        AnnotationSpec.builder(RequestMapping.class)
                                .addMember("value", "$S", "/api")
                                .build()
                )
                .returns(String.class)
                .addStatement("$T.out.println($S)", System.class, "Hello, JavaPoet!")
                .addStatement("return \"Response from Generated code!\"")
                .build();

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

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

        javaFile.writeTo(System.out);
        System.out.println("\n");
        try {
            javaFile.writeTo(Paths.get("src/main/java/"));
        } catch (Exception e){
            System.out.println("Exception occurred!");
            e.printStackTrace();
        }
    }
}

(Note: The code portion has been provided without translation, as per your request.)

英文:

I'm working on spring as part of my classwork and using Javapoet for code generation.

Is there a way I can create Spring Beans via JavaPoet?

I have a use case where I wish to create Java classes based on the configuration and load them up into spring context as beans.

I am aware I can use the @Profile to achieve the same, but I have been asked to do it via Javapoet because the annotation would be too easy.

Update - Here is my main class

	package com.example.PhotoAppDiscoveryService;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.javapoet.AnnotationSpec;
import org.springframework.javapoet.JavaFile;
import org.springframework.javapoet.MethodSpec;
import org.springframework.javapoet.TypeSpec;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.lang.model.element.Modifier;
import java.io.IOException;
import java.nio.file.Paths;
@SpringBootApplication
public class PhotoAppDiscoveryServiceApplication {
public static void main(String[] args) throws IOException {
generateRestController();
SpringApplication.run(PhotoAppDiscoveryServiceApplication.class, args);
}
private static void generateRestController() throws IOException {
MethodSpec main = MethodSpec.methodBuilder("getMapper")
.addModifiers(Modifier.PUBLIC)
.addAnnotation(
AnnotationSpec.builder(RequestMapping.class)
.addMember("value", "$S", "/api")
.build()
)
.returns(String.class)
.addStatement("$T.out.println($S)", System.class, "Hello, JavaPoet!")
.addStatement("return \"Response from Generated code!\"")
.build();
TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
.addAnnotation(RestController.class)
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
.addMethod(main)
.build();
JavaFile javaFile = JavaFile.builder("com.example.PhotoAppDiscoveryService", helloWorld)
.build();
javaFile.writeTo(System.out);
System.out.println("\n");
try {
javaFile.writeTo(Paths.get("src/main/java/"));
} catch (Exception e){
System.out.println("Exception occurred!");
e.printStackTrace();
}
}
}

答案1

得分: 0

I was able to create spring beans using JavaPoet by following the steps below.

  1. 使用JavaPoet创建Spring Bean,按照以下步骤进行。

  2. Create a Class that will generate new Java classes using javaPoet.

  3. 创建一个类,该类将使用javaPoet生成新的Java类。

  4. Call this class in the "process-classes" phase.

  5. 在"process-classes"阶段调用这个类。

  6. Now, a new Java class will be generated as per your specification.

  7. 现在,根据您的规范将生成一个新的Java类。

  8. What's left is to compile this newly generated class and ask Maven to include this while creating an artifact jar.

  9. 剩下的工作是编译这个新生成的类,并要求Maven在创建构建工件jar时包括它。

  10. We can achieve this by running the compile goal of the maven-compiler-plugin in the "prepare-package" phase.

  11. 我们可以通过在"prepare-package"阶段运行maven-compiler-plugin的编译目标来实现这一点。

Dynamic_Controller_service.java

Dynamic_Controller_service.java

package com.example.PhotoAppDiscoveryService.Dynamic_Controller;

import org.springframework.javapoet.AnnotationSpec;
import org.springframework.javapoet.JavaFile;
import org.springframework.javapoet.MethodSpec;
import org.springframework.javapoet.TypeSpec;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.lang.model.element.Modifier;
import java.io.IOException;
import java.nio.file.Paths;

// This class is responsible for generating a dynamic controller
// 这个类负责生成一个动态控制器
public class Dynamic_Controller_service {

public static void main(String[] args) {
try {
generateRestController();
} catch (IOException | InstantiationException | IllegalAccessException e) {
System.out.println("Exception occurred during class generation: " + e.getMessage());
e.printStackTrace();
}
}
public static boolean generateRestController() throws IOException, InstantiationException, IllegalAccessException {
System.out.println("Begin Generating!");
MethodSpec main = MethodSpec.methodBuilder("getMapper")
.addModifiers(Modifier.PUBLIC)
.addAnnotation(
AnnotationSpec.builder(RequestMapping.class)
.addMember("value", "$S", "/api")
.build()
)
.returns(String.class)
.addStatement("$T.out.println($S)", System.class, "Hello, JavaPoet!")
.addStatement("return \"Response from Generated code!\"")
.build();
TypeSpec controller = TypeSpec.classBuilder("HelloWorld")
.addAnnotation(RestController.class)
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
.addMethod(main)
.build();
JavaFile javaFile = JavaFile.builder("com.example.PhotoAppDiscoveryService.Dynamic_Controller.generated", controller)
.build();
javaFile.writeTo(System.out);
System.out.println("\n");
try {
javaFile.writeTo(Paths.get("src/main/java"));
} catch (Exception e) {
System.out.println("Exception occurred!");
e.printStackTrace();
return false;
}
return true;
}

}

  1. This class needs to have a main method.

  2. 这个类需要有一个main方法。

  3. The main method is invoked by the exec plugin during the specified phase.

  4. exec插件在指定阶段调用main方法。

Pom.xml

Pom.xml


4.0.0 org.springframework.boot
spring-boot-starter-parent
3.1.1
com.example
PhotoAppDiscoveryService
0.0.1-SNAPSHOT
PhotoAppDiscoveryService
Demo project for Spring Boot <java.version>17</java.version>
<spring-cloud.version>2022.0.3</spring-cloud.version>


org.springframework.boot
spring-boot-starter-web


org.springframework.boot
spring-boot-starter-test
test


com.squareup
javapoet
1.10.0


net.minidev
accessors-smart
2.4.11





org.springframework.cloud
spring-cloud-dependencies
${spring-cloud.version}
pom
import



org.springframework.boot
spring-boot-maven-plugin
org.codehaus.mojo
exec-maven-plugin


generate-sources process-classes
java


com.example.PhotoAppDiscoveryService.Dynamic_Controller.Dynamic_Controller_service
true


maven-compiler-plugin
3.8.1


compile-generator prepare-package
compile


${project.build.source

英文:

I was able to create spring beans using JavaPoet by following the steps below.

  1. Create a Class that will generate new Java classes using javaPoet.
  2. Call this class in the "process-classes" phase.
  3. Now, a new Java class will be generated as per your specification.
  4. What's left is to compile this newly generated class and ask Maven to include this while creating an artifact jar.
  5. We can achieve this by running the compile goal of the maven-compiler-plugin in the "prepare-package" phase.
  6. This way, the generated class (Java Bean in my case), will be picked up by the application during startup.

Dynamic_Controller_service.java

package com.example.PhotoAppDiscoveryService.Dynamic_Controller;
import org.springframework.javapoet.AnnotationSpec;
import org.springframework.javapoet.JavaFile;
import org.springframework.javapoet.MethodSpec;
import org.springframework.javapoet.TypeSpec;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.lang.model.element.Modifier;
import java.io.IOException;
import java.nio.file.Paths;
// This class is responsible for generating a dynamic controller
public class Dynamic_Controller_service {
public static void main(String[] args) {
try {
generateRestController();
} catch (IOException | InstantiationException | IllegalAccessException e) {
System.out.println(&quot;Exception occured durung class generation: &quot; + e.getMessage());
e.printStackTrace();
}
}
public static boolean generateRestController() throws IOException, InstantiationException, IllegalAccessException {
System.out.println(&quot;Begin Generating!&quot;);
MethodSpec main = MethodSpec.methodBuilder(&quot;getMapper&quot;)
.addModifiers(Modifier.PUBLIC)
.addAnnotation(
AnnotationSpec.builder(RequestMapping.class)
.addMember(&quot;value&quot;, &quot;$S&quot;, &quot;/api&quot;)
.build()
)
.returns(String.class)
.addStatement(&quot;$T.out.println($S)&quot;, System.class, &quot;Hello, JavaPoet!&quot;)
.addStatement(&quot;return \&quot;Response from Generated code!\&quot;&quot;)
.build();
TypeSpec controller = TypeSpec.classBuilder(&quot;HelloWorld&quot;)
.addAnnotation(RestController.class)
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
.addMethod(main)
.build();
JavaFile javaFile = JavaFile.builder(&quot;com.example.PhotoAppDiscoveryService.Dynamic_Controller.generated&quot;, controller)
.build();
javaFile.writeTo(System.out);
System.out.println(&quot;\n&quot;);
try {
javaFile.writeTo(Paths.get(&quot;src/main/java&quot;));
} catch (Exception e) {
System.out.println(&quot;Exception occurred!&quot;);
e.printStackTrace();
return false;
}
return true;
}
}
  1. This class needs to have a main method.
  2. The main method is invoked by the exec plugin during the specified phase.

Pom.xml

&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;project xmlns=&quot;http://maven.apache.org/POM/4.0.0&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
xsi:schemaLocation=&quot;http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd&quot;&gt;
&lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;
&lt;parent&gt;
&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
&lt;artifactId&gt;spring-boot-starter-parent&lt;/artifactId&gt;
&lt;version&gt;3.1.1&lt;/version&gt;
&lt;relativePath/&gt; &lt;!-- lookup parent from repository --&gt;
&lt;/parent&gt;
&lt;groupId&gt;com.example&lt;/groupId&gt;
&lt;artifactId&gt;PhotoAppDiscoveryService&lt;/artifactId&gt;
&lt;version&gt;0.0.1-SNAPSHOT&lt;/version&gt;
&lt;name&gt;PhotoAppDiscoveryService&lt;/name&gt;
&lt;description&gt;Demo project for Spring Boot&lt;/description&gt;
&lt;properties&gt;
&lt;java.version&gt;17&lt;/java.version&gt;
&lt;spring-cloud.version&gt;2022.0.3&lt;/spring-cloud.version&gt;
&lt;/properties&gt;
&lt;dependencies&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
&lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
&lt;artifactId&gt;spring-boot-starter-test&lt;/artifactId&gt;
&lt;scope&gt;test&lt;/scope&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;com.squareup&lt;/groupId&gt;
&lt;artifactId&gt;javapoet&lt;/artifactId&gt;
&lt;version&gt;1.10.0&lt;/version&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;net.minidev&lt;/groupId&gt;
&lt;artifactId&gt;accessors-smart&lt;/artifactId&gt;
&lt;version&gt;2.4.11&lt;/version&gt;
&lt;/dependency&gt;
&lt;/dependencies&gt;
&lt;dependencyManagement&gt;
&lt;dependencies&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.springframework.cloud&lt;/groupId&gt;
&lt;artifactId&gt;spring-cloud-dependencies&lt;/artifactId&gt;
&lt;version&gt;${spring-cloud.version}&lt;/version&gt;
&lt;type&gt;pom&lt;/type&gt;
&lt;scope&gt;import&lt;/scope&gt;
&lt;/dependency&gt;
&lt;/dependencies&gt;
&lt;/dependencyManagement&gt;
&lt;build&gt;
&lt;plugins&gt;
&lt;plugin&gt;
&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
&lt;artifactId&gt;spring-boot-maven-plugin&lt;/artifactId&gt;
&lt;/plugin&gt;
&lt;!--	Run the compiled Generator class		--&gt;
&lt;plugin&gt;
&lt;groupId&gt;org.codehaus.mojo&lt;/groupId&gt;
&lt;artifactId&gt;exec-maven-plugin&lt;/artifactId&gt;
&lt;executions&gt;
&lt;execution&gt;
&lt;id&gt;generate-sources&lt;/id&gt;
&lt;phase&gt;process-classes&lt;/phase&gt;
&lt;goals&gt;
&lt;goal&gt;java&lt;/goal&gt;
&lt;/goals&gt;
&lt;configuration&gt;
&lt;mainClass&gt;com.example.PhotoAppDiscoveryService.Dynamic_Controller.Dynamic_Controller_service&lt;/mainClass&gt;
&lt;addOutputToClasspath&gt;true&lt;/addOutputToClasspath&gt;
&lt;/configuration&gt;
&lt;/execution&gt;
&lt;/executions&gt;
&lt;/plugin&gt;
&lt;!--	Now, compile the Generated Java POJO after running the above main class		--&gt;
&lt;plugin&gt;
&lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;
&lt;version&gt;3.8.1&lt;/version&gt;
&lt;executions&gt;
&lt;execution&gt;
&lt;id&gt;compile-generator&lt;/id&gt;
&lt;phase&gt;prepare-package&lt;/phase&gt;
&lt;goals&gt;
&lt;goal&gt;compile&lt;/goal&gt;
&lt;/goals&gt;
&lt;configuration&gt;
&lt;!--							&lt;compilePath&gt;${project.build.sourceDirectory}/com/example/PhotoAppDiscoveryService/Dynamic_Controller&lt;/compilePath&gt;--&gt;
&lt;!--							&lt;compilePath&gt;${project.build.sourceDirectory}/com.example.PhotoAppDiscoveryService.Dynamic_Controller&lt;/compilePath&gt;--&gt;
&lt;includes&gt;${project.build.sourceDirectory}/com.example.PhotoAppDiscoveryService.Dynamic_Controller.generated.*.java&lt;/includes&gt;
&lt;!--							&lt;outputDirectory&gt;target/generated-sources&lt;/outputDirectory&gt;--&gt;
&lt;/configuration&gt;
&lt;/execution&gt;
&lt;/executions&gt;
&lt;/plugin&gt;
&lt;!--			--&gt;
&lt;/plugins&gt;
&lt;/build&gt;
&lt;/project&gt;
  1. The generated classes will be located under - target/classes/<package>

huangapple
  • 本文由 发表于 2023年7月4日 20:14:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/76612500.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定