jooq pojo匹配规则

DefaultRecordMapper 关键类

核心部分译文

如果默认构造函数可用并且没有 JPA Column注释,或者 jOOQjavax.persistence在类路径上找不到 API,jOOQ 将Record通过命名约定映射 值:
如果Field.getName()是MY_field(区分大小写!),那么这个字段的值将被设置在所有这些上(不管可见性):

单参数实例方法 MY_field(...)
单参数实例方法 myField(...)
单参数实例方法 setMY_field(...)
单参数实例方法 setMyField(...)
非最终实例成员字段 MY_field
非最终实例成员字段 myField
如果Field.getName()是MY_field.MY_nested_field (区分大小写!),则该字段的值将被视为嵌套值 MY_nested_field,该值设置在传递给所有这些(无论可见性)的嵌套 POJO 上:

单参数实例方法 MY_field(...)
单参数实例方法 myField(...)
单参数实例方法 setMY_field(...)
单参数实例方法 setMyField(...)
非最终实例成员字段 MY_field
非最终实例成员字段 myField

官方链接
https://www.jooq.org/javadoc/3.16.x/org.jooq/org/jooq/Record.html#into(java.lang.Class)

void from​(Object source)
   throws MappingException
Load data into this record from a source.
The mapping algorithm is this:

If source is an array
Loading of data is delegated to fromArray(Object...)

If source is a Map
Loading of data is delegated to fromMap(Map)

If source is an Iterable
Loading of data is equivalent to loading fromArray(Object...), transforming the Iterable to an array, first.

If any JPA Column annotations are found on the Class of the provided source, only those are used. Matching candidates are:
Public no-argument instance methods annotated with Column
Public no-argument instance methods starting with getXXX or isXXX, if there exists a matching public single-argument setXXX() instance method that is annotated with Column
Public instance member fields annotated with Column
Additional matching rules:
Column.name() must match Field.getName(). All other annotation attributes are ignored
Only the first match per field is used
Matching methods have a higher priority than matching member fields
Explicitly matching methods have a higher priority than implicitly matching methods (implicitly matching getter = setter is annotated)
Static methods / member fields are ignored
If there are no JPA Column annotations, or jOOQ can't find the javax.persistence API on the classpath, jOOQ will map members by naming convention:
If Field.getName() is MY_field (case-sensitive!), then this field's value will be fetched from the first of these:

Public no-argument instance method MY_field()
Public no-argument instance method myField()
Public no-argument instance method getMY_field()
Public no-argument instance method getMyField()
Public instance member field MY_field
Public instance member field myField
Other restrictions
primitive types are supported.
General notes
The resulting record will have its internal "changed" flags set to true for all values. This means that UpdatableRecord.store() will perform an INSERT statement. If you wish to store the record using an UPDATE statement, use DSLContext.executeUpdate(UpdatableRecord) instead.

This is the same as calling record.from(source, record.fields())

Parameters:
source - The source object to copy data from
Throws:
MappingException - wrapping any reflection exception that might have occurred while mapping records
See Also:
into(Class), from(Object, Field...)

官方链接
https://www.jooq.org/javadoc/3.16.x/org.jooq/org/jooq/impl/DefaultRecordMapper.html

public class DefaultRecordMapper<R extends Record,​E>
extends Object
implements RecordMapper<R,​E>
This is the default implementation for RecordMapper types, which applies to Record.into(Class), Result.into(Class), and similar calls.
The mapping algorithm is this:

If <E> is an array type:
The resulting array is of the nature described in Record.intoArray(). Arrays more specific than Object[] can be specified as well, e.g. String[]. If conversion to the element type of more specific arrays fails, a MappingException is thrown, wrapping conversion exceptions.

If <E> is a field "value type" and <R extends Record1<?>>, i.e. it has exactly one column:
Any Java type available from SQLDataType qualifies as a well-known "value type" that can be converted from a single-field Record1. The following rules apply:

If <E> is a reference type like String, Integer, Long, Timestamp, etc., then converting from <R> to <E> is mere convenience for calling Record.getValue(int, Class) with fieldIndex = 0
If <E> is a primitive type, the mapping result will be the corresponding wrapper type. null will map to the primitive type's initialisation value, e.g. 0 for int, 0.0 for double, false for boolean.
If <E> is a TableRecord type (e.g. from a generated record), then its meta data are used:
Generated TableRecord types reference their corresponding generated Table types, which provide TableField meta data through Fields.fields(). All target Fields.fields() are looked up in the source table via Fields.indexOf(Field) and their values are mapped. Excess source values and missing target values are ignored.

If a default constructor is available and any JPA Column annotations are found on the provided <E>, only those are used:
If <E> contains single-argument instance methods of any visibility annotated with Column, those methods are invoked
If <E> contains no-argument instance methods of any visibility starting with getXXX or isXXX, annotated with Column, then matching setXXX() instance methods of any visibility are invoked
If <E> contains instance member fields of any visibility annotated with Column, those members are set
Additional rules:
The same annotation can be re-used for several methods/members
Column.name() must match Field.getName(). All other annotation attributes are ignored
Static methods / member fields are ignored
Final member fields are ignored
If a default constructor is available and if there are no JPA Column annotations, or jOOQ can't find the javax.persistence API on the classpath, jOOQ will map Record values by naming convention:
If Field.getName() is MY_field (case-sensitive!), then this field's value will be set on all of these (regardless of visibility):

Single-argument instance method MY_field(...)
Single-argument instance method myField(...)
Single-argument instance method setMY_field(...)
Single-argument instance method setMyField(...)
Non-final instance member field MY_field
Non-final instance member field myField
If Field.getName() is MY_field.MY_nested_field (case-sensitive!), then this field's value will be considered a nested value MY_nested_field, which is set on a nested POJO that is passed to all of these (regardless of visibility):

Single-argument instance method MY_field(...)
Single-argument instance method myField(...)
Single-argument instance method setMY_field(...)
Single-argument instance method setMyField(...)
Non-final instance member field MY_field
Non-final instance member field myField
If no default constructor is available, but at least one constructor annotated with ConstructorProperties is available, that one is used
The standard JavaBeans ConstructorProperties annotation is used to match constructor arguments against POJO members or getters.
If the property names provided to the constructor match the record's columns via the aforementioned naming conventions, that information is used.
If those POJO members or getters have JPA annotations, those will be used according to the aforementioned rules, in order to map Record values onto constructor arguments.
If those POJO members or getters don't have JPA annotations, the aforementioned naming conventions will be used, in order to map Record values onto constructor arguments.
When several annotated constructors are found, the first one is chosen, randomly.
When invoking the annotated constructor, values are converted onto constructor argument types
If Kotlin is available and the argument class has Kotlin reflection meta data available, and Settings.isMapConstructorParameterNamesInKotlin() is turned on, parameter names are reflected and used.
The Kotlin compiler adds meta data available for reflection using Kotlin reflection APIs to derive parameter names.
If no default constructor is available, but at least one "matching" constructor is available, that one is used
A "matching" constructor is one with exactly as many arguments as this record holds fields
When several "matching" constructors are found, the first one is chosen (as reported by Class.getDeclaredConstructors()). This choice is non-deterministic as neither the JVM nor the JDK guarantee any order of methods or constructors.
When Settings.isMapConstructorParameterNames() is turned on, and parameter names are available through reflection on Executable.getParameters(), then values are mapped by name, otherwise by index. (see #4627)
When invoking the "matching" constructor, values are converted onto constructor argument types
If no default constructor is available, no "matching" constructor is available, but Settings.isMapConstructorParameterNames() is turned on, and parameter names are available through reflection on Executable.getParameters(), the first constructor is used
The first constructor is chosen (as reported by Class.getDeclaredConstructors()). This choice is non-deterministic as neither the JVM nor the JDK guarantee any order of methods or constructors.
When invoking that constructor, values are converted onto constructor argument types
If the supplied type is an interface or an abstract class
Abstract types are instantiated using Java reflection Proxy mechanisms. The returned proxy will wrap a HashMap containing properties mapped by getters and setters of the supplied type. Methods (even JPA-annotated ones) other than standard POJO getters and setters are not supported. Details can be seen in Reflect.as(Class).

Other restrictions
<E> must provide a default or a "matching" constructor. Non-public default constructors are made accessible using Constructor.setAccessible(boolean)
primitive types are supported. If a value is null, this will result in setting the primitive type's default value (zero for numbers, or false for booleans). Hence, there is no way of distinguishing null and 0 in that case.
This mapper is returned by the DefaultRecordMapperProvider. You can override this behaviour by specifying your own custom RecordMapperProvider in Configuration.recordMapperProvider()

Author:
Lukas Eder
See Also:
RecordMapper, DefaultRecordMapperProvider, Configuration
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值