曾经有人在知乎上问过,为什么要自己弄个博客或者用 Git 吗? 看看这个应该就知道了吧。 因为有很长一段时间都没有在 OSCHINA 上发布博客了,因为老是审核不通过。 账号也大半年也没有登录过了,今天登录下就这样了。 你说有什么问题,提前邮件通知下也行呀,辛亏也就只是在上面看看热闹。 https://www.isharkfly.com/t/github/15725
曾经有人在知乎上问过,为什么要自己弄个博客或者用 Git 吗? 看看这个应该就知道了吧。 因为有很长一段时间都没有在 OSCHINA 上发布博客了,因为老是审核不通过。 账号也大半年也没有登录过了,今天登录下就这样了。 你说有什么问题,提前邮件通知下也行呀,辛亏也就只是在上面看看热闹。 https://www.isharkfly.com/t/github/15725
如果有文件大小大于 100M,GitHub 是会被限制推送到仓库中的,大概率情况会显示下面的错误: remote: Resolving deltas: 100% (3601/3601), done. remote: error: Trace: aea1f450da6f2ef7bfce457c715d0fbb9b0f6d428fdca80233aff34b601ff59b remote: error: See https://gh.io/lfs for more information. remote: error: File Ektron_Prod/App_Data/GeoIPOrg.dat is 139.96 MB; this exceeds GitHub's file size limit of 100.00 MB remote: error: GH001: Large files detected. You may want to try Git Large File Storage - https://git-lfs.github.com. 对于上面的问题,我们需要使用 LFS 服务。 找到合并信息 运行下面的代命令,找到我们合并后仓库中的合并信息: git lfs migrate info --everything --above="100MB" 这个命令将会找到在当前仓库中有那些文件的扩展名大小超过 100MB。 我们得到了下面的输出。 migrate: Sorting commits: ..., done. migrate: Examining commits: 100% (17/17), done. *.dat 587 MB 4/13 files 31% LFS Objects 0 B 0/4517 files 0% 提交处理 从上面的输出中,我们看到了 .dat 文件有超过 100 MB。 下一步,我们需要运行命令对针对这个文件的提交进行处理。 git lfs migrate import --everything --include="*.dat" 随后,控制台输出: migrate: Sorting commits: ..., done. migrate: Rewriting commits: 100% (17/17), done. master 7f1f2a07b4dc972e6243984675bd28a3ea15b212 -> 3de8026c759fe6a22199d4df7c640e1bbd1b28e0 migrate: Updating refs: ..., done. migrate: checkout: ..., done. 使用命令进行提交 运行下面的命令,将本地代码仓库提交到远程: git push --all origin -u 当然,在这个提交之前,需要设置远程仓库的地址,这个你可以通过修改 config 文件进行修改。 再次确认所有 LFS 文件提交 在合并的过程中,可能会有些大型文件没有提交到 LSF 上面。 所以需要运行下下面的命令,再次确认所有的 LSF 文件被提交。 git lfs push origin --all https://www.isharkfly.com/t/svn-git-100-m-push/15723
介绍 在本文中,我们会对 Optional 类进行一些说明,并且会解释下如果在使用 Optional 类的时候可能在 Jackson 中进行序列化和反序列化的过程中出现的问题。 针对上面的问题,本文会将会介绍在 Jackson 中如何处理 Optional 对象,和如果 Optional 对象可能出现潜在的 Null 的解决方案。 问题概览 首先让我们来看看如果使用 Jackson 来对 Optional 数据类型进行序列化和反序列化中出现的问题。 Maven 依赖 针对 Jackson,我们可以使用最新的版本。 当我们对本文进行更新的时候,jackson-core 的最新版本为 2.17.0。 <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.13.3</version> </dependency> 定义 Book 对象 随后让我们来定义一个 Book 对象,在 Book 对象中,我们有一个使用 Optional 的字段。 当然在这个 Book 对象中,我们还需要添加 Getter 和 Setter 方法,在文章中,我们就省略到这些方法了。 public class Book { private String title; private Optional<String> subTitle; } 在的对数据对象进行初始化的时候,我们需要注意对 Optional 对象设置值的方式,因为不同的值会影响序列化和反序列化的情况。 序列化 让我们先来实例化 Book 这个对象: Book book = new Book(); book.setTitle("Oliver Twist"); book.setSubTitle(Optional.of("The Parish Boy's Progress")); 随后,我们使用 Jackson 的 ObjectMapper 方法来对实例化后的对象进行序列化,我们使用下面的代码来进行序列化: String result = mapper.writeValueAsString(book); 从输出的字段中,我们可以看到输出的字符串内容中并没有输出具体的值,而是输出为下面的内容: {"title":"Oliver Twist","subTitle":{"present":true}} 尽管上面的输出看起来有点奇怪,但是上面的输出却是正确的情况,因为这个和 Optional 的特性是有关的。 方法 isPresent() Optional 的 public getter 方法,这就意味着在序列化的时候基于我们对象中存储的具体的值,Jackson 将会输出 True 或者 False 。 这是 Jackson 当前正确的输出方式。 但,我们可能考虑在输出的时候输出具体的值,至于怎么输出这个具体的值的方法,我们在后续的解决方案中提出。 反序列化 现在,让我们使用上面的代码来对对象数据进行反序列化,考察使用下面的代码: @Test(expected = JsonMappingException.class) public void givenFieldWithValue_whenDeserializing_thenThrowException String bookJson = "{ \"title\": \"Oliver Twist\", \"subTitle\": \"foo\" }"; Book result = mapper.readValue(bookJson, Book.class); } 当上面的代码运行的时候将会提示下面的错误信息: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `java.util.Optional` (no Creators, like default constructor, exist): no String-argument constructor/factory method to deserialize from String value ('foo') at [Source: (String)"{ "title": "Oliver Twist", "subTitle": "foo" }"; line: 1, column: 40] (through reference chain: com.ossez.jackson.optionalwithjackson.Book["subTitle"]) 上面的错误信息针对 Jackson 来说是正确的,因为 Jackson 是需要一个构造方法来把 subtitle 参数的值来对 Optional 对象进行数据初始化。 解决方案 我们希望的是 Optional 对象应该把一个空的数据设置为 null,如果不是空的数据,Optional 应该使用值来进行处理。 针对上面的要求,Jackson 已经提供了解决方案,Jackson 针对 JDK8 的新增模块设置了一系列数据类型,这里就包括了 Optional。 Maven 依赖 首先,我们需要使用针对 JDK 8 使用的依赖,这个依赖的名称为:jackson-datatype-jdk8 <dependency> <groupId>com.fasterxml.jackson.datatype</groupId> <artifactId>jackson-datatype-jdk8</artifactId> <version>2.17.0</version> </dependency> 现在,我们需要把上面的依赖注册到 ObjectMapper: ObjectMapper mapper = new ObjectMapper(); mapper.registerModule(new Jdk8Module()); 或者上面的 2 句话也可以简化成 1 句话: ObjectMapper mapper = new ObjectMapper().registerModule(new Jdk8Module()); 序列化 现在,让我们来进行测试。 让我们再次使用上面的代码来对 Book 这个对象进行序列化和反序列化,然后我们在对输出的字符串进行查看。 Book book = new Book(); book.setTitle("Oliver Twist"); book.setSubTitle(Optional.of("The Parish Boy's Progress")); String serializedBook = mapper.writeValueAsString(book); assertThat(from(serializedBook).getString("subTitle")) .isEqualTo("The Parish Boy's Progress"); 如果我们尝试序列化一个空的 Book 对象的话,那么 Optional 字段中存储的数据为 null。 book.setSubTitle(Optional.empty());…
介绍 Jackson-jr 是一个轻量级的Java JSON 处理库。这个库被设计用来替代 Jackson 的复杂性。对比 Jackson 的复杂 API,Jackson-jr 的启动速度更快,包大小更小。 虽然Jackson databind(如ObjectMapper)是通用数据绑定的良好选择,但它的占用空间(Jar包大小)和启动开销在某些领域可能存在问题:比如移动端,特别是对于轻量使用(读或写)。这种情况下,完整的Jackson API是让人接受不了的。 由于所有这些原因,Jackson 官方决定创建一个更简单、更小的库:Jackson-jr。它仍旧构建在 Streaming API 之上,但不依赖于 databind 和annotation。因此,它的大小(jar和运行时内存使用)要小得多,它的API非常紧凑,所以适合APP等移动端。 它仅仅只依赖了 jackson-core 模块,所以体积上控制得非常的好。Jackson 单单三大核心模块大小合计1700KB左右(320 + 70 + 1370)。而Jackson-jr的体积控制在了95KB(就算加上core模块的320也不到500KB)。 针对实际开发的情况,很多时候我们只需要对 JSON 数据进行读取和写入,至于一些过于复杂和强大的属性,我们可能也用不上,因此针对一些 JSON 数据使用场景比较单一的情况,Jackson-jr 就显得更有优势了。 所以,Jackson-jr 的主要情况就是在针对 JSON 格式的读写上面,如果你只需要简单的读和些,Jackson-jr 通常是你的一个选择。 在本文中,我们对 Jackson-jr 的简单使用进行一些说明和示例。 开始使用 Jackson-jr Jackson-jr 提供的是轻量和高效的 JSON 处理模块。所以 Jackson-jr 针对 JSON 数据结构只提供了简单的数据读取和写入功能。 当然 Jackson-jr 是可以处理对象和数组的。 在开始使用 Jackson-jr 之前,我们需要把需要的包添加到 Maven 项目的 pom 文件中。 当前的可以使用的最新版本为:2.17.0 <dependency> <groupId>com.fasterxml.jackson.jr</groupId> <artifactId>jackson-jr-all</artifactId> <version>2.17.0</version> </dependency> XML 针对 Gradle 可以使用不同的表达方式,唯一需要注意一点的就是版本号。 处理 JSON 对象 尽管我们是使用 Jackson-jr 来处理 JSON 字符串,和 Jackson 一样,字符串也会被处理成为 JSON 对象:每一个 JSON 实例是不可变(immutable )的,同时也是线程安全的。 正是因为有上面的特性,我们可以在多线程程序,单例模式,Spring Bean 中安全的使用创建的 JSON 对象。 创建 JSON 对象和数组 针对创建的 JSON 对象,我们可以使用类似 LinkedHashMap 来创建对象,对于数组,我们就可以用我们常用的 ArrayList。 因为 JSON 对象使用的是 LinkedHashMap,所以我们可以利用 Map 的特性,使用 LinkedHashMap.put() 方法来 Push 数据到 Map 中。 @Test public void createJsonStringTest() throws IOException { System.out.println(JSON.std.with(JSON.Feature.PRETTY_PRINT_OUTPUT) .asString(new LinkedHashMap<String, Object>() {{ put("name", "John Doe"); put("age", 30); }})); } Java Jackson-jr Composer Jackson-jr 同时还提供了 Composer 的这个创建方法,这个创建方法更加直接。 你可以按照你的想法直接进行定义和输出,在这之前,我们通常需要定义一个对象,然后对对象进行完成数据后再输出,对于一些简单的 JSON 格式。我们可以不用定义对象了,而是直接使用。 public static String jsonComposer() throws IOException { return JSON.std.with(JSON.Feature.PRETTY_PRINT_OUTPUT) .composeString() .startObject() .startArrayField("objectArray") .startObject() .put("name", "name1") .put("age", 11) .end() .startObject() .put("name", "name2") .put("age", 12) .end() .end() .startArrayField("array") .add(1) .add(2) .add(3) .end() .startObjectField("object") .put("name", "name3") .put("age", 13) .end() .put("last", true) .end() .finish(); } Java 运行上面的程序后,程序将会输出: { "objectArray" : [ { "name" : "name1", "age" : 11 }, { "name" : "name2", "age" : 12 } ], "array" : [ 1, 2, 3 ], "object" : { "name" : "name3", "age" : 13 }, "last" : true } Plain text 序列化和反序列化 Jackson-jr 可以让我们非常容易的把 Java 对象进行序列化,同时也能够非常容易的让我们从 JSON 字符串中读取为 Java 对象。 在对对象进行读写的时候,我们也可以对读写的属性进行定义,例如对输出的文本进行格式化或者使用自定义的日期属性进行输出,然后再从 Java 对象中写入到 String 字符串。 Jackson-jr 同时也能够支持复杂的数据结构,例如对象嵌套和数组等。通过对我们对象的关联关系的定义,我们可以让 JSON 字符串在进行反序列化序列化的时候完成对象映射,对于 Java 到 String 字符串的输出,其实也是一样。 // Serialization String json = JSON.std.with(JSON.Feature.PRETTY_PRINT_OUTPUT) .asString(person); // Deserialization…
关于Jackson-jr 对比 Jackson 的内容,有人在做了一张下面的图。 简单点来说就 Jackson-jr 是Jackson 的轻量级应用,因为我们在很多时候都用不到 Jackson 的很多复杂功能。 对很多应用来说,我们可能只需要使用简单的 JSON 读写即可。 如我们用不到什么复杂的功能,并且使用了 Jackson-jr 能够满足你的项目使用的话,就直接使用 Jackson-jr 即可。 如发现 Jackson-jr 没有办法满足你的所有需求的时候,可以再切换到传统的 Jackson 包。 https://www.isharkfly.com/t/jackson-jr-jackson/15708
Jackson-jr 是一个轻量级的Java JSON 处理库。这个库被设计用来替代 Jackson 的复杂性。对比 Jackson 的复杂 API,Jackson-jr 的启动速度更快,包大小更小。 虽然Jackson databind(如ObjectMapper)是通用数据绑定的良好选择,但它的占用空间(Jar包大小)和启动开销在某些领域可能存在问题:比如移动端,特别是对于轻量使用(读或写)。这种情况下,完整的Jackson API是让人接受不了的。 由于所有这些原因,Jackson 官方决定创建一个更简单、更小的库:Jackson-jr。它仍旧构建在 Streaming API 之上,但不依赖于 databind 和annotation。因此,它的大小(jar和运行时内存使用)要小得多,它的API非常紧凑,所以适合APP等移动端。 它仅仅只依赖了 jackson-core 模块,所以体积上控制得非常的好。Jackson 单单三大核心模块大小合计1700KB左右(320 + 70 + 1370)。而Jackson-jr的体积控制在了95KB(就算加上core模块的320也不到500KB)。 针对实际开发的情况,很多时候我们只需要对 JSON 数据进行读取和写入,至于一些过于复杂和强大的属性,我们可能也用不上,因此针对一些 JSON 数据使用场景比较单一的情况,Jackson-jr 就显得更有优势了。 所以,Jackson-jr 的主要情况就是在针对 JSON 格式的读写上面,如果你只需要简单的读和些,Jackson-jr 通常是你的一个选择。 性能 有关 JSON 处理数据的能力,Github 上有个项目进行了一些测试。 项目的地址为:GitHub - fabienrenaud/java-json-benchmark: Performance testing of serialization and deserialization of Java JSON libraries 根据项目测试的结果来看,Jackson 的处理能力是所有参加测试的包的性能最好的。 Jackson-jr 和 Jackson 是同一个社区的产品,因此性能上面完全不需要担心。 https://www.isharkfly.com/t/java-jackson-jr/15709
在 Gitea 的用户管理部分,有一个 SSH 和 GPG 的选项。 单击这个选项,可以在选项上添加 Key。 Key 的来源 如是 Windows 的用户,可以选择 Kleopatra 这个软件。 通过这个软件生成的 Key 的界面中有一个导出功能。 单击这个导出,就会出现一个新的界面,把这个新界面中的内容复制粘贴到添加 GPG 的 Key 的对话框中即可。 如果你是用的 GitHub 的话,也可以同样的操作,也是拷贝这个内容。 通常这个内容只需要拷贝 1 次就可以了,如果更换了 Key,那么 GPG 还需要重新复制一下。 上图显示了 GPG key 的大致情况。 当完成签名后在界面中显示的图片如下图: 看起来好看些了。 https://www.isharkfly.com/t/gitea/15707
提示的错误信息: INFO] ------------------------------------------------------------------------ [ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.10.1:compile (default-compile) on project core-java-9: Compilation failure [ERROR] exporting a package from system module java.base is not allowed with --release [ERROR] [ERROR] -> [Help 1] [ERROR] [ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch. [ERROR] Re-run Maven using the -X switch to enable full debug logging. [ERROR] [ERROR] For more information about the errors and possible solutions, please read the following articles: [ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException [ERROR] [ERROR] After correcting the problems, you can resume the build with the command [ERROR] mvn <args> -rf :core-java-9 问题和解决 出现上面错误的原因是 JDK9 开始,–release 和 --add-exports 参数不能同时使用。 在我们的项目编译的时候添加了 --add-exports 参数。 这个会在 JDK 9 的时候报错。 我们可以把这个参数从编译环境中删除。 https://www.isharkfly.com/t/java-release/15702
作为 IT 搬砖人,一直都认为键盘没有什么太大关系。 每次都是公司发什么用什么。 但随着用几年后,发现现在的键盘经常出问题,比如说调节音量的时候通常莫名其妙的卡死,要不就是最大音量要不就是最小音量。 按键 M 不知道什么原因巨难按下去,有时候还感觉莫名其妙的卡在哪里。 回想这么多年,用的都是 104 键,一直没有来得及用什么比较好的机械键盘,随后发现键盘这东西就应该是生产力工具,不好的键盘确实有点感觉影响心情,遂决定换个键盘。 选型 正是对罗技见面的一些些失望,所以就先给看看有什么比较好的选项。 键盘用途:键盘的主要用途是工作需要,基本上不玩游戏,所以,游戏键盘就在考虑范围之内了,同时也并不需要类似游戏键盘的那种炫酷灯光。 连通性:随时可能需要会联通 iPad 和电脑,主流编程使用的计算机是 Windows 的计算机,不太希望使用 2.4G 的接收器,因为这个 2.4 G的接收器还需要占据一个 USB 接口。上网刷评测的时候说在连通性上,有线的肯定是要好过于无线的,但日常的工作就是调试程序,输入文本和邮件沟通。这种延迟对应该不会构成任何影响。简单点来说就是需要具有无线联通能力。 手感:已经有点受够了罗技这种普通键盘的手感了,想换下机械键盘。还记得读书的那个时候感觉都是机械键盘的天下和带轨迹球的鼠标,现在全是光电鼠标了,绕了一圈又绕回去了。 真是时间是一个挺有意思的东西,用了一圈居然又用回去了。 罗技 如果说考虑键盘就不得不说罗技这个牌子了。 用过的很多键盘都是罗技的,主要是性能比较稳定,兼容性没有问题,随便插上就能用,同时也因为家里和公司用的都是这个牌子,键盘鼠标换用也很方便。 这次主要原因也是罗技的键盘出了问题,所以想着就能不能抛开这牌子换一个牌子看看。 罗技也又机械键盘,上面的价格在 179 美元左右,叫做 MX 机械键盘系列。 MX Mechanical大概不是机械键盘里的顶格产品。但是MX Mechanical的优势在于对罗技生态的兼容性极佳,Options+Flow使用体验还是非常棒的。如果你使用的是罗技办公鼠标尤其是MX系列的旗舰办公鼠标的话,这个吸引力会非常大。 NuPhy 这个键盘应该就是在高颜值上,每款做得都非常漂亮。 对我们这种工科屌丝来说可能吸引并不是很大。 不过从官网上发的图片来看,每款都是那么炫酷。 HHKB 这个牌子还是最近在搜索键盘的时候才记起来还有这么个牌子。 最主要的是在日本以外的市场不是那么好买,更重要的是这个价格还是有点高的。如果不是特别发烧的这种级别,可能大部分人都不会入手这个牌子。 更何况这个键盘本身就是小键盘,对一般的使用者来说还是有一定的使用曲线的,不是和其他键盘都一样拿来就能用的那种。 可能还真是念旧了,第一眼居然是看上了 HHKB,而且还选的是和最古老的机械键盘相同的颜色布局。 下单 纠结了一顿饭的时间,决定下单 HHKB。 亚马逊上的价格是 299,然后查询了下官网,官网的价格也是 299。 本着多一事不如少一事的想法,就官网下单了,如果不着急的话,可以选择免邮费,就是时间长点。 有一种 3000 块钱的包可以买,1 块钱的邮费绝对不能出的感觉。 虽然有输入 Coupon 折扣码的地方,但 Google 到处找了下都没有找到可用的 Coupon,感觉就是压根不打算打折的意思。 有点过分了。 收到键盘时候的样子。 是非常简单的包装盒,说以前是有键帽拔除器的,现在这个也没有了,貌似也省掉了。 有点找到了大学时候学习计算机的感觉。 收到键盘后的第一件事情 收到键盘后的第一件时间就是调整 DIP。 本文提及的键盘配置方案,适用于包括 HHKB Pro 2 在内的大部分现役产品。 对 HHKB 机身后方的六个开关,我推荐使用如下的配置: Windows: 开启 1 3 4 号开关 MacOS: 开启 2 3 4 号开关 第 6 号开关是自动休眠。 关于自动休眠的情况就是,如果设置了自动休眠,那么休眠的时间是 30 分钟,当键盘休眠 后,不能通过敲打任何键盘的方式重新进行连接。 经过我的试验,是需要重新摁一下电源键才能重新打开电源。 如果第 6 号开关设置为 ON 的话,那么就不会对键盘进行休眠。唯一的问题就是电源消耗更快。 对我们的日常使用来说,应该还是需要把这个开关设置为不要休眠。 Windows 和 Mac 的模式 有关 Windows 和 Mac 模式的区别上,可以看看这个表。 从表里面可以看出来,HHKB 键盘对 Mac 的电脑兼容更多的模式。 主要区别就是对比 Windows 模式而言,Mac 的模式还多了一个对电源的控制。 可以通过 HHKB 的功能键对电源进行控制,Windows 模式下,没有这个功能。 https://www.isharkfly.com/t/topic/15659
完整的错误信息为: [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.3.1:resources (default-resources) on project core-java-io: filtering C:\WorkDir\Repository\iSharkfly-Docs\java-tutorials\core-java-modules\core-java-io\src\main\resources\dirCompressed.zip to C:\WorkDir\Repository\iSharkfly-Docs\java-tutorials\core-java-modules\core-java-io\target\classes\dirCompressed.zip failed with MalformedInputException: Input length = 1 -> [Help 1] [ERROR] [ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch. [ERROR] Re-run Maven using the -X switch to enable full debug logging. [ERROR] [ERROR] For more information about the errors and possible solutions, please read the following articles: [ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException [ERROR] [ERROR] After correcting the problems, you can resume the build with the command [ERROR] mvn <args> -rf :core-java-io 问题和解决 出现上面错误的原因是在资源文件进行拷贝的时候的校验问题。 我们需要拷贝一个 zip 的资源文件,但是 Maven 在拷贝的时候会进行校验,这会导致拷贝失败。 所以我们可以添加配置: <nonFilteredFileExtensions> <nonFilteredFileExtension>zip</nonFilteredFileExtension> </nonFilteredFileExtensions> 到 插件 maven-resources-plugin 中。 添加后的完整插件配置为: <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-resources-plugin</artifactId> <version>${maven-resources-plugin.version}</version> <configuration> <encoding>UTF-8</encoding> <nonFilteredFileExtensions> <nonFilteredFileExtension>zip</nonFilteredFileExtension> </nonFilteredFileExtensions> </configuration> </plugin> 当完成上面的配置后,资源文件就可以顺利在编译的时候拷贝了。 https://www.isharkfly.com/t/java-maven-dircompressed-zip-failed-with-malformedinputexception/15694