【问题标题】:Transforming java source code to move annotations from getters to properties转换 java 源代码以将注释从 getter 移动到属性
【发布时间】:2019-10-28 06:33:34
【问题描述】:

我有大约 300 个 JPA 实体,其中的 getter 使用持久性注释进行注释。我想找到一种方法将所有此类注释移至属性并删除所有 getter 和 setter。我手动为这些课程中的大约 100 个进行了此操作,但这是非常耗时且令人麻木的工作。

我正在查看Spoon 之类的源代码转换工具,但仍不确定它是否能完成我需要它做的事情。

更具体地说,我该如何转换这段代码:

@Entity
@Table(name = "crm_ticket")
public class CrmTicket implements Serializable {

    private static final long serialVersionUID = -902718555957517699L;

    private CrmAccount crmAccount;
    private ItsType subType;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "account")
    public CrmAccount getCrmAccount() {
        return crmAccount;
    }

    public void setCrmAccount(CrmAccount crmAccount) {
        this.crmAccount = crmAccount;
    }

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "sub_type")
    public ItsType getSubType() {
        return subType;
    }

    public void setSubType(ItsType type) {
        this.subType = type;
    }
}

到这里:

@Entity
@Table(name = "crm_ticket")
@Data
public class CrmTicket implements Serializable {

    private static final long serialVersionUID = -902718555957517699L;
    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "account")
    private CrmAccount crmAccount;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "sub_type")
    private ItsType subType;
}

【问题讨论】:

  • 我想知道如何限制这个问题的范围?就目前而言,它非常具体!您如何转换一个类,以便将来自 getter 的注释放在属性上?这个问题还不够具体吗?
  • 我投票决定重新开放,但我怀疑它可能会再次关闭,因为听起来您正在寻找场外资源/工具。也许描述了你到目前为止尝试过的东西。就我个人而言,我可能会使用某种 awk 脚本,但这只是我自己。肯定会好奇你最终选择了什么解决方案。
  • 谢谢@SiKing。我最初尝试使用 awk/sed,但这种转换需要该工具具备一些 Java 语法知识。我将使用 Spoon 在这里发布我的解决方案,这是一个非常酷的源转换工具。

标签: java inria-spoon program-transformation


【解决方案1】:

Spoon 可以很好地解决这个问题,您可以使用 aField.addAnnotation 和 aSetter.delete

【讨论】:

    【解决方案2】:

    我最终使用了Spoon。没那么痛。我配置了他们的 maven 插件来运行我的处理器,它转换了我的实体类的代码。然后我将生成的代码复制回我的项目并删除了插件配置。

    这是我的处理器代码:

    public class JpaAnnotationMover extends AbstractProcessor<CtMethod> {
    
        Pattern p1 = Pattern.compile("return.*this\\.(.*?)$");
        Pattern p2 = Pattern.compile("return(.*?)$");
    
        @Override
        public boolean isToBeProcessed(CtMethod method) {
            return isInEntity(method) && isAGetter(method) && hasOneStatement(method) && !isTransient(method);
        }
    
        @Override
        public void process(CtMethod ctMethod) {
    CtType parentClass = ctMethod.getParent(CtType.class);
            String fieldName = getFieldName(ctMethod);
    
            if (fieldName == null) {
                log.warn(String.format("expected field name for %s not found.", ctMethod.getSimpleName()));
                return;
            }
    
            CtField field = parentClass.getField(fieldName);
            if (field == null) {
                log.warn(String.format("Expected field %s not found.", fieldName));
                return;
            }
    
            for (CtAnnotation<? extends Annotation> annotation : ctMethod.getAnnotations()) {
                field.addAnnotation(annotation);
            }
    
            parentClass.removeMethod(ctMethod);
            log.info(String.format("Processed method %s:%s", parentClass.getSimpleName(), ctMethod.getSimpleName()));
    
            // find corresponding setter
            String setterName = "set" + WordUtils.capitalize(fieldName);
    
            @SuppressWarnings("unchecked") CtMethod setter = parentClass
                    .getMethod(getFactory().Type().createReference("void"), setterName, ctMethod.getType());
    
            if (setter == null) {
                log.warn(String.format("Unable to find setter for %s", fieldName));
                return;
            }
    
            parentClass.removeMethod(setter);
    
            if (!parentClass.hasAnnotation(Data.class)) {
                parentClass.addAnnotation(getFactory().createAnnotation(getFactory().Type().createReference(Data.class)));
            }
    }
    
    private Boolean isInEntity(CtMethod method) {
            CtType parentClass = method.getParent(CtType.class);
            return parentClass.hasAnnotation(Entity.class);
        }
    
        private Boolean isAGetter(CtMethod method) {
            return method.getSimpleName().contains("get");
        }
    
        private Boolean hasOneStatement(CtMethod method) {
            return method.getBody().getStatements().size() == 1;
        }
    
        private Boolean isTransient(CtMethod method) {
            return method.hasAnnotation(Transient.class);
        }
    
        private String getFieldName(CtMethod method) {
            String statement = method.getBody().getLastStatement().toString();
            Matcher m = p1.matcher(statement);
            Matcher m2 = p2.matcher(statement);
            return m.matches() ? m.group(1).trim() : m2.matches() ? m2.group(1).trim() : null;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2011-01-17
      • 1970-01-01
      • 2015-01-09
      • 2016-03-27
      • 2014-09-05
      • 2021-06-23
      • 1970-01-01
      • 1970-01-01
      • 2010-12-24
      相关资源
      最近更新 更多