如何以编程方式创建java文件

时间:2012-08-01 15:03:50

标签: java reflection code-generation bcel

我正在创建一个util-class,它编写.java Files作为转换器生成器。

此util-class将生成AConverter.java'(参见下面的示例)

我想知道如何编写util-class。
我用Google搜索,并发现建议使用apache bcel。但我找不到一个例子来编写.java File中的String并让它在我的程序中运行。

期望是......

class ADTO
{
    private String empId;
    private String empName;
    private String dept;

    //setters and getters
}

class ABO
{
    private String loginId;
    private String userName;
    private String group;

    //setter and getter
}

class AConverter
{
    public void doConvertFromDB(ADTO source, ABO dest)
    {
        dest.setLoginId(source.getEmpId());
        ...
    }

    public void doConvertFromBO(ABO source, ADTO dest)
    {
        dest.setEmpId(source.getLoginId());
        ...

    public ADTO getSourceClass()
    {
        return ADTO.class;
    }

    public ABO getDestClass()
    {
        return ABO.class;
    }
}

上面的类AConverter将由新的Util-class生成。

2 个答案:

答案 0 :(得分:4)

你几乎可以肯定从尝试以不同的方式做到这一点,这个方案失败的方式数量令人担忧地大。以下是一些建议:

  1. 添加某种施法者方法:

    class ADTO
    {
        private String empId;
        private String empName;
        private String dept;
    
        // setters and getters
    
        public ABO toABO() // caster method (ABO will need a toADTO() as well)
        {
            ABO a = new ABO();
    
            a.setSomething(getSomethingEquivalent());
            ...
    
            return a;
        }
    }
    
  2. 代理类,可能是目标类的子类。你需要2个,每个类派生一个。

    class ADTO_Proxy extends ADTO
    {
        private ABO abo;
    
        public ADTO_Proxy(ABO a)
        {
            super();
            abo = a;
        }
    
        @override
        public String getEmployeeId()
        {
            return abo.getLoginId();
        }
    
        // other setters and getters
    }
    
  3. 不是尝试创建适配器,而是合并类。可以通过以下方式轻松完成:

    class ADTO
    {
        private String empId;
        private String empName;
        private String dept;
    
        // getters and setters for each variable by each name
        public String getEmployeeId()
        { return empId; }
        public String getLoginId()
        { return empId; }
    
        public String getEmployeeName()
        { return empName; }
        public String getUsername()
        { return empName; }
    
        public String getDepartment()
        { return dept; }
        public String getGroup()
        { return dept; }
    
        // setters
    }
    

    这也可以通过接口来完成。

  4. HateYourselfLater™评级:

    第一种方法排名为2,三者中最好的。获得的评分是因为您不会发现自己不小心在两者之间切换而且不需要更改其他代码。

    第二种方法在三者中间排列-3。获得的评分是因为您可能偶尔会混淆另一种类型的对象,可能会产生意外的副作用。如果省略代理类中的setter,则可以将此值降低到0,但这会限制功能。

    第三种方法获得-5,这是三者中最差的。获得的评分是因为副作用有很多可能性,冗余代码可能会在以后绊倒你。但是,你可以通过重构一切来正确使用一个类来制作速率1,但这可能需要很多工作,你现在就会讨厌自己。

    那就是说,你最初生成一个类的想法是在两个等级之间转换大约-10,因为它将非常难以维护并且对底层类的任何变化都非常敏感,并且可能很容易打破。

    HateYourselfLater™量表的范围从-10到10,其中10是最大量的,而-10是最大的仇恨量。

    原始答案:

    你想要一个反编译器。有几个java反编译器可供选择,我将列出一些:

    • Showmycode - 易于使用,体面的反编译,online(因此不适合公司资料),内置类名和嵌套匿名类
    • Jad - 可下载,CLI,可以工作但产生丑陋的代码,linux版本已经过时(如果需要,可以使用带有葡萄酒的Windows版本),搞砸枚举,foreach循环和一些尝试/捕获
    • Fernflower - CLI,很难找到,三者的最佳输出,作者是SO用户,看起来不错的输出,搞砸尝试/捕捉有时候

    它们都不是完美的,但这只是因为一些数据在编译过程中丢失了,反编译器必须猜测程序最初的样子。

答案 1 :(得分:0)

你可以做多件事。

你应该准确地决定你想做什么,然后找一个匹配的库为你做,并学习那个库。

BCEL就是这样一个图书馆。我过去曾成功使用过Java-APT用于类似目的。

为了您的理解,我将在下面写一些关于生成课程的内容,但是请不要自己开发,最有可能最终会陷入困境。

如果你想让你的类在你当前运行的同一个JVM中可用(与之相反:你想生成代码,然后再次编译整个程序并重新启动它),那么你必须:

  1. 创建文件,将字符串写入其中。
  2. 编译文件(这样做的粗略方法是从代码中调用javac)
  3. 将类加载到类加载器中。