Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/320.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 静态创建SimpleName到CanonicalName映射_Java_Regex_Class_Ant_Classloader - Fatal编程技术网

Java 静态创建SimpleName到CanonicalName映射

Java 静态创建SimpleName到CanonicalName映射,java,regex,class,ant,classloader,Java,Regex,Class,Ant,Classloader,我需要创建一个映射,将我们的域类的简单名称映射到它们的完全规范名称。我只想对包结构下的类执行此操作,这些类实现了Serializable 在序列化中,我们经常使用类的规范名称——这是一种很好的默认行为,因为它是一种非常保守的方法,但是我们的模型对象将在包之间移动,我不希望这表示需要迁移脚本的突破性更改,所以我想要这个映射。我已经为我们的序列化程序设置了工具来使用这个映射,现在我只需要一个好的策略来填充它。这很令人沮丧 第一种选择:让每个类静态地声明自己 最明显也是最烦人的:编辑每个有问题的类以包

我需要创建一个映射,将我们的域类的简单名称映射到它们的完全规范名称。我只想对包结构下的类执行此操作,这些类实现了
Serializable

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

第一种选择:让每个类静态地声明自己 最明显也是最烦人的:编辑每个有问题的类以包含代码

static{
    Bootstrapper.classAliases.put(
        ThisClass.class.getSimpleName(), 
        ThisClass.class.getCanonicalName()
    );
}
我知道我一开始就可以做到,我开始了,我真的很讨厌它。这是不可能被正确维护的,新的类将会被引入,有人会忘记添加这一行,我会给自己带来麻烦

第二种选择:通读jar 遍历应用程序所在的jar,加载每个类,并查看是否应将其添加到此映射中。这个解决方案闻起来很糟糕——我扰乱了正常的加载顺序,并且与特定的部署方案紧密耦合。很快就放弃了

第三种选择:使用
java.lang.Instrumentation
需要我使用java代理运行java。关于部署的更多细节

第四种选择:劫持类装载机 我的第一个想法是看看是否可以将侦听器添加到类加载器中,然后侦听所需的类是否正在加载,并在它们加载到JVM时将它们添加到该映射中。严格地说,这不是静态的,但它已经足够接近了

在发现类加载器的树状本质,以及不同线程和不同库使用的各种不同方案之后,我认为实现这个解决方案既过于复杂,又会导致bug

第五种选择:利用构建系统&属性文件 这似乎是一个更好的解决方案,但我没有蚂蚁的技能来做到这一点。我的计划是在每个文件中搜索模式

//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
//使用人类可读的正则表达式
[whitespace]*package[whitespace]*com.mycompany[char]*;
[字符不是“类”]*
类[whitespace]+([nameCharacter]+)[char not'{']*实现[char not'{']Serializable[char not'{']']'{'
//使用notepad++的正则表达式
\s*包\s+([A-Za-z\.\u]*);*class\s+(\w+)\s+实现\s+[\w,\uz]*可序列化
然后以[pathFound][className]=[className]的形式将每个匹配条目写入属性文件

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

我是否遗漏了一些明显的东西?为什么这么难做到?我知道java类的懒惰本质意味着该语言与问“有什么类”的代码是对立的,我想我的问题是这个问题的衍生问题,但我还是很惊讶,我要花这么多的时间才能做到这一点

所以我想我的问题有两个:

  • 你将如何着手制作这张地图
  • 如果它将与您的构建系统一起使用,那么需要什么ant代码来完成它?这值得转换为gradle吗

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

签出类池&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())));
}
List classes=new ArrayList();
//使用ApacheCommons I/O,您可以使用glob模式来填充\u项目中的所有\u类\u文件
用于(文件文件:项目中的所有\u类\u文件){
ClassPool default=ClassPool.getDefault();
add(default.makeClass(新的FileInputStream(file.getPath()));
}
“类”列表将为您准备好所有要处理的类。您可以将其添加到某个始终加载的入口点类中的静态块中

如果这对您不起作用,下一个赌注是使用javaagent来做这件事。做这件事并不难,但它会对您的部署产生一些影响(应该提供代理库jar&将-javaagent添加到启动参数中)