openpnp - src - 配置文件载入过程的初步分析

news2024/11/29 2:43:55

文章目录

    • openpnp - src - 配置文件载入过程的初步分析
    • 概述
    • 笔记
    • 自己编译用的git版本
    • 报错截图
    • 问题1 - 怎么在调试状态下, 定位到抛异常的第一现场?
    • 结合单步调试找到的现场, 来分析报错的原因
    • openpnp配置文件读取的流程
    • END

openpnp - src - 配置文件载入过程的初步分析

概述

从openpnp - dev - 2022_0801那天最后的代码, 编译除了一份可执行程序给自己用.
用官方打包的发布版 dev - 2022_0801运行, 居然读取我自己版本的配置文件失败.
将自己打包的那份dev-2022_0801, 再将版本退一个版本, 也会读取配置文件失败. 估计官方打包没用dev-2022_0801那天的最后版本.

通过git版本比对, 结合报错信息, 大概知道是新版本有个类, 添加了一个新属性, 导致旧版本读取不了新版本增加的属性时, 因为没有那个旧类没有那个新增加的属性, 导致抛出异常.

作为新手, 想弄清为啥读取配置文件报错, 错在哪里. 顺便看一下openpnp序列化配置文件的过程. 多一些了解, 总是没错的…

笔记

自己编译用的git版本

在这里插入图片描述
不太理解为啥官方打包的版本是2022/8/1下午的时间, 但是却没采用2022/8/1那天最新的实现. 而且提交时间只差了3分钟, 还是同一个人提交的, 迷惑…

编译openpnp工程的过程已经做了笔记(openpnp - 软件调试环境搭建).

报错截图

先用官方版本的dev-2022/8/1的发布包标定的设备.

后来发现openpnp有点bug, 修正了, 此时正常用, 但是配置文件被新版本(比官方版本晚3分钟的git版本, 修正后, 重新编译)改了, machine.xml中的视觉方案类中多了一个类属性.

偶然用官方发布的dev-2022_0801实验, 才发现报错如下:
在这里插入图片描述
根据报错提示, 可以知道 machine.xml中有个属性 settle-test-move-mm 在类org.openpnp.machine.referene.solutions.VisionSolutions中没有, 导致了抛异常报错.

看到这个报错后, 有2个想法:

  • 具体报错点在哪里? (等以后出现版本和配置文件不匹配时, 可以迅速定位到发生异常的类, 还可以知道报错前, 哪里是抛异常的第一现场?)
  • openpnp配置文件有4个xml, 这些配置文件读取的流程大致是从哪里到哪里?

用了一天, 将上面2个问题搞定了. 心里舒坦多了.

问题1 - 怎么在调试状态下, 定位到抛异常的第一现场?

我是第一次调试这个问题, 不断的下条件断点. 最后可以2步就到达报错现场. 如果不设置条件断点, 那基本就是不可调试的.

在这里插入图片描述
在这里插入图片描述
F8步过loadMachine(file), 如果没有其他条件断点, 就会直接进入437行的抛异常实现, 就会看到报错对话框.
F7步入loadMachine(file), 先F8, 如果哪步会导致进入437行报错断点, 再F7那个函数. 结合条件断点, 就能定位到抛异常的第一现场.
然后 CTRL + ALT + 向左的箭头, 就可以回到最后一次F8的代码实现. 然后停掉程序, 看看是不是第一现场, F7, F8, 直到找到第一现场.

当断住后, 如果不是我们要的调试代码, 按F9, 让程序继续跑, 命中我们后续的断点继续调试. 如果确定断点没用了, 就在一个断点上右击, 进入断点编辑器, 禁止掉不用的断点(不用删除, 可能找调试痕迹还有用).

在这里插入图片描述
这里就是找到的抛异常的第一现场.
2个条件断点都一样, 如下:

((null != name) && (19 == name.length()) && (0x73 == name.value[0]))

这个条件断点, 是找name == “visual-solutions”, 为了简单, 值判断了name的长度和第一个字符, 已经可以正确断住了. 如果只判断一个字符值不好使, 那就再挑一个字符值, 看情况, 条件写的越少越好.

在IDEA中下字符串的条件断点的方法已经做了笔记(java - IDEA IDE - 设置字符串断点).

因为报错的第一现场是在第三方jar包中, 只读的无法添加调试代码, 所以下条件断点能捕获到调试点就行.

结合单步调试找到的现场, 来分析报错的原因

第一现场的代码如下:

   private void readAttribute(InputNode node, Object source, Section section, LabelMap map) throws Exception {
      String name = node.getName(); // 取节点名称
      String path = section.getAttribute(name); // 取属性的path
      // map这里是类实际的属性值的集合
      // path是xml中指定的这个类的属性名称
      Label label = map.getLabel(path); // 拿属性的path去取属性的值
      
      if(label == null) {
      	// 这里是没取到属性的值, 也就是旧版本openpnp读取新版本配置文件, 因为具体的类没有这个属性, 自然无法将xml中规定的类属性设置到类的到属性成员中.
      	// 这里就是抛异常的第一现场
         Position line = node.getPosition(); // 报错的行数, 这里取的值不准, 没有参考价值. 文件是应该包含该属性的类, 行数(line)根本不对. 不怪IDEA, 因为这个属性就不存在, 用属性的代码行数自然也不对.
         Class expect = context.getType(type, source); // 好像是发生错误的类名称

		// 如果map是要求严格匹配(类的属性和xml中必须严格对应), 缓存也是要求严格匹配的, 就抛出异常报错.
         if(map.isStrict(context) && revision.isEqual()) {   
         	// 然后就进入这里, 抛异常, 异常的内容就在报错框中被我们看到           
            throw new AttributeException("Attribute '%s' does not have a match in %s at %s", path, expect, line);
         }            
      } else {
         readInstance(node, source, label);
      }         
   }

openpnp配置文件读取的流程

只看用户空间的代码(主干函数), 进了第三方库的实现就不看了.

从main函数开始
D:\my_openpnp\openpnp_github\src\main\java\org\openpnp\Main.java

    public static void main(String[] args) {


        monkeyPatchBeansBinding();
        
        for (String s : args) {
            if (s.equals("--version")) {
                System.out.println(getVersion());
                System.exit(0);
            }
        }
        
        // http://developer.apple.com/library/mac/#documentation/Java/Conceptual/Java14Development/07-NativePlatformIntegration/NativePlatformIntegration.html#//apple_ref/doc/uid/TP40001909-212952-TPXREF134
        System.setProperty("apple.laf.useScreenMenuBar", "true");
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        }
        catch (Exception e) {
            throw new Error(e);
        }

        File configurationDirectory = new File(System.getProperty("user.home"));
        configurationDirectory = new File(configurationDirectory, ".openpnp2");

        if (System.getProperty("configDir") != null) {
            configurationDirectory = new File(System.getProperty("configDir"));
        }

        configurationDirectory.mkdirs();

        configureLogging(configurationDirectory);

        Configuration.initialize(configurationDirectory);
        final Configuration configuration = Configuration.get();
        Locale.setDefault(Configuration.get().getLocale());

        ThemeInfo theme = configuration.getThemeInfo();
        new ThemeSettingsPanel().setTheme(theme, configuration.getFontSize(), configuration.isAlternateRows());
        ThemeDialog.getInstance().setOldTheme(theme);

        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    MainFrame frame = new MainFrame(configuration); // 进入MainFrame实现读配置
                    frame.setVisible(true);
                    Logger.info(String.format("Bienvenue, Bienvenido, Willkommen, Hello, Namaskar, Welkom, Bonjour to OpenPnP version %s.", Main.getVersion()));
                    configuration.getScripting().on("Startup", null);
                }
                catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }
}

D:\my_openpnp\openpnp_github\src\main\java\org\openpnp\gui\MainFrame.java

public MainFrame(Configuration configuration) {
// 巨大的一个函数, 只看相关实现
// ...
        registerBoardImporters();

        addComponentListener(componentListener);
        
        boolean configurationLoaded = false;
        while (!configurationLoaded) {
	        try {
	            configuration.load(); // 这里载入配置文件(4个.xml), 如果配置文件过不去, 就会抛一场.
	            scriptFileWatcher = new ScriptFileWatcher(configuration.getScripting());
	            scriptFileWatcher.setMenu(mnScripts);
	            
	            if (Configuration.get().getMachine().getProperty("Welcome2_0_Dialog_Shown") == null) {
	                Welcome2_0Dialog dialog = new Welcome2_0Dialog(this);
	                dialog.setSize(750, 550);
	                dialog.setLocationRelativeTo(null);
	                dialog.setModal(true);
	                dialog.setVisible(true);
	                Configuration.get().getMachine().setProperty("Welcome2_0_Dialog_Shown", true);
	            }
	            configurationLoaded = true;    
	        }
	        catch (Exception e) {
	        	// 这里就是用户看到报错提示框的地方
	            e.printStackTrace();
	            if (!MessageBoxes.errorBoxWithRetry(this, "Configuration Load Error", //$NON-NLS-1$
	                    "There was a problem loading the configuration. The reason was:<br/><br/>" //$NON-NLS-1$
	                            + e.getMessage() + "<br/><br/>" //$NON-NLS-1$
	                            + "Please check your configuration files and try again. They are located at: " //$NON-NLS-1$
	                            + configuration.getConfigurationDirectory().getAbsolutePath()
	                            + "<br/><br/>" //$NON-NLS-1$
	                            + "If you would like to start with a fresh configuration, just delete the entire directory at the location above.<br/><br/>" //$NON-NLS-1$
	                            + "Retry loading (else openpnp will exit) ?")) { //$NON-NLS-1$
	            	System.exit(1);
	            }
	        }
	    }
        splitWindows();
    }
}

D:\my_openpnp\openpnp_github\src\main\java\org\openpnp\model\Configuration.java

	// 用户空间读取配置的函数
	// .xml和具体的类是对应的, 就是序列化xml文件到类的属性
    public synchronized void load() throws Exception {
        boolean forceSave = false;
        boolean overrideUserConfig = Boolean.getBoolean("overrideUserConfig");

		// 1. 读取packages.xml到具体类的属性
        try {
            File file = new File(configurationDirectory, "packages.xml");
            if (overrideUserConfig || !file.exists()) {
                Logger.info("No packages.xml found in configuration directory, loading defaults.");
                file = File.createTempFile("packages", "xml");
                FileUtils.copyURLToFile(ClassLoader.getSystemResource("config/packages.xml"), file);
                forceSave = true;
            }
            loadPackages(file);
        }
        catch (Exception e) {
            String message = e.getMessage();
            if (e.getCause() != null && e.getCause().getMessage() != null) {
                message = e.getCause().getMessage();
            }
            throw new Exception("Error while reading packages.xml (" + message + ")", e);
        }

		// 2. 读取parts.xml到具体类的属性
        try {
            File file = new File(configurationDirectory, "parts.xml");
            if (overrideUserConfig || !file.exists()) {
                Logger.info("No parts.xml found in configuration directory, loading defaults.");
                file = File.createTempFile("parts", "xml");
                FileUtils.copyURLToFile(ClassLoader.getSystemResource("config/parts.xml"), file);
                forceSave = true;
            }
            loadParts(file);
        }
        catch (Exception e) {
            String message = e.getMessage();
            if (e.getCause() != null && e.getCause().getMessage() != null) {
                message = e.getCause().getMessage();
            }
            throw new Exception("Error while reading parts.xml (" + message + ")", e);
        }

		// 3. 读取vision-settings.xml到具体类的属性
        try {
            File file = new File(configurationDirectory, "vision-settings.xml");
            if (overrideUserConfig || !file.exists()) {
                Logger.info("No vision-settings.xml found in configuration directory, loading defaults.");
                file = File.createTempFile("visionSettings", "xml");
                FileUtils.copyURLToFile(ClassLoader.getSystemResource("config/vision-settings.xml"), file);
                forceSave = true;
            }
            loadVisionSettings(file);
        }
        catch (Exception e) {
            String message = e.getMessage();
            if (e.getCause() != null && e.getCause().getMessage() != null) {
                message = e.getCause().getMessage();
            }
            throw new Exception("Error while reading vision-settings.xml (" + message + ")", e);
        }

		// 4. 读取machine.xml到具体类的属性
		// 这次调试, 就能看到是在读取machine.xml配置文件时, 抛异常.
        try {
            File file = new File(configurationDirectory, "machine.xml");
            if (overrideUserConfig || !file.exists()) {
                Logger.info("No machine.xml found in configuration directory, loading defaults.");
                file = File.createTempFile("machine", "xml");
                FileUtils.copyURLToFile(ClassLoader.getSystemResource("config/machine.xml"), file);
                forceSave = true;
            }
            loadMachine(file); // 这里具体都配置文件
        }
        catch (Exception e) {
            String message = e.getMessage();
            if (e.getCause() != null && e.getCause().getMessage() != null) {
                message = e.getCause().getMessage();
            }
            throw new Exception("Error while reading machine.xml (" + message + ")", e);
        }

        loaded = true;

        // Tell all listeners the configuration is loaded. Use a snapshot of the list in order to tolerate new
        // listener additions that may happen through object migration.
        for (ConfigurationListener listener : new ArrayList<>(listeners)) {
            listener.configurationLoaded(this);
        }

        if (forceSave) {
            Logger.info("Defaults were loaded. Saving to configuration directory.");
            configurationDirectory.mkdirs();
            save();
        }

        for (ConfigurationListener listener : listeners) {
            listener.configurationComplete(this);
        }
    }

	// 下面是保存配置文件的函数
    public synchronized void save() throws Exception {
        LocalDateTime now = LocalDateTime.now();

    private void loadMachine(File file) throws Exception {
        Serializer serializer = createSerializer();
        // serializer.read 已经离开用户代码, 去了第三方库中.
        // 如果不是调试代码, 就不用去看了.
        MachineConfigurationHolder holder = serializer.read(MachineConfigurationHolder.class, file);
        machine = holder.machine;
    }

END

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1145797.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MATLAB 安装教程(最新最全图文详解)

目录 一.简介 二.安装步骤 软件&#xff1a;MATLAB版本&#xff1a;2022b语言&#xff1a;简体中文大小&#xff1a;19.37G安装环境&#xff1a;Win11/Win10硬件要求&#xff1a;CPU2.6GHz 内存8G(或更高&#xff09;下载通道①百度网盘丨64位下载链接&#xff1a; https://pa…

【转信创】银河麒麟:系统安全机制

银河麒麟执行脚本时一直显示权限不足&#xff0c;可能需要修改安全状态。 查看当前kysec的相关安全状态&#xff1a; getstatus 修改当前Kysec的相关安全状态&#xff1a; # 设置Kysec安全状态为软/强制模式&#xff1b; sudo setstatus softmode/normal # 关闭执行控制功能…

Flutter笔记:完全基于Flutter绘图技术绘制一个精美的Dash图标(中)

Flutter笔记 完全基于Flutter绘图技术绘制一个精美的Dart语言吉祥物Dash&#xff08;中&#xff09; 作者&#xff1a;李俊才 &#xff08;jcLee95&#xff09;&#xff1a;https://blog.csdn.net/qq_28550263 邮箱 &#xff1a;291148484163.com 本文地址&#xff1a;https://…

图神经网络及其在知识图谱的应用

一 应用领域 道路交通&#xff0c;动态预测 自动驾驶&#xff0c;无人机场景 化学&#xff0c;医疗等场景 物理模型相关 二 图基本模块定义 V Vertex点 E Edge 边&#xff08;向量&#xff09; U Global 图 &#xff08;例如&#xff1a;全局向量&#xff09; 无论事…

nodejs+vue全国公考岗位及报考人数分析

传统的搜索引擎尽管解决了信息搜索问题&#xff0c;但无法进行有效的数据分析和优质资源的获取。并且&#xff0c;人们的需求不同&#xff0c;数据的要求也不同。为了解决这一问题&#xff0c;定向抓取数据的爬虫诞生了。它的诞生把人们从重复性的劳动中解放出来&#xff0c;节…

macbook如何格式化硬盘 mac系统硬盘格式化需要选择哪种格式

很多mac用户想要格式化硬盘&#xff0c;却不知道正确的格式方法。小白用户看到如此多的硬盘格式却不知道选择哪个。今天小编就来教大家&#xff0c;macbook如何格式化硬盘&#xff0c;以及mac系统格式化硬盘&#xff0c;需要选择哪种格式。 一、macbook如何格式化硬盘 macboo…

利用AI Chat 将电子书自动截屏并保存成pdf文件

电子书如果要下载下来&#xff0c;无非就两种类型的方法&#xff0c;一种是从内部破解&#xff0c;通常是某些极客将软件破解成免费版&#xff0c;但是风险也大。另一种是从外部破解&#xff0c;就是截屏保存&#xff0c;然后将所有图片拼成pdf文件。 如果要将整本电子书截屏保…

Flutter笔记:完全基于Flutter绘图技术绘制一个精美的Dash图标(上)

Flutter笔记 完全基于Flutter绘图技术绘制一个精美的Dart语言吉祥物Dash&#xff08;上&#xff09; 作者&#xff1a;李俊才 &#xff08;jcLee95&#xff09;&#xff1a;https://blog.csdn.net/qq_28550263 邮箱 &#xff1a;291148484163.com 本文地址&#xff1a;https://…

测开 (Junit 单元测试框架)

目录 了解 Junit 引入相关依赖 1、Junit注解 Test BeforeEach、BeforeAll AfterEach && AfterAll 2、断言 1、Assertions - assertEquals 方法 2、Assertions - assertNotEquals 方法 3、Assertions - assertTrue && assertFalse方法 4、Assertions…

nodejs+vue人脸识别考勤管理系统的设计与实现-计算机毕业设计

根据分析&#xff0c;本系统主要有3个角色&#xff1a;管理员、用户、考勤系统。 &#xff08;1&#xff09;管理员&#xff1a;管理员信息的添加、删除、修改和查询&#xff0c;用户信息添加、删除、修改和查询。 &#xff08;2&#xff09;用户&#xff1a;用户的注册和登录&…

[红蓝攻防]MDOG(全新UI重制版)为Xss跨站而生,数据共享,表单劫持,URL重定向

说明 功能Cookie窃取表单劫持(钓鱼账密)重定向流量劫持多平台数据推送钉钉数据推送 运行窗口 ./dist目录下已生成exe文件,双击打开 Cookie窃取 点击运行服务,复制以上的payload,payload怎么变形那么你可已去混淆 payload在页面执行 受害者访问存在xss漏洞的页面时受到攻击,…

【软考】系统集成项目管理工程师(十)项目质量管理【3分】

一、质量概念 1、定义 国际&#xff1a;反应实体满足主体明确和隐含需求的能力的特性总和 国内&#xff1a;一组固有特性满足要求的程度 2、质量与等级 质量&#xff1a;作为实现的性能或成果&#xff0c;是一系列内在特性满足要求的程度ISO9000 等级&#xff1a;作为设计意…

阅读JDK源码的经验分享

理论先行。阅读某一个模块时&#xff0c;先搜索它的理论支撑&#xff0c;甚至可以先看别人的阅读经验&#xff0c;有了一个大致的了轮廓之后&#xff0c;自己再去实践。 必须试用。面对一个新的类&#xff0c;最好是先搜索一下它的基本用法&#xff0c;写成一个小的示例&#…

Camtasia mac版怎么加字幕 Camtasia mac版怎么打马赛克

在视频制作过程中&#xff0c;字幕和马赛克是两项非常常用的编辑功能&#xff0c;添加字幕可以提高观众的观看体验&#xff0c;添加马赛克可以保护视频创作者不想公开的画面内容。Camtasia作为一款知名的视频制作软件&#xff0c;在具备基本的录制和视频编辑功能的同时&#xf…

麻匪音频识别-网易云-BetterNCM(目前仅网易云支持)

麻匪音频识别-网易云-BetterNCM&#xff08;目前仅网易云支持&#xff09; 这个东西很帅的哦&#xff0c;你网易云放什么歌他就联动什么&#xff0c;自动变 首先下载一点东西 1.steam 2.steam里面搜索wallpaper下载&#xff08;这个免费的哈&#xff09; 3.然后到这个界面 搜…

【软考】系统集成项目管理工程师(十一)项目人力资源管理【2分】

一、 人力资源管理【ITO口诀版】 二、 规划人力资源管理 1、定义 &#xff08;1&#xff09;确定项目的角色、职责以及汇报关系&#xff0c;并编制人员配备管理计划 &#xff08;2&#xff09;作为项目最初阶段的一部分。但是这一过程的结果应当在项目的整个生命周期中进行经…

GoLand GC(垃圾回收机制)简介及调优

GC(Garbage Collector)垃圾回收机制及调优 简单理解GC机制 其实gc机制特别容易理解&#xff0c;就是物理内存的自动清理工。我们可以把内存想象成一个房间&#xff0c;程序运行时会在这个房间里存放各种东西&#xff0c;但有时候我们会忘记把不再需要的东西拿出去&#xff0c…

Go学习第十五章——Gin参数绑定bind与验证器

Go web框架——Gin&#xff08;参数绑定bind与验证器&#xff09; 1 bind参数绑定1.1 JSON参数1.2 Query参数1.3 Uri绑定动态参数1.4 ShouldBind自动绑定 2 验证器2.1 常用验证器2.2 gin内置验证器2.3 自定义验证的错误信息2.4 自定义验证器 1 bind参数绑定 在Gin框架中&#…

Unity Meta Quest 一体机开发(三):Oculus Integration 基本原理、概念与结构+玩家角色基本配置

文章目录 &#x1f4d5;教程说明&#x1f4d5;输入数据&#x1f4d5;Oculus Integration 处理手部数据的推荐流程&#x1f4d5;VR 中交互的基本概念&#x1f4d5;Oculus Integration 中的交互流程&#x1f4d5;配置一个基本的玩家物体⭐OVRCameraRig⭐OVRInteraction⭐OVRHandP…

MC红显材质包安装

红显材质包安装 UP介绍视频 https://www.bilibili.com/video/BV1ML4y1u7nd/?vd_source3b8afcc2613780d7607382bae034945a 材质包下载地址&#xff1a; 需要 OptiFine 或 CITResewn 模组&#xff08;以后还会支持其他自定义贴图模组&#xff09; 下载&#xff1a;https://xek…