Skip to content

Commit 9e0bd4d

Browse files
committed
fixed "Concept not found" exception when a concept is not generated by api-gen
The model may contain more concepts than what is used in the Kotlin project. Often you have expression like this: rootNodes.filterIsInstances<N_MyConcept> Then the missing concept are not required and the exception doesn't indicate an actual problem.
1 parent 1ae9504 commit 9e0bd4d

File tree

4 files changed

+98
-5
lines changed

4 files changed

+98
-5
lines changed

metamodel-runtime/src/commonMain/kotlin/org/modelix/metamodel/TypedLanguagesRegistry.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package org.modelix.metamodel
33
import org.modelix.model.api.ILanguageRepository
44
import org.modelix.model.api.INode
55
import org.modelix.model.api.resolve
6+
import org.modelix.model.api.tryResolve
67
import kotlin.jvm.JvmName
78
import kotlin.reflect.KClass
89
import kotlin.reflect.cast
@@ -36,8 +37,8 @@ object TypedLanguagesRegistry : ILanguageRepository {
3637
}
3738

3839
fun wrapNode(node: INode): ITypedNode {
39-
val concept = (node.getConceptReference()?.resolve() as? GeneratedConcept<*, *>)
40-
?: throw IllegalArgumentException("Unknown concept: ${node.getConceptReference()}")
40+
val concept = (node.getConceptReference()?.tryResolve() as? GeneratedConcept<*, *>)
41+
?: return UnknownConceptInstance(node)
4142
return concept.wrap(node)
4243
}
4344
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
package org.modelix.metamodel
2+
3+
import org.modelix.model.api.IChildLink
4+
import org.modelix.model.api.IConcept
5+
import org.modelix.model.api.IConceptReference
6+
import org.modelix.model.api.ILanguage
7+
import org.modelix.model.api.INode
8+
import org.modelix.model.api.IProperty
9+
import org.modelix.model.api.IReferenceLink
10+
import org.modelix.model.area.IArea
11+
12+
abstract class EmptyConcept : IConcept {
13+
override fun isAbstract(): Boolean = true
14+
15+
override fun isSubConceptOf(superConcept: IConcept?): Boolean = superConcept == this
16+
17+
override fun getDirectSuperConcepts(): List<IConcept> = emptyList()
18+
19+
override fun isExactly(concept: IConcept?): Boolean = concept == this
20+
21+
override fun getOwnProperties(): List<IProperty> = emptyList()
22+
23+
override fun getOwnChildLinks(): List<IChildLink> = emptyList()
24+
25+
override fun getOwnReferenceLinks(): List<IReferenceLink> = emptyList()
26+
27+
override fun getAllProperties(): List<IProperty> = emptyList()
28+
29+
override fun getAllChildLinks(): List<IChildLink> = emptyList()
30+
31+
override fun getAllReferenceLinks(): List<IReferenceLink> = emptyList()
32+
33+
override fun getProperty(name: String): IProperty {
34+
throw IllegalArgumentException("Cannot get property '$name'. No concept information available for '${getUID()}'.")
35+
}
36+
37+
override fun getChildLink(name: String): IChildLink {
38+
throw IllegalArgumentException("Cannot get link '$name'. No concept information available for '${getUID()}'.")
39+
}
40+
41+
override fun getReferenceLink(name: String): IReferenceLink {
42+
throw IllegalArgumentException("Cannot get link '$name'. No concept information available for '${getUID()}'.")
43+
}
44+
}
45+
46+
object NullConcept : EmptyConcept(), IConceptReference {
47+
override fun getReference(): IConceptReference = this
48+
49+
override val language: ILanguage?
50+
get() = null
51+
52+
override fun getUID(): String = "null"
53+
54+
override fun getShortName(): String = "null"
55+
56+
override fun getLongName(): String = getShortName()
57+
58+
override fun resolve(area: IArea?): IConcept? {
59+
return this
60+
}
61+
62+
override fun serialize(): String = "null"
63+
}
64+
65+
data class UnknownConcept(private val ref: IConceptReference) : EmptyConcept() {
66+
override fun getReference(): IConceptReference {
67+
return ref
68+
}
69+
70+
override val language: ILanguage?
71+
get() = null
72+
73+
override fun getUID(): String = ref.getUID()
74+
75+
override fun getShortName(): String = "Unknown[${ref.getUID()}]"
76+
77+
override fun getLongName(): String = getShortName()
78+
}
79+
80+
data class UnknownTypedConcept(private val ref: IConceptReference?) : ITypedConcept {
81+
override val _concept: IConcept
82+
get() = ref?.let { UnknownConcept(it) } ?: NullConcept
83+
}
84+
85+
data class UnknownConceptInstance(val node: INode) : ITypedNode {
86+
override val _concept: ITypedConcept
87+
get() = UnknownTypedConcept(node.getConceptReference())
88+
89+
override fun unwrap(): INode = node
90+
}

model-api/src/commonMain/kotlin/org/modelix/model/api/IConceptReference.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,4 @@ interface IConceptReference {
4747
}
4848

4949
fun IConceptReference.resolve(): IConcept = ILanguageRepository.resolveConcept(this)
50+
fun IConceptReference.tryResolve(): IConcept? = ILanguageRepository.tryResolveConcept(this)

model-api/src/commonMain/kotlin/org/modelix/model/api/ILanguageRepository.kt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@ interface ILanguageRepository {
66
private var repositories: Set<ILanguageRepository> = setOf(DefaultLanguageRepository)
77

88
fun resolveConcept(ref: IConceptReference): IConcept {
9+
return tryResolveConcept(ref) ?: throw RuntimeException("Concept not found: $ref")
10+
}
11+
fun tryResolveConcept(ref: IConceptReference): IConcept? {
912
val concepts = repositories.mapNotNull { it.resolveConcept(ref.getUID()) }
1013
return when (concepts.size) {
11-
0 -> {
12-
throw RuntimeException("Concept not found: $ref")
13-
}
14+
0 -> null
1415
1 -> concepts.first()
1516
else -> throw RuntimeException("Multiple concepts found for $ref: $concepts")
1617
}

0 commit comments

Comments
 (0)