From f829e060ed6403177272814606d82b3224c334f5 Mon Sep 17 00:00:00 2001 From: wangqi Date: Sat, 16 Nov 2024 18:00:27 +0800 Subject: [PATCH] feature: update annotation processor --- .../processor/CarpAnnotationProcessor.java | 2 + .../plugins/AbstractClassGeneratePlugin.java | 26 ++++ .../plugins/AbstractMethodGeneratePlugin.java | 26 ++++ .../plugins/AbstractProcessorPlugin.java | 116 ++++++++++++++++++ .../processor/plugins/ElementMethod.java | 15 +++ .../plugins/{web => }/IndexedValue.java | 4 +- .../plugins/jackson/JacksonGetter.java | 33 +++++ .../javapoet/JacksonJavapoetPlugin.java | 56 +++++++++ .../processor/plugins/web/HandlerWriter.java | 2 - .../processor/plugins/web/WebPlugin.java | 65 ++-------- 10 files changed, 283 insertions(+), 62 deletions(-) create mode 100644 carp-support/carp-annotation-processor/src/main/java/cn/sliew/carp/support/annotation/processor/plugins/AbstractClassGeneratePlugin.java create mode 100644 carp-support/carp-annotation-processor/src/main/java/cn/sliew/carp/support/annotation/processor/plugins/AbstractMethodGeneratePlugin.java create mode 100644 carp-support/carp-annotation-processor/src/main/java/cn/sliew/carp/support/annotation/processor/plugins/AbstractProcessorPlugin.java create mode 100644 carp-support/carp-annotation-processor/src/main/java/cn/sliew/carp/support/annotation/processor/plugins/ElementMethod.java rename carp-support/carp-annotation-processor/src/main/java/cn/sliew/carp/support/annotation/processor/plugins/{web => }/IndexedValue.java (90%) create mode 100644 carp-support/carp-annotation-processor/src/main/java/cn/sliew/carp/support/annotation/processor/plugins/jackson/JacksonGetter.java create mode 100644 carp-support/carp-annotation-processor/src/main/java/cn/sliew/carp/support/annotation/processor/plugins/jackson/javapoet/JacksonJavapoetPlugin.java diff --git a/carp-support/carp-annotation-processor/src/main/java/cn/sliew/carp/support/annotation/processor/CarpAnnotationProcessor.java b/carp-support/carp-annotation-processor/src/main/java/cn/sliew/carp/support/annotation/processor/CarpAnnotationProcessor.java index ee4e3cd..978ea80 100644 --- a/carp-support/carp-annotation-processor/src/main/java/cn/sliew/carp/support/annotation/processor/CarpAnnotationProcessor.java +++ b/carp-support/carp-annotation-processor/src/main/java/cn/sliew/carp/support/annotation/processor/CarpAnnotationProcessor.java @@ -18,6 +18,7 @@ package cn.sliew.carp.support.annotation.processor; +import cn.sliew.carp.support.annotation.processor.plugins.jackson.javapoet.JacksonJavapoetPlugin; import cn.sliew.carp.support.annotation.processor.plugins.web.WebPlugin; import com.google.auto.common.BasicAnnotationProcessor; import com.google.auto.service.AutoService; @@ -47,6 +48,7 @@ public class CarpAnnotationProcessor extends AbstractProcessor { public synchronized void init(ProcessingEnvironment processingEnv) { super.init(processingEnv); plugins.add(new WebPlugin()); + plugins.add(new JacksonJavapoetPlugin()); plugins.forEach(plugin -> plugin.init(processingEnv)); } diff --git a/carp-support/carp-annotation-processor/src/main/java/cn/sliew/carp/support/annotation/processor/plugins/AbstractClassGeneratePlugin.java b/carp-support/carp-annotation-processor/src/main/java/cn/sliew/carp/support/annotation/processor/plugins/AbstractClassGeneratePlugin.java new file mode 100644 index 0000000..89b6d7a --- /dev/null +++ b/carp-support/carp-annotation-processor/src/main/java/cn/sliew/carp/support/annotation/processor/plugins/AbstractClassGeneratePlugin.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.sliew.carp.support.annotation.processor.plugins; + +/** + * 生成一个新的类,实现特定接口 + */ +public abstract class AbstractClassGeneratePlugin extends AbstractProcessorPlugin { + +} diff --git a/carp-support/carp-annotation-processor/src/main/java/cn/sliew/carp/support/annotation/processor/plugins/AbstractMethodGeneratePlugin.java b/carp-support/carp-annotation-processor/src/main/java/cn/sliew/carp/support/annotation/processor/plugins/AbstractMethodGeneratePlugin.java new file mode 100644 index 0000000..955730e --- /dev/null +++ b/carp-support/carp-annotation-processor/src/main/java/cn/sliew/carp/support/annotation/processor/plugins/AbstractMethodGeneratePlugin.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.sliew.carp.support.annotation.processor.plugins; + +/** + * 在原类中生成一个新方法 + */ +public abstract class AbstractMethodGeneratePlugin extends AbstractProcessorPlugin { + +} diff --git a/carp-support/carp-annotation-processor/src/main/java/cn/sliew/carp/support/annotation/processor/plugins/AbstractProcessorPlugin.java b/carp-support/carp-annotation-processor/src/main/java/cn/sliew/carp/support/annotation/processor/plugins/AbstractProcessorPlugin.java new file mode 100644 index 0000000..595ed82 --- /dev/null +++ b/carp-support/carp-annotation-processor/src/main/java/cn/sliew/carp/support/annotation/processor/plugins/AbstractProcessorPlugin.java @@ -0,0 +1,116 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.sliew.carp.support.annotation.processor.plugins; + +import cn.sliew.carp.support.annotation.processor.CarpProcessorPlugin; +import cn.sliew.carp.support.annotation.processor.util.ProcessingEnvUtils; +import com.palantir.javapoet.JavaFile; +import com.palantir.javapoet.TypeSpec; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.util.ElementFilter; +import javax.tools.Diagnostic; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * 生成一个新的类,实现特定接口 + */ +public abstract class AbstractProcessorPlugin implements CarpProcessorPlugin { + + protected ProcessingEnvironment processingEnv; + + @Override + public void init(ProcessingEnvironment processingEnv) { + this.processingEnv = processingEnv; + } + + @Override + public Collection process(Set annotated) { + Map> nameDataListMap = ElementFilter + .methodsIn(annotated) + .stream() + .collect(Collectors.groupingBy(ElementMethod::new)); + + return nameDataListMap + .entrySet() + .stream() + .flatMap(entry -> handle(entry.getKey(), entry.getValue())) + .toList(); + } + + + private Stream handle(ElementMethod elementMethod, List handlers) { + return handlers.stream() + .map(IndexedValue.indexed()) + .map(element -> handle(elementMethod, element)); + } + + private JavaFile handle(ElementMethod elementMethod, IndexedValue indexedValue) { + try { + return getJavaFile(elementMethod, indexedValue); + } catch (Exception e) { + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, e.getMessage(), indexedValue.value()); + throw e; + } + } + + private JavaFile getJavaFile(ElementMethod elementMethod, IndexedValue indexedValue) { + var handlerMethod = indexedValue.value(); + var typeSpec = createType(elementMethod, indexedValue, handlerMethod); + String packageName = ProcessingEnvUtils.getPackageName(processingEnv, handlerMethod); + return JavaFile.builder(packageName, typeSpec).build(); + } + + protected abstract TypeSpec createType(ElementMethod elementMethod, IndexedValue indexedValue, ExecutableElement handlerMethod); + + protected void log(String msg) { + if (processingEnv.getOptions().containsKey("debug")) { + processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, msg); + } + } + + protected void error(String msg, Element element) { + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, msg, element); + } + + protected void error(String msg, Element element, AnnotationMirror annotation) { + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, msg, element, annotation); + } + + protected void fatalError(Exception e) { + // We don't allow exceptions of any kind to propagate to the compiler + StringWriter writer = new StringWriter(); + e.printStackTrace(new PrintWriter(writer)); + fatalError(writer.toString()); + } + + protected void fatalError(String msg) { + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "FATAL ERROR: " + msg); + } +} diff --git a/carp-support/carp-annotation-processor/src/main/java/cn/sliew/carp/support/annotation/processor/plugins/ElementMethod.java b/carp-support/carp-annotation-processor/src/main/java/cn/sliew/carp/support/annotation/processor/plugins/ElementMethod.java new file mode 100644 index 0000000..81319bd --- /dev/null +++ b/carp-support/carp-annotation-processor/src/main/java/cn/sliew/carp/support/annotation/processor/plugins/ElementMethod.java @@ -0,0 +1,15 @@ +package cn.sliew.carp.support.annotation.processor.plugins; + +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.Name; +import javax.lang.model.element.TypeElement; + +public record ElementMethod(TypeElement typeElement, Name annotatedMethodName) { + ElementMethod(ExecutableElement element) { + this((TypeElement) element.getEnclosingElement(), element.getSimpleName()); + } + + public String toMethodName(int index) { + return "%s$%s$%d$Generated".formatted(typeElement.getSimpleName().toString(), annotatedMethodName.toString(), index); + } +} \ No newline at end of file diff --git a/carp-support/carp-annotation-processor/src/main/java/cn/sliew/carp/support/annotation/processor/plugins/web/IndexedValue.java b/carp-support/carp-annotation-processor/src/main/java/cn/sliew/carp/support/annotation/processor/plugins/IndexedValue.java similarity index 90% rename from carp-support/carp-annotation-processor/src/main/java/cn/sliew/carp/support/annotation/processor/plugins/web/IndexedValue.java rename to carp-support/carp-annotation-processor/src/main/java/cn/sliew/carp/support/annotation/processor/plugins/IndexedValue.java index 60b8bc0..63f9161 100644 --- a/carp-support/carp-annotation-processor/src/main/java/cn/sliew/carp/support/annotation/processor/plugins/web/IndexedValue.java +++ b/carp-support/carp-annotation-processor/src/main/java/cn/sliew/carp/support/annotation/processor/plugins/IndexedValue.java @@ -16,11 +16,11 @@ * limitations under the License. */ -package cn.sliew.carp.support.annotation.processor.plugins.web; +package cn.sliew.carp.support.annotation.processor.plugins; import java.util.function.Function; -record IndexedValue(int index, T value) { +public record IndexedValue(int index, T value) { static Function> indexed() { return new Function<>() { int index = 1; diff --git a/carp-support/carp-annotation-processor/src/main/java/cn/sliew/carp/support/annotation/processor/plugins/jackson/JacksonGetter.java b/carp-support/carp-annotation-processor/src/main/java/cn/sliew/carp/support/annotation/processor/plugins/jackson/JacksonGetter.java new file mode 100644 index 0000000..30cce67 --- /dev/null +++ b/carp-support/carp-annotation-processor/src/main/java/cn/sliew/carp/support/annotation/processor/plugins/jackson/JacksonGetter.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.sliew.carp.support.annotation.processor.plugins.jackson; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.SOURCE) +@Target(ElementType.METHOD) +public @interface JacksonGetter { + + Class mapping(); + + String attribute(); +} diff --git a/carp-support/carp-annotation-processor/src/main/java/cn/sliew/carp/support/annotation/processor/plugins/jackson/javapoet/JacksonJavapoetPlugin.java b/carp-support/carp-annotation-processor/src/main/java/cn/sliew/carp/support/annotation/processor/plugins/jackson/javapoet/JacksonJavapoetPlugin.java new file mode 100644 index 0000000..f10981d --- /dev/null +++ b/carp-support/carp-annotation-processor/src/main/java/cn/sliew/carp/support/annotation/processor/plugins/jackson/javapoet/JacksonJavapoetPlugin.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.sliew.carp.support.annotation.processor.plugins.jackson.javapoet; + +import cn.sliew.carp.support.annotation.processor.plugins.AbstractMethodGeneratePlugin; +import cn.sliew.carp.support.annotation.processor.plugins.IndexedValue; +import cn.sliew.carp.support.annotation.processor.plugins.ElementMethod; +import cn.sliew.carp.support.annotation.processor.plugins.jackson.JacksonGetter; +import com.palantir.javapoet.JavaFile; +import com.palantir.javapoet.TypeSpec; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import java.lang.annotation.Annotation; +import java.util.Collection; +import java.util.Set; + +public class JacksonJavapoetPlugin extends AbstractMethodGeneratePlugin { + + @Override + public void init(ProcessingEnvironment processingEnv) { + super.init(processingEnv); + } + + @Override + public Class supported() { + return JacksonGetter.class; + } + + @Override + public Collection process(Set annotated) { + return null; + } + + @Override + protected TypeSpec createType(ElementMethod nameData, IndexedValue indexedValue, ExecutableElement handlerMethod) { + return null; + } +} diff --git a/carp-support/carp-annotation-processor/src/main/java/cn/sliew/carp/support/annotation/processor/plugins/web/HandlerWriter.java b/carp-support/carp-annotation-processor/src/main/java/cn/sliew/carp/support/annotation/processor/plugins/web/HandlerWriter.java index b14f47d..a36094d 100644 --- a/carp-support/carp-annotation-processor/src/main/java/cn/sliew/carp/support/annotation/processor/plugins/web/HandlerWriter.java +++ b/carp-support/carp-annotation-processor/src/main/java/cn/sliew/carp/support/annotation/processor/plugins/web/HandlerWriter.java @@ -20,14 +20,12 @@ import com.palantir.javapoet.*; -import javax.annotation.processing.Generated; import javax.annotation.processing.ProcessingEnvironment; import javax.lang.model.element.*; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; import javax.lang.model.util.ElementFilter; import javax.lang.model.util.Types; -import javax.tools.Diagnostic; import java.util.List; import java.util.Objects; diff --git a/carp-support/carp-annotation-processor/src/main/java/cn/sliew/carp/support/annotation/processor/plugins/web/WebPlugin.java b/carp-support/carp-annotation-processor/src/main/java/cn/sliew/carp/support/annotation/processor/plugins/web/WebPlugin.java index 94bfcc4..50cb7ae 100644 --- a/carp-support/carp-annotation-processor/src/main/java/cn/sliew/carp/support/annotation/processor/plugins/web/WebPlugin.java +++ b/carp-support/carp-annotation-processor/src/main/java/cn/sliew/carp/support/annotation/processor/plugins/web/WebPlugin.java @@ -18,33 +18,23 @@ package cn.sliew.carp.support.annotation.processor.plugins.web; -import cn.sliew.carp.support.annotation.processor.CarpProcessorPlugin; -import cn.sliew.carp.support.annotation.processor.util.ProcessingEnvUtils; -import com.palantir.javapoet.JavaFile; +import cn.sliew.carp.support.annotation.processor.plugins.AbstractClassGeneratePlugin; +import cn.sliew.carp.support.annotation.processor.plugins.IndexedValue; +import cn.sliew.carp.support.annotation.processor.plugins.ElementMethod; import com.palantir.javapoet.TypeName; import com.palantir.javapoet.TypeSpec; import javax.annotation.processing.ProcessingEnvironment; -import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.Name; -import javax.lang.model.util.ElementFilter; -import javax.tools.Diagnostic; import java.lang.annotation.Annotation; -import java.util.Collection; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; -public class WebPlugin implements CarpProcessorPlugin { +public class WebPlugin extends AbstractClassGeneratePlugin { - private ProcessingEnvironment processingEnv; private HandlerWriter handlerWriter; @Override public void init(ProcessingEnvironment processingEnv) { - this.processingEnv = processingEnv; + super.init(processingEnv); this.handlerWriter = new HandlerWriter(processingEnv); } @@ -54,54 +44,13 @@ public Class supported() { } @Override - public Collection process(Set annotated) { - return ElementFilter.methodsIn(annotated).stream() - .collect(Collectors.groupingBy(NameData::new)) - .entrySet() - .stream() - .flatMap(entry -> handle(entry.getKey(), entry.getValue())) - .toList(); - } - - - private Stream handle(NameData nameData, List handlers) { - return handlers.stream() - .map(IndexedValue.indexed()) - .map(element -> handle(nameData, element)); - } - - private JavaFile handle(NameData nameData, IndexedValue indexedValue) { - try { - return getJavaFile(nameData, indexedValue); - } catch (Exception e) { - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, e.getMessage(), indexedValue.value()); - throw e; - } - } - - private JavaFile getJavaFile(NameData nameData, IndexedValue indexedValue) { - var handlerMethod = indexedValue.value(); - var typeSpec = createType(nameData, indexedValue, handlerMethod); - String packageName = ProcessingEnvUtils.getPackageName(processingEnv, handlerMethod); - return JavaFile.builder(packageName, typeSpec).build(); - } - - private TypeSpec createType(NameData nameData, IndexedValue indexedValue, ExecutableElement handlerMethod) { + protected TypeSpec createType(ElementMethod elementMethod, IndexedValue indexedValue, ExecutableElement handlerMethod) { return handlerWriter.buildHandler( - nameData.toHandlerMethodName(indexedValue.index()), + elementMethod.toMethodName(indexedValue.index()), handlerMethod, TypeName.get(handlerMethod.getEnclosingElement().asType()), handlerMethod.getAnnotation(RequestHandle.class) ); } - private record NameData(Name controllerName, Name handleName) { - NameData(ExecutableElement element) { - this(element.getEnclosingElement().getSimpleName(), element.getSimpleName()); - } - - String toHandlerMethodName(int index) { - return "%s$%s$%s$handler".formatted(controllerName.toString(), handleName.toString(), index); - } - } }