EN · DE · RU · FR · ES

#1359: CollectionUtils.kt

projectforge-business/src/main/kotlin/org/projectforge/framework/persistence/utils/CollectionUtils.kt Класс Kotlin, projectforge-business/src/main/kotlin/org/projectforge/framework/persistence/utils/CollectionUtils.kt 169 строк · 105 кода · 51 комментарий · 13 пустых
Назначение: Исходный файл: framework/persistence/utils/CollectionUtils.kt. CollectionUtils.kt является частью приложения управления проектами с открытым исходным кодом ProjectForge.

Исходный код (первые 100 строк)

/////////////////////////////////////////////////////////////////////////////
//
// Project ProjectForge Community Edition
//         www.projectforge.org
//
// Copyright (C) 2001-2026 Micromata GmbH, Germany (www.micromata.com)
//
// ProjectForge is dual-licensed.
//
// This community edition is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation; version 3 of the License.
//
// This community edition is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
// Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, see http://www.gnu.org/licenses/.
//
/////////////////////////////////////////////////////////////////////////////

package org.projectforge.framework.persistence.utils

import org.projectforge.framework.persistence.api.IdObject
import kotlin.reflect.full.isSubclassOf
import kotlin.reflect.jvm.jvmErasure

object CollectionUtils {
    class CompareCollectionsResult<T>(
        /** Новые записи в src, ещё не являющиеся частью dest. */
        val added: Collection<T>? = null,
        /** Удалённые записи в src, которые нужно удалить в dest. */
        val removed: Collection<T>? = null,
        /** Записи, присутствующие как в src, так и в dest. */
        val kept: Collection<T>? = null,
    ) {
        /**
         * Возвращает первую запись из added, removed или kept. Необходимо для проверки,
         * следует ли сохранять историю изменений для этих записей.
         */
        val anyOrNull: T?
            get() = added?.firstOrNull() ?: removed?.firstOrNull() ?: kept?.firstOrNull()
    }

    fun getTypeClassOfEntries(col: Collection<*>?): Class<*> {
        return getTypeClassOfEntriesOrNull(col)!!
    }

    fun getTypeClassOfEntriesOrNull(col: Collection<*>?): Class<*>? {
        col ?: return null
        return col.firstOrNull()?.javaClass
    }

    fun isCollection(property: kotlin.reflect.KProperty1<*, *>): Boolean {
        return property.returnType.jvmErasure.isSubclassOf(Collection::class)
    }

    /**
     * Объединяет идентификаторы заданной коллекции в строку CSV. Записи сортируются по идентификатору.
     * Используется, например, в записях истории для представления удалённых и добавленных записей коллекции.
     */
    fun joinToStringOfIds(col: Collection<IdObject<Long>>?, filterNotNull: Boolean = true): String? {
        col ?: return null
        return joinToString(col, filterNotNull, idOnly = true)
    }

    /**
     * Объединяет заданную коллекцию в строку CSV. Записи сортируются.
     */
    fun joinToString(col: Collection<Any?>?, filterNotNull: Boolean = true, idOnly: Boolean = false): String? {
        col ?: return null
        var filtered = if (filterNotNull) col.filterNotNull() else col
        if (filtered.isEmpty()) {
            return ""
        }
        val first = filtered.first()
        if (first is Comparable<*>) { // Сортировка возможна:
            filtered = filtered.sortedWith(compareBy { it as Comparable<*> })
        } else if (first is IdObject<*> && first.id is Comparable<*>) { // Сортировка возможна:
            filtered = filtered.sortedWith(compareBy { ((it as IdObject<*>).id as? Comparable<*>) })
        }
        return filtered.joinToString(separator = ",") { if (idOnly) toString(it) else it.toString() }
    }

    private fun toString(entry: Any?): String {
        return if (entry == null) {
            "null"
        } else if (entry is IdObject<*>) {
            entry.id.toString()
        } else {
            entry.toString()
        }
    }

    /**
     * Сравнивает две коллекции и возвращает добавленные, удалённые и сохранённые записи.
     * @param src Исходная коллекция.
     * @param dest Целевая коллекция.

История Git

868d6abb7 2025 -> 2026
48a93dedb Цветной лог консоли. Экспорт UserGroupCache для отладки и сравнения теперь работает. CollectionUtil улучшен. Добавлен KotlinStringExtension.shortenMiddle().
63081666f Заголовки исходных файлов: 2024 -> 2025.
61f05ce90 Работа над миграцией в процессе...
5989b32fd BaseDao: рефакторинг механизма onChangeListener.

868d6abb7

2025 -> 2026
868d6abb75cd191a892911ac8e45058932cf9074
diff --git a/projectforge-business/src/main/kotlin/org/projectforge/framework/persistence/utils/CollectionUtils.kt b/projectforge-business/src/main/kotlin/org/projectforge/framework/persistence/utils/CollectionUtils.kt
index 7ca7f9101..52deaa7d3 100644
--- a/projectforge-business/src/main/kotlin/org/projectforge/framework/persistence/utils/CollectionUtils.kt
+++ b/projectforge-business/src/main/kotlin/org/projectforge/framework/persistence/utils/CollectionUtils.kt
@@ -3,7 +3,7 @@
 // Project ProjectForge Community Edition
 //         www.projectforge.org
 //
-// Copyright (C) 2001-2025 Micromata GmbH, Germany (www.micromata.com)
+// Copyright (C) 2001-2026 Micromata GmbH, Germany (www.micromata.com)
 //
 // ProjectForge is dual-licensed.
 //

48a93dedb

Цветной лог консоли. Экспорт UserGroupCache для отладки и сравнения теперь работает. CollectionUtil улучшен. Добавлен KotlinStringExtension.shortenMiddle().
48a93dedb542a7f4100f86f6f4c9c1b8b8f41027
diff --git a/projectforge-business/src/main/kotlin/org/projectforge/framework/persistence/utils/CollectionUtils.kt b/projectforge-business/src/main/kotlin/org/projectforge/framework/persistence/utils/CollectionUtils.kt
index 91ad1f77c..7ca7f9101 100644
--- a/projectforge-business/src/main/kotlin/org/projectforge/framework/persistence/utils/CollectionUtils.kt
+++ b/projectforge-business/src/main/kotlin/org/projectforge/framework/persistence/utils/CollectionUtils.kt
@@ -61,17 +61,37 @@ object CollectionUtils {
      * Joins the id's of the given collection to a csv string. The entries are sorted by id.
      * Used for example in history entries, representing the removed and added entries of a collection.
      */
-    fun joinToStringOfIds(col: Collection<IdObject<Long>>?): String? {
+    fun joinToStringOfIds(col: Collection<IdObject<Long>>?, filterNotNull: Boolean = true): String? {
         col ?: return null
-        return joinToString(col.map { it.id })
+        return joinToString(col, filterNotNull, idOnly = true)
     }
 
     /**
      * Joins the given collection to a csv string. The entries are sorted.
      */
-    fun <T : Comparable<T>> joinToString(col: Collection<T?>?): String? {
+    fun joinToString(col: Collection<Any?>?, filterNotNull: Boolean = true, idOnly: Boolean = false): String? {
         col ?: return null
-        return col.filterNotNull().sorted().joinToString(separator = ",")
+        var filtered = if (filterNotNull) col.filterNotNull() else col
+        if (filtered.isEmpty()) {
+            return ""
+        }
+        val first = filtered.first()
+        if (first is Comparable<*>) { // Sorting is possible:
+            filtered = filtered.sortedWith(compareBy { it as Comparable<*> })
+        } else if (first is IdObject<*> && first.id is Comparable<*>) { // Sorting is possible:
+            filtered = filtered.sortedWith(compareBy { ((it as IdObject<*>).id as? Comparable<*>) })
+        }
+        return filtered.joinToString(separator = ",") { if (idOnly) toString(it) else it.toString() }
+    }
+
+    private fun toString(entry: Any?): String {
+        return if (entry == null) {
+            "null"
+        } else if (entry is IdObject<*>) {
+            entry.id.toString()
+        } else {
+            entry.toString()
+        }
     }
 
     /**

63081666f

Заголовки исходных файлов: 2024 -> 2025.
63081666f620fb87315f01b817e560e0b2f6a33a
diff --git a/projectforge-business/src/main/kotlin/org/projectforge/framework/persistence/utils/CollectionUtils.kt b/projectforge-business/src/main/kotlin/org/projectforge/framework/persistence/utils/CollectionUtils.kt
index 795d4b20b..91ad1f77c 100644
--- a/projectforge-business/src/main/kotlin/org/projectforge/framework/persistence/utils/CollectionUtils.kt
+++ b/projectforge-business/src/main/kotlin/org/projectforge/framework/persistence/utils/CollectionUtils.kt
@@ -3,7 +3,7 @@
 // Project ProjectForge Community Edition
 //         www.projectforge.org
 //
-// Copyright (C) 2001-2024 Micromata GmbH, Germany (www.micromata.com)
+// Copyright (C) 2001-2025 Micromata GmbH, Germany (www.micromata.com)
 //
 // ProjectForge is dual-licensed.
 //

61f05ce90

Работа над миграцией в процессе...
61f05ce90d175668026491c93a758f1ec6524c32
diff --git a/projectforge-business/src/main/kotlin/org/projectforge/framework/persistence/utils/CollectionUtils.kt b/projectforge-business/src/main/kotlin/org/projectforge/framework/persistence/utils/CollectionUtils.kt
index 9ea824f86..795d4b20b 100644
--- a/projectforge-business/src/main/kotlin/org/projectforge/framework/persistence/utils/CollectionUtils.kt
+++ b/projectforge-business/src/main/kotlin/org/projectforge/framework/persistence/utils/CollectionUtils.kt
@@ -23,7 +23,6 @@
 
 package org.projectforge.framework.persistence.utils
 
-import kotlinx.collections.immutable.toImmutableList
 import org.projectforge.framework.persistence.api.IdObject
 import kotlin.reflect.full.isSubclassOf
 import kotlin.reflect.jvm.jvmErasure
@@ -92,10 +91,10 @@ object CollectionUtils {
             if (useDest.isNullOrEmpty()) {
                 return CompareCollectionsResult()
             }
-            return CompareCollectionsResult(removed = useDest.toImmutableList())
+            return CompareCollectionsResult(removed = useDest.toList())
         }
         if (useDest.isNullOrEmpty()) {
-            return CompareCollectionsResult(added = useSrc.toImmutableList())
+            return CompareCollectionsResult(added = useSrc.toList())
         }
         val added = getAddedEntries(src = useSrc, dest = useDest)
         val removed = getAddedEntries(src = useDest, dest = useSrc)

5989b32fd

BaseDao: рефакторинг механизма onChangeListener.
5989b32fdbe63a7ade7eabba11a8c2b042ecd66b
diff --git a/projectforge-business/src/main/kotlin/org/projectforge/framework/persistence/utils/CollectionUtils.kt b/projectforge-business/src/main/kotlin/org/projectforge/framework/persistence/utils/CollectionUtils.kt
index 332777d2b..9ea824f86 100644
--- a/projectforge-business/src/main/kotlin/org/projectforge/framework/persistence/utils/CollectionUtils.kt
+++ b/projectforge-business/src/main/kotlin/org/projectforge/framework/persistence/utils/CollectionUtils.kt
@@ -25,6 +25,8 @@ package org.projectforge.framework.persistence.utils
 
 import kotlinx.collections.immutable.toImmutableList
 import org.projectforge.framework.persistence.api.IdObject
+import kotlin.reflect.full.isSubclassOf
+import kotlin.reflect.jvm.jvmErasure
 
 object CollectionUtils {
     class CompareCollectionsResult<T>(
@@ -52,6 +54,10 @@ object CollectionUtils {
         return col.firstOrNull()?.javaClass
     }
 
+    fun isCollection(property: kotlin.reflect.KProperty1<*, *>): Boolean {
+        return property.returnType.jvmErasure.isSubclassOf(Collection::class)
+    }
+
     /**
      * Joins the id's of the given collection to a csv string. The entries are sorted by id.
      * Used for example in history entries, representing the removed and added entries of a collection.