JSR-308和Checker框架为jOOQ 3.9添加了更多类型安全性

Java 8引入了JSR-308,它为Java语言添加了新的注释功能。 最重要的是:键入注释。 现在可以像下面这样设计怪物了:

该推文中显示的代码确实可以编译。 现在可以注释每种类型,以便以任何自定义方式增强类型系统。 为什么,你可能会问? 这种语言增强的主要驱动用例之一是checker框架 ,这是一个开放源代码库,可让您轻松实现任意编译器插件以进行复杂的类型检查。 最无聊和琐碎的例子是可空性。 考虑以下代码:

import org.checkerframework.checker.nullness.qual.Nullable;class YourClassNameHere {void foo(Object nn, @Nullable Object nbl) {nn.toString(); // OKnbl.toString(); // Failif (nbl != null)nbl.toString(); // OK again}
}

上面的示例可以直接在checker框架实时演示控制台中运行 。 使用以下注释处理器编译以上代码:

javac -processor org.checkerframework.checker.nullness.NullnessChecker afile.java

产量:

错误:[dereference.of.nullable]取消引用可能为空的引用nbl:5:9

太棒了! 例如,它的工作方式与在Ceylon或Kotlin中 实现的流敏感类型非常相似,不同之处在于它更为冗长。 但是它也要强大得多,因为可以使用注释处理器直接在Java中实现实现增强的和带注释的Java类型系统的规则! 通过某种方式使注解图灵完整。��

这对jOOQ有什么帮助?

jOOQ已经提供了两种类型的API文档注释。 这些注释是:

  • @PlainSQL –表示DSL方法接受“纯SQL”字符串,这可能会带来SQL注入风险
  • @Support –表示DSL方法可以本机工作,或者可以针对给定的SQLDialect集进行仿真

这种方法的一个示例是CONNECT BY子句 ,该子句得到Cubrid,Informix和Oracle的支持,为了方便起见,它也被重载为也接受“普通SQL”谓词:

@Support({ CUBRID, INFORMIX, ORACLE })
@PlainSQL
SelectConnectByConditionStep<R> connectBy(String sql);

到目前为止,这些注释仅用于文档目的。 使用jOOQ 3.9后,不再可用。 现在,我们向jOOQ API引入了两个新的注释:

  • org.jooq.Allow –允许在给定范围内使用一组方言(或@PlainSQL批注)
  • org.jooq.Require –在给定范围内要求通过@Support注释支持一组方言

最好通过示例来解释。 让我们先看看@PlainSQL

限制对

使用jOOQ API的最大优点之一就是SQL注入已经成为过去。 由于jOOQ是内部特定于域的语言,因此用户确实可以直接在Java代码中直接定义SQL表达式树,而不是像JDBC那样使用声明的字符串化版本。 表达式树是用Java编译的,因此不可能通过用户输入注入任何不需要的或无法预见的表达式。

但是有一个例外。 jOOQ并不支持每个数据库中的所有SQL功能。 这就是jOOQ附带丰富的“普通SQL” API的原因,在该API中,可以将自定义SQL字符串嵌入SQL表达式树中的任何位置。 例如,上面的CONNECT BY子句:

DSL.using(configuration).select(level()).connectBy("level < ?", bindValue).fetch();

上面的jOOQ查询转换为以下SQL查询:

SELECT level
FROM dual
CONNECT BY level < ?

如您所见,完全有可能“做错”并产生SQL注入风险,就像在JDBC中一样:

DSL.using(configuration).select(level()).connectBy("level < " + bindValue).fetch();

区别非常细微。 使用jOOQ 3.9和checker框架,现在可以指定以下Maven编译器配置:

<plugin><artifactId>maven-compiler-plugin</artifactId><version>3.3</version><configuration><source>1.8</source><target>1.8</target><fork>true</fork><annotationProcessors><annotationProcessor>org.jooq.checker.PlainSQLChecker</annotationProcessor></annotationProcessors><compilerArgs><arg>-Xbootclasspath/p:1.8</arg></compilerArgs></configuration>
</plugin>

org.jooq.checker.PlainSQLChecker将确保不会编译使用带有@PlainSQL注释的API的客户端代码。 我们收到的错误消息是这样的:

C:\ Users \ lukas \ workspace \ jOOQ \ jOOQ-examples \ jOOQ-checker-framework-example \ src \ main \ java \ org \ jooq \ example \ checker \ PlainSQLCheckerTests.java:[17,17]错误:[普通]当前范围不允许使用SQL。 使用@ Allow.PlainSQL。]

如果您知道自己在做什么,并且绝对必须在非常特定的位置(范围)使用jOOQ的@PlainSQL API,则可以使用@Allow.PlainSQL对该位置(范围)进行注释,并且代码可以再次正常编译:

// Scope: Single method.
@Allow.PlainSQL
public List<Integer> iKnowWhatImDoing() {return DSL.using(configuration).select(level()).connectBy("level < ?", bindValue).fetch(0, int.class);
}

甚至:

// Scope: Entire class.
@Allow.PlainSQL
public class IKnowWhatImDoing {public List<Integer> iKnowWhatImDoing() {return DSL.using(configuration).select(level()).connectBy("level < ?", bindValue).fetch(0, int.class);}
}

甚至(但是您可能只是关闭检查器):

// Scope: entire package (put in package-info.java)
@Allow.PlainSQL
package org.jooq.example.checker;

好处是显而易见的。 如果安全性对您非常重要(应该如此),则只需在每个开发人员版本或至少在CI版本中启用org.jooq.checker.PlainSQLChecker ,并在“偶然”使用@PlainSQL API时获得编译错误遇到。

限制对

现在,对于大多数用户而言,更有趣的是能够检查客户端代码中使用的jOOQ API是否确实支持您的数据库。 例如,上面的CONNECT BY子句仅在Oracle中受支持(如果我们忽略不太流行的Cubrid和Informix数据库)。 假设您仅使用Oracle。 您要确保您使用的所有jOOQ API都与Oracle兼容。 现在,您可以将以下注释添加到所有使用jOOQ API的软件包中:

// Scope: entire package (put in package-info.java)
@Allow(ORACLE)
package org.jooq.example.checker;

现在,只需激活org.jooq.checker.SQLDialectChecker来键入代码以检查@Allow符合性,即可完成:

<plugin><artifactId>maven-compiler-plugin</artifactId><version>3.3</version><configuration><source>1.8</source><target>1.8</target><fork>true</fork><annotationProcessors><annotationProcessor>org.jooq.checker.SQLDialectChecker</annotationProcessor></annotationProcessors><compilerArgs><arg>-Xbootclasspath/p:1.8</arg></compilerArgs></configuration>
</plugin>

从现在开始,每当您使用任何jOOQ API时,上述检查器都将验证以下三个值是否为true:

  • 正在使用的jOOQ API未使用@Support注释
  • 使用的jOOQ API带有@Support注释,但没有任何显式的SQLDialect (即“可在所有数据库上工作”),例如DSLContext.select()
  • 使用的jOOQ API带有@Support注释,并带有SQLDialects引用的至少一个@Allow

因此,在这样标注的包装中……

// Scope: entire package (put in package-info.java)
@Allow(ORACLE)
package org.jooq.example.checker;

……使用这样注释的方法就可以了:

@Support({ CUBRID, INFORMIX, ORACLE })
@PlainSQL
SelectConnectByConditionStep<R> connectBy(String sql);

…但是使用这样注释的方法不是:

@Support({ MARIADB, MYSQL, POSTGRES })
SelectOptionStep<R> forShare();

为了允许使用此方法,例如,客户端代码除了可以使用ORACLE语言外,还可以使用MYSQL语言:

// Scope: entire package (put in package-info.java)
@Allow({ MYSQL, ORACLE })
package org.jooq.example.checker;

从现在开始,此程序包中的所有代码都可能引用支持MySQL和/或Oracle的方法。

@Allow批注有助于在全局级别上访问API。 多个@Allow注释(范围可能不同)创建了允许的方言的@Allow取关系,如下所示:

// Scope: class
@Allow(MYSQL)
class MySQLAllowed {@Allow(ORACLE)void mySQLAndOracleAllowed() {DSL.using(configuration).select()// Works, because Oracle is allowed.connectBy("...")// Works, because MySQL is allowed.forShare();}
}

从上面可以看出,析取两个方言不能确保给定的语句在两个数据库中都可以使用。 所以…

如果我希望同时支持两个数据库怎么办?

在这种情况下,我们将使用新的@Require注释。 多个@Require注释(范围可能不同)创建所需方言的合集,如下所示:

// Scope: class
@Allow
@Require({ MYSQL, ORACLE })
class MySQLAndOracleRequired {@Require(ORACLE)void onlyOracleRequired() {DSL.using(configuration).select()// Works, because only Oracle is required.connectBy("...")// Doesn't work because Oracle is required.forShare();}
}

如何使用

假设您的应用程序仅需要与Oracle一起使用。 现在,您可以在软件包上添加以下注释,例如,由于在您的代码中不允许将MySQL作为方言,因此您将无法使用任何仅MySQL的API:

@Allow(ORACLE)
package org.jooq.example.checker;

现在,随着需求的变化,您还希望从应用程序中也开始支持MySQL。 只需将软件包规格更改为以下内容,然后开始修复jOOQ使用中的所有编译错误。

// Both dialects are allowed, no others are
@Allow({ MYSQL, ORACLE })// Both dialects are also required on each clause
@Require({ MYSQL, ORACLE })
package org.jooq.example.checker;

默认值

默认情况下,对于任何范围, org.jooq.checker.SQLDialectChecker都采用以下注释:

  • 什么都不允许。 每个@Allow批注都会添加到允许的方言集中。
  • 一切都是必需的。 每个@Require批注将从必填方言集中删除。

实际观看

这些功能将是jOOQ 3.9的组成部分。 只需添加以下依赖项即可使用它们:

<dependency><!-- Use org.jooq            for the Open Source editionorg.jooq.pro        for commercial editions, org.jooq.pro-java-6 for commercial editions with Java 6 support,org.jooq.trial      for the free trial edition --><groupId>org.jooq</groupId><artifactId>jooq-checker</artifactId><version>${org.jooq.version}</version>
</dependency>

…,然后为您的编译器插件选择适当的注释处理器。

不能等到jOOQ 3.9吗? 不用了 只需从GitHub上检查3.9.0-SNAPSHOT版本,然后按照此处给出的示例项目进行操作:

  • https://github.com/jOOQ/jOOQ/tree/master/jOOQ-examples/jOOQ-checker-framework-example

做完了! 从现在开始,使用jOOQ时,您可以确保编写的任何代码都可以在计划支持的所有数据库上运行!

我认为,今年的Annotatiomaniac冠军头衔应该交给检查框架的制定者:

有关检查器框架的更多信息:

  • http://types.cs.washington.edu/checker-framework/
  • http://eisop.uwaterloo.ca/live#mode=display(实时演示)

翻译自: https://www.javacodegeeks.com/2016/05/jsr-308-checker-framework-add-even-typesafety-jooq-3-9.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/353146.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux NTP服务配置 for Oracle RAC

安装Oracle 11g RAC时&#xff0c;我们需要配置ntp服务。在使用虚拟机的情况下对于时钟同步方式的配置有很多种方式&#xff0c;可以使用vmware自带的时钟同步功能&#xff0c;也可以直接将本地的一个节点用作时间服务器。本文介绍直接配置ntp方式的时钟服务器。1、查看两节点的…

java字符编码方式总结

java字符编码方式总结一、概要在JAVA应用程序特别是基于WEB的程序中&#xff0c;经常遇到字符的编码问题。为了防止出现乱码&#xff0c;首先需要了解JAVA是如何处理字符的&#xff0c;这样就可以有目的地在输入/输出环节中增加必要的转码。其次&#xff0c;由于各种服务器有不…

按键扫描

unsigned char Trg,cont,num;void key_sm(void) { uchar Read;ReadP0^0xff;TrgRead&(Read^cont);contRead; } void key_hs(){  switch(Trg)   {     case 0x01:       num;     break;     case 0x02:       num--;     break;     d…

Mathematica函数大全

一、运算符及特殊符号 Line1; 执行Line&#xff0c;不显示结果 Line1,line2 顺次执行Line1&#xff0c;2&#xff0c;并显示结果 ?name 关于系统变量name 的信息 ??name 关于系统变量name 的全部信息 !command 执行Dos 命令 n! N 的阶乘 !!filename 显示文件内容 <<fi…

oem是代工还是贴牌_食用油OEM贴牌代工业务要注意哪些问题?

近年来食用油OEM业务逐渐增加&#xff0c;OEM是英文 Original Equipment Manufacturer的缩写&#xff0c;被译为代工生产或贴牌生产&#xff0c;通常是指品牌商委托有生产能力且品质有保证的油脂加工厂来生产食用油产品&#xff0c;对自己及对方的品牌不会有冲突&#xff0c;且…

java 简化判断_简化Java内存分析

java 简化判断作为一名典型的Java开发人员&#xff0c;除了遵循关闭连接&#xff0c;流等典型的最佳实践外&#xff0c;我从未监视过应用程序的内存使用情况。最近&#xff0c;我们在JBoss服务器中遇到了一些问题&#xff0c;不得不深入研究内存管理Java中最好的事情之一是&…

DRF的序列化组件

rest rest下的url url唯一代表资源&#xff0c;http请求方式来区分用户行为 url的设计规范 GET&#xff1a; 127.0.0.1:9001/books/       # 获取所有数据 GET: 127.0.0.1:9001/books/{id}      # 获取单条数据 POST&#xff1a; 127.0.0.1:9001/books/      # 增…

15crmo焊接后多长时间探伤_承压设备渗透探伤检测方法简单操作思路

啥是渗透检测渗透检测俗称渗透探伤&#xff0c;是一种以毛细管作用原理为基础用于检查表面开口缺陷的无损检测方法。它与射线检测、超声检测、磁粉检测和涡流检测一起&#xff0c;并称为5种常规的无损检测方法&#xff0c;渗透检测始于本世纪初&#xff0c;是目视检查以外最早应…

SpringBoot实战(五)之Thymeleaf

Thymeleaf同jsp、volocity、freemarker等共同的职能是MVC模式中的视图展示层&#xff0c;即View。 当然了&#xff0c;SpringBoot中也可以用jsp,不过不推荐这种用法&#xff0c;比较推崇的就是使用Thymeleaf。 关于Thymeleaf学习&#xff0c;建议参考官方文档:https://www.thym…

Arrays.sort()

今天在做一个按更新时间搜寻出某个文件夹里面的所有文件&#xff0c;由于自己写算法比较花费时间&#xff0c;干脆就用j2se提供的类Arrays提供的sort&#xff08;&#xff09;方法&#xff0c;这样就比较省力。对于基本数据类型只要Arrays.sort(数组)[“注&#xff1a;数组是声…

Thymeleaf 3 – Thymeleaf 3和Spring MVC快速入门

Thymeleaf 3发布到达。 新版本带来了许多新功能&#xff0c;例如HTML5支持以及不带标记的文本模板支持– [# th:utext"${thymeleaf.version}" /] &#xff0c;改进的内联功能– <p>Thymeleaf [[${thymeleaf.version}]] is great!</p> &#xff0c;性能改…

rmi远程代码执行漏洞_【最新漏洞简讯】WebLogic远程代码执行漏洞 (CVE202014645)

↑ 点击上方“SecMind安全管家”关注我们 情报编号&#xff1a;W1120200715漏洞概述WebLogic是Oracle公司出品的用于开发、集成、部署和管理大型分布式Web应用、网络应用和数据库应用的Java应用服务器&#xff0c;全球使用广泛。WebLogic的远程方法调用RMI通信使用T3协议&#…

python 的内存回收,及深浅Copy详解

一、python中的变量及引用1.1 python中的不可变类型&#xff1a;数字(num)、字符串(str)、元组(tuple)、布尔值(bool<True,False>) 接下来我们讲完后你就懂了为什么它们是不可变对象了。 都知道python中一切都是对象&#xff0c;而变量就是这些对象的引用&#xff0c;什么…

不是技术牛人,如何拿到国内IT巨头的Offer

不久前&#xff0c;byvoid面阿里星计划的面试结果截图泄漏&#xff0c;引起无数IT屌丝的羡慕敬仰。看看这些牛人&#xff0c;NOI金牌&#xff0c;开源社区名人&#xff0c;三年级开始写Basic...在跪拜之余我们不禁要想&#xff0c;和这些牛人比&#xff0c;作为绝大部分技术屌丝…

layui列表筛选列_Shopify搜索产品并筛选产品列表功能介绍

搜索产品并筛选产品列表 您的所有产品都列在 Shopify 的产品区域中。每个页面列出 50 种产品。要整理产品列表&#xff0c;并在跨多个页面的列表中查找产品&#xff0c;您可以对列表进行排序、搜索和筛选。默认情况下&#xff0c;产品列表按产品名称的字母顺序(从 A 到 Z)进行排…

远程调用 quartz_如何远程管理Quartz

远程调用 quartz选项1&#xff1a;JMX 许多人问他们是否可以通过JMX管理Quartz&#xff0c;但我不确定为什么Quartz doc甚至不会提及它。 是的&#xff0c;您可以使用quartz.properties的以下命令启用石英中的JMX org.quartz.scheduler.jmx.export true之后&#xff0c;您可以…

DOM解析器

1.DOM标准 DOM&#xff08;Document Object Model&#xff0c;文档对象模型&#xff09;是W3C制定的一套规范标准&#xff0c;即规定了解析文件的接口。各种语言可以按照DOM规范去实现这些接口&#xff0c;给出解析文件的解析器。 各种基于DOM规范解析器必须按照DOM规范在内…

批量打印pdf并合并_批量打印CAD图(无删减版)

前面两期小编出的PDF教程想必用了的人都觉得还不错吧&#xff1f;(此处应有掌声)上一期提到的CAD批量打印今天放出来了&#xff0c;擦亮眼睛往下看很多时候大批量的一堆图纸要输出&#xff0c;比如下面这个当然这批图纸并不多&#xff0c;也只是局部的&#xff0c;通常一个项目…

expect详解及自动登录脚本的实现

expect可以让一些交互的任务自动完成&#xff0c;我们可以将一些交互过程写入脚本&#xff0c;ssh登录就是一个简单的实现&#xff0c;下面将介绍expect的用法。 1 安装 yum install -y expect 2 语法介绍 expect - send 这两个指令会配合使用&#xff0c;当expect接收到一个和…

极端懒惰:使用Spring Boot开发JAX-RS服务

我认为可以公平地说&#xff0c;作为软件开发人员&#xff0c;我们一直在寻找编写较少代码的方法&#xff0c;这些方法可以自动完成或不能自动完成更多工作。 考虑到这一点&#xff0c;作为Spring产品组合的骄傲成员的Spring Boot项目破坏了传统方法&#xff0c;极大地加快了并…