fix: Don't autogenerate message id (0.3 TCK has a test for a null one)#899
fix: Don't autogenerate message id (0.3 TCK has a test for a null one)#899kabir wants to merge 6 commits into
Conversation
This became apparent since in non-Quarkus environments you have to set a bunch of JVM flags, and also introduce default constructors, which in turn means making fields non-final. Additionally, added default constructors for some CDI beans to work in stricter CDI environments than Quarkus
There was a problem hiding this comment.
Code Review
This pull request refactors several core specification classes in the compat-0.3 module (such as Message_v0_3, Task_v0_3, and various security schemes and parts) from standard classes to Java records. This change updates all getter method invocations to record accessor methods across clients, transports, mappers, and tests. Additionally, a new test infrastructure module tests/server-common is introduced. The review feedback highlights potential NullPointerException risks and validation failures if messageId is null, recommending that messageId be marked as @Nullable in Message_v0_3 and properly null-checked before being set in the protobuf builder in ProtoUtils_v0_3.
| public record Message_v0_3( | ||
| Role role, | ||
| List<Part_v0_3<?>> parts, | ||
| String messageId, | ||
| @Nullable String contextId, | ||
| @Nullable String taskId, | ||
| @Nullable List<String> referenceTaskIds, | ||
| @Nullable Map<String, Object> metadata, | ||
| @Nullable List<String> extensions, | ||
| String kind | ||
| ) implements EventKind_v0_3, StreamingEventKind_v0_3 { | ||
|
|
||
| public static final String KIND = "message"; | ||
|
|
||
| public Message_v0_3 { | ||
| Assert.checkNotNullParam("role", role); | ||
| Assert.checkNotNullParam("parts", parts); | ||
| parts = List.copyOf(parts); | ||
| if (parts.isEmpty()) { | ||
| throw new IllegalArgumentException("Parts cannot be empty"); | ||
| } | ||
| Assert.checkNotNullParam("role", role); | ||
| if (! kind.equals(MESSAGE)) { | ||
| throw new IllegalArgumentException("Invalid Message"); | ||
| } | ||
| Assert.checkNotNullParam("messageId", messageId); | ||
| this.role = role; | ||
| this.parts = parts; | ||
| this.messageId = messageId; | ||
| this.contextId = contextId; | ||
| this.taskId = taskId; | ||
| this.referenceTaskIds = referenceTaskIds; | ||
| this.metadata = metadata; | ||
| this.extensions = extensions; | ||
| this.kind = kind; | ||
| } | ||
|
|
||
| public void check() { | ||
| Assert.checkNotNullParam("kind", kind); | ||
| Assert.checkNotNullParam("parts", parts); | ||
| if (parts.isEmpty()) { | ||
| throw new IllegalArgumentException("Parts cannot be empty"); | ||
| if (kind == null) { | ||
| kind = KIND; | ||
| } | ||
| Assert.checkNotNullParam("role", role); | ||
| if (!kind.equals(MESSAGE)) { | ||
| if (!kind.equals(KIND)) { | ||
| throw new IllegalArgumentException("Invalid Message"); | ||
| } | ||
| Assert.checkNotNullParam("messageId", messageId); | ||
| } | ||
|
|
||
| public Role getRole() { | ||
| return role; | ||
| } | ||
|
|
||
| public List<Part_v0_3<?>> getParts() { | ||
| return parts; | ||
| } | ||
|
|
||
| public String getMessageId() { | ||
| return messageId; | ||
| } | ||
|
|
||
| public String getContextId() { | ||
| return contextId; | ||
| } | ||
|
|
||
| public String getTaskId() { | ||
| return taskId; | ||
| } | ||
|
|
||
| public Map<String, Object> getMetadata() { | ||
| return metadata; | ||
| } | ||
|
|
||
| public void setTaskId(String taskId) { | ||
| this.taskId = taskId; | ||
| } | ||
|
|
||
| public void setContextId(String contextId) { | ||
| this.contextId = contextId; | ||
| } | ||
|
|
||
| public List<String> getReferenceTaskIds() { | ||
| return referenceTaskIds; | ||
| } | ||
|
|
||
| public List<String> getExtensions() { | ||
| return extensions; | ||
| } |
There was a problem hiding this comment.
Since the 0.3 TCK has a test for a null messageId (as mentioned in the PR title), messageId should be annotated with @Nullable and the non-null assertion Assert.checkNotNullParam("messageId", messageId); should be removed from the constructor to prevent unexpected validation failures.
public record Message_v0_3(
Role role,
List<Part_v0_3<?>> parts,
@Nullable String messageId,
@Nullable String contextId,
@Nullable String taskId,
@Nullable List<String> referenceTaskIds,
@Nullable Map<String, Object> metadata,
@Nullable List<String> extensions,
String kind
) implements EventKind_v0_3, StreamingEventKind_v0_3 {
public static final String KIND = "message";
public Message_v0_3 {
Assert.checkNotNullParam("role", role);
Assert.checkNotNullParam("parts", parts);
parts = List.copyOf(parts);
if (parts.isEmpty()) {
throw new IllegalArgumentException("Parts cannot be empty");
}
if (kind == null) {
kind = KIND;
}
if (!kind.equals(KIND)) {
throw new IllegalArgumentException("Invalid Message");
}
}| builder.setMessageId(message.getMessageId()); | ||
| if (message.getContextId() != null) { | ||
| builder.setContextId(message.getContextId()); | ||
| builder.setMessageId(message.messageId()); |
There was a problem hiding this comment.
If messageId can be null, calling builder.setMessageId(message.messageId()) directly will throw a NullPointerException because protobuf's generated setters do not accept null values. A null check should be added here, similar to contextId and taskId.
if (message.messageId() != null) {
builder.setMessageId(message.messageId());
}Signed-off-by: Emmanuel Hugonnet <ehugonne@redhat.com>
Fixing the constructors
Move AgentExecutorProducer_v0_3 from compat-0.3/server-conversion test-jar into a new compat-0.3/tests/server-common module to fix CDI ambiguous dependency errors in downstream consumers that depend on both the v0.3 and v1.0 test-jars. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
No description provided.