vlambda博客
学习文章列表

JSON 文件映射成 Java 枚举

(给ImportNew加星标,提高Java技能)

编译:ImportNew/唐尤华

medium.com/better-programming/map-a-json-file-to-enum-in-java-d399bac0759d


本文以瑞士奶酪为例介绍了如何从头把 JSON 文件映射成 Java 枚举。


最近为一个回头客新做了一个 Java 项目。第一个任务用 JSON 属性文件实现程序全局配置。


功能完成之后发现这个解决方案用起来很方便,打算写一篇博客分享。由于之前没有写过任何 Java 技术博客,发现这个过程相当挑战而且趣味。


0. 引言


本文涵盖以下内容:


  1. 创建新项目

  2. 读取 JSON 文件和属性

  3. 创建枚举

  4. 把属性映射为泛型枚举


注意: 如果你已经有了一个项目,可以跳过接下来的第一章。同样,如果不使用 Maven 也可以跳过,按照自己的设置添加要使用的开发库。


1. 创建新项目


首先,用 Maven starter 工具新建项目。在终端中运行以下命令:


$ mvn archetype:generate -DgroupId=com.jsontoenum.app -DartifactId=json-to-enum -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.4 -DinteractiveMode=false


如果一切顺利,跳转到下面目录应该能够成功编译:


$ cd json-to-enum/ && mvn package


2. 读取 JSON 文件和属性


起初,我自己实现了一个快速解决方案,但是对结果一点也不满意。这就是为什么试着在网上寻找一个现成的解决方案,结果发现了神奇的 com.typesafe.config 开源三方库。


它提供了读取 JSON 文件和访问属性需要的所有功能,没有依赖而且兼容 Java 8。


至少这一次,用谷歌搜索是一个绝妙的主意。


使用前,需要在到pom.xml 中增加依赖:


<dependency>
<groupId>com.typesafe</groupId>
<artifactId>config</artifactId>
<version>1.3.4</version>
</dependency>


此外,还要把下列 <resources/><plugins/> 信息添加到<build/>中,以便顺利加载(即将创建的) JSON 文件并把刚才 JAR 文件中引用的依赖项打包。


<resources>
<resource>
<directory>src/resources</directory>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>


build 配置完毕,现在可以进入下一步,创建 JSON 属性文件。


默认情况下,configuration 开发库会把名为 application.json的文件作为属性源文件加载。


简单起见,在新文件夹 src/resources/ 中用默认文件名创建配置,包含以下 JSON 内容:

{
"swiss": {
"cheese": "gruyere"
}
}


一切设置妥当,开始编码。


修改程序,在src/main/java/com/jsontoenum/app 文件夹中的App.java 中初始化并从 JSON 文件加载属性,然后输出我们喜爱的 cheese名称。


package com.jsontoenum.app;
import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
public class App {
public static void main(String[] args) {
// 加载并初始化 configuration 开发库
final Config conf = ConfigFactory.load();
// 读取 JSON 属性值
final String cheese = conf.getString("swiss.cheese");
System.out.println(String.format("I like %s 🧀", cheese));
}
}


在终端中执行下列命令,全部编译并运行程序:


$ mvn package && java -cp target/json-to-enum-1.0-SNAPSHOT.jar com.jsontoenum.app.App


如果一切正常,在控制台输出的末尾应显示下列内容:


[INFO] -------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] -------------------------------------------------------------
[INFO] Total time: 2.179 s
[INFO] Finished at: 2019-08-16T15:04:35+02:00
[INFO] -------------------------------------------------------------
I like gruyere


3. 创建枚举


尽管能够读取 JSON 属性已经很酷了,但我很快意识到,由于应用程序的行为各有不同,在开发新功能时必须把属性映射为枚举。


而且,瑞士产的奶酪不止一种。


因此,下一步可以在文件夹 src/main/java/com/jsontoenum/app/ 中创建一个枚举,可以列出产自讲法语国家的奶酪:


package com.jsontoenum.app;
public enum Cheese {
GRUYERE,
TETE_DE_MOINE,
CHAUX_DABEL,
RACLETTE,
VACHERIN,
TOMME
}


4. 把属性映射到泛型枚举


本文使用奶酪只是为了演示。很明显,瑞士还出口许多其他产品,比如巧克力和手表。


同样,正在开发的应用程序不只包含一个枚举。这就是为什么不仅要专门添加一个方法来解析单个枚举类型的属性,还要在 App.java 中声明为泛型。


private static <E extends Enum<E>> E getEnumProperty(final Config conf, final String key, final Class<E> myClass) {
// 如果 config 未加载
if (conf == null) {
return null;
}
// 如果 config 不包含 key
if (!conf.hasPath(key)) {
return null;
}
// 和之前一样,加载 key 值
final String keyValue = conf.getString(key);
// 判断属性值存在
if (keyValue == null || keyValue.isEmpty()) {
return null;
}
// 把属性值映射为枚举
return Enum.valueOf(myClass, keyValue.toUpperCase());
}


最后的测试,可以改进main方法加载枚举,测试结果是否是我们喜欢的奶酪:


public static void main(String[] args) {
// 加载并初始化 configuration 开发库
final Config conf = ConfigFactory.load();
// 获取 JSON 属性值
final Cheese cheese =
getEnumProperty(conf, "swiss.cheese", Cheese.class);
if (Cheese.GRUYERE.equals(cheese)) {
System.out.println(String.format("I really like %s 🧀", cheese));
} else {
System.out.println(String.format("%s is ok", cheese));
}
}


以上是所有内容。


用之前的命令行运行,如果一切按计划进行,输出结果如下:


[INFO] -------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] -------------------------------------------------------------
[INFO] Total time: 2.437 s
[INFO] Finished at: 2019-08-16T15:43:42+02:00
[INFO] -------------------------------------------------------------
I really like GRUYERE


5. 精华


如果想要省去新建项目和复制代码的麻烦,我已经在网上发布了这个项目,请随意。


$ git clone https://github.com/peterpeterparker/json-to-enum.git


我要飞得更高~🚀


David


推荐阅读

(点击标题可跳转阅读)





看完本文有收获?请转发分享给更多人

关注「ImportNew」,提升Java技能

好文章,我在看❤️