英文:
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.
-
使用JavaPoet创建Spring Bean,按照以下步骤进行。
-
Create a Class that will generate new Java classes using javaPoet.
-
创建一个类,该类将使用javaPoet生成新的Java类。
-
Call this class in the "process-classes" phase.
-
在"process-classes"阶段调用这个类。
-
Now, a new Java class will be generated as per your specification.
-
现在,根据您的规范将生成一个新的Java类。
-
What's left is to compile this newly generated class and ask Maven to include this while creating an artifact jar.
-
剩下的工作是编译这个新生成的类,并要求Maven在创建构建工件jar时包括它。
-
We can achieve this by running the compile goal of the maven-compiler-plugin in the "prepare-package" phase.
-
我们可以通过在"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;
}
}
-
This class needs to have a main method.
-
这个类需要有一个main方法。
-
The main method is invoked by the exec plugin during the specified phase.
-
exec插件在指定阶段调用main方法。
Pom.xml
Pom.xml
<spring-cloud.version>2022.0.3</spring-cloud.version>
英文:
I was able to create spring beans using JavaPoet by following the steps below.
- Create a Class that will generate new Java classes using javaPoet.
- Call this class in the "process-classes" phase.
- Now, a new Java class will be generated as per your specification.
- What's left is to compile this newly generated class and ask Maven to include this while creating an artifact jar.
- We can achieve this by running the compile goal of the maven-compiler-plugin in the "prepare-package" phase.
- 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("Exception occured durung 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;
}
}
- This class needs to have a main method.
- The main method is invoked by the exec plugin during the specified phase.
Pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>PhotoAppDiscoveryService</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>PhotoAppDiscoveryService</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>17</java.version>
<spring-cloud.version>2022.0.3</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.squareup</groupId>
<artifactId>javapoet</artifactId>
<version>1.10.0</version>
</dependency>
<dependency>
<groupId>net.minidev</groupId>
<artifactId>accessors-smart</artifactId>
<version>2.4.11</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<!-- Run the compiled Generator class -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<executions>
<execution>
<id>generate-sources</id>
<phase>process-classes</phase>
<goals>
<goal>java</goal>
</goals>
<configuration>
<mainClass>com.example.PhotoAppDiscoveryService.Dynamic_Controller.Dynamic_Controller_service</mainClass>
<addOutputToClasspath>true</addOutputToClasspath>
</configuration>
</execution>
</executions>
</plugin>
<!-- Now, compile the Generated Java POJO after running the above main class -->
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<executions>
<execution>
<id>compile-generator</id>
<phase>prepare-package</phase>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<!-- <compilePath>${project.build.sourceDirectory}/com/example/PhotoAppDiscoveryService/Dynamic_Controller</compilePath>-->
<!-- <compilePath>${project.build.sourceDirectory}/com.example.PhotoAppDiscoveryService.Dynamic_Controller</compilePath>-->
<includes>${project.build.sourceDirectory}/com.example.PhotoAppDiscoveryService.Dynamic_Controller.generated.*.java</includes>
<!-- <outputDirectory>target/generated-sources</outputDirectory>-->
</configuration>
</execution>
</executions>
</plugin>
<!-- -->
</plugins>
</build>
</project>
- The generated classes will be located under - target/classes/<package>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论