javac AbstractProcessor


說明

Annotation Processor是javac的一個工具,它用來在編譯時掃描和處理注解,通過Annotation Processor可以獲取到注解和被注解類的相關信息,然后根據注解自動生成Java代碼,省去了手動編寫,提高了編碼效率。

它可以做什么

在編譯的時候動態生成類或者改變類的代碼!如:

lomock:減少get 和set方法的模板代碼生成

mapstruct: 動態生成po vo 互轉的Convert類

hibernate-jpamodelge 動態生成PO類的元數據映射,減少操作字段的模板代碼

需求

公司內部自己實現了一套基於redis 的CRUD的ORM框架

     //保存活動信息
        BookingActivitySettingRo bookingActivitySettingRo=new BookingActivitySettingRo();
        bookingActivitySettingRo.setId(1L);
        bookingActivitySettingRo.setActivityName("哈哈哈");
        bookingActivitySettingRedisDao.save(bookingActivitySettingRo);
        //查詢
        bookingActivitySettingRedisDao.findOne(1L);
        //批量查詢
        bookingActivitySettingRedisDao.findByIds(Arrays.asList(1l,2l));
        //刪除
        bookingActivitySettingRedisDao.delete(bookingActivitySettingRo.getId());
        //編輯
        BookingActivitySettingRo settingRedisDaoOne= bookingActivitySettingRedisDao.findOne(1L);
        settingRedisDaoOne.setActivityName("我是修改名字");
        bookingActivitySettingRedisDao.save(settingRedisDaoOne);

為了解決以下問題 

針對並發場景只操作RO部分字段,優化以下場景的寫法導致魔法值過多不易維護問題
1.並發編輯操作,只操作指定字段,避免整個ro回填,覆蓋了其他線程修改的值
2.並發查詢操作,追求性能,RO字段過多,只查詢關心部分字段 hmget
基礎工程redis版本1.3.0-SNAPSHO,增加了編譯時自動生成映射類

 

 

 

 

 

自定義Processor

參考了hibernate-jpamodelge的實現

1.實現自定義Processor繼承AbstractProcessor重寫process方法

/**
 * @Project 商品uaa
 * @PackageName cn.wine.ms.common.gennerator
 * @ClassName RedisRoAbstractProcessor
 * @Author qiang.li
 * @Date 2020/12/28 1:13 下午
 * @Description 用於編譯時針對打了RO注解的類 生成key的映射,優化hset等redis操作部分字段寫魔法值的問題
 */
@SupportedAnnotationTypes({"cn.wine.base.redis.annotation.Ro"})//你的注解的全名稱
@SupportedSourceVersion(SourceVersion.RELEASE_8)//jdk環境為java8
public class RedisRoProcessor extends AbstractProcessor {
    /**
     * {@inheritDoc}
     * @param annotations
     * @param roundEnvironment
     */
    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnvironment) {
        //遍歷所有打了注解的類
        if (!roundEnvironment.processingOver() && annotations.size() != 0) {
            Set<? extends Element> elements = roundEnvironment.getRootElements();
            Iterator var4 = elements.iterator();
            while (var4.hasNext()) {
                Element element = (Element) var4.next();
                //只處理打了RO注解的類
                if (this.isRoEntity(element)) {
                    try {
                        createClass(element);
                    }catch (Exception e){
                        processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,e.getMessage());
                    }
                }
            }
        }
        return true;
    }
    /**
     * 創建class文件
     * @param element
     * @throws IOException
     */
    public void createClass(Element element) throws IOException {
        //獲得full類名
        String className=(((TypeElement)element).getQualifiedName()).toString();
        //獲得包名
        String metaModelPackage=className.substring(0,className.lastIndexOf("."));
        //獲得屬性元數據
        List<? extends Element> fieldsOfClass = ElementFilter.fieldsIn(element.getEnclosedElements());
        //生成classBody
        String classBody=generateClassBody(fieldsOfClass);
        //用戶截取原始類名的startIndex
        Integer index=className.lastIndexOf(".")+1;
        //獲得class名字
        String simpleClassName=className.substring(index,className.length());
        //新類的className
        String newClassName=String.format("%s_",simpleClassName);
        //根據名字創建class文件
        createFile(newClassName,metaModelPackage,classBody);
    }
    public void  createFile(String genarateClassName,String metaModelPackage,String body) throws IOException {
        //生成包名
        String generatePackageName = metaModelPackage;
        //創建Java 文件
        JavaFileObject f =processingEnv.getFiler().createSourceFile(genarateClassName);
        try(Writer w = f.openWriter();){
            PrintWriter pw = new PrintWriter(w);
            pw.println("package " + generatePackageName + ";");
            pw.println("\npublic class " + genarateClassName + " { ");
            pw.println(body);
            pw.println("    }");
            pw.flush();
        }
    }

    /**
     * 構建class內容
     * @param fieldsOfClass
     * @return
     */
    public String  generateClassBody(List<? extends Element> fieldsOfClass){
        StringBuilder body=new StringBuilder();
        for(Element element:fieldsOfClass){
            body.append(String.format("    public final static String %s=\"%s\";",element.getSimpleName(),element.getSimpleName()));
            body.append("\n\n");
        }
        return body.toString();
    }

    /**
     * 是否是打了RO注解的Entity
     * @param element
     * @return
     */
    private boolean isRoEntity(Element element) {
        return containsAnnotation(element, new String[]{"cn.wine.base.redis.annotation.Ro"});
    }

    /**
     * 是否有打了指定注解
     * @param element
     * @return
     */
    public static boolean containsAnnotation(Element element, String... annotations) {
        assert element != null;

        assert annotations != null;

        List<String> annotationClassNames = new ArrayList();
        Collections.addAll(annotationClassNames, annotations);
        List<? extends AnnotationMirror> annotationMirrors = element.getAnnotationMirrors();
        Iterator var4 = annotationMirrors.iterator();

        AnnotationMirror mirror;
        do {
            if (!var4.hasNext()) {
                return false;
            }

            mirror = (AnnotationMirror)var4.next();
        } while(!annotationClassNames.contains(mirror.getAnnotationType().toString()));

        return true;
    }
}

2.在resource下新增META-INF/services並創建文件javax.annotation.processing.Processor 

將自定義的processor的全名稱配置進去

#注:如果搭配jpa和mapstract或者lomack的processr沖突 通過以下類似配置解決
# <plugin>
 #                <groupId>org.apache.maven.plugins</groupId>
 #                <artifactId>maven-compiler-plugin</artifactId>
 #                <version>3.7.0</version>
 #                <configuration>
 #                    <source>${java.version}</source>
 #                    <target>${java.version}</target>
 #                    <annotationProcessorPaths>
 #                        <path>
 #                            <groupId>org.projectlombok</groupId>
 #                            <artifactId>lombok</artifactId>
 #                            <version>${lombok.version}</version>
 #                        </path>
 #                        <path>
 #                            <groupId>org.mapstruct</groupId>
 #                            <artifactId>mapstruct-processor</artifactId>
 #                            <version>1.2.0.Final</version>
 #                        </path>
 #                        <path>
 #                            <groupId>org.hibernate</groupId>
 #                            <artifactId>hibernate-jpamodelgen</artifactId>
 #                            <version>5.2.17.final</version>
 #                        </path>
 #                    </annotationProcessorPaths>
 #                </configuration>
 #            </plugin>
#
cn.wine.base.redis.gennerator.RedisRoProcessor

 

 

 

 然后在其他使用的地方引入這個jar就行了

與其他Processor使用沖突解決

      <plugin>
                            <groupId>org.apache.maven.plugins</groupId>
                            <artifactId>maven-compiler-plugin</artifactId>
                            <version>3.7.0</version>
                            <configuration>
                                <source>${java.version}</source>
                                <target>${java.version}</target>
                                <annotationProcessorPaths>
                                    <path>
                                        <groupId>org.projectlombok</groupId>
                                        <artifactId>lombok</artifactId>
                                        <version>${lombok.version}</version>
                                    </path>
                                    <path>
                                        <groupId>org.mapstruct</groupId>
                                        <artifactId>mapstruct-processor</artifactId>
                                        <version>1.2.0.Final</version>
                                    </path>
                                    <path>
                                        <groupId>org.hibernate</groupId>
                                        <artifactId>hibernate-jpamodelgen</artifactId>
                                        <version>5.2.17.final</version>
                                    </path>
                                    <path>
                                        <groupId>cn.wine</groupId>
                                        <artifactId>support-redis</artifactId>
                                        <version>${support-redis.version}</version>
                                    </path>
                                </annotationProcessorPaths>
                            </configuration>
                        </plugin>

 

如何調試

1.新建一個remote

 

 2.指定mvnDebugger

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM