java类生成json数据_如何用Java生成数据类

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 YAML file.

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

Here’s the example YAML file:

这是示例YAML文件:

User:
    name: Name
    age: Integer

Name:
    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 main() method does two things:

main()方法有两件事:

  • 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<ClassSpecification> 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<ClassSpecification> 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 YAML reader 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.

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

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

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

The content of ClassSpecification.java is shown below:

ClassSpecification.java的内容如下所示:

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

The content of FieldSpecification.java is:

FieldSpecification.java的内容是:

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 YAML reader uses the SnakeYAML library to parse YAML files. SnakeYAML makes a YAML file’s content available in data structures like maps and lists.

YAML阅读器使用SnakeYAML库来解析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: Integer

Name:
    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: Name
age: 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 YAML reader.

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

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

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

private Map<String, Map<String, String>> 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<String, Map<String, String>> yamlClassSpecifications = 
		(Map<String, Map<String, String>>) yaml.load(reader);

	return yamlClassSpecifications;
}

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

使用yamlClassSpecifications作为输入, YAML阅读器创建ClassSpecification对象:

private List<ClassSpecification> createClassSpecificationsFrom(Map<String, Map<String, String>> yamlClassSpecifications) {
	final Map<String, List<FieldSpecification>> classNameToFieldSpecificationsMap 
		= createClassNameToFieldSpecificationsMap(yamlClassSpecifications);

	List<ClassSpecification> 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 YAML reader creates a ClassSpecification object for each entry in that map.

然后, YAML阅读器为该映射中的每个条目创建一个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)

Apache FreeMarker 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.

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

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

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

public class ${classSpecification.name}{
<#list classSpecification.fieldSpecifications as field>
    private ${field.type} ${field.name};
</#list>
    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};
    }
</#list>    
}

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};
</#list>

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 JavaDataClassGenerator:

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

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

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

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 Github.

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

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, Project Lombok is an alternative without code generation.

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

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 my GitHub project.

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

You can contact me on Twitter or LinkedIn.

您可以通过TwitterLinkedIn与我联系。

The original version of this article was posted on dev.to

本文的原始版本发布在dev.to上

翻译自: https://www.freecodecamp.org/news/how-to-generate-data-classes-in-java-fead8fa354a2/

java类生成json数据

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值