在本文中,我们将为Speedment创建一个插件,该插件使用Gson生成序列化和反序列化逻辑,从而使其在数据库实体和JSON字符串之间进行映射非常容易。 这将有助于展示Speedment代码生成的可扩展性,同时探索Gson库的一些很酷的功能。
Speedment是用于Java的代码生成工具,它连接到数据库并用作生成项目的实体和管理器文件的参考。 该工具是非常模块化的,允许您编写自己的插件来修改结果代码的外观。 几个人在Gitter聊天中提到的一件事是,Speedment实体被声明为抽象的,这阻止了它们被自动反序列化。 在本文中,我们将研究如何通过自动为数据库中的每个表生成一个自定义TypeAdapter来使用Gson反序列化Speedment实体。 这不仅可以在使用数据库内容的JSON表示时为我们提供更好的性能,而且还可以作为有关如何扩展代码生成器以解决问题的一般示例。
步骤1:创建插件项目
在上一篇文章中,我详细介绍了如何为Speedment创建新的插件,所以这里是简短的版本。 创建一个新的Maven项目并将Speedment和Gson设置为依赖项。
pom.xml
<name>Speedment Gson Plugin</name>
<description>A plugin for Speedment that generates Gson Type Adapters for every table in the database.
</description><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target><speedment.version>2.3.7</speedment.version>
</properties><dependencies><dependency><groupId>com.speedment</groupId><artifactId>speedment</artifactId><version>${speedment.version}</version></dependency><dependency><artifactId>gson</artifactId><groupId>com.google.code.gson</groupId><version>2.6.2</version></dependency>
</dependencies>
步骤2:为类型适配器创建翻译器类
接下来,我们需要创建将为我们生成新型适配器的转换器。 翻译器是一个类,它描述生成的文件将具有的名称,路径和内容。 为此,它提供了许多便利的方法来简化代码生成。 转换器的基本结构如下所示。
GeneratedTypeAdapterTranslator.java
...
public GeneratedTypeAdapterTranslator(Speedment speedment, Generator gen, Table table) {super(speedment, gen, table, Class::of);
}@Override
protected Class makeCodeGenModel(File file) {return newBuilder(file, getClassOrInterfaceName()).forEveryTable((clazz, table) -> {// Code generation goes here}).build();
}@Override
protected String getClassOrInterfaceName() {return "Generated" + getSupport().typeName() + "TypeAdapter";
}@Override
protected String getJavadocRepresentText() {return "A Gson Type Adapter";
}@Override
public boolean isInGeneratedPackage() {return true;
}
...
每个转换器都是使用可使用newBuilder()方法调用的构建器模式构建的。 稍后在我们要修改现有翻译器时,这一点变得很重要。 实际的代码在构建器的forEveryTable()方法内部生成。 这是一个回调,将针对感兴趣范围中遇到的每个表执行该回调。 在这种情况下,翻译器一次只能在一个表上执行,因此回调将只执行一次。
有关GeneratedTypeAdapterTranslator-class的完整资源,请转到此github页面 。
步骤3:创建用于修改管理器界面的装饰器
但是,仅生成一堆TypeAdapter是不够的。 我们希望将新代码集成到已经存在的管理器中。 为此,我们需要定义一个装饰器,该装饰器将在执行默认逻辑后应用于每个生成的管理器。
GeneratedManagerDecorator.java
public final class GeneratedManagerDecorator
implements TranslatorDecorator<Table, Interface> {@Overridepublic void apply(JavaClassTranslator<Table, Interface> translator) {translator.onMake((file, builder) -> {builder.forEveryTable(Translator.Phase.POST_MAKE, (clazz, table) -> {clazz.add(Method.of("fromJson", translator.getSupport().entityType()).add(Field.of("json", STRING)));});});}
}
装饰器与翻译器类似,不同之处在于它仅定义应对现有文件进行的更改。 每个装饰器都在特定阶段执行。 在本例中,我们要在生成默认代码后执行,因此我们选择POST_MAKE。 我们要添加的逻辑很简单。 在接口中,我们需要fromJson(String)的其他方法。 我们不需要定义toJson,因为每个Speedment管理器都已经从继承的接口获得了toJson。
步骤4:创建用于修改Manager实施的装饰器
管理器实现的修改有些棘手。 我们需要为其添加一个Gson实例作为成员变量,刚刚添加的新接口方法的实现,使用Gson而不是内置序列化器的toJson方法的替代,并且我们需要修改manager构造函数使用我们的新TypeAdapter实例化Gson。
GeneratedManagerImplDecorator.java
public final class GeneratedManagerImplDecorator
implements TranslatorDecorator<Table, Class> {@Overridepublic void apply(JavaClassTranslator<Table, Class> translator) {final String entityName = translator.getSupport().entityName();final String typeAdapterName = "Generated" + entityName + "TypeAdapter";final String absoluteTypeAdapterName =translator.getSupport().basePackageName() + ".generated." + typeAdapterName;Final Type entityType = translator.getSupport().entityType();translator.onMake((file, builder) -> {builder.forEveryTable(Translator.Phase.POST_MAKE, (clazz, table) -> {// Make sure GsonBuilder and the generated type adapter // are imported.file.add(Import.of(Type.of(GsonBuilder.class)));file.add(Import.of(Type.of(absoluteTypeAdapterName)));// Add a Gson instance as a private memberclazz.add(Field.of("gson", Type.of(Gson.class)).private_().final_());// Find the constructor and define gson in itclazz.getConstructors().forEach(constr -> {constr.add("this.gson = new GsonBuilder()",indent(".setDateFormat(\"" + DATE_FORMAT + "\")"),indent(".registerTypeAdapter(" + entityName + ".class, new " + typeAdapterName + "(this))"),indent(".create();"));});// Override the toJson()-methodclazz.add(Method.of("toJson", STRING).public_().add(OVERRIDE).add(Field.of("entity", entityType)).add("return gson.toJson(entity, " + entityName + ".class);"));// Override the fromJson()-methodclazz.add(Method.of("fromJson", entityType).public_().add(OVERRIDE).add(Field.of("json", STRING)).add("return gson.fromJson(json, " + entityName + ".class);"));});});}
}
步骤5:将所有新类安装到平台中
创建所有新类后,我们需要创建一个组件和一个组件安装程序,可以从要使用该插件的任何项目中引用该组件和组件安装程序。
GsonComponent.java
public final class GsonComponent extends AbstractComponent {public GsonComponent(Speedment speedment) {super(speedment);}@Overridepublic void onResolve() {final CodeGenerationComponent code = getSpeedment().getCodeGenerationComponent();code.put(Table.class, GeneratedTypeAdapterTranslator.KEY, GeneratedTypeAdapterTranslator::new);code.add(Table.class, StandardTranslatorKey.GENERATED_MANAGER, new GeneratedManagerDecorator());code.add(Table.class,StandardTranslatorKey.GENERATED_MANAGER_IMPL, new GeneratedManagerImplDecorator());}@Overridepublic Class<GsonComponent> getComponentClass() {return GsonComponent.class;}@Overridepublic Software asSoftware() {return AbstractSoftware.with("Gson Plugin", "1.0", APACHE_2);}@Overridepublic Component defaultCopy(Speedment speedment) {return new GsonComponent(speedment);}
}
GsonComponentInstaller.java
public final class GsonComponentInstaller
implements ComponentConstructor<GsonComponent> {@Overridepublic GsonComponent create(Speedment speedment) {return new GsonComponent(speedment);}
}
用法
当我们想在项目中使用我们的新插件时,我们只需将其添加为pom中的依赖项部分中的依赖项,以及作为speedment maven插件下的依赖项。 然后,我们向插件添加配置标签,如下所示:
<plugin><groupId>com.speedment</groupId><artifactId>speedment-maven-plugin</artifactId><version>${speedment.version}</version><dependencies><dependency><groupId>com.speedment.plugins</groupId><artifactId>gson</artifactId><version>1.0.0</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.39</version></dependency></dependencies><configuration><components><component implementation="com.speedment.plugins.gson.GsonComponentInstaller" /></components></configuration>
</plugin>
然后,我们可以重新生成代码,然后应该可以访问新的序列化和反序列化逻辑。
final String pippi = "{" + "\"id\":1," +"\"bookId\":-8043771945249889258," +"\"borrowedStatus\":\"AVAILABLE\"," + "\"title\":\"Pippi Långström\"," + "\"authors\":\"Astrid Lindgren\"," + "\"published\":\"1945-11-26\"," + "\"summary\":\"A story about the world's strongest little girl.\"" + "}";books.fromJson(pippi).persist();
摘要
在本文中,我们创建了一个新的Speedment插件,该插件为数据库中的每个表生成了Gson TypeAdapters,并将这些适配器与现有的管理器集成在一起。 如果您想要更多有关如何使用Speedment代码生成器来提高生产力的示例, 请查看GitHub页面 !
直到下一次!
翻译自: https://www.javacodegeeks.com/2016/10/insert-read-database-using-json.html