静态地为CanonicalName映射创建SimpleName

时间:2015-01-21 06:30:18

标签: java regex class ant classloader

我需要创建一个我们的域类简单名称的映射到它们的完全规范名称。我想只对我们的包结构下的类实现这一点,并实现Serializable

在序列化中,我们使用类的规范名称 - 这是一个很好的默认行为,因为它是一种非常保守的方法,但我们的模型对象将在包之间移动,我不希望它代表一个破坏需要迁移脚本的更改,所以我想要这张地图。我已经将我们的序列化程序用到了这个地图,现在我只需要一个很好的策略来填充它。 令人沮丧的

第一种选择:让每个班级静态宣布

最明显也最烦人:编辑每个有问题的类以包含代码

static{
    Bootstrapper.classAliases.put(
        ThisClass.class.getSimpleName(), 
        ThisClass.class.getCanonicalName()
    );
}

我知道我可以从一开始就做到这一点,我开始吧,我真的讨厌它。这是不可能正确维护的,会引入新课程,有人会忘记添加这一行,我会让自己陷入困境。

第二种选择:通读jar

遍历我们的应用程序所在的jar,加载每个类,并查看是否应该将其添加到此映射中。这个解决方案闻起来非常糟糕 - 我正在扰乱正常的加载顺序,而且我与特定的部署方案紧密相关。很快就放弃了。

第三种选择:使用java.lang.Instrumentation

要求我用java代理运行java。有关部署的更多细节。

第四种选择:劫持类加载器

我的第一个想法是看看我是否可以向类加载器添加一个监听器,然后监听我加载的所需类,将它们加载到JVM中时将它们添加到这个映射中。严格来说,这不是静态,但它足够接近。

在发现类加载器的树状特性以及不同线程和不同库使用的各种不同方案之后,我认为实现此解决方案既复杂又容易导致错误。

第五种选择:利用构建系统&属性文件

这个似乎是更好的解决方案之一,但我没有蚂蚁技能来做到这一点。我的计划是搜索每个文件的模式

//using human readable regex
[whitespace]* package [whitespace]* com.mycompany [char]*;
[char not 'class']* 
class [whitespace]+ (<capture:"className">[nameCharacter]+) [char not '{']* implements [char not '{'] Serializable [char not '{'] '{'
//using notepad++'s regex
\s*package\s+([A-Za-z\._]*);.*class\s+(\w+)\s+implements\s+[\w,_<>\s]*Serializable

然后将[pathFound] [className] = [className]形式的每个匹配条目写出到属性文件。

然后我添加了一些相当简单的代码,以便在运行时将此属性文件加载到地图中。

我错过了一些明显的东西吗?为什么这么难做?我知道java类的懒惰本质意味着语言与代码提出“什么类有什么”的问题是对立的,我猜我的问题是这个问题的衍生物,但是,我仍然对我有多惊讶我不得不划伤我的大脑来做这件事。

所以我想我的问题是2折:

  • 你会怎么做这张地图?
  • 如果它与您的构建系统一致,那么执行它所需的蚂蚁代码是什么?这值得转换为gradle for?

感谢您的帮助

1 个答案:

答案 0 :(得分:0)

我会从你的第五种选择开始。因此,有一个名为 - javassist的字节码操作项目,它允许您加载.class文件并使用java对象处理它们。例如,你可以加载一个“Foo.class”并开始询问它,比如给我你的包,公共方法等。

查看ClassPool&amp; CtClass对象。

List<CtClass> classes = new ArrayList<>();

// Using apache commons I/O you can use a glob pattern to populate ALL_CLASS_FILES_IN_PROJECT
for (File file : ALL_CLASS_FILES_IN_PROJECT) {
  ClassPool default = ClassPool.getDefault();
  classes.add(default.makeClass(new FileInputStream(file.getPath())));
}

班级列表将准备好您现在可以处理的所有课程。您可以将此添加到一些始终加载的入口点类中的静态块。

如果这不适合你,下一个赌注是使用javaagent来做到这一点。它并不难做到,但它会对你的部署产生一些影响(代理lib jar应该可用,并且-javaagent被添加到启动args中)。