【问题标题】:Use JCodeModel to generate toString() method使用 JCodeModel 生成 toString() 方法
【发布时间】:2018-06-01 00:24:18
【问题描述】:

我正在尝试使用 com.sun.codemodel.JCodeModel 生成 Java 值对象。

我已经设法生成 hashcode()equals() 方法,但我正在努力使用 toString()

我需要以下toString() 实现

return "ClassName [field1 = " + field1 + ", field2 = " + field2 ... ", fieldN = " + fieldN + "]";

如何创建一个JCodeModel JExpression,其中包含与JExpr.ref(fieldVar.name()) 连接的JExpr.lit(field1.name())

我所做的只是生成一个类似于以下的字符串文字:-

return "ClassName [field1 =  field1 + field2 = field2 ... fieldN = + fieldN + ]";

到目前为止,这是我的骨架方法:-

final Map<String, JFieldVar> fields = jclass.fields();
final JMethod toString = jclass.method(JMod.PUBLIC, String.class, "toString");
final Set<String> excludes = new HashSet<String>(Arrays.asList(ruleFactory.getGenerationConfig().getToStringExcludes()));

final JBlock body = toString.body();

for (JFieldVar fieldVar : fields.values()) {
    if (excludes.contains(fieldVar.name()) || ((fieldVar.mods().getValue() & JMod.STATIC) == JMod.STATIC)) {
        continue;
    }

    ??????????????

}

body._return(?????????);

toString.annotate(Override.class);

【问题讨论】:

    标签: java tostring jcodemodel


    【解决方案1】:

    这里的关键点很可能是您可以通过JExpression#plus 方法将多个JExpression 对象与+ 运算符组合在一起。

    这是一个示例,其中包含一个简单示例类的定义,以及一个通用生成toString 方法的方法:

    import java.util.Arrays;
    import java.util.Collection;
    import java.util.Map;
    
    import com.sun.codemodel.CodeWriter;
    import com.sun.codemodel.JBlock;
    import com.sun.codemodel.JCodeModel;
    import com.sun.codemodel.JDefinedClass;
    import com.sun.codemodel.JExpr;
    import com.sun.codemodel.JExpression;
    import com.sun.codemodel.JFieldVar;
    import com.sun.codemodel.JMethod;
    import com.sun.codemodel.JMod;
    import com.sun.codemodel.writer.SingleStreamCodeWriter;
    
    public class CodeModelToStringTest
    {
        public static void main(String[] args) throws Exception
        {
            JCodeModel codeModel = new JCodeModel();
            JDefinedClass definedClass = codeModel._class("com.example.Example");
    
            definedClass.field(JMod.PUBLIC, String.class, "exampleString");
            definedClass.field(JMod.PROTECTED, int.class, "exampleInt");
            definedClass.field(JMod.PRIVATE, float.class, "exampleFloat");
    
            definedClass.field(JMod.PRIVATE, String.class, "excludedString");
            definedClass.field(JMod.STATIC, String.class, "staticString");
    
            createToStringMethod(definedClass, Arrays.asList("excludedString"));
    
            CodeWriter codeWriter = new SingleStreamCodeWriter(System.out);
            codeModel.build(codeWriter);
        }
    
        private static void createToStringMethod(
            JDefinedClass definedClass,
            Collection<String> excludedFieldNames)
        {
            Map<String, JFieldVar> fields = definedClass.fields();
            JMethod toString =
                definedClass.method(JMod.PUBLIC, String.class, "toString");
            toString.annotate(Override.class);
    
            JBlock body = toString.body();
    
            JExpression expression = JExpr.lit(definedClass.name() + " [");
    
            boolean first = true;
            for (JFieldVar fieldVar : fields.values())
            {
                if ((fieldVar.mods().getValue() & JMod.STATIC) == JMod.STATIC)
                {
                    continue;
                }
                if (excludedFieldNames.contains(fieldVar.name()))
                {
                    continue;
                }
                if (!first)
                {
                    expression = expression.plus(JExpr.lit(", "));
                }
                expression = expression.plus(JExpr.lit(fieldVar.name()+" = "));
                expression = expression.plus(JExpr.ref(fieldVar.name()));
                first = false;
            }
            expression = expression.plus(JExpr.lit("]"));
    
            body._return(expression);
    
    
        }
    }
    

    使用toString 方法生成的类如下所示:

    package com.example;
    
    
    public class Example {
    
        public String exampleString;
        protected int exampleInt;
        private float exampleFloat;
        private String excludedString;
        static String staticString;
    
        @Override
        public String toString() {
            return ((((((((("Example ["+"exampleString = ")+ exampleString)+", ")+"exampleInt = ")+ exampleInt)+", ")+"exampleFloat = ")+ exampleFloat)+"]");
        }
    
    }
    

    CodeModel 在每个二进制操作周围插入( 括号) 的事实导致代码看起来不那么漂亮。但这是可以理解的:否则,他们将不得不考虑运算符的优先级,并且使用和代码生成本身可能会困难。

    但是,这个toString 方法的结果将是

    Example [exampleString = null, exampleInt = 0, exampleFloat = 0.0]
    

    根据您的示例,这应该是您所期望的。

    【讨论】:

    • 非常感谢您花时间解决我的问题。唯一的缺点是 CodeModel 插入的括号过多。
    • @Hector 这已在stackoverflow.com/q/12961769/3182664 中提出,但我认为这是一个“美学”(而不是技术)问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-15
    • 2015-09-01
    • 1970-01-01
    • 2012-06-14
    • 1970-01-01
    相关资源
    最近更新 更多