Java :: Geci是在单元测试期间运行的代码生成器。 如果生成的代码适合源代码的实际版本,则测试不会失败。 如果需要进行任何修改,则测试会修改源代码并失败。 例如,有一个新的字段需要一个setter和getter,然后访问器生成器将生成新的setter和getter,然后失败。 如果没有新字段,那么生成的代码就是已经存在的代码,没有理由触摸源代码:启动生成器的测试成功完成。
因为Java :: Geci生成器在运行时作为测试运行,并且因为它们需要访问为其生成代码的Java代码结构,所以Java反射是这些生成器的关键。
为了帮助代码生成器执行任务, javageci-tools
模块中提供了许多支持方法。
com.javax0.geci javageci-tools 1.1.1
在本文中,我将在此模块中编写一个类: Selector
,可以帮助您基于逻辑表达式选择字段,方法或类。
介绍
类javax0.geci.tools.reflection.Selector
有点像正则表达式类Pattern
。 您可以创建一个调用静态方法compile(String expression)
的实例。 在实例上,您可以调用match(Object x)
,其中x
对象可以是Field
, Method
或Class
,也可以是任何这些对象的类型(我们将其称为CFoM)。 如果x
符合已编译的表达式,则match()
方法将返回true
。
选择器表达式
该表达式是一个Java字符串。 可以与任何CFoM匹配的简单至true
。 同样, false
将不匹配任何内容。 到目前为止,微不足道。 表达式可以包含其他条件。 public
, private
volatile
等可以用于匹配具有任何修饰符的CFoM。 如果您在CFoM上使用诸如volatile
的东西而不能是volatile(类或方法),则将得到IllegalArgumentException。
对于课程,您可以具有以下条件:
-
interface
当类是接口 -
primitive
时,它是一个基本类型 -
annotation
时为注释 -
anonymous
-
array
-
enum
-
member
-
local
也许您可能会查找成员类和本地类。 学习一点Java永远不会太晚。 在开发此工具之前,我不知道有可能查询一个类是本地类。
这些条件很简单。 您也可以使用模式匹配。 如果编写extends ~ /regex/
,它将仅匹配扩展名称与正则表达式regex
匹配的类的类。 您还可以将name
, simpleName
和canonicalName
与正则表达式进行匹配。 如果我们的CFoM x
是一个方法或字段,则检查返回类型,除非是name
因为它们也有一个名字。
条件
有许多条件可以使用,这里我只列出一个子集。 包含所有单词的详细文档位于https://github.com/verhas/javageci/blob/master/FILTER_EXPRESSIONS.md
这是一个开胃菜:
protected
, package
, static
, public
, final
, synthetic
,
synchronized
, native
, strict
, default
, vararg
, implements
,
overrides
, void
, transient
, volatile
, abstract
表达结构
检查一件事情不会有太大帮助。 并且还将方法compile()
的参数称为“表达式”表明存在更多内容。
您可以将条件组合成完整的逻辑表达式。 您可以创建一个选择器Selector.compile("final | volatile")
来匹配所有线程安全的字段,这些字段可以是final
或volatile
或两者都是(在Java中是不可能的,但是选择器表达式不会在意)。 您还可以说Selector.compile("public & final & static")
以仅匹配那些public
, final
和static
字段。 或者,您可以Selector.compile("!public & final & static")
来匹配final
和static
字段,这些字段是private
, protected
或package private,也称为“ not public”。 您还可以应用括号,并使用括号来构建相当复杂的逻辑表达式。
采用
该用法可以是任何严重依赖反射的应用程序。 在Java :: Geci中,该表达式可以在任何为该方法或某个类的字段生成某些代码的生成filter
参数中使用。 在这种情况下, filter
可以选择需要代码生成的字段或方法。 例如,在访问器生成filter
的情况下, filter
的默认值为true
:为所有字段生成设置器和获取器。 如果只需要专用字段的设置方法和获取方法,则可以指定filter="private"
。 如果您还想排除最终字段,则可以编写`filter =”!final&private”。 在这种情况下,您将无法获得最终字段的吸气剂。 (默认情况下根本不会为最终字段生成设置程序。生成器很聪明。)
使用流,非常容易编写表达式,例如
Arrays.stream(TestSelector.class.getDeclaredFields()) .filter(Selector.compile( "private & primitive" .filter(Selector.compile( "private & primitive" )::match) .collect(Collectors.toSet());
它将返回私有和原始的字段集。 请注意,在这种情况下,您会有一些选择器编译开销(尽管对于流而言只有一次),并且在某些情况下,性能可能不可接受。
实验一下,看看它是否适合您的需求。
我只是忘了补充:您还可以在运行时调用selector(String,Function)
和/或selectorRe(String,Function)
方法来扩展选择器。
翻译自: https://www.javacodegeeks.com/2019/06/reflection-selector-expression.html