@@ -1232,34 +1232,46 @@ equivalent to `ROW<myField INT, myOtherField BOOLEAN>`.
1232
1232
1233
1233
### User-Defined Data Types
1234
1234
1235
- {{< tabs "udf" >}}
1236
- {{< tab "Java/Scala" >}}
1237
- <span class =" label label-danger " >Attention</span > User-defined data types are not fully supported yet. They are
1238
- currently (as of Flink 1.11) only exposed as unregistered structured types in parameters and return types of functions.
1235
+ #### ` STRUCTURED `
1239
1236
1240
- A structured type is similar to an object in an object-oriented programming language. It contains
1241
- zero, one or more attributes. Each attribute consists of a name and a type.
1237
+ Data type for a user-defined object.
1242
1238
1243
- There are two kinds of structured types:
1239
+ Compared to ` ROW ` , which may also be considered a "struct-like" type, structured types are distinguishable even if they
1240
+ contain the same set of fields. For example, ` Visit(amount DOUBLE) ` is distinct from ` Interaction(amount DOUBLE) ` due
1241
+ its identifier.
1244
1242
1245
- - Types that are stored in a catalog and are identified by a _ catalog identifier_ (like ` cat.db.MyType ` ). Those
1246
- are equal to the SQL standard definition of structured types.
1243
+ Similar to classes in object-oriented programming languages, structured types are identified by a class name and contain
1244
+ zero, one or more attributes. Each attribute has a name, a type, and an optional description. A type cannot be defined
1245
+ in such a way that one of its attribute types (transitively) refers to itself.
1247
1246
1248
- - Anonymously defined, unregistered types (usually reflectively extracted) that are identified by
1249
- an _ implementation class_ (like ` com.myorg.model.MyType ` ). Those are useful when programmatically
1250
- defining a table program. They enable reusing existing JVM classes without manually defining the
1251
- schema of a data type again.
1247
+ Structured types are internally converted by the system into suitable data structures. Serialization and equality checks
1248
+ are managed by the system based on the logical type.
1252
1249
1253
- #### Registered Structured Types
1250
+ {{< tabs "udt" >}}
1251
+ {{< tab "SQL" >}}
1252
+ ``` sql
1253
+ STRUCTURED< ' c' , n0 t0, n1 t1, ...>
1254
+ STRUCTURED< ' c' , n0 t0, n1 t1 ' d1' , ...>
1255
+ ```
1256
+ The type can be declared using ` STRUCTURED<'c', n0 t0 'd0', n1 t1 'd1', ...> ` where ` c ` is the class name, ` n ` is the
1257
+ unique name of a field, ` t ` is the logical type of a field, ` d ` is the optional description of a field.
1258
+ {{< /tab >}}
1254
1259
1255
- Currently, registered structured types are not supported. Thus, they cannot be stored in a catalog
1256
- or referenced in a ` CREATE TABLE ` DDL.
1260
+ {{< tab "Java/Scala" >}}
1261
+ Usually structured types are defined ** inline** and can be reflectively extracted from a corresponding implementation class.
1262
+ For example, in the signature of an ` eval() ` method for functions. This is useful when programmatically defining a table
1263
+ program. They enable reusing existing JVM classes without manually defining the schema of a data type again.
1257
1264
1258
- #### Unregistered Structured Types
1265
+ If the class name matches a class in the classpath, the system will convert a structured object to a JVM object at the edges
1266
+ of the table ecosystem (e.g. when bridging to a function or connector). The implementation class must provide either a
1267
+ zero-argument constructor or a full constructor that assigns all attributes.
1259
1268
1260
- Unregistered structured types can be created from regular POJOs (Plain Old Java Objects) using automatic reflective extraction.
1269
+ But the class name does not need to be resolvable in the classpath, it may be used solely to distinguish between objects with
1270
+ identical attribute sets. However, in Table API and UDF calls, the system will attempt to resolve the class name to an
1271
+ actual implementation class. If resolution fails, ` Row ` is used as a fallback.
1261
1272
1262
- The implementation class of a structured type must meet the following requirements:
1273
+ Inline structured types can be created from regular POJOs (Plain Old Java Objects) if the implementation class meets the
1274
+ following requirements:
1263
1275
- The class must be globally accessible which means it must be declared ` public ` , ` static ` , and not ` abstract ` .
1264
1276
- The class must offer a default constructor with zero arguments or a full constructor that assigns all
1265
1277
fields.
@@ -1281,15 +1293,51 @@ For some classes an annotation is required in order to map the class to a data t
1281
1293
to assign a fixed precision and scale for ` java.math.BigDecimal ` ).
1282
1294
{{< /tab >}}
1283
1295
{{< tab "Python" >}}
1296
+ ``` python
1297
+ Not supported.
1298
+ ```
1284
1299
{{< /tab >}}
1285
1300
{{< /tabs >}}
1286
1301
1287
1302
** Declaration**
1288
1303
1289
1304
{{< tabs "c5e5527b-b09d-4dc5-9549-8fd2bfc7cc2a" >}}
1290
- {{< tab "Java" >}}
1305
+ {{< tab "Java/Scala" >}}
1306
+ Structured types are usually declared via their implementation classes:
1307
+
1291
1308
``` java
1292
- class User {
1309
+ // A simple POJO that qualifies as a structured type.
1310
+ // Note: Without a fully assigning constructor, the order of fields will be alphabetical.
1311
+ // The final data type will be:
1312
+ // STRUCTURED<'com.myorg.Customer', active BOOLEAN, id INT NOT NULL, name STRING, properties MAP<STRING, STRING>>
1313
+ class Customer {
1314
+ public int id;
1315
+ public String name;
1316
+ public Map<String , String > properties;
1317
+ public boolean active;
1318
+ }
1319
+
1320
+ // A POJO with a fully assigning constructor defining the field order.
1321
+ // The final data type will be:
1322
+ // STRUCTURED<'com.myorg.Customer', id INT NOT NULL, name STRING, properties MAP<STRING, STRING>, active BOOLEAN>
1323
+ class Customer {
1324
+ public int id;
1325
+ public String name;
1326
+ public Map<String , String > properties;
1327
+ public boolean active;
1328
+
1329
+ public Customer (int id , String name , Map<String , String > properties , boolean active ) {
1330
+ this . id = id;
1331
+ this . name = name;
1332
+ this . properties = properties;
1333
+ this . active = active;
1334
+ }
1335
+ }
1336
+
1337
+ // A POJO that uses the @DataTypeHint annotations for supporting the reflective extraction.
1338
+ // The final data type will be:
1339
+ // STRUCTURED<'com.myorg.Customer', age INT NOT NULL, modelClass RAW(...), name STRING, totalBalance DECIMAL(10, 2)>
1340
+ class Customer {
1293
1341
1294
1342
// extract fields automatically
1295
1343
public int age;
@@ -1301,35 +1349,30 @@ class User {
1301
1349
// enrich the extraction with forcing using RAW types
1302
1350
public @DataTypeHint ("RAW ") Class<?> modelClass;
1303
1351
}
1304
-
1305
- DataTypes . of(User . class);
1306
1352
```
1307
1353
1308
- ** Bridging to JVM Types**
1309
-
1310
- | Java Type | Input | Output | Remarks |
1311
- | :-------------------------------------| :-----:| :------:| :----------------------------------------|
1312
- | * class* | X | X | Originating class or subclasses (for input) or <br >superclasses (for output). * Default* |
1313
- | ` org.apache.flink.types.Row ` | X | X | Represent the structured type as a row. |
1314
- | ` org.apache.flink.table.data.RowData ` | X | X | Internal data structure. |
1315
-
1316
- {{< /tab >}}
1317
- {{< tab "Scala" >}}
1318
- ``` scala
1319
- case class User (
1354
+ Or via explicit declaration:
1355
+ ``` java
1356
+ // Provide an implementation class
1357
+ DataTypes . STRUCTURED (MyPojo . class, DataTypes . FIELD (n0, t0), DataTypes . FIELD (n1, t1), ... );
1320
1358
1321
- // extract fields automatically
1322
- age : Int ,
1323
- name : String ,
1359
+ // Provide a class name only, the class is resolved only if available in the classpath
1360
+ DataTypes . STRUCTURED (" com.myorg.MyPojo" , DataTypes . FIELD (n0, t0), DataTypes . FIELD (n1, t1), ... );
1324
1361
1325
- // enrich the extraction with precision information
1326
- @ DataTypeHint (" DECIMAL(10, 2)" ) totalBalance : java.math.BigDecimal ,
1362
+ // Full example
1363
+ DataTypes . STRUCTURED (
1364
+ Customer . class,
1365
+ DataTypes . FIELD (" age" , DataTypes . INT (). notNull()),
1366
+ DataTypes . FIELD (" name" , DataTypes . STRING ())
1367
+ );
1368
+ ```
1327
1369
1328
- // enrich the extraction with forcing using a RAW type
1329
- @ DataTypeHint ( " RAW " ) modelClass : Class [_]
1330
- )
1370
+ Or via explicit extraction:
1371
+ ``` java
1372
+ DataTypes . of( Class );
1331
1373
1332
- DataTypes .of(classOf [User ])
1374
+ // For example:
1375
+ DataTypes . of(Customer . class);
1333
1376
```
1334
1377
1335
1378
** Bridging to JVM Types**
0 commit comments