博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java类生成json数据_如何用Java生成数据类
阅读量:2524 次
发布时间:2019-05-11

本文共 11397 字,大约阅读时间需要 37 分钟。

java类生成json数据

Kotlin has a concise syntax to declare data classes:

Kotlin具有简洁的语法来声明数据类:

data class User(val name: String, val age: Int)

The equivalent Java syntax is verbose. You have to create a Java class with private fields. And getter and setter methods for the fields. And additional methods like equals(), hashCode() and toString().

等效的Java语法很冗长。 您必须使用私有字段创建一个Java类。 以及字段的gettersetter方法。 以及其他方法,例如equals()hashCode()toString()

But who says you have to create the Java code by hand?

但是谁说您必须手动创建Java代码?

In this article, I’ll show you how to generate Java source files from a file.

在本文中,我将向您展示如何从文件生成Java源文件。

Here’s the example YAML file:

这是示例YAML文件:

User:    name: Name    age: IntegerName:    firstName: String    lastName: String

The example output of the code generator is two Java source files, User.java and Name.java.

代码生成器的示例输出是两个Java源文件, User.javaName.java

public class User{    private Name name;    private Integer age;        public User(){    }    public Name getName(){        return name;    }    public void setName(Name name){        this.name = name;    }    public Integer getAge(){        return age;    }    public void setAge(Integer age){        this.age = age;    }}

Name.java is similar.

Name.java与此类似。

The point of this article is: You’ll learn how to program a code generator from scratch. And it’s easy to adapt it to your needs.

本文的重点是:您将学习如何从头开始编写代码生成器。 而且很容易适应您的需求。

主要方法 (The main method)

The method does two things:

方法有两件事:

  • Step 1: Read in the YAML file, into class specifications

    步骤1:将YAML文件读入类规范
  • Step 2: Generate Java source files from the class specifications

    步骤2:根据类规范生成Java源文件

It decouples reading and generating. You can change the input format in the future, or support more input formats.

它使读取和生成分离。 您将来可以更改输入格式,或支持更多输入格式。

Here’s the main() method:

这是main()方法:

public static void main(String[] args) throws Exception {    // Make sure there is exactly one command line argument,     // the path to the YAML file    if (args.length != 1) {        System.out.println("Please supply exactly one argument, the path to the YAML file.");        return;    }      // Get the YAML file's handle & the directory it's contained in    // (generated files will be placed there)    final String yamlFilePath = args[0];    final File yamlFile = new File(yamlFilePath);    final File outputDirectory = yamlFile.getParentFile();      // Step 1: Read in the YAML file, into class specifications    YamlClassSpecificationReader yamlReader = new YamlClassSpecificationReader();    List
classSpecifications = yamlReader.read(yamlFile); // Step 2: Generate Java source files from class specifications JavaDataClassGenerator javaDataClassGenerator = new JavaDataClassGenerator(); javaDataClassGenerator.generateJavaSourceFiles(classSpecifications, outputDirectory); System.out.println("Successfully generated files to: " + outputDirectory.getAbsolutePath());}

步骤1:将YAML文件读入类规范 (Step 1: Read the YAML file into class specifications)

Let me explain what happens in this line:

让我解释一下这一行会发生什么:

List
classSpecifications = yamlReader.read(yamlFile);

A class specification is a definition of a class to be generated and its fields.Remember the User in the example YAML file?

类规范是要生成的类及其字段的定义。在示例YAML文件中还记得User吗?

User:    name: Name    age: Integer

When the reads that, it will create one ClassSpecification object, with the name User. And that class specification will reference two FieldSpecification objects, called name and age.

当读取该内容时,它将创建一个名为User ClassSpecification对象。 并且该类规范将引用两个FieldSpecification对象,即nameage

The code for the ClassSpecification class and the FieldSpecification class is simple.

ClassSpecification类和FieldSpecification类的代码很简单。

The content of is shown below:

的内容如下所示:

public class ClassSpecification {    private String name;    private List
fieldSpecifications; public ClassSpecification(String className, List
fieldSpecifications) { this.name = className; this.fieldSpecifications = fieldSpecifications; } public String getName() { return name; } public List
getFieldSpecifications() { return Collections.unmodifiableList(fieldSpecifications); }}

The content of is:

的内容是:

public class FieldSpecification {    private String name;    private String type;      public FieldSpecification(String fieldName, String fieldType) {        this.name = fieldName;        this.type = fieldType;    }      public String getName() {        return name;    }      public String getType() {        return type;    }}

The only remaining question for Step 1 is: how do you get from a YAML file to objects of these classes?

步骤1剩下的唯一问题是:如何从YAML文件获取这些类的对象?

The uses the library to parse YAML files. SnakeYAML makes a YAML file’s content available in data structures like maps and lists.

使用库来解析YAML文件。 SnakeYAML使YAML文件的内容在地图和列表等数据结构中可用。

For this article, you only need to understand maps — because that’s what we use in the YAML files.

对于本文,您只需要了解地图-因为这就是我们在YAML文件中使用的内容。

Look at the example again:

再看一个例子:

User:    name: Name    age: IntegerName:    firstName: String    lastName: String

What you see here is two nested maps.

您在这里看到的是两个嵌套地图。

The key of the outer map is the class name (like User).

外部映射的键是类名(如User )。

When you get the value for the User key, you get a map of the class fields:

当您获得User键的值时,您将获得一个类字段的映射:

name: Nameage: Integer

The key of this inner map is the field name, and the value is the field type.

此内部映射的关键字是字段名称,而值是字段类型。

It’s a map of strings to a map of strings to strings. That’s important to understand the code of the .

这是字符串映射到字符串映射到字符串。 这对于理解的代码很重要。

Here’s the method that reads in the complete YAML file contents:

这是读取完整YAML文件内容的方法:

private Map
> readYamlClassSpecifications(Reader reader) { Yaml yaml = new Yaml(); // Read in the complete YAML file to a map of strings to a map of strings to strings Map
> yamlClassSpecifications = (Map
>) yaml.load(reader); return yamlClassSpecifications;}

With the yamlClassSpecifications as input, the creates the ClassSpecification objects:

使用yamlClassSpecifications作为输入, 创建ClassSpecification对象:

private List
createClassSpecificationsFrom(Map
> yamlClassSpecifications) { final Map
> classNameToFieldSpecificationsMap = createClassNameToFieldSpecificationsMap(yamlClassSpecifications); List
classSpecifications = classNameToFieldSpecificationsMap.entrySet().stream() .map(e -> new ClassSpecification(e.getKey(), e.getValue())) .collect(toList()); return classSpecifications;}

The createClassNameToFieldSpecificationsMap() method creates

createClassNameToFieldSpecificationsMap()方法创建

  • the field specifications for each class, and based on these

    每个类别的字段规范,并基于这些
  • a map of each class name to its field specifications.

    每个类名称与其字段规范的映射。

Then the creates a ClassSpecification object for each entry in that map.

然后, 为该映射中的每个条目创建一个ClassSpecification对象。

The contents of the YAML file are now available to Step 2 in a YAML independent way. We’re done with Step 1.

现在,可以以独立于YAML的方式将YAML文件的内容用于步骤2。 我们完成了步骤1。

步骤2:根据类规范生成Java源文件 (Step 2: Generate Java source files from the class specifications)

is a Java template engine that produces textual output. Templates are written in the FreeMarker Template Language (FTL). It allows static text to mix with the content of Java objects.

是一个Java模板引擎,可产生文本输出。 模板以FreeMarker模板语言(FTL)编写。 它允许静态文本与Java对象的内容混合。

Here’s the template to generate the Java source files, :

这是生成Java源文件的模板:

public class ${classSpecification.name}{<#list classSpecification.fieldSpecifications as field>    private ${field.type} ${field.name};
public ${classSpecification.name}(){ }<#list classSpecification.fieldSpecifications as field> public ${field.type} get${field.name?cap_first}(){ return ${field.name}; } public void set${field.name?cap_first}(${field.type} ${field.name}){ this.${field.name} = ${field.name}; }
}

Let’s look at the first line:

让我们看第一行:

public class ${classSpecification.name}{

You can see it begins with the static text of a class declaration: public class. The interesting bit is in the middle: ${classSpecification.name}.

您可以看到它以类声明的静态文本开头: public class 。 有趣的地方在中间: ${classSpecification.name}

When Freemarker processes the template, it accesses the classSpecification object in its model. It calls the getName() method on it.

当Freemarker处理模板时,它将访问其模型中的classSpecification对象。 它对其调用getName()方法。

What about this part of the template?

模板的这部分呢?

<#list classSpecification.fieldSpecifications as field>    private ${field.type} ${field.name};

At first, Freemarker calls classSpecification.getFieldSpecifications(). It then iterates over the field specifications.

首先,Freemarker调用classSpecification.getFieldSpecifications() 。 然后,它遍历字段规范。

One last thing. That line is a bit odd:

最后一件事。 那条线有点奇怪:

public ${field.type} get${field.name?cap_first}(){

Let’s say the example field is age: Integer (in YAML). Freemarker translates this to:

假设示例字段是age: Integer (在YAML中)。 Freemarker将此翻译为:

public Integer getAge(){

So ?cap_first means: capitalize the first letter, as the YAML file contains age in lower case letters.

所以?cap_first意思是:大写第一个字母,因为YAML文件包含使用小写字母的age

Enough about templates. How do you generate the Java source files?

足够的模板。 您如何生成Java源文件?

First, you need to configure FreeMarker by creating a Configuration instance. This happens in the constructor of the :

首先,您需要通过创建Configuration实例来配置FreeMarker。 这发生在的构造函数中:

To generate source files, the iterates over the class specifications, and generates a source file for each:

为了生成源文件, 遍历类规范,并为每个规范生成源文件:

And that’s it.

就是这样。

结论 (Conclusion)

I showed you how to build a Java source code generator based on YAML files. I picked YAML because it is easy to process, and thus easy to teach. You can replace it with another format if you like.

我向您展示了如何基于YAML文件构建Java源代码生成器。 我之所以选择YAML,是因为它易于处理,因此易于教授。 如果愿意,可以将其替换为其他格式。

You can find the complete code on .

您可以在上找到完整的代码。

To make the code as understandable as possible, I took a few shortcuts:

为了使代码尽可能容易理解,我采取了一些捷径:

  • no methods like equals(), hashCode() and toString()

    没有像equals()hashCode()toString()

  • no inheritance of data classes

    没有数据类的继承
  • generated Java classes are in the default package

    生成的Java类在默认包中
  • the output directory is the same as the input directory

    输出目录与输入目录相同
  • error handling hasn’t been my focus

    错误处理不是我关注的重点

A production-ready solution would need to deal with those issues. Also, for data classes, is an alternative without code generation.

生产就绪的解决方案将需要处理这些问题。 此外,对于数据类, 是不生成代码的替代方案。

So think of this article as a beginning, not an end. Imagine what is possible. A few examples:

因此,请将本文视为起点,而不是终点。 想象一下有什么可能。 一些例子:

  • scaffold JPA entity classes or Spring repositories

    脚手架JPA实体类或Spring存储库
  • generate several classes from one specification, based on patterns in your application

    根据您的应用程序中的模式,从一个规范生成多个类
  • generate code in different programming languages

    生成不同编程语言的代码
  • produce documentation

    产生文件

I currently use this approach to translate natural language requirements directly to code, for research purposes. What will you do?

我目前使用这种方法将自然语言要求直接转换为代码,以用于研究目的。 你会怎么做?

If you want to know what I’m hacking on, visit .

如果您想知道我正在黑客攻击的内容,请访问 。

You can contact me on or .

您可以通过或与我联系。

The original version of this article was posted on

本文的原始版本发布在

翻译自:

java类生成json数据

转载地址:http://gywzd.baihongyu.com/

你可能感兴趣的文章
(最小点覆盖) poj 2226
查看>>
(树形DP) poj 3659
查看>>
获取类的属性名和值
查看>>
python对json的操作总结
查看>>
学习进度表第十一周
查看>>
js屏蔽回车键
查看>>
Memcached通用类(基于enyim.com Memcached Client)
查看>>
c#组元(Tuple)的使用
查看>>
【NO.66】转 Yahoo的军规条例
查看>>
vim基础学习之搜索功能
查看>>
session和cookie
查看>>
tftp 开发板ping不通PC机
查看>>
未在本地计算机上注册“Microsoft.Jet.OLEDB.4.0”
查看>>
Erdos
查看>>
docker初学
查看>>
面向对象的程序第三次实验作业
查看>>
Windows 安装启动apache时出现错误的解决方法
查看>>
Object.prototype.toString()
查看>>
int.Parse()与int.TryParse()
查看>>
c#调用钩子
查看>>