diff --git a/merlin-core/src/main/kotlin/de/micromata/merlin/excel/BeanUtils.kt b/merlin-core/src/main/kotlin/de/micromata/merlin/excel/BeanUtils.kt index f8924b3c..e6de61eb 100644 --- a/merlin-core/src/main/kotlin/de/micromata/merlin/excel/BeanUtils.kt +++ b/merlin-core/src/main/kotlin/de/micromata/merlin/excel/BeanUtils.kt @@ -81,7 +81,7 @@ object BeanUtils { fun getGetterMethod(clazz: Class<*>, fieldname: String): Method? { val methods: Array = getAllDeclaredGetters(clazz) for (m in methods) { - if (m.name == "get${fieldname.capitalize()}") { + if (m.name == "get${fieldname.replaceFirstChar { it.uppercase() }}") { return m } } diff --git a/merlin-core/src/main/kotlin/de/micromata/merlin/excel/ExcelColumnDef.kt b/merlin-core/src/main/kotlin/de/micromata/merlin/excel/ExcelColumnDef.kt index 88b80382..3248be99 100644 --- a/merlin-core/src/main/kotlin/de/micromata/merlin/excel/ExcelColumnDef.kt +++ b/merlin-core/src/main/kotlin/de/micromata/merlin/excel/ExcelColumnDef.kt @@ -33,7 +33,7 @@ constructor( * If not given, [columnHeadname] in decapitalized form will be used. */ var targetProperty: String? = null - get() = if (field != null) field else columnHeadname?.decapitalize() + get() = if (field != null) field else columnHeadname?.replaceFirstChar { it.lowercase() } private set /** diff --git a/merlin-core/src/main/kotlin/de/micromata/merlin/excel/ExcelRow.kt b/merlin-core/src/main/kotlin/de/micromata/merlin/excel/ExcelRow.kt index 9303fcbf..f8d4584c 100644 --- a/merlin-core/src/main/kotlin/de/micromata/merlin/excel/ExcelRow.kt +++ b/merlin-core/src/main/kotlin/de/micromata/merlin/excel/ExcelRow.kt @@ -193,7 +193,7 @@ class ExcelRow(val sheet: ExcelSheet, val row: Row) { continue } for (alias in colDef.columnAliases) { - searchResult = getPropertyValue(obj, colDef, alias.decapitalize(), ignoreProperties) + searchResult = getPropertyValue(obj, colDef, alias.replaceFirstChar { it.lowercase() }, ignoreProperties) if (searchResult != null) { processPropertyValue(obj, searchResult, colDef, process) break @@ -253,7 +253,7 @@ class ExcelRow(val sheet: ExcelSheet, val row: Row) { return PropertySearchResult(false, BeanUtils.getValue(obj, getter)) } } - val field = BeanUtils.getDeclaredField(obj::class.java, identifier.decapitalize()) + val field = BeanUtils.getDeclaredField(obj::class.java, identifier.replaceFirstChar { it.lowercase() }) if (field != null) { sheet.cache.autoFillCache.foundPropertiesMap[colDef] = WorkingCache.Property(field) return PropertySearchResult(false, BeanUtils.getValue(obj, field)) diff --git a/merlin-core/src/main/kotlin/de/micromata/merlin/excel/ExcelSheet.kt b/merlin-core/src/main/kotlin/de/micromata/merlin/excel/ExcelSheet.kt index 87a3e270..ae1b1214 100644 --- a/merlin-core/src/main/kotlin/de/micromata/merlin/excel/ExcelSheet.kt +++ b/merlin-core/src/main/kotlin/de/micromata/merlin/excel/ExcelSheet.kt @@ -103,7 +103,7 @@ class ExcelSheet internal constructor(val excelWorkbook: ExcelWorkbook, val poiS } for (listener in columnDef.getColumnListeners()!!) { if (listener is ExcelColumnValidator) { - if (columnDef._columnNumber < 0) { + if (columnDef._columnNumber < 0 && listener.isRequired) { addValidationError(createValidationErrorMissingColumnByName(columnDef.columnHeadname)) } } diff --git a/merlin-core/src/main/kotlin/de/micromata/merlin/excel/ExcelWorkbook.kt b/merlin-core/src/main/kotlin/de/micromata/merlin/excel/ExcelWorkbook.kt index 48484a84..7b867502 100644 --- a/merlin-core/src/main/kotlin/de/micromata/merlin/excel/ExcelWorkbook.kt +++ b/merlin-core/src/main/kotlin/de/micromata/merlin/excel/ExcelWorkbook.kt @@ -20,12 +20,15 @@ private val log = KotlinLogging.logger {} /** * Wraps and enhances a POI workbook. */ +@Suppress("unused", "MemberVisibilityCanBePrivate") class ExcelWorkbook -@JvmOverloads constructor( +@JvmOverloads +constructor( /** * Is used e. g. for getting number cell values as String. */ - val locale: Locale = Locale.getDefault() + val locale: Locale = Locale.getDefault(), + workbook: Workbook? = XSSFWorkbook(), ) : AutoCloseable { lateinit var pOIWorkbook: Workbook @@ -37,10 +40,10 @@ class ExcelWorkbook private var inputStream: InputStream? = null var filename: String? = null - val filenameExtension: String? + val filenameExtension: String get() = File(filename ?: "unkown.xlsx").extension - val filenameWithoutExtension: String? + val filenameWithoutExtension: String get() = File(filename ?: "unkown.xlsx").nameWithoutExtension var formulaEvaluator: FormulaEvaluator? = null @@ -57,7 +60,7 @@ class ExcelWorkbook workbook: Workbook, locale: Locale = Locale.getDefault() ) - : this(locale) { + : this(locale, null) { pOIWorkbook = workbook } @@ -73,7 +76,7 @@ class ExcelWorkbook excelFile: File, locale: Locale = Locale.getDefault() ) - : this(locale) { + : this(locale, null) { try { val fis = FileInputStream(excelFile) open(fis, excelFile.name) @@ -93,12 +96,12 @@ class ExcelWorkbook filename: String, locale: Locale = Locale.getDefault() ) - : this(locale) { + : this(locale, null) { open(inputStream, filename) } /** - * @param inputStream The input stream to read the Excel content from. + * @param byteArray Byte array to read the Excel content from. * @param filename Only for logging purposes if any error occurs. */ @JvmOverloads @@ -107,10 +110,16 @@ class ExcelWorkbook filename: String, locale: Locale = Locale.getDefault() ) - : this(locale) { + : this(locale, null) { open(byteArray.inputStream(), filename) } + init { + if (workbook != null) { + pOIWorkbook = workbook + } + } + private fun open(inputStream: InputStream, filename: String) { this.filename = File(filename).name this.inputStream = inputStream @@ -201,7 +210,7 @@ class ExcelWorkbook * * @see Workbook.cloneSheet */ - fun cloneSheet(sheetNum: Int, name: String?): ExcelSheet? { + fun cloneSheet(sheetNum: Int, name: String?): ExcelSheet { val index = pOIWorkbook.numberOfSheets val poiSheet: Sheet = this.pOIWorkbook.cloneSheet(sheetNum) this.pOIWorkbook.setSheetName(index, name) @@ -216,7 +225,7 @@ class ExcelWorkbook /** * Remove the sheet at the given position. * - * @param index + * @param idx * @return this for chaining. */ fun removeSheetAt(idx: Int) { diff --git a/merlin-core/src/main/kotlin/de/micromata/merlin/utils/BeanHelper.kt b/merlin-core/src/main/kotlin/de/micromata/merlin/utils/BeanHelper.kt index 7db0cf04..fd6a572d 100644 --- a/merlin-core/src/main/kotlin/de/micromata/merlin/utils/BeanHelper.kt +++ b/merlin-core/src/main/kotlin/de/micromata/merlin/utils/BeanHelper.kt @@ -23,8 +23,6 @@ package de.micromata.merlin.utils import de.micromata.merlin.excel.importer.ImportLogger -import org.apache.commons.lang3.ArrayUtils -import org.apache.commons.lang3.StringUtils import org.slf4j.LoggerFactory import java.lang.reflect.Method import java.lang.reflect.Modifier @@ -32,6 +30,7 @@ import java.math.BigDecimal import java.math.BigInteger import java.time.LocalDate import java.time.LocalDateTime +import java.util.* /** * Stores one imported object (e. g. MS Excel row as bean object). It also contains information about the status: New object or modified @@ -40,23 +39,21 @@ import java.time.LocalDateTime * @author Kai Reinhard (k.reinhard@micromata.de) */ object BeanHelper { - //private val log = LoggerFactory.getLogger(BeanHelper::class.java) - @JvmStatic @JvmOverloads fun determineGetter(clazz: Class<*>, fieldname: String, onlyPublicGetter: Boolean = true): Method? { - val cap = StringUtils.capitalize(fieldname) + val cap = fieldname.replaceFirstChar { it.uppercase() } val methods: Array = getAllDeclaredMethods(clazz) ?: return null for (method in methods) { if (onlyPublicGetter && !Modifier.isPublic(method.modifiers)) { continue } val matches = - if (Boolean::class.javaPrimitiveType!!.isAssignableFrom(method.returnType)) { - "is$cap" == method.name || "has$cap" == method.name || "get$cap" == method.name - } else { - "get$cap" == method.name - } + if (Boolean::class.javaPrimitiveType!!.isAssignableFrom(method.returnType)) { + "is$cap" == method.name || "has$cap" == method.name || "get$cap" == method.name + } else { + "get$cap" == method.name + } if (matches) { if (!method.isBridge) { // Don't return bridged methods (methods defined in interface or super class with different return type). return method @@ -73,7 +70,7 @@ object BeanHelper { var methods = cls.declaredMethods while (cls.superclass != null) { cls = cls.superclass - methods = ArrayUtils.addAll(methods, *cls.declaredMethods) as Array + methods += cls.declaredMethods } return methods } @@ -88,7 +85,7 @@ object BeanHelper { */ @JvmStatic fun determineSetter(clazz: Class<*>, fieldname: String): Method? { - val cap = fieldname.capitalize() + val cap = fieldname.replaceFirstChar { it.uppercaseChar() } val methods: Array = getAllDeclaredMethods(clazz) ?: return null for (method in methods) { if ("set$cap" == method.name && method.parameterTypes.size == 1) {