Skip to content

Commit 7fd82af

Browse files
author
yevhenii-nadtochii
committed
Rename MessageStateValidation to OptionGenerator
1 parent 16663a6 commit 7fd82af

File tree

5 files changed

+95
-22
lines changed

5 files changed

+95
-22
lines changed

java/src/main/kotlin/io/spine/validation/java/JavaValidationRenderer.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ import io.spine.validation.CompilationMessage
4242
*/
4343
public class JavaValidationRenderer : JavaRenderer() {
4444

45-
private val valueConverter = JavaValueConverter(typeSystem)
45+
private val valueConverter by lazy { JavaValueConverter(typeSystem) }
4646

4747
override fun render(sources: SourceFileSet) {
4848
// We receive `grpc` and `kotlin` output sources roots here as well.

java/src/main/kotlin/io/spine/validation/java/MessageValidationCode.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ private typealias BuilderPsiClass = PsiClass
7979
internal class MessageValidationCode(
8080
private val message: CompilationMessage,
8181
private val typeSystem: TypeSystem,
82-
private val generators: List<MessageStateValidation>
82+
private val generators: List<OptionGenerator>
8383
) {
8484
private val messageType: TypeName = message.name
8585
private val messageClassName = messageType.javaClassName(typeSystem)
@@ -186,7 +186,8 @@ internal class MessageValidationCode(
186186
*/
187187
private fun MessagePsiClass.declarePrivateValidateMethod() {
188188
val ruleConstraints = constraints
189-
val generatedConstraints = generators.flatMap { it.constraints(messageType) }
189+
// We are temporarily ignoring members for standalone generators.
190+
val generatedConstraints = generators.flatMap { it.codeFor(messageType).constraints }
190191
val psiMethod = elementFactory.createMethodFromText(
191192
"""
192193
|private java.util.Optional<io.spine.validate.ValidationError> validate(io.spine.base.FieldPath parent) {
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* Copyright 2025, TeamDev. All rights reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Redistribution and use in source and/or binary forms, with or without
11+
* modification, must retain the above copyright notice and the following
12+
* disclaimer.
13+
*
14+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15+
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16+
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17+
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
18+
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19+
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
20+
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21+
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22+
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25+
*/
26+
27+
package io.spine.validation.java
28+
29+
import io.spine.protodata.ast.TypeName
30+
import io.spine.validation.java.protodata.CodeBlock
31+
import io.spine.validation.java.protodata.MemberDeclaration
32+
33+
/**
34+
* Generates Java code for a specific option.
35+
*/
36+
internal interface OptionGenerator {
37+
38+
/**
39+
* Generates validation code for the option within the provided
40+
* message [type].
41+
*
42+
* If multiple fields declare the option, the returned code handles them all.
43+
*/
44+
fun codeFor(type: TypeName): OptionCode
45+
}
46+
47+
/**
48+
* Java code handling all applications of a specific option within a message.
49+
*/
50+
internal class OptionCode(
51+
52+
/**
53+
* Code blocks to be added to the `validate()` method of the message.
54+
*/
55+
val constraints: List<CodeBlock>,
56+
57+
/**
58+
* Additional class-level declarations required by the validation logic.
59+
*
60+
* Some constraints may require defining extra fields or methods.
61+
*/
62+
val declarations: List<MemberDeclaration> = emptyList()
63+
)

java/src/main/kotlin/io/spine/validation/java/RequiredOption.kt

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -59,18 +59,25 @@ import io.spine.validation.protodata.toBuilder
5959
internal class RequiredOption(
6060
private val querying: Querying,
6161
private val converter: JavaValueConverter
62-
) : MessageStateValidation {
62+
) : OptionGenerator {
6363

64-
private val allViews by lazy {
64+
/**
65+
* All required fields in the current compilation process.
66+
*/
67+
private val allRequiredFields by lazy {
6568
querying.select<RequiredField>()
6669
.all()
6770
}
6871

69-
override fun constraints(type: TypeName): List<CodeBlock> =
70-
allViews.filter { it.id.type == type }
71-
.map { constraints(it) }
72+
override fun codeFor(type: TypeName): OptionCode {
73+
val requiredMessageFields = allRequiredFields.filter { it.id.type == type }
74+
val constraints = requiredMessageFields.map { constraints((it)) }
75+
return OptionCode(constraints)
76+
}
7277

73-
// How do we know about variables `violations` and `parent`?
78+
// TODO:2025-01-31:yevhenii.nadtochii: The OptionGenerater is already aware about `validate()`
79+
// method, it should pass expressions for `violations` and `parent` variables. So, not to
80+
// hardcode them as text.
7481
private fun constraints(view: RequiredField): CodeBlock {
7582
val field = view.subject
7683
val getter = This<Message>()
@@ -88,12 +95,9 @@ internal class RequiredOption(
8895
)
8996
}
9097

91-
/**
92-
* This approach with `equals()` is unified. Now we
93-
*/
94-
// TODO:2025-01-31:yevhenii.nadtochii: Consider migration from the universal test
95-
// to type-specific tests. This approach with `equals()` was great for rules.
96-
// But now we can write, i.e., `list.size() == 0` instead of comparing it with empty
98+
// TODO:2025-01-31:yevhenii.nadtochii: Consider migration from the general check
99+
// to type-specific checks. This approach with `equals()` was great for rules.
100+
// But now we can write, i.e., `list.size() == 0` instead of comparing it with an empty
97101
// collection, which is always created just for that.
98102
private fun defaultValue(field: Field): Expression<*> {
99103
val unsetValue = UnsetValue.forField(field)!!
@@ -108,7 +112,7 @@ internal class RequiredOption(
108112

109113
// TODO:2025-01-31:yevhenii.nadtochii: Set `field_value` when `TypeConverter` knows
110114
// how to convert collections: Could not find a wrapper type for `java.util.Collections$EmptyList`.
111-
// I suppose the same story is with maps. An empty list is a default value for empty repeated.
115+
// I suppose the same story is with maps. An empty list is a default value for empty `repeated`.
112116
private fun violation(
113117
field: Field,
114118
path: Expression<FieldPath>,
@@ -125,6 +129,7 @@ internal class RequiredOption(
125129
return violation
126130
}
127131

132+
// TODO:2025-01-31:yevhenii.nadtochii: This method should be shared with `SetOnceConstraints`.
128133
private fun Field.templateString(
129134
template: String,
130135
placeholders: Map<ErrorPlaceholder, Expression<String>>

java/src/main/kotlin/io/spine/validation/java/MessageStateValidation.kt renamed to java/src/main/kotlin/io/spine/validation/java/protodata/MemberDeclaration.kt

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,16 @@
2424
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2525
*/
2626

27-
package io.spine.validation.java
27+
package io.spine.validation.java.protodata
2828

29-
import io.spine.protodata.ast.TypeName
30-
import io.spine.validation.java.protodata.CodeBlock
29+
import io.spine.protodata.java.AnElement
3130

32-
internal interface MessageStateValidation {
31+
/**
32+
* Represents class level member declaration.
33+
*/
34+
public open class MemberDeclaration(code: String) : AnElement(code)
3335

34-
fun constraints(type: TypeName): List<CodeBlock>
35-
}
36+
// We already need the following children: FieldDeclaration, MethodDeclaration.
37+
// Also, we need the context. So, that instead of `Expression<Message>.call("getField")`
38+
// we could use `Context<Message>.call("getField"). We don't really need an explicit
39+
// `this` everywhere.

0 commit comments

Comments
 (0)