This is an automated email from the ASF dual-hosted git repository.

dockerzhang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/inlong.git


The following commit(s) were added to refs/heads/master by this push:
     new 006029809 [INLONG-7820][Manager] Support style and font when exporting 
Excel file (#7822)
006029809 is described below

commit 0060298093dcd775bb0c64f1ceb252fa991274d7
Author: feat <[email protected]>
AuthorDate: Wed Apr 12 21:28:02 2023 +0800

    [INLONG-7820][Manager] Support style and font when exporting Excel file 
(#7822)
---
 .../manager/common/tool/excel/ExcelTool.java       | 195 ++++++++++++------
 .../common/tool/excel/annotation/ExcelField.java   |   5 +-
 .../annotation/{ExcelField.java => Font.java}      |  35 ++--
 .../annotation/{ExcelField.java => Style.java}     |  50 ++---
 .../common/tool/excel/tuple/ImmutableQuartet.java  | 155 +++++++++++++++
 .../manager/common/tool/excel/tuple/Quartet.java   | 217 +++++++++++++++++++++
 .../inlong/manager/pojo/stream/StreamField.java    |  16 +-
 7 files changed, 561 insertions(+), 112 deletions(-)

diff --git 
a/inlong-manager/manager-common/src/main/java/org/apache/inlong/manager/common/tool/excel/ExcelTool.java
 
b/inlong-manager/manager-common/src/main/java/org/apache/inlong/manager/common/tool/excel/ExcelTool.java
index fd0df0297..e8173488f 100644
--- 
a/inlong-manager/manager-common/src/main/java/org/apache/inlong/manager/common/tool/excel/ExcelTool.java
+++ 
b/inlong-manager/manager-common/src/main/java/org/apache/inlong/manager/common/tool/excel/ExcelTool.java
@@ -24,15 +24,22 @@ import org.apache.commons.lang3.tuple.Pair;
 import org.apache.commons.lang3.tuple.Triple;
 import org.apache.inlong.manager.common.tool.excel.annotation.ExcelEntity;
 import org.apache.inlong.manager.common.tool.excel.annotation.ExcelField;
+import org.apache.inlong.manager.common.tool.excel.annotation.Font;
+import org.apache.inlong.manager.common.tool.excel.annotation.Style;
 import 
org.apache.inlong.manager.common.tool.excel.validator.ExcelCellValidator;
 import org.apache.inlong.manager.common.util.Preconditions;
+import org.apache.poi.ss.usermodel.BorderStyle;
 import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.FillPatternType;
+import org.apache.poi.ss.usermodel.IndexedColors;
 import org.apache.poi.ss.usermodel.Row;
 import org.apache.poi.ss.util.CellRangeAddressList;
 import org.apache.poi.xssf.usermodel.XSSFCell;
+import org.apache.poi.xssf.usermodel.XSSFCellStyle;
 import org.apache.poi.xssf.usermodel.XSSFDataValidation;
 import org.apache.poi.xssf.usermodel.XSSFDataValidationConstraint;
 import org.apache.poi.xssf.usermodel.XSSFDataValidationHelper;
+import org.apache.poi.xssf.usermodel.XSSFFont;
 import org.apache.poi.xssf.usermodel.XSSFRichTextString;
 import org.apache.poi.xssf.usermodel.XSSFRow;
 import org.apache.poi.xssf.usermodel.XSSFSheet;
@@ -49,13 +56,11 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
-import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.stream.Collectors;
-import java.util.stream.IntStream;
 
 import static org.apache.inlong.manager.common.util.Preconditions.expectTrue;
 
@@ -65,32 +70,20 @@ import static 
org.apache.inlong.manager.common.util.Preconditions.expectTrue;
 public class ExcelTool {
 
     private static final int CONSTRAINT_MAX_LENGTH = 255;
+
     private ExcelTool() {
 
     }
 
     private static final Logger LOGGER = 
LoggerFactory.getLogger(ExcelTool.class);
-    private static final int DEFAULT_COLUMN_WIDTH = 10000;
+    private static final String DEFAULT_SHEET_NAME = "Sheet 1";
+    private static final int DEFAULT_ROW_COUNT = 30;
 
     /**
      * Extracts the header row from a given class and returns it as a list of 
strings.
      */
-    public static <E> List<String> extractHeader(Class<E> e1Class) {
-        List<String> list = new LinkedList<>();
-        Field[] fields = e1Class.getDeclaredFields();
-        if (fields.length > 0) {
-            for (Field field : fields) {
-                field.setAccessible(true);
-                ExcelField excel = field.getAnnotation(ExcelField.class);
-                if (excel != null) {
-                    String excelName = excel.name();
-                    list.add(excelName);
-                }
-            }
-            return !list.isEmpty() ? list : Collections.emptyList();
-        } else {
-            return Collections.emptyList();
-        }
+    public static List<String> extractHeader(List<Pair<Field, ExcelField>> 
fieldMetas) {
+        return fieldMetas.stream().map(fieldMeta -> 
fieldMeta.getRight().name()).collect(Collectors.toList());
     }
 
     /**
@@ -109,32 +102,51 @@ public class ExcelTool {
 
     public static <T> void doWrite(List<Map<String, String>> maps, Class<T> 
clazz, OutputStream out)
             throws IOException {
-        List<String> heads = extractHeader(clazz);
-        if (heads.isEmpty()) {
+        Field[] fields = clazz.getDeclaredFields();
+        List<Pair<Field, ExcelField>> fieldMetas = extractFieldMetas(fields);
+        if (fieldMetas.isEmpty()) {
             throw new IllegalArgumentException(
                     "At least one field must be marked as Excel Field by 
annotation @ExcelField in class " + clazz);
         }
+        List<String> headNames = extractHeader(fieldMetas);
         try (XSSFWorkbook hwb = new XSSFWorkbook()) {
-            XSSFSheet sheet = hwb.createSheet("Sheet 1");
-
-            for (int index = 0; index < heads.size(); index++) {
-                sheet.setColumnWidth(index, DEFAULT_COLUMN_WIDTH);
+            // Set sheet name
+            ExcelEntity excelEntity = clazz.getAnnotation(ExcelEntity.class);
+            String sheetName = excelEntity.name();
+            if (StringUtils.isBlank(sheetName)) {
+                sheetName = DEFAULT_SHEET_NAME;
             }
-            fillSheetHeader(sheet.createRow(0), heads);
+            XSSFSheet sheet = hwb.createSheet(sheetName);
+            // Set width of column
+            for (int index = 0; index < fieldMetas.size(); index++) {
+                Pair<Field, ExcelField> fieldMeta = fieldMetas.get(index);
+                sheet.setColumnWidth(index, 
fieldMeta.getRight().style().width());
+            }
+            // Fill header with cellStyle
+            fillSheetHeader(sheet.createRow(0), headNames);
             // Fill validation
-            Field[] fields = clazz.getDeclaredFields();
-            fillSheetValidation(clazz, sheet, fields);
+            fillSheetValidation(sheet, fieldMetas, clazz.getCanonicalName());
             // Fill content if data exist.
+            List<XSSFCellStyle> contentStyles = createContentCellStyle(hwb, 
fieldMetas);
             if (CollectionUtils.isNotEmpty(maps)) {
-                fillSheetContent(sheet, heads, maps);
+                fillSheetContent(sheet, headNames, maps, contentStyles);
+            } else {
+                fillEmptySheetContent(sheet, headNames.size(), contentStyles);
             }
-
             hwb.write(out);
         }
         out.close();
         LOGGER.info("Database export succeeded");
     }
 
+    private static List<Pair<Field, ExcelField>> extractFieldMetas(Field[] 
fields) {
+        return Arrays.stream(fields)
+                .peek(field -> field.setAccessible(true))
+                .map(field -> Pair.of(field, 
field.getAnnotation(ExcelField.class)))
+                .filter(fieldMeta -> fieldMeta.getRight() != null)
+                .collect(Collectors.toList());
+    }
+
     /**
      * Fills the output stream with the provided class meta.
      */
@@ -143,52 +155,109 @@ public class ExcelTool {
         doWrite(null, clazz, out);
     }
 
+    private static List<XSSFCellStyle> createContentCellStyle(XSSFWorkbook 
workbook,
+            List<Pair<Field, ExcelField>> fieldMetas) {
+        return fieldMetas.stream().map(fieldMeta -> {
+            XSSFCellStyle style = workbook.createCellStyle();
+            ExcelField excelField = fieldMeta.getRight();
+            Style excelStyle = excelField.style();
+            Font excelFont = excelField.font();
+            // Set foreground color
+            style.setFillForegroundColor(excelStyle.bgColor().getIndex());
+            style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+            // Set font
+            XSSFFont font = workbook.createFont();
+            font.setFontName(excelFont.name());
+            font.setColor(excelFont.color().getIndex());
+            font.setFontHeightInPoints(excelFont.size());
+            font.setBold(excelFont.bold());
+            font.setItalic(excelFont.italic());
+            style.setFont(font);
+            // Set border
+            BorderStyle borderBottom = excelStyle.bottomBorderStyle();
+            BorderStyle borderTop = excelStyle.topBorderStyle();
+            BorderStyle borderLeft = excelStyle.leftBorderStyle();
+            BorderStyle borderRight = excelStyle.rightBorderStyle();
+            BorderStyle borderAll = excelStyle.allBorderStyle();
+            if (borderAll != BorderStyle.NONE) {
+                borderBottom = borderTop = borderLeft = borderRight = 
borderAll;
+            }
+            style.setBorderBottom(borderBottom);
+            style.setBorderTop(borderTop);
+            style.setBorderLeft(borderLeft);
+            style.setBorderRight(borderRight);
+            // Set border color
+            IndexedColors bottomBorderColor = excelStyle.bottomBorderColor();
+            IndexedColors topBorderColor = excelStyle.topBorderColor();
+            IndexedColors leftBorderColor = excelStyle.leftBorderColor();
+            IndexedColors rightBorderColor = excelStyle.rightBorderColor();
+            IndexedColors allBorderColor = excelStyle.allBorderColor();
+            if (allBorderColor != IndexedColors.BLACK) {
+                bottomBorderColor = topBorderColor = leftBorderColor = 
rightBorderColor = allBorderColor;
+            }
+            style.setBottomBorderColor(bottomBorderColor.getIndex());
+            style.setTopBorderColor(topBorderColor.getIndex());
+            style.setLeftBorderColor(leftBorderColor.getIndex());
+            style.setRightBorderColor(rightBorderColor.getIndex());
+            return style;
+        }).collect(Collectors.toList());
+
+    }
+
+    private static void fillEmptySheetContent(XSSFSheet sheet, int colCount, 
List<XSSFCellStyle> contentCellStyles) {
+        for (int index = 1; index < DEFAULT_ROW_COUNT; index++) {
+            XSSFRow row = sheet.createRow(index);
+            for (int colIndex = 0; colIndex < colCount; colIndex++) {
+                XSSFCell cell = row.createCell(colIndex);
+                cell.setCellStyle(contentCellStyles.get(colIndex));
+            }
+        }
+    }
+
     /**
      * Fills the content rows of a given sheet with the provided content maps 
and headers.
      */
-    private static void fillSheetContent(XSSFSheet sheet, List<String> heads, 
List<Map<String, String>> contents) {
+    private static void fillSheetContent(XSSFSheet sheet, List<String> heads, 
List<Map<String, String>> contents,
+            List<XSSFCellStyle> contentStyles) {
         Optional.ofNullable(contents)
-                .ifPresent(c -> IntStream.range(0, c.size())
-                        .forEach(lineId -> {
-                            Map<String, String> line = contents.get(lineId);
-                            Row row = sheet.createRow(lineId + 1);
-                            IntStream.range(0, heads.size()).forEach(colId -> {
-                                String title = heads.get(colId);
-                                String originValue = line.get(title);
-                                String value = 
StringUtils.isNotBlank(originValue) ? originValue : "";
-                                Cell cell = row.createCell(colId);
-                                cell.setCellValue(value);
-                            });
-                        }));
+                .ifPresent(content -> {
+                    int rowSize = content.size();
+                    for (int lineId = 0; lineId < rowSize; lineId++) {
+                        Map<String, String> line = contents.get(lineId);
+                        Row row = sheet.createRow(lineId + 1);
+                        int headSize = heads.size();
+                        for (int colId = 0; colId < headSize; colId++) {
+                            String title = heads.get(colId);
+                            String originValue = line.get(title);
+                            String value = StringUtils.isNotBlank(originValue) 
? originValue : "";
+                            Cell cell = row.createCell(colId);
+                            cell.setCellValue(value);
+                            cell.setCellStyle(contentStyles.get(colId));
+                        }
+                    }
+                });
     }
 
     private static void fillSheetHeader(XSSFRow row, List<String> heads) {
-        IntStream.range(0, heads.size()).forEach(index -> {
+        int headSize = heads.size();
+        for (int index = 0; index < headSize; index++) {
             XSSFCell cell = row.createCell(index);
             cell.setCellValue(new XSSFRichTextString(heads.get(index)));
-        });
+        }
     }
+
     /**
-     * Fills the validation constraints for a given sheet based on the 
provided class and fields.
+     * Fills the validation constraints for a given sheet based on the 
provided class and fieldMetas.
      *
-     * @param clazz  the class to use for validation constraints
-     * @param sheet  the sheet to fill with validation constraints
-     * @param fields the fields to use for validation constraints
+     * @param sheet      the sheet to fill with validation constraints
+     * @param fieldMetas the fieldMetas to use for validation constraints
+     * @param className  the class to use for validation constraints
      */
-    private static <T> void fillSheetValidation(Class<T> clazz, XSSFSheet 
sheet, Field[] fields) {
-        List<Pair<String, ExcelField>> excelFields = new ArrayList<>();
-
-        for (Field field : fields) {
-            field.setAccessible(true);
-            ExcelField excelField = field.getAnnotation(ExcelField.class);
-            if (excelField != null) {
-                excelFields.add(Pair.of(field.getName(), excelField));
-            }
-        }
-
-        int bound = excelFields.size();
+    private static void fillSheetValidation(XSSFSheet sheet, List<Pair<Field, 
ExcelField>> fieldMetas,
+            String className) {
+        int bound = fieldMetas.size();
         for (int index = 0; index < bound; index++) {
-            Pair<String, ExcelField> excelFieldPair = excelFields.get(index);
+            Pair<Field, ExcelField> excelFieldPair = fieldMetas.get(index);
             Class<? extends ExcelCellValidator> validator = 
excelFieldPair.getRight().validator();
 
             Optional<List<String>> optionalList = 
Optional.ofNullable(validator)
@@ -208,7 +277,7 @@ public class ExcelTool {
             }
             if (String.join("\n", valueOfCol).length() > 
CONSTRAINT_MAX_LENGTH) {
                 throw new IllegalArgumentException(
-                        "field '" + excelFieldPair.getLeft() + "' in class '" 
+ clazz.getCanonicalName()
+                        "field '" + excelFieldPair.getLeft().getName() + "' in 
class '" + className
                                 + "' valid message length must be less than 
255 characters");
             }
 
diff --git 
a/inlong-manager/manager-common/src/main/java/org/apache/inlong/manager/common/tool/excel/annotation/ExcelField.java
 
b/inlong-manager/manager-common/src/main/java/org/apache/inlong/manager/common/tool/excel/annotation/ExcelField.java
index fa836d5c3..4a7f1375a 100644
--- 
a/inlong-manager/manager-common/src/main/java/org/apache/inlong/manager/common/tool/excel/annotation/ExcelField.java
+++ 
b/inlong-manager/manager-common/src/main/java/org/apache/inlong/manager/common/tool/excel/annotation/ExcelField.java
@@ -41,9 +41,12 @@ public @interface ExcelField {
      * Data transfer method from Excel to Object
      */
     ExcelCellDataTransfer x2oTransfer() default ExcelCellDataTransfer.NONE;
-
     /**
      * Validator for the field
      */
     Class<? extends ExcelCellValidator> validator() default 
ExcelCellValidator.class;
+
+    Font font() default @Font;
+
+    Style style() default @Style;
 }
diff --git 
a/inlong-manager/manager-common/src/main/java/org/apache/inlong/manager/common/tool/excel/annotation/ExcelField.java
 
b/inlong-manager/manager-common/src/main/java/org/apache/inlong/manager/common/tool/excel/annotation/Font.java
similarity index 64%
copy from 
inlong-manager/manager-common/src/main/java/org/apache/inlong/manager/common/tool/excel/annotation/ExcelField.java
copy to 
inlong-manager/manager-common/src/main/java/org/apache/inlong/manager/common/tool/excel/annotation/Font.java
index fa836d5c3..f97d1a951 100644
--- 
a/inlong-manager/manager-common/src/main/java/org/apache/inlong/manager/common/tool/excel/annotation/ExcelField.java
+++ 
b/inlong-manager/manager-common/src/main/java/org/apache/inlong/manager/common/tool/excel/annotation/Font.java
@@ -17,33 +17,24 @@
 
 package org.apache.inlong.manager.common.tool.excel.annotation;
 
-import org.apache.inlong.manager.common.tool.excel.ExcelCellDataTransfer;
-import 
org.apache.inlong.manager.common.tool.excel.validator.ExcelCellValidator;
+import org.apache.poi.ss.usermodel.IndexedColors;
 
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
-/**
- * Annotation for Excel field
- */
-@Target({ElementType.FIELD})
+@Target(ElementType.FIELD)
 @Retention(RetentionPolicy.RUNTIME)
-public @interface ExcelField {
-
-    /**
-     * Name of the field in Excel
-     */
-    String name();
-
-    /**
-     * Data transfer method from Excel to Object
-     */
-    ExcelCellDataTransfer x2oTransfer() default ExcelCellDataTransfer.NONE;
-
-    /**
-     * Validator for the field
-     */
-    Class<? extends ExcelCellValidator> validator() default 
ExcelCellValidator.class;
+public @interface Font {
+
+    short size() default 12;
+
+    IndexedColors color() default IndexedColors.BLACK;
+
+    String name() default "Arial";
+
+    boolean bold() default false;
+
+    boolean italic() default false;
 }
diff --git 
a/inlong-manager/manager-common/src/main/java/org/apache/inlong/manager/common/tool/excel/annotation/ExcelField.java
 
b/inlong-manager/manager-common/src/main/java/org/apache/inlong/manager/common/tool/excel/annotation/Style.java
similarity index 54%
copy from 
inlong-manager/manager-common/src/main/java/org/apache/inlong/manager/common/tool/excel/annotation/ExcelField.java
copy to 
inlong-manager/manager-common/src/main/java/org/apache/inlong/manager/common/tool/excel/annotation/Style.java
index fa836d5c3..90ad50e8c 100644
--- 
a/inlong-manager/manager-common/src/main/java/org/apache/inlong/manager/common/tool/excel/annotation/ExcelField.java
+++ 
b/inlong-manager/manager-common/src/main/java/org/apache/inlong/manager/common/tool/excel/annotation/Style.java
@@ -17,33 +17,39 @@
 
 package org.apache.inlong.manager.common.tool.excel.annotation;
 
-import org.apache.inlong.manager.common.tool.excel.ExcelCellDataTransfer;
-import 
org.apache.inlong.manager.common.tool.excel.validator.ExcelCellValidator;
+import org.apache.poi.ss.usermodel.BorderStyle;
+import org.apache.poi.ss.usermodel.IndexedColors;
 
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
-/**
- * Annotation for Excel field
- */
-@Target({ElementType.FIELD})
+@Target(ElementType.FIELD)
 @Retention(RetentionPolicy.RUNTIME)
-public @interface ExcelField {
-
-    /**
-     * Name of the field in Excel
-     */
-    String name();
-
-    /**
-     * Data transfer method from Excel to Object
-     */
-    ExcelCellDataTransfer x2oTransfer() default ExcelCellDataTransfer.NONE;
-
-    /**
-     * Validator for the field
-     */
-    Class<? extends ExcelCellValidator> validator() default 
ExcelCellValidator.class;
+public @interface Style {
+
+    IndexedColors bgColor() default IndexedColors.BLACK;
+
+    IndexedColors allBorderColor() default IndexedColors.BLACK;
+
+    BorderStyle allBorderStyle() default BorderStyle.NONE;
+
+    IndexedColors bottomBorderColor() default IndexedColors.BLACK;
+
+    IndexedColors topBorderColor() default IndexedColors.BLACK;
+
+    IndexedColors leftBorderColor() default IndexedColors.BLACK;
+
+    IndexedColors rightBorderColor() default IndexedColors.BLACK;
+
+    BorderStyle bottomBorderStyle() default BorderStyle.NONE;
+
+    BorderStyle topBorderStyle() default BorderStyle.NONE;
+
+    BorderStyle leftBorderStyle() default BorderStyle.NONE;
+
+    BorderStyle rightBorderStyle() default BorderStyle.NONE;
+
+    int width() default 5000;
 }
diff --git 
a/inlong-manager/manager-common/src/main/java/org/apache/inlong/manager/common/tool/excel/tuple/ImmutableQuartet.java
 
b/inlong-manager/manager-common/src/main/java/org/apache/inlong/manager/common/tool/excel/tuple/ImmutableQuartet.java
new file mode 100644
index 000000000..9259311ab
--- /dev/null
+++ 
b/inlong-manager/manager-common/src/main/java/org/apache/inlong/manager/common/tool/excel/tuple/ImmutableQuartet.java
@@ -0,0 +1,155 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.inlong.manager.common.tool.excel.tuple;
+
+/**
+ * <p>An immutable quartet consisting of four {@code Object} elements.</p>
+ *
+ * <p>Although the implementation is immutable, there is no restriction on the 
objects
+ * that may be stored. If mutable objects are stored in the quartet, then the 
quartet
+ * itself effectively becomes mutable. The class is also {@code final}, so a 
subclass
+ * can not add undesirable behavior.</p>
+ *
+ * <p>#ThreadSafe# if all four objects are thread-safe</p>
+ *
+ * @param <L> the f1 element type
+ * @param <M> the f2 element type
+ * @param <R> the f3 element type
+ * @param <S> the f4 element type
+ */
+public final class ImmutableQuartet<L, M, R, S> extends Quartet<L, M, R, S> {
+
+    /**
+     * An empty array.
+     * <p>
+     * Consider using {@link #emptyArray()} to avoid generics warnings.
+     * </p>
+     */
+    public static final ImmutableQuartet<?, ?, ?, ?>[] EMPTY_ARRAY = new 
ImmutableQuartet[0];
+
+    /**
+     * An immutable quartet of nulls.
+     */
+    private static final ImmutableQuartet NULL = of(null, null, null, null);
+
+    /**
+     * Serialization version
+     */
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * Returns the empty array singleton that can be assigned without compiler 
warning.
+     *
+     * @param <L> the f1 element type
+     * @param <M> the f2 element type
+     * @param <R> the f3 element type
+     * @param <S> the f4 element type
+     * @return the empty array singleton that can be assigned without compiler 
warning.
+     */
+    @SuppressWarnings("unchecked")
+    public static <L, M, R, S> ImmutableQuartet<L, M, R, S>[] emptyArray() {
+        return (ImmutableQuartet<L, M, R, S>[]) EMPTY_ARRAY;
+    }
+
+    /**
+     * Returns an immutable quartet of nulls.
+     *
+     * @param <L> the f1 element of this quartet. Value is {@code null}.
+     * @param <M> the f2 element of this quartet. Value is {@code null}.
+     * @param <R> the f3 element of this quartet. Value is {@code null}.
+     * @param <S> the f4 element of this quartet. Value is {@code null}.
+     * @return an immutable quartet of nulls.
+     */
+    public static <L, M, R, S> ImmutableQuartet<L, M, R, S> nullTriple() {
+        return NULL;
+    }
+
+    /**
+     * <p>Obtains an immutable quartet of four objects inferring the generic 
types.</p>
+     *
+     * <p>This factory allows the quartet to be created using inference to
+     * obtain the generic types.</p>
+     *
+     * @param <L> the f1 element type
+     * @param <M> the f2 element type
+     * @param <R> the f3 element type
+     * @param <S> the f4 element type
+     * @param f1  the f1 element, may be null
+     * @param f2  the f2 element, may be null
+     * @param f3  the f3 element, may be null
+     * @param f4  the f4 element, may be null
+     * @return a quartet formed from the four parameters, not null
+     */
+    public static <L, M, R, S> ImmutableQuartet<L, M, R, S> of(final L f1, 
final M f2, final R f3, final S f4) {
+        return new ImmutableQuartet<>(f1, f2, f3, f4);
+    }
+
+    /**
+     * F1 object
+     */
+    public final L f1;
+    /**
+     * F2 object
+     */
+    public final M f2;
+
+    /**
+     * F3 object
+     */
+    public final R f3;
+
+    /**
+     * F4 object
+     */
+    public final S f4;
+
+    /**
+     * Create a new quartet instance.
+     *
+     * @param f1 the f1 value, may be null
+     * @param f2 the f2 value, may be null
+     * @param f3 the f3 value, may be null
+     */
+    public ImmutableQuartet(final L f1, final M f2, final R f3, final S f4) {
+        super();
+        this.f1 = f1;
+        this.f2 = f2;
+        this.f3 = f3;
+        this.f4 = f4;
+    }
+
+    @Override
+    public L getF1() {
+        return f1;
+    }
+
+    @Override
+    public M getF2() {
+        return f2;
+    }
+
+    @Override
+    public R getF3() {
+        return f3;
+    }
+
+    @Override
+    public S getF4() {
+        return f4;
+    }
+}
diff --git 
a/inlong-manager/manager-common/src/main/java/org/apache/inlong/manager/common/tool/excel/tuple/Quartet.java
 
b/inlong-manager/manager-common/src/main/java/org/apache/inlong/manager/common/tool/excel/tuple/Quartet.java
new file mode 100644
index 000000000..34a65a170
--- /dev/null
+++ 
b/inlong-manager/manager-common/src/main/java/org/apache/inlong/manager/common/tool/excel/tuple/Quartet.java
@@ -0,0 +1,217 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.inlong.manager.common.tool.excel.tuple;
+
+import org.apache.commons.lang3.builder.CompareToBuilder;
+
+import java.io.Serializable;
+import java.util.Objects;
+
+/**
+ * <p>A triple consisting of four elements.</p>
+ *
+ * <p>This class is an abstract implementation defining the basic API.
+ * It refers to the elements as 'f1', 'f2' , 'f3' and 'f4'.</p>
+ *
+ * <p>Subclass implementations may be mutable or immutable.
+ * However, there is no restriction on the type of the stored objects that may 
be stored.
+ * If mutable objects are stored in the triple, then the triple itself 
effectively becomes mutable.</p>
+ *
+ * @param <L> the f1 element type
+ * @param <M> the f2 element type
+ * @param <R> the f3 element type
+ * @param <S> the f4 element type
+ */
+public abstract class Quartet<L, M, R, S> implements Comparable<Quartet<L, M, 
R, S>>, Serializable {
+
+    private static final class QuarterAdapter<L, M, R, S> extends Quartet<L, 
M, R, S> {
+
+        private static final long serialVersionUID = 1L;
+
+        @Override
+        public L getF1() {
+            return null;
+        }
+
+        @Override
+        public M getF2() {
+            return null;
+        }
+
+        @Override
+        public R getF3() {
+            return null;
+        }
+
+        @Override
+        public S getF4() {
+            return null;
+        }
+    }
+
+    /**
+     * Serialization version
+     */
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * An empty array.
+     * <p>
+     * Consider using {@link #emptyArray()} to avoid generics warnings.
+     * </p>
+     *
+     */
+    public static final QuarterAdapter<?, ?, ?, ?>[] EMPTY_ARRAY = new 
QuarterAdapter[0];
+
+    /**
+     * Returns the empty array singleton that can be assigned without compiler 
warning.
+     *
+     * @param <L> the f1 element type
+     * @param <M> the f2 element type
+     * @param <R> the f3 element type
+     * @param <S> the f4 element type
+     * @return the empty array singleton that can be assigned without compiler 
warning.
+     */
+    @SuppressWarnings("unchecked")
+    public static <L, M, R, S> Quartet<L, M, R, S>[] emptyArray() {
+        return (QuarterAdapter<L, M, R, S>[]) EMPTY_ARRAY;
+    }
+
+    /**
+     * <p>Obtains an immutable triple of four objects inferring the generic 
types.</p>
+     *
+     * <p>This factory allows the triple to be created using inference to
+     * obtain the generic types.</p>
+     *
+     * @param <L> the f1 element type
+     * @param <M> the f2 element type
+     * @param <R> the f3 element type
+     * @param f1  the f1 element, may be null
+     * @param f2  the f2 element, may be null
+     * @param f3  the f3 element, may be null
+     * @return a triple formed from the four parameters, not null
+     */
+    public static <L, M, R, S> Quartet<L, M, R, S> of(final L f1, final M f2, 
final R f3, final S f4) {
+        return new ImmutableQuartet<>(f1, f2, f3, f4);
+    }
+
+    // -----------------------------------------------------------------------
+
+    /**
+     * <p>Compares the triple based on the f1 element, followed by the f2 
element and f3 element,
+     * finally the f4 element.
+     * The types must be {@code Comparable}.</p>
+     *
+     * @param other the other triple, not null
+     * @return negative if this is less, zero if equal, positive if greater
+     */
+    @Override
+    public int compareTo(final Quartet<L, M, R, S> other) {
+        return new CompareToBuilder().append(getF1(), other.getF1())
+                .append(getF2(), other.getF2())
+                .append(getF3(), other.getF3())
+                .append(getF4(), other.getF4())
+                .toComparison();
+    }
+
+    /**
+     * <p>Compares this triple to another based on the four elements.</p>
+     *
+     * @param obj the object to compare to, null returns false
+     * @return true if the elements of the triple are equal
+     */
+    @Override
+    public boolean equals(final Object obj) {
+        if (obj == this) {
+            return true;
+        }
+        if (obj instanceof Quartet<?, ?, ?, ?>) {
+            final Quartet<?, ?, ?, ?> other = (Quartet<?, ?, ?, ?>) obj;
+            return Objects.equals(getF1(), other.getF1())
+                    && Objects.equals(getF2(), other.getF2())
+                    && Objects.equals(getF3(), other.getF3())
+                    && Objects.equals(getF4(), other.getF4());
+        }
+        return false;
+    }
+
+    /**
+     * <p>Gets the f1 element from this triple.</p>
+     *
+     * @return the f1 element, may be null
+     */
+    public abstract L getF1();
+
+    /**
+     * <p>Gets the f2 element from this triple.</p>
+     *
+     * @return the f2 element, may be null
+     */
+    public abstract M getF2();
+
+    /**
+     * <p>Gets the f3 element from this triple.</p>
+     *
+     * @return the f3 element, may be null
+     */
+    public abstract R getF3();
+
+    /**
+     * <p>Gets the f4 element from this triple.</p>
+     *
+     * @return the f4 element, may be null
+     */
+    public abstract S getF4();
+
+    /**
+     * <p>Returns a suitable hash code.</p>
+     *
+     * @return the hash code
+     */
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(getF1()) ^ Objects.hashCode(getF2()) ^ 
Objects.hashCode(getF3())
+                ^ Objects.hashCode(getF4());
+    }
+
+    /**
+     * <p>Returns a String representation of this triple using the format 
{@code ($f1,$f2,$f3,$4)}.</p>
+     *
+     * @return a string describing this object, not null
+     */
+    @Override
+    public String toString() {
+        return "(" + getF1() + "," + getF2() + "," + getF3() + "," + getF4() + 
")";
+    }
+
+    /**
+     * <p>Formats the receiver using the given format.</p>
+     *
+     * <p>This uses {@link java.util.Formattable} to perform the formatting. 
Three variables may
+     * be used to embed the f1 and f3 elements. Use {@code %1$s} for the f1
+     * element, {@code %2$s} for the f2 , {@code %3$s} for the f3 element and 
{@code %4$s} for the f4 element.
+     * The default format used by {@code toString()} is {@code 
(%1$s,%2$s,%3$s,%4$s)}.</p>
+     *
+     * @param format the format string, optionally containing {@code %1$s}, 
{@code %2$s} and {@code %3$s}, not null
+     * @return the formatted string, not null
+     */
+    public String toString(final String format) {
+        return String.format(format, getF1(), getF2(), getF3(), getF4());
+    }
+
+}
diff --git 
a/inlong-manager/manager-pojo/src/main/java/org/apache/inlong/manager/pojo/stream/StreamField.java
 
b/inlong-manager/manager-pojo/src/main/java/org/apache/inlong/manager/pojo/stream/StreamField.java
index 68dcbe5af..fffe2a213 100644
--- 
a/inlong-manager/manager-pojo/src/main/java/org/apache/inlong/manager/pojo/stream/StreamField.java
+++ 
b/inlong-manager/manager-pojo/src/main/java/org/apache/inlong/manager/pojo/stream/StreamField.java
@@ -25,7 +25,11 @@ import lombok.Data;
 import lombok.NoArgsConstructor;
 import org.apache.inlong.manager.common.tool.excel.annotation.ExcelEntity;
 import org.apache.inlong.manager.common.tool.excel.annotation.ExcelField;
+import org.apache.inlong.manager.common.tool.excel.annotation.Font;
+import org.apache.inlong.manager.common.tool.excel.annotation.Style;
 import 
org.apache.inlong.manager.common.tool.excel.validator.NonEmptyCellValidator;
+import org.apache.poi.ss.usermodel.BorderStyle;
+import org.apache.poi.ss.usermodel.IndexedColors;
 
 import java.io.Serializable;
 
@@ -37,7 +41,7 @@ import java.io.Serializable;
 @NoArgsConstructor
 @AllArgsConstructor
 @ApiModel("Stream field configuration")
-@ExcelEntity(name = "StreamField excel template")
+@ExcelEntity(name = "InLong-StreamField-Template")
 public class StreamField implements Serializable {
 
     @ApiModelProperty("Field index")
@@ -49,15 +53,19 @@ public class StreamField implements Serializable {
     @ApiModelProperty(value = "inlong stream id", required = true)
     private String inlongStreamId;
 
-    @ExcelField(name = "Field name", validator = NonEmptyCellValidator.class)
+    @ExcelField(name = "Field name", validator = NonEmptyCellValidator.class,
+
+            font = @Font(size = 16), style = @Style(bgColor = 
IndexedColors.LIGHT_TURQUOISE, width = 9000, allBorderColor = 
IndexedColors.BLUE, allBorderStyle = BorderStyle.THIN))
     @ApiModelProperty(value = "Field name", required = true)
     private String fieldName;
 
-    @ExcelField(name = "Field type", validator = 
StreamFieldTypeCellValidator.class)
+    @ExcelField(name = "Field type", validator = 
StreamFieldTypeCellValidator.class,
+
+            font = @Font(size = 16), style = @Style(bgColor = 
IndexedColors.LIGHT_TURQUOISE, width = 6000, allBorderColor = 
IndexedColors.BLUE, allBorderStyle = BorderStyle.THIN))
     @ApiModelProperty(value = "Field type", required = true)
     private String fieldType;
 
-    @ExcelField(name = "Field comment")
+    @ExcelField(name = "Field comment", font = @Font(size = 16), style = 
@Style(bgColor = IndexedColors.LIGHT_TURQUOISE, width = 10000, allBorderColor = 
IndexedColors.BLUE, allBorderStyle = BorderStyle.THIN))
     @ApiModelProperty("Field comment")
     private String fieldComment;
 


Reply via email to