Skip to content

Commit f4af6a3

Browse files
authored
fix: reject gRPC message without a messageId (a2aproject#569)
Failure is reported in the TCK by the tests/optional/features/test_invalid_business_logic.py::test_missing_required_message_fields test. Signed-off-by: Jeff Mesnil <[email protected]>
1 parent 2564040 commit f4af6a3

File tree

2 files changed

+21
-1
lines changed

2 files changed

+21
-1
lines changed

spec-grpc/src/main/java/io/a2a/grpc/mapper/A2ACommonFieldMapper.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
import org.mapstruct.Mapper;
1515
import org.mapstruct.Named;
1616

17+
import io.a2a.spec.InvalidParamsError;
18+
1719
/**
1820
* Common field mapping utilities shared across all mappers.
1921
* <p>
@@ -46,6 +48,24 @@ default String emptyToNull(String value) {
4648
return (value == null || value.isEmpty()) ? null : value;
4749
}
4850

51+
/**
52+
* Validates that a required string field is not null or empty.
53+
* <p>
54+
* Throws an exception if the protobuf string is null or empty.
55+
* Use this with {@code @Mapping(qualifiedByName = "requireNonEmpty")}.
56+
*
57+
* @param value the protobuf string value
58+
* @return the value if not null/empty
59+
* @throws IllegalArgumentException if value is null or empty
60+
*/
61+
@Named("requireNonEmpty")
62+
default String requireNonEmpty(String value) {
63+
if (value == null || value.isEmpty()) {
64+
throw new InvalidParamsError("Required field cannot be null or empty");
65+
}
66+
return value;
67+
}
68+
4969
/**
5070
* Converts null strings to empty strings for protobuf.
5171
* <p>

spec-grpc/src/main/java/io/a2a/grpc/mapper/MessageMapper.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public interface MessageMapper {
3636
* Uses Builder pattern explicitly configured via @BeanMapping.
3737
*/
3838
@BeanMapping(builder = @Builder(buildMethod = "build"))
39-
@Mapping(target = "messageId", source = "messageId", qualifiedByName = "emptyToNull")
39+
@Mapping(target = "messageId", source = "messageId", qualifiedByName = "requireNonEmpty")
4040
@Mapping(target = "contextId", source = "contextId", qualifiedByName = "emptyToNull")
4141
@Mapping(target = "taskId", source = "taskId", qualifiedByName = "emptyToNull")
4242
@Mapping(target = "metadata", source = "metadata", qualifiedByName = "metadataFromProto")

0 commit comments

Comments
 (0)