first commit
						commit
						36af820313
					
				| @ -0,0 +1,5 @@ | ||||
| /annotation-processor/target/ | ||||
| /annotation-user/target/ | ||||
| /annotation_processing.iml | ||||
| /annotation-processor/annotationprocessor.iml | ||||
| /.idea/ | ||||
| @ -0,0 +1,29 @@ | ||||
| <?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||||
|   <parent> | ||||
|     <artifactId>annotation_processing</artifactId> | ||||
|     <groupId>com.roadl</groupId> | ||||
|     <version>1.0-SNAPSHOT</version> | ||||
|   </parent> | ||||
|   <modelVersion>4.0.0</modelVersion> | ||||
| 
 | ||||
|   <artifactId>annotation-processor</artifactId> | ||||
| 
 | ||||
|   <properties> | ||||
|     <auto-service.version>1.0-rc2</auto-service.version> | ||||
|   </properties> | ||||
| 
 | ||||
|   <dependencies> | ||||
| 
 | ||||
|     <dependency> | ||||
|       <groupId>com.google.auto.service</groupId> | ||||
|       <artifactId>auto-service</artifactId> | ||||
|       <version>${auto-service.version}</version> | ||||
|       <scope>provided</scope> | ||||
|     </dependency> | ||||
| 
 | ||||
|   </dependencies> | ||||
| 
 | ||||
| </project> | ||||
| @ -0,0 +1,136 @@ | ||||
| package com.roadl.annoprocessor; | ||||
| 
 | ||||
| import com.google.auto.service.AutoService; | ||||
| import java.io.IOException; | ||||
| import java.io.PrintWriter; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
| import java.util.Set; | ||||
| import java.util.stream.Collectors; | ||||
| import javax.annotation.processing.AbstractProcessor; | ||||
| import javax.annotation.processing.Processor; | ||||
| import javax.annotation.processing.RoundEnvironment; | ||||
| import javax.annotation.processing.SupportedAnnotationTypes; | ||||
| import javax.annotation.processing.SupportedSourceVersion; | ||||
| import javax.lang.model.SourceVersion; | ||||
| import javax.lang.model.element.Element; | ||||
| import javax.lang.model.element.TypeElement; | ||||
| import javax.lang.model.type.ExecutableType; | ||||
| import javax.tools.Diagnostic; | ||||
| import javax.tools.JavaFileObject; | ||||
| 
 | ||||
| @SupportedAnnotationTypes("com.roadl.annoprocessor.BuilderProperty") | ||||
| @SupportedSourceVersion(SourceVersion.RELEASE_8) | ||||
| @AutoService(Processor.class) | ||||
| public class BuilderProcessor extends AbstractProcessor { | ||||
| 
 | ||||
|   @Override | ||||
|   public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { | ||||
|     for (TypeElement annotation : annotations) { | ||||
|       Set<? extends Element> annotatedElements = roundEnv.getElementsAnnotatedWith(annotation); | ||||
| 
 | ||||
|       Map<Boolean, List<Element>> annotatedMethods = annotatedElements.stream().collect( | ||||
|           Collectors.partitioningBy(element -> | ||||
|               ((ExecutableType) element.asType()).getParameterTypes().size() == 1 | ||||
|                   && element.getSimpleName().toString().startsWith("set"))); | ||||
| 
 | ||||
|       List<Element> setters = annotatedMethods.get(true); | ||||
|       List<Element> otherMethods = annotatedMethods.get(false); | ||||
| 
 | ||||
|       otherMethods.forEach(element -> | ||||
|           processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, | ||||
|               "@com.roadl.annoprocessor.BuilderProperty must be applied to a setXxx method " | ||||
|                   + "with a single argument", element)); | ||||
| 
 | ||||
|       if (setters.isEmpty()) { | ||||
|         continue; | ||||
|       } | ||||
|       String className = ((TypeElement) setters.get(0) | ||||
|           .getEnclosingElement()).getQualifiedName().toString(); | ||||
| 
 | ||||
|       Map<String, String> setterMap = setters.stream().collect(Collectors.toMap( | ||||
|           setter -> setter.getSimpleName().toString(), | ||||
|           setter -> ((ExecutableType) setter.asType()) | ||||
|               .getParameterTypes().get(0).toString() | ||||
|       )); | ||||
| 
 | ||||
|       try { | ||||
|         writeBuilderFile(className, setterMap); | ||||
|       } catch (IOException e) { | ||||
|         e.printStackTrace(); | ||||
|       } | ||||
|     } | ||||
|     return true; | ||||
|   } | ||||
| 
 | ||||
|   private void writeBuilderFile( | ||||
|       String className, Map<String, String> setterMap) | ||||
|       throws IOException { | ||||
| 
 | ||||
|     String packageName = null; | ||||
|     int lastDot = className.lastIndexOf('.'); | ||||
|     if (lastDot > 0) { | ||||
|       packageName = className.substring(0, lastDot); | ||||
|     } | ||||
| 
 | ||||
|     String simpleClassName = className.substring(lastDot + 1); | ||||
|     String builderClassName = className + "Builder"; | ||||
|     String builderSimpleClassName = builderClassName | ||||
|         .substring(lastDot + 1); | ||||
| 
 | ||||
|     JavaFileObject builderFile = processingEnv.getFiler() | ||||
|         .createSourceFile(builderClassName); | ||||
| 
 | ||||
|     try (PrintWriter out = new PrintWriter(builderFile.openWriter())) { | ||||
| 
 | ||||
|       if (packageName != null) { | ||||
|         out.print("package "); | ||||
|         out.print(packageName); | ||||
|         out.println(";"); | ||||
|         out.println(); | ||||
|       } | ||||
| 
 | ||||
|       out.print("public class "); | ||||
|       out.print(builderSimpleClassName); | ||||
|       out.println(" {"); | ||||
|       out.println(); | ||||
| 
 | ||||
|       out.print("    private "); | ||||
|       out.print(simpleClassName); | ||||
|       out.print(" object = new "); | ||||
|       out.print(simpleClassName); | ||||
|       out.println("();"); | ||||
|       out.println(); | ||||
| 
 | ||||
|       out.print("    public "); | ||||
|       out.print(simpleClassName); | ||||
|       out.println(" build() {"); | ||||
|       out.println("        return object;"); | ||||
|       out.println("    }"); | ||||
|       out.println(); | ||||
| 
 | ||||
|       setterMap.entrySet().forEach(setter -> { | ||||
|         String methodName = setter.getKey(); | ||||
|         String argumentType = setter.getValue(); | ||||
| 
 | ||||
|         out.print("    public "); | ||||
|         out.print(builderSimpleClassName); | ||||
|         out.print(" "); | ||||
|         out.print(methodName); | ||||
| 
 | ||||
|         out.print("("); | ||||
| 
 | ||||
|         out.print(argumentType); | ||||
|         out.println(" value) {"); | ||||
|         out.print("        object."); | ||||
|         out.print(methodName); | ||||
|         out.println("(value);"); | ||||
|         out.println("        return this;"); | ||||
|         out.println("    }"); | ||||
|         out.println(); | ||||
|       }); | ||||
| 
 | ||||
|       out.println("}"); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,12 @@ | ||||
| package com.roadl.annoprocessor; | ||||
| 
 | ||||
| import java.lang.annotation.ElementType; | ||||
| import java.lang.annotation.Retention; | ||||
| import java.lang.annotation.RetentionPolicy; | ||||
| import java.lang.annotation.Target; | ||||
| 
 | ||||
| @Target(ElementType.METHOD) | ||||
| @Retention(RetentionPolicy.SOURCE) | ||||
| public @interface BuilderProperty { | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,21 @@ | ||||
| <?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||||
|   <parent> | ||||
|     <artifactId>annotation_processing</artifactId> | ||||
|     <groupId>com.roadl</groupId> | ||||
|     <version>1.0-SNAPSHOT</version> | ||||
|   </parent> | ||||
|   <modelVersion>4.0.0</modelVersion> | ||||
| 
 | ||||
|   <artifactId>annotation-user</artifactId> | ||||
| 
 | ||||
|   <dependencies> | ||||
|     <dependency> | ||||
|       <groupId>com.roadl</groupId> | ||||
|       <artifactId>annotation-processor</artifactId> | ||||
|       <version>1.0-SNAPSHOT</version> | ||||
|     </dependency> | ||||
|   </dependencies> | ||||
| </project> | ||||
| @ -0,0 +1,26 @@ | ||||
| package com.roadl.annouser; | ||||
| 
 | ||||
| import com.roadl.annoprocessor.BuilderProperty; | ||||
| 
 | ||||
| public class Person { | ||||
|   private int age; | ||||
|   private String name; | ||||
| 
 | ||||
| 
 | ||||
|   public int getAge() { | ||||
|     return age; | ||||
|   } | ||||
| 
 | ||||
|   @BuilderProperty | ||||
|   public void setAge(int age) { | ||||
|     this.age = age; | ||||
|   } | ||||
| 
 | ||||
|   public String getName() { | ||||
|     return name; | ||||
|   } | ||||
|   @BuilderProperty | ||||
|   public void setName(String name) { | ||||
|     this.name = name; | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,15 @@ | ||||
| package com.roadl.annouser; | ||||
| 
 | ||||
| import org.junit.Test; | ||||
| import static org.junit.Assert.assertEquals; | ||||
| 
 | ||||
| public class PersonBuilderUnitTest { | ||||
|   @Test | ||||
|   public void whenBuildPersonWithBuilder_thenObjectHasPropertyValues() { | ||||
| 
 | ||||
|     Person person = new PersonBuilder().setAge(25).setName("John").build(); | ||||
| 
 | ||||
|     assertEquals(25, person.getAge()); | ||||
|     assertEquals("John", person.getName()); | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,45 @@ | ||||
| <?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||||
|   <modelVersion>4.0.0</modelVersion> | ||||
| 
 | ||||
|   <groupId>com.roadl</groupId> | ||||
|   <artifactId>annotation_processing</artifactId> | ||||
|   <packaging>pom</packaging> | ||||
|   <version>1.0-SNAPSHOT</version> | ||||
| 
 | ||||
|   <modules> | ||||
|     <module>annotation-processor</module> | ||||
|     <module>annotation-user</module> | ||||
|   </modules> | ||||
| 
 | ||||
|   <dependencies> | ||||
|     <!-- https://mvnrepository.com/artifact/junit/junit --> | ||||
|     <dependency> | ||||
|       <groupId>junit</groupId> | ||||
|       <artifactId>junit</artifactId> | ||||
|       <version>4.12</version> | ||||
|       <scope>test</scope> | ||||
|     </dependency> | ||||
|   </dependencies> | ||||
| 
 | ||||
| 
 | ||||
|   <!-- | ||||
|   [ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:compile (default-compile) on project annotation-processor: Compilation failure: Compilation failure: | ||||
|   [ERROR] Source option 5 is no longer supported. Use 6 or later. | ||||
|   --> | ||||
|   <build> | ||||
|     <plugins> | ||||
|       <plugin> | ||||
|         <groupId>org.apache.maven.plugins</groupId> | ||||
|         <artifactId>maven-compiler-plugin</artifactId> | ||||
|         <configuration> | ||||
|           <source>1.8</source> | ||||
|           <target>1.8</target> | ||||
|         </configuration> | ||||
|       </plugin> | ||||
|     </plugins> | ||||
|   </build> | ||||
| 
 | ||||
| </project> | ||||
					Loading…
					
					
				
		Reference in New Issue